blob: 9c3a91e740dc082b2a17f449b4f63ad5edd98366 [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"
lrn@chromium.org1c092762011-05-09 09:42:16 +000033#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000034#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000035#include "execution.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036#include "snapshot.h"
37#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000038#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000040#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000041#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000043static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000053using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000054using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000055using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000056using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000057using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000058using ::v8::FunctionTemplate;
59using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000060using ::v8::HandleScope;
61using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000062using ::v8::Message;
63using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000064using ::v8::Object;
65using ::v8::ObjectTemplate;
66using ::v8::Persistent;
67using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000068using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000069using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000070using ::v8::TryCatch;
71using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000072using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000073using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074
lrn@chromium.org32d961d2010-06-30 09:09:34 +000075namespace i = ::i;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000076
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000077
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000078static void ExpectString(const char* code, const char* expected) {
79 Local<Value> result = CompileRun(code);
80 CHECK(result->IsString());
81 String::AsciiValue ascii(result);
82 CHECK_EQ(expected, *ascii);
83}
84
85
86static void ExpectBoolean(const char* code, bool expected) {
87 Local<Value> result = CompileRun(code);
88 CHECK(result->IsBoolean());
89 CHECK_EQ(expected, result->BooleanValue());
90}
91
92
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000093static void ExpectTrue(const char* code) {
94 ExpectBoolean(code, true);
95}
96
97
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000098static void ExpectFalse(const char* code) {
99 ExpectBoolean(code, false);
100}
101
102
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000103static void ExpectObject(const char* code, Local<Value> expected) {
104 Local<Value> result = CompileRun(code);
105 CHECK(result->Equals(expected));
106}
107
108
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000109static void ExpectUndefined(const char* code) {
110 Local<Value> result = CompileRun(code);
111 CHECK(result->IsUndefined());
112}
113
114
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115static int signature_callback_count;
116static v8::Handle<Value> IncrementingSignatureCallback(
117 const v8::Arguments& args) {
118 ApiTestFuzzer::Fuzz();
119 signature_callback_count++;
120 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
121 for (int i = 0; i < args.Length(); i++)
122 result->Set(v8::Integer::New(i), args[i]);
123 return result;
124}
125
126
127static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
128 ApiTestFuzzer::Fuzz();
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++) {
131 result->Set(v8::Integer::New(i), args[i]);
132 }
133 return result;
134}
135
136
137THREADED_TEST(Handles) {
138 v8::HandleScope scope;
139 Local<Context> local_env;
140 {
141 LocalContext env;
142 local_env = env.local();
143 }
144
145 // Local context should still be live.
146 CHECK(!local_env.IsEmpty());
147 local_env->Enter();
148
149 v8::Handle<v8::Primitive> undef = v8::Undefined();
150 CHECK(!undef.IsEmpty());
151 CHECK(undef->IsUndefined());
152
153 const char* c_source = "1 + 2 + 3";
154 Local<String> source = String::New(c_source);
155 Local<Script> script = Script::Compile(source);
156 CHECK_EQ(6, script->Run()->Int32Value());
157
158 local_env->Exit();
159}
160
161
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162THREADED_TEST(ReceiverSignature) {
163 v8::HandleScope scope;
164 LocalContext env;
165 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
166 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
167 fun->PrototypeTemplate()->Set(
168 v8_str("m"),
169 v8::FunctionTemplate::New(IncrementingSignatureCallback,
170 v8::Handle<Value>(),
171 sig));
172 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
173 signature_callback_count = 0;
174 CompileRun(
175 "var o = new Fun();"
176 "o.m();");
177 CHECK_EQ(1, signature_callback_count);
178 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
179 sub_fun->Inherit(fun);
180 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
181 CompileRun(
182 "var o = new SubFun();"
183 "o.m();");
184 CHECK_EQ(2, signature_callback_count);
185
186 v8::TryCatch try_catch;
187 CompileRun(
188 "var o = { };"
189 "o.m = Fun.prototype.m;"
190 "o.m();");
191 CHECK_EQ(2, signature_callback_count);
192 CHECK(try_catch.HasCaught());
193 try_catch.Reset();
194 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
195 sub_fun->Inherit(fun);
196 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
197 CompileRun(
198 "var o = new UnrelFun();"
199 "o.m = Fun.prototype.m;"
200 "o.m();");
201 CHECK_EQ(2, signature_callback_count);
202 CHECK(try_catch.HasCaught());
203}
204
205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206THREADED_TEST(ArgumentSignature) {
207 v8::HandleScope scope;
208 LocalContext env;
209 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
210 cons->SetClassName(v8_str("Cons"));
211 v8::Handle<v8::Signature> sig =
212 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
213 v8::Handle<v8::FunctionTemplate> fun =
214 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
215 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
216 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
217
218 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000219 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
221 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000222 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
224 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000225 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
227 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
228 cons1->SetClassName(v8_str("Cons1"));
229 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
230 cons2->SetClassName(v8_str("Cons2"));
231 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
232 cons3->SetClassName(v8_str("Cons3"));
233
234 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
235 v8::Handle<v8::Signature> wsig =
236 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
237 v8::Handle<v8::FunctionTemplate> fun2 =
238 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
239
240 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
241 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
242 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
243 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
244 v8::Handle<Value> value4 = CompileRun(
245 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
246 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000247 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248
249 v8::Handle<Value> value5 = CompileRun(
250 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000251 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
253 v8::Handle<Value> value6 = CompileRun(
254 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000255 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256
257 v8::Handle<Value> value7 = CompileRun(
258 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
259 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000260 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000261
262 v8::Handle<Value> value8 = CompileRun(
263 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000264 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000265}
266
267
268THREADED_TEST(HulIgennem) {
269 v8::HandleScope scope;
270 LocalContext env;
271 v8::Handle<v8::Primitive> undef = v8::Undefined();
272 Local<String> undef_str = undef->ToString();
273 char* value = i::NewArray<char>(undef_str->Length() + 1);
274 undef_str->WriteAscii(value);
275 CHECK_EQ(0, strcmp(value, "undefined"));
276 i::DeleteArray(value);
277}
278
279
280THREADED_TEST(Access) {
281 v8::HandleScope scope;
282 LocalContext env;
283 Local<v8::Object> obj = v8::Object::New();
284 Local<Value> foo_before = obj->Get(v8_str("foo"));
285 CHECK(foo_before->IsUndefined());
286 Local<String> bar_str = v8_str("bar");
287 obj->Set(v8_str("foo"), bar_str);
288 Local<Value> foo_after = obj->Get(v8_str("foo"));
289 CHECK(!foo_after->IsUndefined());
290 CHECK(foo_after->IsString());
291 CHECK_EQ(bar_str, foo_after);
292}
293
294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000295THREADED_TEST(AccessElement) {
296 v8::HandleScope scope;
297 LocalContext env;
298 Local<v8::Object> obj = v8::Object::New();
299 Local<Value> before = obj->Get(1);
300 CHECK(before->IsUndefined());
301 Local<String> bar_str = v8_str("bar");
302 obj->Set(1, bar_str);
303 Local<Value> after = obj->Get(1);
304 CHECK(!after->IsUndefined());
305 CHECK(after->IsString());
306 CHECK_EQ(bar_str, after);
307
308 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
309 CHECK_EQ(v8_str("a"), value->Get(0));
310 CHECK_EQ(v8_str("b"), value->Get(1));
311}
312
313
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314THREADED_TEST(Script) {
315 v8::HandleScope scope;
316 LocalContext env;
317 const char* c_source = "1 + 2 + 3";
318 Local<String> source = String::New(c_source);
319 Local<Script> script = Script::Compile(source);
320 CHECK_EQ(6, script->Run()->Int32Value());
321}
322
323
324static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000325 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000326 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000327 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000328 return converted;
329}
330
331
332class TestResource: public String::ExternalStringResource {
333 public:
334 static int dispose_count;
335
336 explicit TestResource(uint16_t* data)
337 : data_(data), length_(0) {
338 while (data[length_]) ++length_;
339 }
340
341 ~TestResource() {
342 i::DeleteArray(data_);
343 ++dispose_count;
344 }
345
346 const uint16_t* data() const {
347 return data_;
348 }
349
350 size_t length() const {
351 return length_;
352 }
353 private:
354 uint16_t* data_;
355 size_t length_;
356};
357
358
359int TestResource::dispose_count = 0;
360
361
362class TestAsciiResource: public String::ExternalAsciiStringResource {
363 public:
364 static int dispose_count;
365
ager@chromium.org5ec48922009-05-05 07:25:34 +0000366 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367 : data_(data),
368 length_(strlen(data)) { }
369
370 ~TestAsciiResource() {
371 i::DeleteArray(data_);
372 ++dispose_count;
373 }
374
375 const char* data() const {
376 return data_;
377 }
378
379 size_t length() const {
380 return length_;
381 }
382 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000383 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384 size_t length_;
385};
386
387
388int TestAsciiResource::dispose_count = 0;
389
390
391THREADED_TEST(ScriptUsingStringResource) {
392 TestResource::dispose_count = 0;
393 const char* c_source = "1 + 2 * 3";
394 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
395 {
396 v8::HandleScope scope;
397 LocalContext env;
398 TestResource* resource = new TestResource(two_byte_source);
399 Local<String> source = String::NewExternal(resource);
400 Local<Script> script = Script::Compile(source);
401 Local<Value> value = script->Run();
402 CHECK(value->IsNumber());
403 CHECK_EQ(7, value->Int32Value());
404 CHECK(source->IsExternal());
405 CHECK_EQ(resource,
406 static_cast<TestResource*>(source->GetExternalStringResource()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408 CHECK_EQ(0, TestResource::dispose_count);
409 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000410 v8::internal::Isolate::Current()->compilation_cache()->Clear();
411 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000412 CHECK_EQ(1, TestResource::dispose_count);
413}
414
415
416THREADED_TEST(ScriptUsingAsciiStringResource) {
417 TestAsciiResource::dispose_count = 0;
418 const char* c_source = "1 + 2 * 3";
419 {
420 v8::HandleScope scope;
421 LocalContext env;
422 Local<String> source =
423 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
424 Local<Script> script = Script::Compile(source);
425 Local<Value> value = script->Run();
426 CHECK(value->IsNumber());
427 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000429 CHECK_EQ(0, TestAsciiResource::dispose_count);
430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 i::Isolate::Current()->compilation_cache()->Clear();
432 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000433 CHECK_EQ(1, TestAsciiResource::dispose_count);
434}
435
436
ager@chromium.org6f10e412009-02-13 10:11:16 +0000437THREADED_TEST(ScriptMakingExternalString) {
438 TestResource::dispose_count = 0;
439 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
440 {
441 v8::HandleScope scope;
442 LocalContext env;
443 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000444 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
446 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000447 bool success = source->MakeExternal(new TestResource(two_byte_source));
448 CHECK(success);
449 Local<Script> script = Script::Compile(source);
450 Local<Value> value = script->Run();
451 CHECK(value->IsNumber());
452 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000454 CHECK_EQ(0, TestResource::dispose_count);
455 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 i::Isolate::Current()->compilation_cache()->Clear();
457 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000458 CHECK_EQ(1, TestResource::dispose_count);
459}
460
461
462THREADED_TEST(ScriptMakingExternalAsciiString) {
463 TestAsciiResource::dispose_count = 0;
464 const char* c_source = "1 + 2 * 3";
465 {
466 v8::HandleScope scope;
467 LocalContext env;
468 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000469 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
471 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000472 bool success = source->MakeExternal(
473 new TestAsciiResource(i::StrDup(c_source)));
474 CHECK(success);
475 Local<Script> script = Script::Compile(source);
476 Local<Value> value = script->Run();
477 CHECK(value->IsNumber());
478 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000480 CHECK_EQ(0, TestAsciiResource::dispose_count);
481 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 i::Isolate::Current()->compilation_cache()->Clear();
483 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000484 CHECK_EQ(1, TestAsciiResource::dispose_count);
485}
486
487
ager@chromium.org5c838252010-02-19 08:53:10 +0000488TEST(MakingExternalStringConditions) {
489 v8::HandleScope scope;
490 LocalContext env;
491
492 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 HEAP->CollectGarbage(i::NEW_SPACE);
494 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000495
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000496 uint16_t* two_byte_string = AsciiToTwoByteString("small");
497 Local<String> small_string = String::New(two_byte_string);
498 i::DeleteArray(two_byte_string);
499
ager@chromium.org5c838252010-02-19 08:53:10 +0000500 // We should refuse to externalize newly created small string.
501 CHECK(!small_string->CanMakeExternal());
502 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
504 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000505 // Old space strings should be accepted.
506 CHECK(small_string->CanMakeExternal());
507
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000508 two_byte_string = AsciiToTwoByteString("small 2");
509 small_string = String::New(two_byte_string);
510 i::DeleteArray(two_byte_string);
511
ager@chromium.org5c838252010-02-19 08:53:10 +0000512 // We should refuse externalizing newly created small string.
513 CHECK(!small_string->CanMakeExternal());
514 for (int i = 0; i < 100; i++) {
515 String::Value value(small_string);
516 }
517 // Frequently used strings should be accepted.
518 CHECK(small_string->CanMakeExternal());
519
520 const int buf_size = 10 * 1024;
521 char* buf = i::NewArray<char>(buf_size);
522 memset(buf, 'a', buf_size);
523 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000524
525 two_byte_string = AsciiToTwoByteString(buf);
526 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000527 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000528 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000529 // Large strings should be immediately accepted.
530 CHECK(large_string->CanMakeExternal());
531}
532
533
534TEST(MakingExternalAsciiStringConditions) {
535 v8::HandleScope scope;
536 LocalContext env;
537
538 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HEAP->CollectGarbage(i::NEW_SPACE);
540 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000541
542 Local<String> small_string = String::New("small");
543 // We should refuse to externalize newly created small string.
544 CHECK(!small_string->CanMakeExternal());
545 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
547 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000548 // Old space strings should be accepted.
549 CHECK(small_string->CanMakeExternal());
550
551 small_string = String::New("small 2");
552 // We should refuse externalizing newly created small string.
553 CHECK(!small_string->CanMakeExternal());
554 for (int i = 0; i < 100; i++) {
555 String::Value value(small_string);
556 }
557 // Frequently used strings should be accepted.
558 CHECK(small_string->CanMakeExternal());
559
560 const int buf_size = 10 * 1024;
561 char* buf = i::NewArray<char>(buf_size);
562 memset(buf, 'a', buf_size);
563 buf[buf_size - 1] = '\0';
564 Local<String> large_string = String::New(buf);
565 i::DeleteArray(buf);
566 // Large strings should be immediately accepted.
567 CHECK(large_string->CanMakeExternal());
568}
569
570
ager@chromium.org6f10e412009-02-13 10:11:16 +0000571THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000572 {
573 v8::HandleScope scope;
574 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
575 Local<String> string =
576 String::NewExternal(new TestResource(two_byte_string));
577 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
578 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
580 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
581 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000582 CHECK(isymbol->IsSymbol());
583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HEAP->CollectAllGarbage(false);
585 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000586}
587
588
589THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000590 {
591 v8::HandleScope scope;
592 const char* one_byte_string = "test string";
593 Local<String> string = String::NewExternal(
594 new TestAsciiResource(i::StrDup(one_byte_string)));
595 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
598 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
599 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000600 CHECK(isymbol->IsSymbol());
601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 HEAP->CollectAllGarbage(false);
603 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000604}
605
606
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000607THREADED_TEST(ScavengeExternalString) {
608 TestResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000609 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 {
611 v8::HandleScope scope;
612 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
613 Local<String> string =
614 String::NewExternal(new TestResource(two_byte_string));
615 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 HEAP->CollectGarbage(i::NEW_SPACE);
617 in_new_space = HEAP->InNewSpace(*istring);
618 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 CHECK_EQ(0, TestResource::dispose_count);
620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CHECK_EQ(1, TestResource::dispose_count);
623}
624
625
626THREADED_TEST(ScavengeExternalAsciiString) {
627 TestAsciiResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000628 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629 {
630 v8::HandleScope scope;
631 const char* one_byte_string = "test string";
632 Local<String> string = String::NewExternal(
633 new TestAsciiResource(i::StrDup(one_byte_string)));
634 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 HEAP->CollectGarbage(i::NEW_SPACE);
636 in_new_space = HEAP->InNewSpace(*istring);
637 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638 CHECK_EQ(0, TestAsciiResource::dispose_count);
639 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 CHECK_EQ(1, TestAsciiResource::dispose_count);
642}
643
644
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000645class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
646 public:
647 static int dispose_calls;
648
649 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
650 : TestAsciiResource(data),
651 dispose_(dispose) { }
652
653 void Dispose() {
654 ++dispose_calls;
655 if (dispose_) delete this;
656 }
657 private:
658 bool dispose_;
659};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000660
661
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000663
664
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000665TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000666 const char* c_source = "1 + 2 * 3";
667
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000668 // Use a stack allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000669 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000670 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000672 {
673 v8::HandleScope scope;
674 LocalContext env;
675 Local<String> source = String::NewExternal(&res_stack);
676 Local<Script> script = Script::Compile(source);
677 Local<Value> value = script->Run();
678 CHECK(value->IsNumber());
679 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000680 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000681 CHECK_EQ(0, TestAsciiResource::dispose_count);
682 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000683 i::Isolate::Current()->compilation_cache()->Clear();
684 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000685 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000686 CHECK_EQ(0, TestAsciiResource::dispose_count);
687
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688 // Use a heap allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000689 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691 TestAsciiResource* res_heap =
692 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000693 {
694 v8::HandleScope scope;
695 LocalContext env;
696 Local<String> source = String::NewExternal(res_heap);
697 Local<Script> script = Script::Compile(source);
698 Local<Value> value = script->Run();
699 CHECK(value->IsNumber());
700 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000702 CHECK_EQ(0, TestAsciiResource::dispose_count);
703 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000704 i::Isolate::Current()->compilation_cache()->Clear();
705 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000706 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000707 CHECK_EQ(1, TestAsciiResource::dispose_count);
708}
709
710
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000711THREADED_TEST(StringConcat) {
712 {
713 v8::HandleScope scope;
714 LocalContext env;
715 const char* one_byte_string_1 = "function a_times_t";
716 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000723
724 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725 Local<String> right = String::New(two_byte_source);
726 i::DeleteArray(two_byte_source);
727
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000728 Local<String> source = String::Concat(left, right);
729 right = String::NewExternal(
730 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731 source = String::Concat(source, right);
732 right = String::NewExternal(
733 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734 source = String::Concat(source, right);
735 right = v8_str(one_byte_string_2);
736 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000737
738 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739 right = String::New(two_byte_source);
740 i::DeleteArray(two_byte_source);
741
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000742 source = String::Concat(source, right);
743 right = String::NewExternal(
744 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745 source = String::Concat(source, right);
746 Local<Script> script = Script::Compile(source);
747 Local<Value> value = script->Run();
748 CHECK(value->IsNumber());
749 CHECK_EQ(68, value->Int32Value());
750 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 i::Isolate::Current()->compilation_cache()->Clear();
752 HEAP->CollectAllGarbage(false);
753 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000754}
755
756
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757THREADED_TEST(GlobalProperties) {
758 v8::HandleScope scope;
759 LocalContext env;
760 v8::Handle<v8::Object> global = env->Global();
761 global->Set(v8_str("pi"), v8_num(3.1415926));
762 Local<Value> pi = global->Get(v8_str("pi"));
763 CHECK_EQ(3.1415926, pi->NumberValue());
764}
765
766
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768 ApiTestFuzzer::Fuzz();
769 return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774 ApiTestFuzzer::Fuzz();
775 args.This()->Set(v8_str("x"), v8_num(1));
776 args.This()->Set(v8_str("y"), v8_num(2));
777 return args.This();
778}
779
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781 ApiTestFuzzer::Fuzz();
782 return v8_num(239);
783}
784
785
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000786THREADED_TEST(FunctionTemplate) {
787 v8::HandleScope scope;
788 LocalContext env;
789 {
790 Local<v8::FunctionTemplate> fun_templ =
791 v8::FunctionTemplate::New(handle_call);
792 Local<Function> fun = fun_templ->GetFunction();
793 env->Global()->Set(v8_str("obj"), fun);
794 Local<Script> script = v8_compile("obj()");
795 CHECK_EQ(102, script->Run()->Int32Value());
796 }
797 // Use SetCallHandler to initialize a function template, should work like the
798 // previous one.
799 {
800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801 fun_templ->SetCallHandler(handle_call);
802 Local<Function> fun = fun_templ->GetFunction();
803 env->Global()->Set(v8_str("obj"), fun);
804 Local<Script> script = v8_compile("obj()");
805 CHECK_EQ(102, script->Run()->Int32Value());
806 }
807 // Test constructor calls.
808 {
809 Local<v8::FunctionTemplate> fun_templ =
810 v8::FunctionTemplate::New(construct_call);
811 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000812 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813 Local<Function> fun = fun_templ->GetFunction();
814 env->Global()->Set(v8_str("obj"), fun);
815 Local<Script> script = v8_compile("var s = new obj(); s.x");
816 CHECK_EQ(1, script->Run()->Int32Value());
817
818 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000820
821 result = v8_compile("(new obj()).m")->Run();
822 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823 }
824}
825
826
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000827static void* expected_ptr;
828static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829 void* ptr = v8::External::Unwrap(args.Data());
830 CHECK_EQ(expected_ptr, ptr);
831 return v8::Boolean::New(true);
832}
833
834
835static void TestExternalPointerWrapping() {
836 v8::HandleScope scope;
837 LocalContext env;
838
839 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841 v8::Handle<v8::Object> obj = v8::Object::New();
842 obj->Set(v8_str("func"),
843 v8::FunctionTemplate::New(callback, data)->GetFunction());
844 env->Global()->Set(v8_str("obj"), obj);
845
846 CHECK(CompileRun(
847 "function foo() {\n"
848 " for (var i = 0; i < 13; i++) obj.func();\n"
849 "}\n"
850 "foo(), true")->BooleanValue());
851}
852
853
854THREADED_TEST(ExternalWrap) {
855 // Check heap allocated object.
856 int* ptr = new int;
857 expected_ptr = ptr;
858 TestExternalPointerWrapping();
859 delete ptr;
860
861 // Check stack allocated object.
862 int foo;
863 expected_ptr = &foo;
864 TestExternalPointerWrapping();
865
866 // Check not aligned addresses.
867 const int n = 100;
868 char* s = new char[n];
869 for (int i = 0; i < n; i++) {
870 expected_ptr = s + i;
871 TestExternalPointerWrapping();
872 }
873
874 delete[] s;
875
876 // Check several invalid addresses.
877 expected_ptr = reinterpret_cast<void*>(1);
878 TestExternalPointerWrapping();
879
880 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881 TestExternalPointerWrapping();
882
883 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884 TestExternalPointerWrapping();
885
886#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000887 // Check a value with a leading 1 bit in x64 Smi encoding.
888 expected_ptr = reinterpret_cast<void*>(0x400000000);
889 TestExternalPointerWrapping();
890
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000891 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892 TestExternalPointerWrapping();
893
894 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895 TestExternalPointerWrapping();
896#endif
897}
898
899
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000900THREADED_TEST(FindInstanceInPrototypeChain) {
901 v8::HandleScope scope;
902 LocalContext env;
903
904 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907 derived->Inherit(base);
908
909 Local<v8::Function> base_function = base->GetFunction();
910 Local<v8::Function> derived_function = derived->GetFunction();
911 Local<v8::Function> other_function = other->GetFunction();
912
913 Local<v8::Object> base_instance = base_function->NewInstance();
914 Local<v8::Object> derived_instance = derived_function->NewInstance();
915 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916 Local<v8::Object> other_instance = other_function->NewInstance();
917 derived_instance2->Set(v8_str("__proto__"), derived_instance);
918 other_instance->Set(v8_str("__proto__"), derived_instance2);
919
920 // base_instance is only an instance of base.
921 CHECK_EQ(base_instance,
922 base_instance->FindInstanceInPrototypeChain(base));
923 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925
926 // derived_instance is an instance of base and derived.
927 CHECK_EQ(derived_instance,
928 derived_instance->FindInstanceInPrototypeChain(base));
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(derived));
931 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932
933 // other_instance is an instance of other and its immediate
934 // prototype derived_instance2 is an instance of base and derived.
935 // Note, derived_instance is an instance of base and derived too,
936 // but it comes after derived_instance2 in the prototype chain of
937 // other_instance.
938 CHECK_EQ(derived_instance2,
939 other_instance->FindInstanceInPrototypeChain(base));
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(derived));
942 CHECK_EQ(other_instance,
943 other_instance->FindInstanceInPrototypeChain(other));
944}
945
946
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000947THREADED_TEST(TinyInteger) {
948 v8::HandleScope scope;
949 LocalContext env;
950 int32_t value = 239;
951 Local<v8::Integer> value_obj = v8::Integer::New(value);
952 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953}
954
955
956THREADED_TEST(BigSmiInteger) {
957 v8::HandleScope scope;
958 LocalContext env;
959 int32_t value = i::Smi::kMaxValue;
960 // We cannot add one to a Smi::kMaxValue without wrapping.
961 if (i::kSmiValueSize < 32) {
962 CHECK(i::Smi::IsValid(value));
963 CHECK(!i::Smi::IsValid(value + 1));
964 Local<v8::Integer> value_obj = v8::Integer::New(value);
965 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966 }
967}
968
969
970THREADED_TEST(BigInteger) {
971 v8::HandleScope scope;
972 LocalContext env;
973 // We cannot add one to a Smi::kMaxValue without wrapping.
974 if (i::kSmiValueSize < 32) {
975 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976 // The code will not be run in that case, due to the "if" guard.
977 int32_t value =
978 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979 CHECK(value > i::Smi::kMaxValue);
980 CHECK(!i::Smi::IsValid(value));
981 Local<v8::Integer> value_obj = v8::Integer::New(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983 }
984}
985
986
987THREADED_TEST(TinyUnsignedInteger) {
988 v8::HandleScope scope;
989 LocalContext env;
990 uint32_t value = 239;
991 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993}
994
995
996THREADED_TEST(BigUnsignedSmiInteger) {
997 v8::HandleScope scope;
998 LocalContext env;
999 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000 CHECK(i::Smi::IsValid(value));
1001 CHECK(!i::Smi::IsValid(value + 1));
1002 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004}
1005
1006
1007THREADED_TEST(BigUnsignedInteger) {
1008 v8::HandleScope scope;
1009 LocalContext env;
1010 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012 CHECK(!i::Smi::IsValid(value));
1013 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015}
1016
1017
1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019 v8::HandleScope scope;
1020 LocalContext env;
1021 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022 uint32_t value = INT32_MAX_AS_UINT + 1;
1023 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1024 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026}
1027
1028
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001029THREADED_TEST(Number) {
1030 v8::HandleScope scope;
1031 LocalContext env;
1032 double PI = 3.1415926;
1033 Local<v8::Number> pi_obj = v8::Number::New(PI);
1034 CHECK_EQ(PI, pi_obj->NumberValue());
1035}
1036
1037
1038THREADED_TEST(ToNumber) {
1039 v8::HandleScope scope;
1040 LocalContext env;
1041 Local<String> str = v8_str("3.1415926");
1042 CHECK_EQ(3.1415926, str->NumberValue());
1043 v8::Handle<v8::Boolean> t = v8::True();
1044 CHECK_EQ(1.0, t->NumberValue());
1045 v8::Handle<v8::Boolean> f = v8::False();
1046 CHECK_EQ(0.0, f->NumberValue());
1047}
1048
1049
1050THREADED_TEST(Date) {
1051 v8::HandleScope scope;
1052 LocalContext env;
1053 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001054 Local<Value> date = v8::Date::New(PI);
1055 CHECK_EQ(3.0, date->NumberValue());
1056 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1057 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001058}
1059
1060
1061THREADED_TEST(Boolean) {
1062 v8::HandleScope scope;
1063 LocalContext env;
1064 v8::Handle<v8::Boolean> t = v8::True();
1065 CHECK(t->Value());
1066 v8::Handle<v8::Boolean> f = v8::False();
1067 CHECK(!f->Value());
1068 v8::Handle<v8::Primitive> u = v8::Undefined();
1069 CHECK(!u->BooleanValue());
1070 v8::Handle<v8::Primitive> n = v8::Null();
1071 CHECK(!n->BooleanValue());
1072 v8::Handle<String> str1 = v8_str("");
1073 CHECK(!str1->BooleanValue());
1074 v8::Handle<String> str2 = v8_str("x");
1075 CHECK(str2->BooleanValue());
1076 CHECK(!v8::Number::New(0)->BooleanValue());
1077 CHECK(v8::Number::New(-1)->BooleanValue());
1078 CHECK(v8::Number::New(1)->BooleanValue());
1079 CHECK(v8::Number::New(42)->BooleanValue());
1080 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1081}
1082
1083
1084static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1085 ApiTestFuzzer::Fuzz();
1086 return v8_num(13.4);
1087}
1088
1089
1090static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1091 ApiTestFuzzer::Fuzz();
1092 return v8_num(876);
1093}
1094
1095
1096THREADED_TEST(GlobalPrototype) {
1097 v8::HandleScope scope;
1098 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1099 func_templ->PrototypeTemplate()->Set(
1100 "dummy",
1101 v8::FunctionTemplate::New(DummyCallHandler));
1102 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1103 templ->Set("x", v8_num(200));
1104 templ->SetAccessor(v8_str("m"), GetM);
1105 LocalContext env(0, templ);
1106 v8::Handle<v8::Object> obj = env->Global();
1107 v8::Handle<Script> script = v8_compile("dummy()");
1108 v8::Handle<Value> result = script->Run();
1109 CHECK_EQ(13.4, result->NumberValue());
1110 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1111 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1112}
1113
1114
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001115THREADED_TEST(ObjectTemplate) {
1116 v8::HandleScope scope;
1117 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1118 templ1->Set("x", v8_num(10));
1119 templ1->Set("y", v8_num(13));
1120 LocalContext env;
1121 Local<v8::Object> instance1 = templ1->NewInstance();
1122 env->Global()->Set(v8_str("p"), instance1);
1123 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1124 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1125 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1126 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1127 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1128 templ2->Set("a", v8_num(12));
1129 templ2->Set("b", templ1);
1130 Local<v8::Object> instance2 = templ2->NewInstance();
1131 env->Global()->Set(v8_str("q"), instance2);
1132 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1133 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1134 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1135 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1136}
1137
1138
1139static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1140 ApiTestFuzzer::Fuzz();
1141 return v8_num(17.2);
1142}
1143
1144
1145static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1146 ApiTestFuzzer::Fuzz();
1147 return v8_num(15.2);
1148}
1149
1150
1151THREADED_TEST(DescriptorInheritance) {
1152 v8::HandleScope scope;
1153 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1154 super->PrototypeTemplate()->Set("flabby",
1155 v8::FunctionTemplate::New(GetFlabby));
1156 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1157
1158 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1159
1160 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1161 base1->Inherit(super);
1162 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1163
1164 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1165 base2->Inherit(super);
1166 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1167
1168 LocalContext env;
1169
1170 env->Global()->Set(v8_str("s"), super->GetFunction());
1171 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1172 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1173
1174 // Checks right __proto__ chain.
1175 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1176 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1177
1178 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1179
1180 // Instance accessor should not be visible on function object or its prototype
1181 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1182 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1183 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1184
1185 env->Global()->Set(v8_str("obj"),
1186 base1->GetFunction()->NewInstance());
1187 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1188 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1189 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1190 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1191 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1192
1193 env->Global()->Set(v8_str("obj2"),
1194 base2->GetFunction()->NewInstance());
1195 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1196 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1197 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1198 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1199 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1200
1201 // base1 and base2 cannot cross reference to each's prototype
1202 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1203 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1204}
1205
1206
1207int echo_named_call_count;
1208
1209
1210static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1211 const AccessorInfo& info) {
1212 ApiTestFuzzer::Fuzz();
1213 CHECK_EQ(v8_str("data"), info.Data());
1214 echo_named_call_count++;
1215 return name;
1216}
1217
1218
1219THREADED_TEST(NamedPropertyHandlerGetter) {
1220 echo_named_call_count = 0;
1221 v8::HandleScope scope;
1222 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1223 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1224 0, 0, 0, 0,
1225 v8_str("data"));
1226 LocalContext env;
1227 env->Global()->Set(v8_str("obj"),
1228 templ->GetFunction()->NewInstance());
1229 CHECK_EQ(echo_named_call_count, 0);
1230 v8_compile("obj.x")->Run();
1231 CHECK_EQ(echo_named_call_count, 1);
1232 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1233 v8::Handle<Value> str = CompileRun(code);
1234 String::AsciiValue value(str);
1235 CHECK_EQ(*value, "oddlepoddle");
1236 // Check default behavior
1237 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1238 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1239 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1240}
1241
1242
1243int echo_indexed_call_count = 0;
1244
1245
1246static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1247 const AccessorInfo& info) {
1248 ApiTestFuzzer::Fuzz();
1249 CHECK_EQ(v8_num(637), info.Data());
1250 echo_indexed_call_count++;
1251 return v8_num(index);
1252}
1253
1254
1255THREADED_TEST(IndexedPropertyHandlerGetter) {
1256 v8::HandleScope scope;
1257 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1258 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1259 0, 0, 0, 0,
1260 v8_num(637));
1261 LocalContext env;
1262 env->Global()->Set(v8_str("obj"),
1263 templ->GetFunction()->NewInstance());
1264 Local<Script> script = v8_compile("obj[900]");
1265 CHECK_EQ(script->Run()->Int32Value(), 900);
1266}
1267
1268
1269v8::Handle<v8::Object> bottom;
1270
1271static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1272 uint32_t index,
1273 const AccessorInfo& info) {
1274 ApiTestFuzzer::Fuzz();
1275 CHECK(info.This()->Equals(bottom));
1276 return v8::Handle<Value>();
1277}
1278
1279static v8::Handle<Value> CheckThisNamedPropertyHandler(
1280 Local<String> name,
1281 const AccessorInfo& info) {
1282 ApiTestFuzzer::Fuzz();
1283 CHECK(info.This()->Equals(bottom));
1284 return v8::Handle<Value>();
1285}
1286
1287
1288v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1289 Local<Value> value,
1290 const AccessorInfo& info) {
1291 ApiTestFuzzer::Fuzz();
1292 CHECK(info.This()->Equals(bottom));
1293 return v8::Handle<Value>();
1294}
1295
1296
1297v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1298 Local<Value> value,
1299 const AccessorInfo& info) {
1300 ApiTestFuzzer::Fuzz();
1301 CHECK(info.This()->Equals(bottom));
1302 return v8::Handle<Value>();
1303}
1304
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001305v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001306 uint32_t index,
1307 const AccessorInfo& info) {
1308 ApiTestFuzzer::Fuzz();
1309 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001310 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001311}
1312
1313
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001314v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001315 const AccessorInfo& info) {
1316 ApiTestFuzzer::Fuzz();
1317 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001318 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001319}
1320
1321
1322v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1323 uint32_t index,
1324 const AccessorInfo& info) {
1325 ApiTestFuzzer::Fuzz();
1326 CHECK(info.This()->Equals(bottom));
1327 return v8::Handle<v8::Boolean>();
1328}
1329
1330
1331v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1332 Local<String> property,
1333 const AccessorInfo& info) {
1334 ApiTestFuzzer::Fuzz();
1335 CHECK(info.This()->Equals(bottom));
1336 return v8::Handle<v8::Boolean>();
1337}
1338
1339
1340v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1341 const AccessorInfo& info) {
1342 ApiTestFuzzer::Fuzz();
1343 CHECK(info.This()->Equals(bottom));
1344 return v8::Handle<v8::Array>();
1345}
1346
1347
1348v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1349 const AccessorInfo& info) {
1350 ApiTestFuzzer::Fuzz();
1351 CHECK(info.This()->Equals(bottom));
1352 return v8::Handle<v8::Array>();
1353}
1354
1355
1356THREADED_TEST(PropertyHandlerInPrototype) {
1357 v8::HandleScope scope;
1358 LocalContext env;
1359
1360 // Set up a prototype chain with three interceptors.
1361 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1362 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1363 CheckThisIndexedPropertyHandler,
1364 CheckThisIndexedPropertySetter,
1365 CheckThisIndexedPropertyQuery,
1366 CheckThisIndexedPropertyDeleter,
1367 CheckThisIndexedPropertyEnumerator);
1368
1369 templ->InstanceTemplate()->SetNamedPropertyHandler(
1370 CheckThisNamedPropertyHandler,
1371 CheckThisNamedPropertySetter,
1372 CheckThisNamedPropertyQuery,
1373 CheckThisNamedPropertyDeleter,
1374 CheckThisNamedPropertyEnumerator);
1375
1376 bottom = templ->GetFunction()->NewInstance();
1377 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1378 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1379
1380 bottom->Set(v8_str("__proto__"), middle);
1381 middle->Set(v8_str("__proto__"), top);
1382 env->Global()->Set(v8_str("obj"), bottom);
1383
1384 // Indexed and named get.
1385 Script::Compile(v8_str("obj[0]"))->Run();
1386 Script::Compile(v8_str("obj.x"))->Run();
1387
1388 // Indexed and named set.
1389 Script::Compile(v8_str("obj[1] = 42"))->Run();
1390 Script::Compile(v8_str("obj.y = 42"))->Run();
1391
1392 // Indexed and named query.
1393 Script::Compile(v8_str("0 in obj"))->Run();
1394 Script::Compile(v8_str("'x' in obj"))->Run();
1395
1396 // Indexed and named deleter.
1397 Script::Compile(v8_str("delete obj[0]"))->Run();
1398 Script::Compile(v8_str("delete obj.x"))->Run();
1399
1400 // Enumerators.
1401 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1402}
1403
1404
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001405static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1406 const AccessorInfo& info) {
1407 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001408 if (v8_str("pre")->Equals(key)) {
1409 return v8_str("PrePropertyHandler: pre");
1410 }
1411 return v8::Handle<String>();
1412}
1413
1414
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001415static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1416 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001417 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001418 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001419 }
1420
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001421 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001422}
1423
1424
1425THREADED_TEST(PrePropertyHandler) {
1426 v8::HandleScope scope;
1427 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1428 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1429 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001430 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001431 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001432 Script::Compile(v8_str(
1433 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1434 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1435 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1436 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1437 CHECK_EQ(v8_str("Object: on"), result_on);
1438 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1439 CHECK(result_post.IsEmpty());
1440}
1441
1442
ager@chromium.org870a0b62008-11-04 11:43:05 +00001443THREADED_TEST(UndefinedIsNotEnumerable) {
1444 v8::HandleScope scope;
1445 LocalContext env;
1446 v8::Handle<Value> result = Script::Compile(v8_str(
1447 "this.propertyIsEnumerable(undefined)"))->Run();
1448 CHECK(result->IsFalse());
1449}
1450
1451
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001452v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001453static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001454
1455
1456static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1457 ApiTestFuzzer::Fuzz();
1458 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1459 if (depth == kTargetRecursionDepth) return v8::Undefined();
1460 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1461 return call_recursively_script->Run();
1462}
1463
1464
1465static v8::Handle<Value> CallFunctionRecursivelyCall(
1466 const v8::Arguments& args) {
1467 ApiTestFuzzer::Fuzz();
1468 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1469 if (depth == kTargetRecursionDepth) {
1470 printf("[depth = %d]\n", depth);
1471 return v8::Undefined();
1472 }
1473 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1474 v8::Handle<Value> function =
1475 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001476 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001477}
1478
1479
1480THREADED_TEST(DeepCrossLanguageRecursion) {
1481 v8::HandleScope scope;
1482 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1483 global->Set(v8_str("callScriptRecursively"),
1484 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1485 global->Set(v8_str("callFunctionRecursively"),
1486 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1487 LocalContext env(NULL, global);
1488
1489 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1490 call_recursively_script = v8_compile("callScriptRecursively()");
1491 v8::Handle<Value> result = call_recursively_script->Run();
1492 call_recursively_script = v8::Handle<Script>();
1493
1494 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1495 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1496}
1497
1498
1499static v8::Handle<Value>
1500 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1501 ApiTestFuzzer::Fuzz();
1502 return v8::ThrowException(key);
1503}
1504
1505
1506static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1507 Local<Value>,
1508 const AccessorInfo&) {
1509 v8::ThrowException(key);
1510 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1511}
1512
1513
1514THREADED_TEST(CallbackExceptionRegression) {
1515 v8::HandleScope scope;
1516 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1517 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1518 ThrowingPropertyHandlerSet);
1519 LocalContext env;
1520 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1521 v8::Handle<Value> otto = Script::Compile(v8_str(
1522 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1523 CHECK_EQ(v8_str("otto"), otto);
1524 v8::Handle<Value> netto = Script::Compile(v8_str(
1525 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1526 CHECK_EQ(v8_str("netto"), netto);
1527}
1528
1529
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001530THREADED_TEST(FunctionPrototype) {
1531 v8::HandleScope scope;
1532 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1533 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1534 LocalContext env;
1535 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1536 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1537 CHECK_EQ(script->Run()->Int32Value(), 321);
1538}
1539
1540
1541THREADED_TEST(InternalFields) {
1542 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001543 LocalContext env;
1544
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001545 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1546 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1547 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001548 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1549 CHECK_EQ(1, obj->InternalFieldCount());
1550 CHECK(obj->GetInternalField(0)->IsUndefined());
1551 obj->SetInternalField(0, v8_num(17));
1552 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1553}
1554
1555
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001556THREADED_TEST(GlobalObjectInternalFields) {
1557 v8::HandleScope scope;
1558 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1559 global_template->SetInternalFieldCount(1);
1560 LocalContext env(NULL, global_template);
1561 v8::Handle<v8::Object> global_proxy = env->Global();
1562 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1563 CHECK_EQ(1, global->InternalFieldCount());
1564 CHECK(global->GetInternalField(0)->IsUndefined());
1565 global->SetInternalField(0, v8_num(17));
1566 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1567}
1568
1569
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001570THREADED_TEST(InternalFieldsNativePointers) {
1571 v8::HandleScope scope;
1572 LocalContext env;
1573
1574 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1575 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1576 instance_templ->SetInternalFieldCount(1);
1577 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1578 CHECK_EQ(1, obj->InternalFieldCount());
1579 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1580
1581 char* data = new char[100];
1582
1583 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001584 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001585 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001586 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001587
1588 // Check reading and writing aligned pointers.
1589 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001591 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1592
1593 // Check reading and writing unaligned pointers.
1594 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001595 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001596 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1597
1598 delete[] data;
1599}
1600
1601
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001602THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1603 v8::HandleScope scope;
1604 LocalContext env;
1605
1606 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1607 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1608 instance_templ->SetInternalFieldCount(1);
1609 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1610 CHECK_EQ(1, obj->InternalFieldCount());
1611 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1612
1613 char* data = new char[100];
1614
1615 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001616 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001617 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001618 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001619
1620 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001622 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1623
1624 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001626 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1627
1628 obj->SetInternalField(0, v8::External::Wrap(aligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001629 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001630 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1631
1632 obj->SetInternalField(0, v8::External::Wrap(unaligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001633 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001634 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1635
1636 delete[] data;
1637}
1638
1639
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001640THREADED_TEST(IdentityHash) {
1641 v8::HandleScope scope;
1642 LocalContext env;
1643
1644 // Ensure that the test starts with an fresh heap to test whether the hash
1645 // code is based on the address.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001646 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001647 Local<v8::Object> obj = v8::Object::New();
1648 int hash = obj->GetIdentityHash();
1649 int hash1 = obj->GetIdentityHash();
1650 CHECK_EQ(hash, hash1);
1651 int hash2 = v8::Object::New()->GetIdentityHash();
1652 // Since the identity hash is essentially a random number two consecutive
1653 // objects should not be assigned the same hash code. If the test below fails
1654 // the random number generator should be evaluated.
1655 CHECK_NE(hash, hash2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001656 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001657 int hash3 = v8::Object::New()->GetIdentityHash();
1658 // Make sure that the identity hash is not based on the initial address of
1659 // the object alone. If the test below fails the random number generator
1660 // should be evaluated.
1661 CHECK_NE(hash, hash3);
1662 int hash4 = obj->GetIdentityHash();
1663 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001664
1665 // Check identity hashes behaviour in the presence of JS accessors.
1666 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1667 {
1668 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1669 Local<v8::Object> o1 = v8::Object::New();
1670 Local<v8::Object> o2 = v8::Object::New();
1671 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1672 }
1673 {
1674 CompileRun(
1675 "function cnst() { return 42; };\n"
1676 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1677 Local<v8::Object> o1 = v8::Object::New();
1678 Local<v8::Object> o2 = v8::Object::New();
1679 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1680 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001681}
1682
1683
1684THREADED_TEST(HiddenProperties) {
1685 v8::HandleScope scope;
1686 LocalContext env;
1687
1688 v8::Local<v8::Object> obj = v8::Object::New();
1689 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1690 v8::Local<v8::String> empty = v8_str("");
1691 v8::Local<v8::String> prop_name = v8_str("prop_name");
1692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001693 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001694
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001695 // Make sure delete of a non-existent hidden value works
1696 CHECK(obj->DeleteHiddenValue(key));
1697
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001698 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1699 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1700 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1701 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001703 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001704
1705 // Make sure we do not find the hidden property.
1706 CHECK(!obj->Has(empty));
1707 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1708 CHECK(obj->Get(empty)->IsUndefined());
1709 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1710 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1711 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1712 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001714 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001715
1716 // Add another property and delete it afterwards to force the object in
1717 // slow case.
1718 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1719 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1720 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1721 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1722 CHECK(obj->Delete(prop_name));
1723 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001726
1727 CHECK(obj->DeleteHiddenValue(key));
1728 CHECK(obj->GetHiddenValue(key).IsEmpty());
1729}
1730
1731
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001732static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001733static v8::Handle<Value> InterceptorForHiddenProperties(
1734 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001735 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001736 return v8::Handle<Value>();
1737}
1738
1739
1740THREADED_TEST(HiddenPropertiesWithInterceptors) {
1741 v8::HandleScope scope;
1742 LocalContext context;
1743
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001744 interceptor_for_hidden_properties_called = false;
1745
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001746 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1747
1748 // Associate an interceptor with an object and start setting hidden values.
1749 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1750 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1751 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1752 Local<v8::Function> function = fun_templ->GetFunction();
1753 Local<v8::Object> obj = function->NewInstance();
1754 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1755 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001756 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001757}
1758
1759
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760THREADED_TEST(External) {
1761 v8::HandleScope scope;
1762 int x = 3;
1763 Local<v8::External> ext = v8::External::New(&x);
1764 LocalContext env;
1765 env->Global()->Set(v8_str("ext"), ext);
1766 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001767 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001768 int* ptr = static_cast<int*>(reext->Value());
1769 CHECK_EQ(x, 3);
1770 *ptr = 10;
1771 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001772
1773 // Make sure unaligned pointers are wrapped properly.
1774 char* data = i::StrDup("0123456789");
1775 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1776 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1777 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1778 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1779
1780 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1781 CHECK_EQ('0', *char_ptr);
1782 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1783 CHECK_EQ('1', *char_ptr);
1784 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1785 CHECK_EQ('2', *char_ptr);
1786 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1787 CHECK_EQ('3', *char_ptr);
1788 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001789}
1790
1791
1792THREADED_TEST(GlobalHandle) {
1793 v8::Persistent<String> global;
1794 {
1795 v8::HandleScope scope;
1796 Local<String> str = v8_str("str");
1797 global = v8::Persistent<String>::New(str);
1798 }
1799 CHECK_EQ(global->Length(), 3);
1800 global.Dispose();
1801}
1802
1803
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001804static int NumberOfWeakCalls = 0;
1805static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1806 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1807 NumberOfWeakCalls++;
1808 handle.Dispose();
1809}
1810
1811THREADED_TEST(ApiObjectGroups) {
1812 HandleScope scope;
1813 LocalContext env;
1814
1815 NumberOfWeakCalls = 0;
1816
1817 Persistent<Object> g1s1;
1818 Persistent<Object> g1s2;
1819 Persistent<Object> g1c1;
1820 Persistent<Object> g2s1;
1821 Persistent<Object> g2s2;
1822 Persistent<Object> g2c1;
1823
1824 {
1825 HandleScope scope;
1826 g1s1 = Persistent<Object>::New(Object::New());
1827 g1s2 = Persistent<Object>::New(Object::New());
1828 g1c1 = Persistent<Object>::New(Object::New());
1829 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1830 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1831 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1832
1833 g2s1 = Persistent<Object>::New(Object::New());
1834 g2s2 = Persistent<Object>::New(Object::New());
1835 g2c1 = Persistent<Object>::New(Object::New());
1836 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1837 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1838 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1839 }
1840
1841 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1842
1843 // Connect group 1 and 2, make a cycle.
1844 CHECK(g1s2->Set(0, g2s2));
1845 CHECK(g2s1->Set(0, g1s1));
1846
1847 {
1848 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1849 Persistent<Value> g1_children[] = { g1c1 };
1850 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1851 Persistent<Value> g2_children[] = { g2c1 };
1852 V8::AddObjectGroup(g1_objects, 2);
1853 V8::AddImplicitReferences(g1s1, g1_children, 1);
1854 V8::AddObjectGroup(g2_objects, 2);
1855 V8::AddImplicitReferences(g2s2, g2_children, 1);
1856 }
1857 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001859
1860 // All object should be alive.
1861 CHECK_EQ(0, NumberOfWeakCalls);
1862
1863 // Weaken the root.
1864 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1865 // But make children strong roots---all the objects (except for children)
1866 // should be collectable now.
1867 g1c1.ClearWeak();
1868 g2c1.ClearWeak();
1869
1870 // Groups are deleted, rebuild groups.
1871 {
1872 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1873 Persistent<Value> g1_children[] = { g1c1 };
1874 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1875 Persistent<Value> g2_children[] = { g2c1 };
1876 V8::AddObjectGroup(g1_objects, 2);
1877 V8::AddImplicitReferences(g1s1, g1_children, 1);
1878 V8::AddObjectGroup(g2_objects, 2);
1879 V8::AddImplicitReferences(g2s2, g2_children, 1);
1880 }
1881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001883
1884 // All objects should be gone. 5 global handles in total.
1885 CHECK_EQ(5, NumberOfWeakCalls);
1886
1887 // And now make children weak again and collect them.
1888 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1889 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001892 CHECK_EQ(7, NumberOfWeakCalls);
1893}
1894
1895
1896THREADED_TEST(ApiObjectGroupsCycle) {
1897 HandleScope scope;
1898 LocalContext env;
1899
1900 NumberOfWeakCalls = 0;
1901
1902 Persistent<Object> g1s1;
1903 Persistent<Object> g1s2;
1904 Persistent<Object> g2s1;
1905 Persistent<Object> g2s2;
1906 Persistent<Object> g3s1;
1907 Persistent<Object> g3s2;
1908
1909 {
1910 HandleScope scope;
1911 g1s1 = Persistent<Object>::New(Object::New());
1912 g1s2 = Persistent<Object>::New(Object::New());
1913 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1915
1916 g2s1 = Persistent<Object>::New(Object::New());
1917 g2s2 = Persistent<Object>::New(Object::New());
1918 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1919 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1920
1921 g3s1 = Persistent<Object>::New(Object::New());
1922 g3s2 = Persistent<Object>::New(Object::New());
1923 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1924 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1925 }
1926
1927 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1928
1929 // Connect groups. We're building the following cycle:
1930 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
1931 // groups.
1932 {
1933 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1934 Persistent<Value> g1_children[] = { g2s1 };
1935 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1936 Persistent<Value> g2_children[] = { g3s1 };
1937 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1938 Persistent<Value> g3_children[] = { g1s1 };
1939 V8::AddObjectGroup(g1_objects, 2);
1940 V8::AddImplicitReferences(g1s1, g1_children, 1);
1941 V8::AddObjectGroup(g2_objects, 2);
1942 V8::AddImplicitReferences(g2s1, g2_children, 1);
1943 V8::AddObjectGroup(g3_objects, 2);
1944 V8::AddImplicitReferences(g3s1, g3_children, 1);
1945 }
1946 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001948
1949 // All object should be alive.
1950 CHECK_EQ(0, NumberOfWeakCalls);
1951
1952 // Weaken the root.
1953 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1954
1955 // Groups are deleted, rebuild groups.
1956 {
1957 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1958 Persistent<Value> g1_children[] = { g2s1 };
1959 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1960 Persistent<Value> g2_children[] = { g3s1 };
1961 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
1962 Persistent<Value> g3_children[] = { g1s1 };
1963 V8::AddObjectGroup(g1_objects, 2);
1964 V8::AddImplicitReferences(g1s1, g1_children, 1);
1965 V8::AddObjectGroup(g2_objects, 2);
1966 V8::AddImplicitReferences(g2s1, g2_children, 1);
1967 V8::AddObjectGroup(g3_objects, 2);
1968 V8::AddImplicitReferences(g3s1, g3_children, 1);
1969 }
1970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001972
1973 // All objects should be gone. 7 global handles in total.
1974 CHECK_EQ(7, NumberOfWeakCalls);
1975}
1976
1977
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001978THREADED_TEST(ScriptException) {
1979 v8::HandleScope scope;
1980 LocalContext env;
1981 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1982 v8::TryCatch try_catch;
1983 Local<Value> result = script->Run();
1984 CHECK(result.IsEmpty());
1985 CHECK(try_catch.HasCaught());
1986 String::AsciiValue exception_value(try_catch.Exception());
1987 CHECK_EQ(*exception_value, "panama!");
1988}
1989
1990
1991bool message_received;
1992
1993
1994static void check_message(v8::Handle<v8::Message> message,
1995 v8::Handle<Value> data) {
1996 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001997 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001998 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 message_received = true;
2000}
2001
2002
2003THREADED_TEST(MessageHandlerData) {
2004 message_received = false;
2005 v8::HandleScope scope;
2006 CHECK(!message_received);
2007 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2008 LocalContext context;
2009 v8::ScriptOrigin origin =
2010 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002011 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2012 &origin);
2013 script->SetData(v8_str("7.56"));
2014 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002015 CHECK(message_received);
2016 // clear out the message listener
2017 v8::V8::RemoveMessageListeners(check_message);
2018}
2019
2020
2021THREADED_TEST(GetSetProperty) {
2022 v8::HandleScope scope;
2023 LocalContext context;
2024 context->Global()->Set(v8_str("foo"), v8_num(14));
2025 context->Global()->Set(v8_str("12"), v8_num(92));
2026 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2027 context->Global()->Set(v8_num(13), v8_num(56));
2028 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2029 CHECK_EQ(14, foo->Int32Value());
2030 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2031 CHECK_EQ(92, twelve->Int32Value());
2032 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2033 CHECK_EQ(32, sixteen->Int32Value());
2034 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2035 CHECK_EQ(56, thirteen->Int32Value());
2036 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2037 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2038 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2039 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2040 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2041 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2042 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2043 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2044 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2045}
2046
2047
2048THREADED_TEST(PropertyAttributes) {
2049 v8::HandleScope scope;
2050 LocalContext context;
2051 // read-only
2052 Local<String> prop = v8_str("read_only");
2053 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2054 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2055 Script::Compile(v8_str("read_only = 9"))->Run();
2056 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2057 context->Global()->Set(prop, v8_num(10));
2058 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2059 // dont-delete
2060 prop = v8_str("dont_delete");
2061 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2062 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2063 Script::Compile(v8_str("delete dont_delete"))->Run();
2064 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2065}
2066
2067
2068THREADED_TEST(Array) {
2069 v8::HandleScope scope;
2070 LocalContext context;
2071 Local<v8::Array> array = v8::Array::New();
2072 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002073 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002074 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002075 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002076 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002077 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002078 CHECK_EQ(3, array->Length());
2079 CHECK(!array->Has(0));
2080 CHECK(!array->Has(1));
2081 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002082 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002083 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002084 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002085 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002086 CHECK_EQ(1, arr->Get(0)->Int32Value());
2087 CHECK_EQ(2, arr->Get(1)->Int32Value());
2088 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002089 array = v8::Array::New(27);
2090 CHECK_EQ(27, array->Length());
2091 array = v8::Array::New(-27);
2092 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002093}
2094
2095
2096v8::Handle<Value> HandleF(const v8::Arguments& args) {
2097 v8::HandleScope scope;
2098 ApiTestFuzzer::Fuzz();
2099 Local<v8::Array> result = v8::Array::New(args.Length());
2100 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002101 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002102 return scope.Close(result);
2103}
2104
2105
2106THREADED_TEST(Vector) {
2107 v8::HandleScope scope;
2108 Local<ObjectTemplate> global = ObjectTemplate::New();
2109 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2110 LocalContext context(0, global);
2111
2112 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002113 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002114 CHECK_EQ(0, a0->Length());
2115
2116 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002117 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002118 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002119 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002120
2121 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002122 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002123 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002124 CHECK_EQ(12, a2->Get(0)->Int32Value());
2125 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002126
2127 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002128 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002129 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002130 CHECK_EQ(14, a3->Get(0)->Int32Value());
2131 CHECK_EQ(15, a3->Get(1)->Int32Value());
2132 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002133
2134 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002135 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002136 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002137 CHECK_EQ(17, a4->Get(0)->Int32Value());
2138 CHECK_EQ(18, a4->Get(1)->Int32Value());
2139 CHECK_EQ(19, a4->Get(2)->Int32Value());
2140 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002141}
2142
2143
2144THREADED_TEST(FunctionCall) {
2145 v8::HandleScope scope;
2146 LocalContext context;
2147 CompileRun(
2148 "function Foo() {"
2149 " var result = [];"
2150 " for (var i = 0; i < arguments.length; i++) {"
2151 " result.push(arguments[i]);"
2152 " }"
2153 " return result;"
2154 "}");
2155 Local<Function> Foo =
2156 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2157
2158 v8::Handle<Value>* args0 = NULL;
2159 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2160 CHECK_EQ(0, a0->Length());
2161
2162 v8::Handle<Value> args1[] = { v8_num(1.1) };
2163 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2164 CHECK_EQ(1, a1->Length());
2165 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2166
2167 v8::Handle<Value> args2[] = { v8_num(2.2),
2168 v8_num(3.3) };
2169 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2170 CHECK_EQ(2, a2->Length());
2171 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2172 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2173
2174 v8::Handle<Value> args3[] = { v8_num(4.4),
2175 v8_num(5.5),
2176 v8_num(6.6) };
2177 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2178 CHECK_EQ(3, a3->Length());
2179 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2180 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2181 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2182
2183 v8::Handle<Value> args4[] = { v8_num(7.7),
2184 v8_num(8.8),
2185 v8_num(9.9),
2186 v8_num(10.11) };
2187 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2188 CHECK_EQ(4, a4->Length());
2189 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2190 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2191 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2192 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2193}
2194
2195
2196static const char* js_code_causing_out_of_memory =
2197 "var a = new Array(); while(true) a.push(a);";
2198
2199
2200// These tests run for a long time and prevent us from running tests
2201// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002202TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002204 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002205 // Set heap limits.
2206 static const int K = 1024;
2207 v8::ResourceConstraints constraints;
2208 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002209 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002210 v8::SetResourceConstraints(&constraints);
2211
2212 // Execute a script that causes out of memory.
2213 v8::HandleScope scope;
2214 LocalContext context;
2215 v8::V8::IgnoreOutOfMemoryException();
2216 Local<Script> script =
2217 Script::Compile(String::New(js_code_causing_out_of_memory));
2218 Local<Value> result = script->Run();
2219
2220 // Check for out of memory state.
2221 CHECK(result.IsEmpty());
2222 CHECK(context->HasOutOfMemoryException());
2223}
2224
2225
2226v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2227 ApiTestFuzzer::Fuzz();
2228
2229 v8::HandleScope scope;
2230 LocalContext context;
2231 Local<Script> script =
2232 Script::Compile(String::New(js_code_causing_out_of_memory));
2233 Local<Value> result = script->Run();
2234
2235 // Check for out of memory state.
2236 CHECK(result.IsEmpty());
2237 CHECK(context->HasOutOfMemoryException());
2238
2239 return result;
2240}
2241
2242
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002243TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002244 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002245 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002246 // Set heap limits.
2247 static const int K = 1024;
2248 v8::ResourceConstraints constraints;
2249 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002250 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002251 v8::SetResourceConstraints(&constraints);
2252
2253 v8::HandleScope scope;
2254 Local<ObjectTemplate> templ = ObjectTemplate::New();
2255 templ->Set(v8_str("ProvokeOutOfMemory"),
2256 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2257 LocalContext context(0, templ);
2258 v8::V8::IgnoreOutOfMemoryException();
2259 Local<Value> result = CompileRun(
2260 "var thrown = false;"
2261 "try {"
2262 " ProvokeOutOfMemory();"
2263 "} catch (e) {"
2264 " thrown = true;"
2265 "}");
2266 // Check for out of memory state.
2267 CHECK(result.IsEmpty());
2268 CHECK(context->HasOutOfMemoryException());
2269}
2270
2271
2272TEST(HugeConsStringOutOfMemory) {
2273 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002274 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002275 // Set heap limits.
2276 static const int K = 1024;
2277 v8::ResourceConstraints constraints;
2278 constraints.set_max_young_space_size(256 * K);
2279 constraints.set_max_old_space_size(2 * K * K);
2280 v8::SetResourceConstraints(&constraints);
2281
2282 // Execute a script that causes out of memory.
2283 v8::V8::IgnoreOutOfMemoryException();
2284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 v8::HandleScope scope;
2286 LocalContext context;
2287
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002288 // Build huge string. This should fail with out of memory exception.
2289 Local<Value> result = CompileRun(
2290 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002291 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002292
2293 // Check for out of memory state.
2294 CHECK(result.IsEmpty());
2295 CHECK(context->HasOutOfMemoryException());
2296}
2297
2298
2299THREADED_TEST(ConstructCall) {
2300 v8::HandleScope scope;
2301 LocalContext context;
2302 CompileRun(
2303 "function Foo() {"
2304 " var result = [];"
2305 " for (var i = 0; i < arguments.length; i++) {"
2306 " result.push(arguments[i]);"
2307 " }"
2308 " return result;"
2309 "}");
2310 Local<Function> Foo =
2311 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2312
2313 v8::Handle<Value>* args0 = NULL;
2314 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2315 CHECK_EQ(0, a0->Length());
2316
2317 v8::Handle<Value> args1[] = { v8_num(1.1) };
2318 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2319 CHECK_EQ(1, a1->Length());
2320 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2321
2322 v8::Handle<Value> args2[] = { v8_num(2.2),
2323 v8_num(3.3) };
2324 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2325 CHECK_EQ(2, a2->Length());
2326 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2327 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2328
2329 v8::Handle<Value> args3[] = { v8_num(4.4),
2330 v8_num(5.5),
2331 v8_num(6.6) };
2332 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2333 CHECK_EQ(3, a3->Length());
2334 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2335 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2336 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2337
2338 v8::Handle<Value> args4[] = { v8_num(7.7),
2339 v8_num(8.8),
2340 v8_num(9.9),
2341 v8_num(10.11) };
2342 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2343 CHECK_EQ(4, a4->Length());
2344 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2345 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2346 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2347 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2348}
2349
2350
2351static void CheckUncle(v8::TryCatch* try_catch) {
2352 CHECK(try_catch->HasCaught());
2353 String::AsciiValue str_value(try_catch->Exception());
2354 CHECK_EQ(*str_value, "uncle?");
2355 try_catch->Reset();
2356}
2357
2358
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002359THREADED_TEST(ConversionNumber) {
2360 v8::HandleScope scope;
2361 LocalContext env;
2362 // Very large number.
2363 CompileRun("var obj = Math.pow(2,32) * 1237;");
2364 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2365 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2366 CHECK_EQ(0, obj->ToInt32()->Value());
2367 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2368 // Large number.
2369 CompileRun("var obj = -1234567890123;");
2370 obj = env->Global()->Get(v8_str("obj"));
2371 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2372 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2373 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2374 // Small positive integer.
2375 CompileRun("var obj = 42;");
2376 obj = env->Global()->Get(v8_str("obj"));
2377 CHECK_EQ(42.0, obj->ToNumber()->Value());
2378 CHECK_EQ(42, obj->ToInt32()->Value());
2379 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2380 // Negative integer.
2381 CompileRun("var obj = -37;");
2382 obj = env->Global()->Get(v8_str("obj"));
2383 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2384 CHECK_EQ(-37, obj->ToInt32()->Value());
2385 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2386 // Positive non-int32 integer.
2387 CompileRun("var obj = 0x81234567;");
2388 obj = env->Global()->Get(v8_str("obj"));
2389 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2390 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2391 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2392 // Fraction.
2393 CompileRun("var obj = 42.3;");
2394 obj = env->Global()->Get(v8_str("obj"));
2395 CHECK_EQ(42.3, obj->ToNumber()->Value());
2396 CHECK_EQ(42, obj->ToInt32()->Value());
2397 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2398 // Large negative fraction.
2399 CompileRun("var obj = -5726623061.75;");
2400 obj = env->Global()->Get(v8_str("obj"));
2401 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2402 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2403 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2404}
2405
2406
2407THREADED_TEST(isNumberType) {
2408 v8::HandleScope scope;
2409 LocalContext env;
2410 // Very large number.
2411 CompileRun("var obj = Math.pow(2,32) * 1237;");
2412 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2413 CHECK(!obj->IsInt32());
2414 CHECK(!obj->IsUint32());
2415 // Large negative number.
2416 CompileRun("var obj = -1234567890123;");
2417 obj = env->Global()->Get(v8_str("obj"));
2418 CHECK(!obj->IsInt32());
2419 CHECK(!obj->IsUint32());
2420 // Small positive integer.
2421 CompileRun("var obj = 42;");
2422 obj = env->Global()->Get(v8_str("obj"));
2423 CHECK(obj->IsInt32());
2424 CHECK(obj->IsUint32());
2425 // Negative integer.
2426 CompileRun("var obj = -37;");
2427 obj = env->Global()->Get(v8_str("obj"));
2428 CHECK(obj->IsInt32());
2429 CHECK(!obj->IsUint32());
2430 // Positive non-int32 integer.
2431 CompileRun("var obj = 0x81234567;");
2432 obj = env->Global()->Get(v8_str("obj"));
2433 CHECK(!obj->IsInt32());
2434 CHECK(obj->IsUint32());
2435 // Fraction.
2436 CompileRun("var obj = 42.3;");
2437 obj = env->Global()->Get(v8_str("obj"));
2438 CHECK(!obj->IsInt32());
2439 CHECK(!obj->IsUint32());
2440 // Large negative fraction.
2441 CompileRun("var obj = -5726623061.75;");
2442 obj = env->Global()->Get(v8_str("obj"));
2443 CHECK(!obj->IsInt32());
2444 CHECK(!obj->IsUint32());
2445}
2446
2447
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002448THREADED_TEST(ConversionException) {
2449 v8::HandleScope scope;
2450 LocalContext env;
2451 CompileRun(
2452 "function TestClass() { };"
2453 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2454 "var obj = new TestClass();");
2455 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2456
2457 v8::TryCatch try_catch;
2458
2459 Local<Value> to_string_result = obj->ToString();
2460 CHECK(to_string_result.IsEmpty());
2461 CheckUncle(&try_catch);
2462
2463 Local<Value> to_number_result = obj->ToNumber();
2464 CHECK(to_number_result.IsEmpty());
2465 CheckUncle(&try_catch);
2466
2467 Local<Value> to_integer_result = obj->ToInteger();
2468 CHECK(to_integer_result.IsEmpty());
2469 CheckUncle(&try_catch);
2470
2471 Local<Value> to_uint32_result = obj->ToUint32();
2472 CHECK(to_uint32_result.IsEmpty());
2473 CheckUncle(&try_catch);
2474
2475 Local<Value> to_int32_result = obj->ToInt32();
2476 CHECK(to_int32_result.IsEmpty());
2477 CheckUncle(&try_catch);
2478
2479 Local<Value> to_object_result = v8::Undefined()->ToObject();
2480 CHECK(to_object_result.IsEmpty());
2481 CHECK(try_catch.HasCaught());
2482 try_catch.Reset();
2483
2484 int32_t int32_value = obj->Int32Value();
2485 CHECK_EQ(0, int32_value);
2486 CheckUncle(&try_catch);
2487
2488 uint32_t uint32_value = obj->Uint32Value();
2489 CHECK_EQ(0, uint32_value);
2490 CheckUncle(&try_catch);
2491
2492 double number_value = obj->NumberValue();
2493 CHECK_NE(0, IsNaN(number_value));
2494 CheckUncle(&try_catch);
2495
2496 int64_t integer_value = obj->IntegerValue();
2497 CHECK_EQ(0.0, static_cast<double>(integer_value));
2498 CheckUncle(&try_catch);
2499}
2500
2501
2502v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2503 ApiTestFuzzer::Fuzz();
2504 return v8::ThrowException(v8_str("konto"));
2505}
2506
2507
ager@chromium.org8bb60582008-12-11 12:02:20 +00002508v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2509 if (args.Length() < 1) return v8::Boolean::New(false);
2510 v8::HandleScope scope;
2511 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002512 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2513 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002514 return v8::Boolean::New(try_catch.HasCaught());
2515}
2516
2517
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002518THREADED_TEST(APICatch) {
2519 v8::HandleScope scope;
2520 Local<ObjectTemplate> templ = ObjectTemplate::New();
2521 templ->Set(v8_str("ThrowFromC"),
2522 v8::FunctionTemplate::New(ThrowFromC));
2523 LocalContext context(0, templ);
2524 CompileRun(
2525 "var thrown = false;"
2526 "try {"
2527 " ThrowFromC();"
2528 "} catch (e) {"
2529 " thrown = true;"
2530 "}");
2531 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2532 CHECK(thrown->BooleanValue());
2533}
2534
2535
ager@chromium.org8bb60582008-12-11 12:02:20 +00002536THREADED_TEST(APIThrowTryCatch) {
2537 v8::HandleScope scope;
2538 Local<ObjectTemplate> templ = ObjectTemplate::New();
2539 templ->Set(v8_str("ThrowFromC"),
2540 v8::FunctionTemplate::New(ThrowFromC));
2541 LocalContext context(0, templ);
2542 v8::TryCatch try_catch;
2543 CompileRun("ThrowFromC();");
2544 CHECK(try_catch.HasCaught());
2545}
2546
2547
2548// Test that a try-finally block doesn't shadow a try-catch block
2549// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002550//
2551// BUG(271): Some of the exception propagation does not work on the
2552// ARM simulator because the simulator separates the C++ stack and the
2553// JS stack. This test therefore fails on the simulator. The test is
2554// not threaded to allow the threading tests to run on the simulator.
2555TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002556 v8::HandleScope scope;
2557 Local<ObjectTemplate> templ = ObjectTemplate::New();
2558 templ->Set(v8_str("CCatcher"),
2559 v8::FunctionTemplate::New(CCatcher));
2560 LocalContext context(0, templ);
2561 Local<Value> result = CompileRun("try {"
2562 " try {"
2563 " CCatcher('throw 7;');"
2564 " } finally {"
2565 " }"
2566 "} catch (e) {"
2567 "}");
2568 CHECK(result->IsTrue());
2569}
2570
2571
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002572static void check_reference_error_message(
2573 v8::Handle<v8::Message> message,
2574 v8::Handle<v8::Value> data) {
2575 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2576 CHECK(message->Get()->Equals(v8_str(reference_error)));
2577}
2578
2579
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002580static v8::Handle<Value> Fail(const v8::Arguments& args) {
2581 ApiTestFuzzer::Fuzz();
2582 CHECK(false);
2583 return v8::Undefined();
2584}
2585
2586
2587// Test that overwritten methods are not invoked on uncaught exception
2588// formatting. However, they are invoked when performing normal error
2589// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002590TEST(APIThrowMessageOverwrittenToString) {
2591 v8::HandleScope scope;
2592 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002593 Local<ObjectTemplate> templ = ObjectTemplate::New();
2594 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2595 LocalContext context(NULL, templ);
2596 CompileRun("asdf;");
2597 CompileRun("var limit = {};"
2598 "limit.valueOf = fail;"
2599 "Error.stackTraceLimit = limit;");
2600 CompileRun("asdf");
2601 CompileRun("Array.prototype.pop = fail;");
2602 CompileRun("Object.prototype.hasOwnProperty = fail;");
2603 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002604 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2605 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002606 CompileRun("ReferenceError.prototype.toString ="
2607 " function() { return 'Whoops' }");
2608 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002609 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2610 CompileRun("asdf;");
2611 CompileRun("ReferenceError.prototype.constructor = void 0;");
2612 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002613 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2614 CompileRun("asdf;");
2615 CompileRun("ReferenceError.prototype = new Object();");
2616 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002617 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2618 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002619 CompileRun("ReferenceError.prototype.constructor = new Object();"
2620 "ReferenceError.prototype.constructor.name = 1;"
2621 "Number.prototype.toString = function() { return 'Whoops'; };"
2622 "ReferenceError.prototype.toString = Object.prototype.toString;");
2623 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002624 v8::V8::RemoveMessageListeners(check_message);
2625}
2626
2627
ager@chromium.org8bb60582008-12-11 12:02:20 +00002628static void receive_message(v8::Handle<v8::Message> message,
2629 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002630 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002631 message_received = true;
2632}
2633
2634
2635TEST(APIThrowMessage) {
2636 message_received = false;
2637 v8::HandleScope scope;
2638 v8::V8::AddMessageListener(receive_message);
2639 Local<ObjectTemplate> templ = ObjectTemplate::New();
2640 templ->Set(v8_str("ThrowFromC"),
2641 v8::FunctionTemplate::New(ThrowFromC));
2642 LocalContext context(0, templ);
2643 CompileRun("ThrowFromC();");
2644 CHECK(message_received);
2645 v8::V8::RemoveMessageListeners(check_message);
2646}
2647
2648
2649TEST(APIThrowMessageAndVerboseTryCatch) {
2650 message_received = false;
2651 v8::HandleScope scope;
2652 v8::V8::AddMessageListener(receive_message);
2653 Local<ObjectTemplate> templ = ObjectTemplate::New();
2654 templ->Set(v8_str("ThrowFromC"),
2655 v8::FunctionTemplate::New(ThrowFromC));
2656 LocalContext context(0, templ);
2657 v8::TryCatch try_catch;
2658 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002659 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002660 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002661 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002662 CHECK(message_received);
2663 v8::V8::RemoveMessageListeners(check_message);
2664}
2665
2666
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002667TEST(APIStackOverflowAndVerboseTryCatch) {
2668 message_received = false;
2669 v8::HandleScope scope;
2670 v8::V8::AddMessageListener(receive_message);
2671 LocalContext context;
2672 v8::TryCatch try_catch;
2673 try_catch.SetVerbose(true);
2674 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2675 CHECK(try_catch.HasCaught());
2676 CHECK(result.IsEmpty());
2677 CHECK(message_received);
2678 v8::V8::RemoveMessageListeners(receive_message);
2679}
2680
2681
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002682THREADED_TEST(ExternalScriptException) {
2683 v8::HandleScope scope;
2684 Local<ObjectTemplate> templ = ObjectTemplate::New();
2685 templ->Set(v8_str("ThrowFromC"),
2686 v8::FunctionTemplate::New(ThrowFromC));
2687 LocalContext context(0, templ);
2688
2689 v8::TryCatch try_catch;
2690 Local<Script> script
2691 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2692 Local<Value> result = script->Run();
2693 CHECK(result.IsEmpty());
2694 CHECK(try_catch.HasCaught());
2695 String::AsciiValue exception_value(try_catch.Exception());
2696 CHECK_EQ("konto", *exception_value);
2697}
2698
2699
2700
2701v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2702 ApiTestFuzzer::Fuzz();
2703 CHECK_EQ(4, args.Length());
2704 int count = args[0]->Int32Value();
2705 int cInterval = args[2]->Int32Value();
2706 if (count == 0) {
2707 return v8::ThrowException(v8_str("FromC"));
2708 } else {
2709 Local<v8::Object> global = Context::GetCurrent()->Global();
2710 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2711 v8::Handle<Value> argv[] = { v8_num(count - 1),
2712 args[1],
2713 args[2],
2714 args[3] };
2715 if (count % cInterval == 0) {
2716 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002717 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002718 int expected = args[3]->Int32Value();
2719 if (try_catch.HasCaught()) {
2720 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002721 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002722 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002723 } else {
2724 CHECK_NE(expected, count);
2725 }
2726 return result;
2727 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002728 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002729 }
2730 }
2731}
2732
2733
2734v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2735 ApiTestFuzzer::Fuzz();
2736 CHECK_EQ(3, args.Length());
2737 bool equality = args[0]->BooleanValue();
2738 int count = args[1]->Int32Value();
2739 int expected = args[2]->Int32Value();
2740 if (equality) {
2741 CHECK_EQ(count, expected);
2742 } else {
2743 CHECK_NE(count, expected);
2744 }
2745 return v8::Undefined();
2746}
2747
2748
ager@chromium.org8bb60582008-12-11 12:02:20 +00002749THREADED_TEST(EvalInTryFinally) {
2750 v8::HandleScope scope;
2751 LocalContext context;
2752 v8::TryCatch try_catch;
2753 CompileRun("(function() {"
2754 " try {"
2755 " eval('asldkf (*&^&*^');"
2756 " } finally {"
2757 " return;"
2758 " }"
2759 "})()");
2760 CHECK(!try_catch.HasCaught());
2761}
2762
2763
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002764// This test works by making a stack of alternating JavaScript and C
2765// activations. These activations set up exception handlers with regular
2766// intervals, one interval for C activations and another for JavaScript
2767// activations. When enough activations have been created an exception is
2768// thrown and we check that the right activation catches the exception and that
2769// no other activations do. The right activation is always the topmost one with
2770// a handler, regardless of whether it is in JavaScript or C.
2771//
2772// The notation used to describe a test case looks like this:
2773//
2774// *JS[4] *C[3] @JS[2] C[1] JS[0]
2775//
2776// Each entry is an activation, either JS or C. The index is the count at that
2777// level. Stars identify activations with exception handlers, the @ identifies
2778// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002779//
2780// BUG(271): Some of the exception propagation does not work on the
2781// ARM simulator because the simulator separates the C++ stack and the
2782// JS stack. This test therefore fails on the simulator. The test is
2783// not threaded to allow the threading tests to run on the simulator.
2784TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002785 v8::HandleScope scope;
2786 Local<ObjectTemplate> templ = ObjectTemplate::New();
2787 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2788 templ->Set(v8_str("CThrowCountDown"),
2789 v8::FunctionTemplate::New(CThrowCountDown));
2790 LocalContext context(0, templ);
2791 CompileRun(
2792 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2793 " if (count == 0) throw 'FromJS';"
2794 " if (count % jsInterval == 0) {"
2795 " try {"
2796 " var value = CThrowCountDown(count - 1,"
2797 " jsInterval,"
2798 " cInterval,"
2799 " expected);"
2800 " check(false, count, expected);"
2801 " return value;"
2802 " } catch (e) {"
2803 " check(true, count, expected);"
2804 " }"
2805 " } else {"
2806 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2807 " }"
2808 "}");
2809 Local<Function> fun =
2810 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2811
2812 const int argc = 4;
2813 // count jsInterval cInterval expected
2814
2815 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2816 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2817 fun->Call(fun, argc, a0);
2818
2819 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2820 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2821 fun->Call(fun, argc, a1);
2822
2823 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2824 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2825 fun->Call(fun, argc, a2);
2826
2827 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2828 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2829 fun->Call(fun, argc, a3);
2830
2831 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2832 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2833 fun->Call(fun, argc, a4);
2834
2835 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2836 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2837 fun->Call(fun, argc, a5);
2838}
2839
2840
2841v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2842 ApiTestFuzzer::Fuzz();
2843 CHECK_EQ(1, args.Length());
2844 return v8::ThrowException(args[0]);
2845}
2846
2847
2848THREADED_TEST(ThrowValues) {
2849 v8::HandleScope scope;
2850 Local<ObjectTemplate> templ = ObjectTemplate::New();
2851 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2852 LocalContext context(0, templ);
2853 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2854 "function Run(obj) {"
2855 " try {"
2856 " Throw(obj);"
2857 " } catch (e) {"
2858 " return e;"
2859 " }"
2860 " return 'no exception';"
2861 "}"
2862 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2863 CHECK_EQ(5, result->Length());
2864 CHECK(result->Get(v8::Integer::New(0))->IsString());
2865 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2866 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2867 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2868 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2869 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2870 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2871}
2872
2873
2874THREADED_TEST(CatchZero) {
2875 v8::HandleScope scope;
2876 LocalContext context;
2877 v8::TryCatch try_catch;
2878 CHECK(!try_catch.HasCaught());
2879 Script::Compile(v8_str("throw 10"))->Run();
2880 CHECK(try_catch.HasCaught());
2881 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2882 try_catch.Reset();
2883 CHECK(!try_catch.HasCaught());
2884 Script::Compile(v8_str("throw 0"))->Run();
2885 CHECK(try_catch.HasCaught());
2886 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2887}
2888
2889
2890THREADED_TEST(CatchExceptionFromWith) {
2891 v8::HandleScope scope;
2892 LocalContext context;
2893 v8::TryCatch try_catch;
2894 CHECK(!try_catch.HasCaught());
2895 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2896 CHECK(try_catch.HasCaught());
2897}
2898
2899
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002900THREADED_TEST(TryCatchAndFinallyHidingException) {
2901 v8::HandleScope scope;
2902 LocalContext context;
2903 v8::TryCatch try_catch;
2904 CHECK(!try_catch.HasCaught());
2905 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
2906 CompileRun("f({toString: function() { throw 42; }});");
2907 CHECK(!try_catch.HasCaught());
2908}
2909
2910
2911v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
2912 v8::TryCatch try_catch;
2913 return v8::Undefined();
2914}
2915
2916
2917THREADED_TEST(TryCatchAndFinally) {
2918 v8::HandleScope scope;
2919 LocalContext context;
2920 context->Global()->Set(
2921 v8_str("native_with_try_catch"),
2922 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
2923 v8::TryCatch try_catch;
2924 CHECK(!try_catch.HasCaught());
2925 CompileRun(
2926 "try {\n"
2927 " throw new Error('a');\n"
2928 "} finally {\n"
2929 " native_with_try_catch();\n"
2930 "}\n");
2931 CHECK(try_catch.HasCaught());
2932}
2933
2934
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002935THREADED_TEST(Equality) {
2936 v8::HandleScope scope;
2937 LocalContext context;
2938 // Check that equality works at all before relying on CHECK_EQ
2939 CHECK(v8_str("a")->Equals(v8_str("a")));
2940 CHECK(!v8_str("a")->Equals(v8_str("b")));
2941
2942 CHECK_EQ(v8_str("a"), v8_str("a"));
2943 CHECK_NE(v8_str("a"), v8_str("b"));
2944 CHECK_EQ(v8_num(1), v8_num(1));
2945 CHECK_EQ(v8_num(1.00), v8_num(1));
2946 CHECK_NE(v8_num(1), v8_num(2));
2947
2948 // Assume String is not symbol.
2949 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2950 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2951 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2952 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2953 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2954 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2955 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2956 CHECK(!not_a_number->StrictEquals(not_a_number));
2957 CHECK(v8::False()->StrictEquals(v8::False()));
2958 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2959
2960 v8::Handle<v8::Object> obj = v8::Object::New();
2961 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2962 CHECK(alias->StrictEquals(obj));
2963 alias.Dispose();
2964}
2965
2966
2967THREADED_TEST(MultiRun) {
2968 v8::HandleScope scope;
2969 LocalContext context;
2970 Local<Script> script = Script::Compile(v8_str("x"));
2971 for (int i = 0; i < 10; i++)
2972 script->Run();
2973}
2974
2975
2976static v8::Handle<Value> GetXValue(Local<String> name,
2977 const AccessorInfo& info) {
2978 ApiTestFuzzer::Fuzz();
2979 CHECK_EQ(info.Data(), v8_str("donut"));
2980 CHECK_EQ(name, v8_str("x"));
2981 return name;
2982}
2983
2984
2985THREADED_TEST(SimplePropertyRead) {
2986 v8::HandleScope scope;
2987 Local<ObjectTemplate> templ = ObjectTemplate::New();
2988 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2989 LocalContext context;
2990 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2991 Local<Script> script = Script::Compile(v8_str("obj.x"));
2992 for (int i = 0; i < 10; i++) {
2993 Local<Value> result = script->Run();
2994 CHECK_EQ(result, v8_str("x"));
2995 }
2996}
2997
ager@chromium.org5c838252010-02-19 08:53:10 +00002998THREADED_TEST(DefinePropertyOnAPIAccessor) {
2999 v8::HandleScope scope;
3000 Local<ObjectTemplate> templ = ObjectTemplate::New();
3001 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3002 LocalContext context;
3003 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3004
3005 // Uses getOwnPropertyDescriptor to check the configurable status
3006 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003007 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003008 "obj, 'x');"
3009 "prop.configurable;"));
3010 Local<Value> result = script_desc->Run();
3011 CHECK_EQ(result->BooleanValue(), true);
3012
3013 // Redefine get - but still configurable
3014 Local<Script> script_define
3015 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3016 " configurable: true };"
3017 "Object.defineProperty(obj, 'x', desc);"
3018 "obj.x"));
3019 result = script_define->Run();
3020 CHECK_EQ(result, v8_num(42));
3021
3022 // Check that the accessor is still configurable
3023 result = script_desc->Run();
3024 CHECK_EQ(result->BooleanValue(), true);
3025
3026 // Redefine to a non-configurable
3027 script_define
3028 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3029 " configurable: false };"
3030 "Object.defineProperty(obj, 'x', desc);"
3031 "obj.x"));
3032 result = script_define->Run();
3033 CHECK_EQ(result, v8_num(43));
3034 result = script_desc->Run();
3035 CHECK_EQ(result->BooleanValue(), false);
3036
3037 // Make sure that it is not possible to redefine again
3038 v8::TryCatch try_catch;
3039 result = script_define->Run();
3040 CHECK(try_catch.HasCaught());
3041 String::AsciiValue exception_value(try_catch.Exception());
3042 CHECK_EQ(*exception_value,
3043 "TypeError: Cannot redefine property: defineProperty");
3044}
3045
3046THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3047 v8::HandleScope scope;
3048 Local<ObjectTemplate> templ = ObjectTemplate::New();
3049 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3050 LocalContext context;
3051 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3052
3053 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3054 "Object.getOwnPropertyDescriptor( "
3055 "obj, 'x');"
3056 "prop.configurable;"));
3057 Local<Value> result = script_desc->Run();
3058 CHECK_EQ(result->BooleanValue(), true);
3059
3060 Local<Script> script_define =
3061 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3062 " configurable: true };"
3063 "Object.defineProperty(obj, 'x', desc);"
3064 "obj.x"));
3065 result = script_define->Run();
3066 CHECK_EQ(result, v8_num(42));
3067
3068
3069 result = script_desc->Run();
3070 CHECK_EQ(result->BooleanValue(), true);
3071
3072
3073 script_define =
3074 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3075 " configurable: false };"
3076 "Object.defineProperty(obj, 'x', desc);"
3077 "obj.x"));
3078 result = script_define->Run();
3079 CHECK_EQ(result, v8_num(43));
3080 result = script_desc->Run();
3081
3082 CHECK_EQ(result->BooleanValue(), false);
3083
3084 v8::TryCatch try_catch;
3085 result = script_define->Run();
3086 CHECK(try_catch.HasCaught());
3087 String::AsciiValue exception_value(try_catch.Exception());
3088 CHECK_EQ(*exception_value,
3089 "TypeError: Cannot redefine property: defineProperty");
3090}
3091
3092
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003093static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3094 char const* name) {
3095 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3096}
ager@chromium.org5c838252010-02-19 08:53:10 +00003097
3098
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003099THREADED_TEST(DefineAPIAccessorOnObject) {
3100 v8::HandleScope scope;
3101 Local<ObjectTemplate> templ = ObjectTemplate::New();
3102 LocalContext context;
3103
3104 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3105 CompileRun("var obj2 = {};");
3106
3107 CHECK(CompileRun("obj1.x")->IsUndefined());
3108 CHECK(CompileRun("obj2.x")->IsUndefined());
3109
3110 CHECK(GetGlobalProperty(&context, "obj1")->
3111 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3112
3113 ExpectString("obj1.x", "x");
3114 CHECK(CompileRun("obj2.x")->IsUndefined());
3115
3116 CHECK(GetGlobalProperty(&context, "obj2")->
3117 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3118
3119 ExpectString("obj1.x", "x");
3120 ExpectString("obj2.x", "x");
3121
3122 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3123 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3124
3125 CompileRun("Object.defineProperty(obj1, 'x',"
3126 "{ get: function() { return 'y'; }, configurable: true })");
3127
3128 ExpectString("obj1.x", "y");
3129 ExpectString("obj2.x", "x");
3130
3131 CompileRun("Object.defineProperty(obj2, 'x',"
3132 "{ get: function() { return 'y'; }, configurable: true })");
3133
3134 ExpectString("obj1.x", "y");
3135 ExpectString("obj2.x", "y");
3136
3137 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3138 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3139
3140 CHECK(GetGlobalProperty(&context, "obj1")->
3141 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3142 CHECK(GetGlobalProperty(&context, "obj2")->
3143 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3144
3145 ExpectString("obj1.x", "x");
3146 ExpectString("obj2.x", "x");
3147
3148 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3149 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3150
3151 // Define getters/setters, but now make them not configurable.
3152 CompileRun("Object.defineProperty(obj1, 'x',"
3153 "{ get: function() { return 'z'; }, configurable: false })");
3154 CompileRun("Object.defineProperty(obj2, 'x',"
3155 "{ get: function() { return 'z'; }, configurable: false })");
3156
3157 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3158 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3159
3160 ExpectString("obj1.x", "z");
3161 ExpectString("obj2.x", "z");
3162
3163 CHECK(!GetGlobalProperty(&context, "obj1")->
3164 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3165 CHECK(!GetGlobalProperty(&context, "obj2")->
3166 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3167
3168 ExpectString("obj1.x", "z");
3169 ExpectString("obj2.x", "z");
3170}
3171
3172
3173THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3174 v8::HandleScope scope;
3175 Local<ObjectTemplate> templ = ObjectTemplate::New();
3176 LocalContext context;
3177
3178 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3179 CompileRun("var obj2 = {};");
3180
3181 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3182 v8_str("x"),
3183 GetXValue, NULL,
3184 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3185 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3186 v8_str("x"),
3187 GetXValue, NULL,
3188 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3189
3190 ExpectString("obj1.x", "x");
3191 ExpectString("obj2.x", "x");
3192
3193 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3194 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3195
3196 CHECK(!GetGlobalProperty(&context, "obj1")->
3197 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3198 CHECK(!GetGlobalProperty(&context, "obj2")->
3199 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3200
3201 {
3202 v8::TryCatch try_catch;
3203 CompileRun("Object.defineProperty(obj1, 'x',"
3204 "{get: function() { return 'func'; }})");
3205 CHECK(try_catch.HasCaught());
3206 String::AsciiValue exception_value(try_catch.Exception());
3207 CHECK_EQ(*exception_value,
3208 "TypeError: Cannot redefine property: defineProperty");
3209 }
3210 {
3211 v8::TryCatch try_catch;
3212 CompileRun("Object.defineProperty(obj2, 'x',"
3213 "{get: function() { return 'func'; }})");
3214 CHECK(try_catch.HasCaught());
3215 String::AsciiValue exception_value(try_catch.Exception());
3216 CHECK_EQ(*exception_value,
3217 "TypeError: Cannot redefine property: defineProperty");
3218 }
3219}
3220
3221
3222static v8::Handle<Value> Get239Value(Local<String> name,
3223 const AccessorInfo& info) {
3224 ApiTestFuzzer::Fuzz();
3225 CHECK_EQ(info.Data(), v8_str("donut"));
3226 CHECK_EQ(name, v8_str("239"));
3227 return name;
3228}
3229
3230
3231THREADED_TEST(ElementAPIAccessor) {
3232 v8::HandleScope scope;
3233 Local<ObjectTemplate> templ = ObjectTemplate::New();
3234 LocalContext context;
3235
3236 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3237 CompileRun("var obj2 = {};");
3238
3239 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3240 v8_str("239"),
3241 Get239Value, NULL,
3242 v8_str("donut")));
3243 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3244 v8_str("239"),
3245 Get239Value, NULL,
3246 v8_str("donut")));
3247
3248 ExpectString("obj1[239]", "239");
3249 ExpectString("obj2[239]", "239");
3250 ExpectString("obj1['239']", "239");
3251 ExpectString("obj2['239']", "239");
3252}
3253
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003254
3255v8::Persistent<Value> xValue;
3256
3257
3258static void SetXValue(Local<String> name,
3259 Local<Value> value,
3260 const AccessorInfo& info) {
3261 CHECK_EQ(value, v8_num(4));
3262 CHECK_EQ(info.Data(), v8_str("donut"));
3263 CHECK_EQ(name, v8_str("x"));
3264 CHECK(xValue.IsEmpty());
3265 xValue = v8::Persistent<Value>::New(value);
3266}
3267
3268
3269THREADED_TEST(SimplePropertyWrite) {
3270 v8::HandleScope scope;
3271 Local<ObjectTemplate> templ = ObjectTemplate::New();
3272 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3273 LocalContext context;
3274 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3275 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3276 for (int i = 0; i < 10; i++) {
3277 CHECK(xValue.IsEmpty());
3278 script->Run();
3279 CHECK_EQ(v8_num(4), xValue);
3280 xValue.Dispose();
3281 xValue = v8::Persistent<Value>();
3282 }
3283}
3284
3285
3286static v8::Handle<Value> XPropertyGetter(Local<String> property,
3287 const AccessorInfo& info) {
3288 ApiTestFuzzer::Fuzz();
3289 CHECK(info.Data()->IsUndefined());
3290 return property;
3291}
3292
3293
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003294THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003295 v8::HandleScope scope;
3296 Local<ObjectTemplate> templ = ObjectTemplate::New();
3297 templ->SetNamedPropertyHandler(XPropertyGetter);
3298 LocalContext context;
3299 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3300 Local<Script> script = Script::Compile(v8_str("obj.x"));
3301 for (int i = 0; i < 10; i++) {
3302 Local<Value> result = script->Run();
3303 CHECK_EQ(result, v8_str("x"));
3304 }
3305}
3306
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003307
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003308THREADED_TEST(NamedInterceptorDictionaryIC) {
3309 v8::HandleScope scope;
3310 Local<ObjectTemplate> templ = ObjectTemplate::New();
3311 templ->SetNamedPropertyHandler(XPropertyGetter);
3312 LocalContext context;
3313 // Create an object with a named interceptor.
3314 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3315 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3316 for (int i = 0; i < 10; i++) {
3317 Local<Value> result = script->Run();
3318 CHECK_EQ(result, v8_str("x"));
3319 }
3320 // Create a slow case object and a function accessing a property in
3321 // that slow case object (with dictionary probing in generated
3322 // code). Then force object with a named interceptor into slow-case,
3323 // pass it to the function, and check that the interceptor is called
3324 // instead of accessing the local property.
3325 Local<Value> result =
3326 CompileRun("function get_x(o) { return o.x; };"
3327 "var obj = { x : 42, y : 0 };"
3328 "delete obj.y;"
3329 "for (var i = 0; i < 10; i++) get_x(obj);"
3330 "interceptor_obj.x = 42;"
3331 "interceptor_obj.y = 10;"
3332 "delete interceptor_obj.y;"
3333 "get_x(interceptor_obj)");
3334 CHECK_EQ(result, v8_str("x"));
3335}
3336
3337
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003338THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3339 v8::HandleScope scope;
3340
3341 v8::Persistent<Context> context1 = Context::New();
3342
3343 context1->Enter();
3344 Local<ObjectTemplate> templ = ObjectTemplate::New();
3345 templ->SetNamedPropertyHandler(XPropertyGetter);
3346 // Create an object with a named interceptor.
3347 v8::Local<v8::Object> object = templ->NewInstance();
3348 context1->Global()->Set(v8_str("interceptor_obj"), object);
3349
3350 // Force the object into the slow case.
3351 CompileRun("interceptor_obj.y = 0;"
3352 "delete interceptor_obj.y;");
3353 context1->Exit();
3354
3355 {
3356 // Introduce the object into a different context.
3357 // Repeat named loads to exercise ICs.
3358 LocalContext context2;
3359 context2->Global()->Set(v8_str("interceptor_obj"), object);
3360 Local<Value> result =
3361 CompileRun("function get_x(o) { return o.x; }"
3362 "interceptor_obj.x = 42;"
3363 "for (var i=0; i != 10; i++) {"
3364 " get_x(interceptor_obj);"
3365 "}"
3366 "get_x(interceptor_obj)");
3367 // Check that the interceptor was actually invoked.
3368 CHECK_EQ(result, v8_str("x"));
3369 }
3370
3371 // Return to the original context and force some object to the slow case
3372 // to cause the NormalizedMapCache to verify.
3373 context1->Enter();
3374 CompileRun("var obj = { x : 0 }; delete obj.x;");
3375 context1->Exit();
3376
3377 context1.Dispose();
3378}
3379
3380
ager@chromium.org5c838252010-02-19 08:53:10 +00003381static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3382 const AccessorInfo& info) {
3383 // Set x on the prototype object and do not handle the get request.
3384 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003385 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003386 return v8::Handle<Value>();
3387}
3388
3389
3390// This is a regression test for http://crbug.com/20104. Map
3391// transitions should not interfere with post interceptor lookup.
3392THREADED_TEST(NamedInterceptorMapTransitionRead) {
3393 v8::HandleScope scope;
3394 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3395 Local<v8::ObjectTemplate> instance_template
3396 = function_template->InstanceTemplate();
3397 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3398 LocalContext context;
3399 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3400 // Create an instance of F and introduce a map transition for x.
3401 CompileRun("var o = new F(); o.x = 23;");
3402 // Create an instance of F and invoke the getter. The result should be 23.
3403 Local<Value> result = CompileRun("o = new F(); o.x");
3404 CHECK_EQ(result->Int32Value(), 23);
3405}
3406
3407
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003408static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3409 const AccessorInfo& info) {
3410 ApiTestFuzzer::Fuzz();
3411 if (index == 37) {
3412 return v8::Handle<Value>(v8_num(625));
3413 }
3414 return v8::Handle<Value>();
3415}
3416
3417
3418static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3419 Local<Value> value,
3420 const AccessorInfo& info) {
3421 ApiTestFuzzer::Fuzz();
3422 if (index == 39) {
3423 return value;
3424 }
3425 return v8::Handle<Value>();
3426}
3427
3428
3429THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3430 v8::HandleScope scope;
3431 Local<ObjectTemplate> templ = ObjectTemplate::New();
3432 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3433 IndexedPropertySetter);
3434 LocalContext context;
3435 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3436 Local<Script> getter_script = Script::Compile(v8_str(
3437 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3438 Local<Script> setter_script = Script::Compile(v8_str(
3439 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3440 "obj[17] = 23;"
3441 "obj.foo;"));
3442 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3443 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3444 "obj[39] = 47;"
3445 "obj.foo;")); // This setter should not run, due to the interceptor.
3446 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3447 "obj[37];"));
3448 Local<Value> result = getter_script->Run();
3449 CHECK_EQ(v8_num(5), result);
3450 result = setter_script->Run();
3451 CHECK_EQ(v8_num(23), result);
3452 result = interceptor_setter_script->Run();
3453 CHECK_EQ(v8_num(23), result);
3454 result = interceptor_getter_script->Run();
3455 CHECK_EQ(v8_num(625), result);
3456}
3457
3458
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003459static v8::Handle<Value> IdentityIndexedPropertyGetter(
3460 uint32_t index,
3461 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003462 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003463}
3464
3465
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003466THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3467 v8::HandleScope scope;
3468 Local<ObjectTemplate> templ = ObjectTemplate::New();
3469 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3470
3471 LocalContext context;
3472 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3473
3474 // Check fast object case.
3475 const char* fast_case_code =
3476 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3477 ExpectString(fast_case_code, "0");
3478
3479 // Check slow case.
3480 const char* slow_case_code =
3481 "obj.x = 1; delete obj.x;"
3482 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3483 ExpectString(slow_case_code, "1");
3484}
3485
3486
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003487THREADED_TEST(IndexedInterceptorWithNoSetter) {
3488 v8::HandleScope scope;
3489 Local<ObjectTemplate> templ = ObjectTemplate::New();
3490 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3491
3492 LocalContext context;
3493 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3494
3495 const char* code =
3496 "try {"
3497 " obj[0] = 239;"
3498 " for (var i = 0; i < 100; i++) {"
3499 " var v = obj[0];"
3500 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3501 " }"
3502 " 'PASSED'"
3503 "} catch(e) {"
3504 " e"
3505 "}";
3506 ExpectString(code, "PASSED");
3507}
3508
3509
ager@chromium.org5c838252010-02-19 08:53:10 +00003510THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3511 v8::HandleScope scope;
3512 Local<ObjectTemplate> templ = ObjectTemplate::New();
3513 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3514
3515 LocalContext context;
3516 Local<v8::Object> obj = templ->NewInstance();
3517 obj->TurnOnAccessCheck();
3518 context->Global()->Set(v8_str("obj"), obj);
3519
3520 const char* code =
3521 "try {"
3522 " for (var i = 0; i < 100; i++) {"
3523 " var v = obj[0];"
3524 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3525 " }"
3526 " 'PASSED'"
3527 "} catch(e) {"
3528 " e"
3529 "}";
3530 ExpectString(code, "PASSED");
3531}
3532
3533
3534THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3535 i::FLAG_allow_natives_syntax = true;
3536 v8::HandleScope scope;
3537 Local<ObjectTemplate> templ = ObjectTemplate::New();
3538 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3539
3540 LocalContext context;
3541 Local<v8::Object> obj = templ->NewInstance();
3542 context->Global()->Set(v8_str("obj"), obj);
3543
3544 const char* code =
3545 "try {"
3546 " for (var i = 0; i < 100; i++) {"
3547 " var expected = i;"
3548 " if (i == 5) {"
3549 " %EnableAccessChecks(obj);"
3550 " expected = undefined;"
3551 " }"
3552 " var v = obj[i];"
3553 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3554 " if (i == 5) %DisableAccessChecks(obj);"
3555 " }"
3556 " 'PASSED'"
3557 "} catch(e) {"
3558 " e"
3559 "}";
3560 ExpectString(code, "PASSED");
3561}
3562
3563
3564THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3565 v8::HandleScope scope;
3566 Local<ObjectTemplate> templ = ObjectTemplate::New();
3567 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3568
3569 LocalContext context;
3570 Local<v8::Object> obj = templ->NewInstance();
3571 context->Global()->Set(v8_str("obj"), obj);
3572
3573 const char* code =
3574 "try {"
3575 " for (var i = 0; i < 100; i++) {"
3576 " var v = obj[i];"
3577 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3578 " }"
3579 " 'PASSED'"
3580 "} catch(e) {"
3581 " e"
3582 "}";
3583 ExpectString(code, "PASSED");
3584}
3585
3586
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003587THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3588 v8::HandleScope scope;
3589 Local<ObjectTemplate> templ = ObjectTemplate::New();
3590 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3591
3592 LocalContext context;
3593 Local<v8::Object> obj = templ->NewInstance();
3594 context->Global()->Set(v8_str("obj"), obj);
3595
3596 const char* code =
3597 "try {"
3598 " for (var i = 0; i < 100; i++) {"
3599 " var expected = i;"
3600 " var key = i;"
3601 " if (i == 25) {"
3602 " key = -1;"
3603 " expected = undefined;"
3604 " }"
3605 " if (i == 50) {"
3606 " /* probe minimal Smi number on 32-bit platforms */"
3607 " key = -(1 << 30);"
3608 " expected = undefined;"
3609 " }"
3610 " if (i == 75) {"
3611 " /* probe minimal Smi number on 64-bit platforms */"
3612 " key = 1 << 31;"
3613 " expected = undefined;"
3614 " }"
3615 " var v = obj[key];"
3616 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3617 " }"
3618 " 'PASSED'"
3619 "} catch(e) {"
3620 " e"
3621 "}";
3622 ExpectString(code, "PASSED");
3623}
3624
3625
ager@chromium.org5c838252010-02-19 08:53:10 +00003626THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3627 v8::HandleScope scope;
3628 Local<ObjectTemplate> templ = ObjectTemplate::New();
3629 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3630
3631 LocalContext context;
3632 Local<v8::Object> obj = templ->NewInstance();
3633 context->Global()->Set(v8_str("obj"), obj);
3634
3635 const char* code =
3636 "try {"
3637 " for (var i = 0; i < 100; i++) {"
3638 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003640 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003641 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003642 " expected = undefined;"
3643 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003645 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3646 " }"
3647 " 'PASSED'"
3648 "} catch(e) {"
3649 " e"
3650 "}";
3651 ExpectString(code, "PASSED");
3652}
3653
3654
3655THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3656 v8::HandleScope scope;
3657 Local<ObjectTemplate> templ = ObjectTemplate::New();
3658 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3659
3660 LocalContext context;
3661 Local<v8::Object> obj = templ->NewInstance();
3662 context->Global()->Set(v8_str("obj"), obj);
3663
3664 const char* code =
3665 "var original = obj;"
3666 "try {"
3667 " for (var i = 0; i < 100; i++) {"
3668 " var expected = i;"
3669 " if (i == 50) {"
3670 " obj = {50: 'foobar'};"
3671 " expected = 'foobar';"
3672 " }"
3673 " var v = obj[i];"
3674 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3675 " if (i == 50) obj = original;"
3676 " }"
3677 " 'PASSED'"
3678 "} catch(e) {"
3679 " e"
3680 "}";
3681 ExpectString(code, "PASSED");
3682}
3683
3684
3685THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3686 v8::HandleScope scope;
3687 Local<ObjectTemplate> templ = ObjectTemplate::New();
3688 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3689
3690 LocalContext context;
3691 Local<v8::Object> obj = templ->NewInstance();
3692 context->Global()->Set(v8_str("obj"), obj);
3693
3694 const char* code =
3695 "var original = obj;"
3696 "try {"
3697 " for (var i = 0; i < 100; i++) {"
3698 " var expected = i;"
3699 " if (i == 5) {"
3700 " obj = 239;"
3701 " expected = undefined;"
3702 " }"
3703 " var v = obj[i];"
3704 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3705 " if (i == 5) obj = original;"
3706 " }"
3707 " 'PASSED'"
3708 "} catch(e) {"
3709 " e"
3710 "}";
3711 ExpectString(code, "PASSED");
3712}
3713
3714
3715THREADED_TEST(IndexedInterceptorOnProto) {
3716 v8::HandleScope scope;
3717 Local<ObjectTemplate> templ = ObjectTemplate::New();
3718 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3719
3720 LocalContext context;
3721 Local<v8::Object> obj = templ->NewInstance();
3722 context->Global()->Set(v8_str("obj"), obj);
3723
3724 const char* code =
3725 "var o = {__proto__: obj};"
3726 "try {"
3727 " for (var i = 0; i < 100; i++) {"
3728 " var v = o[i];"
3729 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3730 " }"
3731 " 'PASSED'"
3732 "} catch(e) {"
3733 " e"
3734 "}";
3735 ExpectString(code, "PASSED");
3736}
3737
3738
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003739THREADED_TEST(MultiContexts) {
3740 v8::HandleScope scope;
3741 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3742 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3743
3744 Local<String> password = v8_str("Password");
3745
3746 // Create an environment
3747 LocalContext context0(0, templ);
3748 context0->SetSecurityToken(password);
3749 v8::Handle<v8::Object> global0 = context0->Global();
3750 global0->Set(v8_str("custom"), v8_num(1234));
3751 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3752
3753 // Create an independent environment
3754 LocalContext context1(0, templ);
3755 context1->SetSecurityToken(password);
3756 v8::Handle<v8::Object> global1 = context1->Global();
3757 global1->Set(v8_str("custom"), v8_num(1234));
3758 CHECK_NE(global0, global1);
3759 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3760 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3761
3762 // Now create a new context with the old global
3763 LocalContext context2(0, templ, global1);
3764 context2->SetSecurityToken(password);
3765 v8::Handle<v8::Object> global2 = context2->Global();
3766 CHECK_EQ(global1, global2);
3767 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3768 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3769}
3770
3771
3772THREADED_TEST(FunctionPrototypeAcrossContexts) {
3773 // Make sure that functions created by cloning boilerplates cannot
3774 // communicate through their __proto__ field.
3775
3776 v8::HandleScope scope;
3777
3778 LocalContext env0;
3779 v8::Handle<v8::Object> global0 =
3780 env0->Global();
3781 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003782 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003783 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003784 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003785 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003786 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003787 proto0->Set(v8_str("custom"), v8_num(1234));
3788
3789 LocalContext env1;
3790 v8::Handle<v8::Object> global1 =
3791 env1->Global();
3792 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003793 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003794 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003795 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003796 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003797 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003798 CHECK(!proto1->Has(v8_str("custom")));
3799}
3800
3801
3802THREADED_TEST(Regress892105) {
3803 // Make sure that object and array literals created by cloning
3804 // boilerplates cannot communicate through their __proto__
3805 // field. This is rather difficult to check, but we try to add stuff
3806 // to Object.prototype and Array.prototype and create a new
3807 // environment. This should succeed.
3808
3809 v8::HandleScope scope;
3810
3811 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3812 "Array.prototype.arr = 4567;"
3813 "8901");
3814
3815 LocalContext env0;
3816 Local<Script> script0 = Script::Compile(source);
3817 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3818
3819 LocalContext env1;
3820 Local<Script> script1 = Script::Compile(source);
3821 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3822}
3823
3824
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003825THREADED_TEST(UndetectableObject) {
3826 v8::HandleScope scope;
3827 LocalContext env;
3828
3829 Local<v8::FunctionTemplate> desc =
3830 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3831 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3832
3833 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3834 env->Global()->Set(v8_str("undetectable"), obj);
3835
3836 ExpectString("undetectable.toString()", "[object Object]");
3837 ExpectString("typeof undetectable", "undefined");
3838 ExpectString("typeof(undetectable)", "undefined");
3839 ExpectBoolean("typeof undetectable == 'undefined'", true);
3840 ExpectBoolean("typeof undetectable == 'object'", false);
3841 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3842 ExpectBoolean("!undetectable", true);
3843
3844 ExpectObject("true&&undetectable", obj);
3845 ExpectBoolean("false&&undetectable", false);
3846 ExpectBoolean("true||undetectable", true);
3847 ExpectObject("false||undetectable", obj);
3848
3849 ExpectObject("undetectable&&true", obj);
3850 ExpectObject("undetectable&&false", obj);
3851 ExpectBoolean("undetectable||true", true);
3852 ExpectBoolean("undetectable||false", false);
3853
3854 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003855 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003856 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003857 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003858 ExpectBoolean("undetectable==undetectable", true);
3859
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003860
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003861 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003862 ExpectBoolean("null===undetectable", false);
3863 ExpectBoolean("undetectable===undefined", false);
3864 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003865 ExpectBoolean("undetectable===undetectable", true);
3866}
3867
3868
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003869
3870THREADED_TEST(ExtensibleOnUndetectable) {
3871 v8::HandleScope scope;
3872 LocalContext env;
3873
3874 Local<v8::FunctionTemplate> desc =
3875 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3876 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3877
3878 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3879 env->Global()->Set(v8_str("undetectable"), obj);
3880
3881 Local<String> source = v8_str("undetectable.x = 42;"
3882 "undetectable.x");
3883
3884 Local<Script> script = Script::Compile(source);
3885
3886 CHECK_EQ(v8::Integer::New(42), script->Run());
3887
3888 ExpectBoolean("Object.isExtensible(undetectable)", true);
3889
3890 source = v8_str("Object.preventExtensions(undetectable);");
3891 script = Script::Compile(source);
3892 script->Run();
3893 ExpectBoolean("Object.isExtensible(undetectable)", false);
3894
3895 source = v8_str("undetectable.y = 2000;");
3896 script = Script::Compile(source);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003897 Local<Value> result = script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003898 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003899}
3900
3901
3902
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003903THREADED_TEST(UndetectableString) {
3904 v8::HandleScope scope;
3905 LocalContext env;
3906
3907 Local<String> obj = String::NewUndetectable("foo");
3908 env->Global()->Set(v8_str("undetectable"), obj);
3909
3910 ExpectString("undetectable", "foo");
3911 ExpectString("typeof undetectable", "undefined");
3912 ExpectString("typeof(undetectable)", "undefined");
3913 ExpectBoolean("typeof undetectable == 'undefined'", true);
3914 ExpectBoolean("typeof undetectable == 'string'", false);
3915 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3916 ExpectBoolean("!undetectable", true);
3917
3918 ExpectObject("true&&undetectable", obj);
3919 ExpectBoolean("false&&undetectable", false);
3920 ExpectBoolean("true||undetectable", true);
3921 ExpectObject("false||undetectable", obj);
3922
3923 ExpectObject("undetectable&&true", obj);
3924 ExpectObject("undetectable&&false", obj);
3925 ExpectBoolean("undetectable||true", true);
3926 ExpectBoolean("undetectable||false", false);
3927
3928 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003929 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003930 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003931 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003932 ExpectBoolean("undetectable==undetectable", true);
3933
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003934
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003935 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00003936 ExpectBoolean("null===undetectable", false);
3937 ExpectBoolean("undetectable===undefined", false);
3938 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003939 ExpectBoolean("undetectable===undetectable", true);
3940}
3941
3942
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003943TEST(UndetectableOptimized) {
3944 i::FLAG_allow_natives_syntax = true;
3945 v8::HandleScope scope;
3946 LocalContext env;
3947
3948 Local<String> obj = String::NewUndetectable("foo");
3949 env->Global()->Set(v8_str("undetectable"), obj);
3950 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
3951
3952 ExpectString(
3953 "function testBranch() {"
3954 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
3955 " if (%_IsUndetectableObject(detectable)) throw 2;"
3956 "}\n"
3957 "function testBool() {"
3958 " var b1 = !%_IsUndetectableObject(undetectable);"
3959 " var b2 = %_IsUndetectableObject(detectable);"
3960 " if (b1) throw 3;"
3961 " if (b2) throw 4;"
3962 " return b1 == b2;"
3963 "}\n"
3964 "%OptimizeFunctionOnNextCall(testBranch);"
3965 "%OptimizeFunctionOnNextCall(testBool);"
3966 "for (var i = 0; i < 10; i++) {"
3967 " testBranch();"
3968 " testBool();"
3969 "}\n"
3970 "\"PASS\"",
3971 "PASS");
3972}
3973
3974
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003975template <typename T> static void USE(T) { }
3976
3977
3978// This test is not intended to be run, just type checked.
3979static void PersistentHandles() {
3980 USE(PersistentHandles);
3981 Local<String> str = v8_str("foo");
3982 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3983 USE(p_str);
3984 Local<Script> scr = Script::Compile(v8_str(""));
3985 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3986 USE(p_scr);
3987 Local<ObjectTemplate> templ = ObjectTemplate::New();
3988 v8::Persistent<ObjectTemplate> p_templ =
3989 v8::Persistent<ObjectTemplate>::New(templ);
3990 USE(p_templ);
3991}
3992
3993
3994static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3995 ApiTestFuzzer::Fuzz();
3996 return v8::Undefined();
3997}
3998
3999
4000THREADED_TEST(GlobalObjectTemplate) {
4001 v8::HandleScope handle_scope;
4002 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4003 global_template->Set(v8_str("JSNI_Log"),
4004 v8::FunctionTemplate::New(HandleLogDelegator));
4005 v8::Persistent<Context> context = Context::New(0, global_template);
4006 Context::Scope context_scope(context);
4007 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4008 context.Dispose();
4009}
4010
4011
4012static const char* kSimpleExtensionSource =
4013 "function Foo() {"
4014 " return 4;"
4015 "}";
4016
4017
4018THREADED_TEST(SimpleExtensions) {
4019 v8::HandleScope handle_scope;
4020 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4021 const char* extension_names[] = { "simpletest" };
4022 v8::ExtensionConfiguration extensions(1, extension_names);
4023 v8::Handle<Context> context = Context::New(&extensions);
4024 Context::Scope lock(context);
4025 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4026 CHECK_EQ(result, v8::Integer::New(4));
4027}
4028
4029
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004030static const char* kEvalExtensionSource1 =
4031 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004032 " var x = 42;"
4033 " return eval('x');"
4034 "}";
4035
4036
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004037static const char* kEvalExtensionSource2 =
4038 "(function() {"
4039 " var x = 42;"
4040 " function e() {"
4041 " return eval('x');"
4042 " }"
4043 " this.UseEval2 = e;"
4044 "})()";
4045
4046
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004047THREADED_TEST(UseEvalFromExtension) {
4048 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004049 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4050 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4051 const char* extension_names[] = { "evaltest1", "evaltest2" };
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("UseEval1()"))->Run();
4056 CHECK_EQ(result, v8::Integer::New(42));
4057 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004058 CHECK_EQ(result, v8::Integer::New(42));
4059}
4060
4061
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004062static const char* kWithExtensionSource1 =
4063 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004064 " var x = 42;"
4065 " with({x:87}) { return x; }"
4066 "}";
4067
4068
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004069
4070static const char* kWithExtensionSource2 =
4071 "(function() {"
4072 " var x = 42;"
4073 " function e() {"
4074 " with ({x:87}) { return x; }"
4075 " }"
4076 " this.UseWith2 = e;"
4077 "})()";
4078
4079
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004080THREADED_TEST(UseWithFromExtension) {
4081 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004082 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4083 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4084 const char* extension_names[] = { "withtest1", "withtest2" };
4085 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004086 v8::Handle<Context> context = Context::New(&extensions);
4087 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004088 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4089 CHECK_EQ(result, v8::Integer::New(87));
4090 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004091 CHECK_EQ(result, v8::Integer::New(87));
4092}
4093
4094
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004095THREADED_TEST(AutoExtensions) {
4096 v8::HandleScope handle_scope;
4097 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4098 extension->set_auto_enable(true);
4099 v8::RegisterExtension(extension);
4100 v8::Handle<Context> context = Context::New();
4101 Context::Scope lock(context);
4102 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4103 CHECK_EQ(result, v8::Integer::New(4));
4104}
4105
4106
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004107static const char* kSyntaxErrorInExtensionSource =
4108 "[";
4109
4110
4111// Test that a syntax error in an extension does not cause a fatal
4112// error but results in an empty context.
4113THREADED_TEST(SyntaxErrorExtensions) {
4114 v8::HandleScope handle_scope;
4115 v8::RegisterExtension(new Extension("syntaxerror",
4116 kSyntaxErrorInExtensionSource));
4117 const char* extension_names[] = { "syntaxerror" };
4118 v8::ExtensionConfiguration extensions(1, extension_names);
4119 v8::Handle<Context> context = Context::New(&extensions);
4120 CHECK(context.IsEmpty());
4121}
4122
4123
4124static const char* kExceptionInExtensionSource =
4125 "throw 42";
4126
4127
4128// Test that an exception when installing an extension does not cause
4129// a fatal error but results in an empty context.
4130THREADED_TEST(ExceptionExtensions) {
4131 v8::HandleScope handle_scope;
4132 v8::RegisterExtension(new Extension("exception",
4133 kExceptionInExtensionSource));
4134 const char* extension_names[] = { "exception" };
4135 v8::ExtensionConfiguration extensions(1, extension_names);
4136 v8::Handle<Context> context = Context::New(&extensions);
4137 CHECK(context.IsEmpty());
4138}
4139
4140
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004141static const char* kNativeCallInExtensionSource =
4142 "function call_runtime_last_index_of(x) {"
4143 " return %StringLastIndexOf(x, 'bob', 10);"
4144 "}";
4145
4146
4147static const char* kNativeCallTest =
4148 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4149
4150// Test that a native runtime calls are supported in extensions.
4151THREADED_TEST(NativeCallInExtensions) {
4152 v8::HandleScope handle_scope;
4153 v8::RegisterExtension(new Extension("nativecall",
4154 kNativeCallInExtensionSource));
4155 const char* extension_names[] = { "nativecall" };
4156 v8::ExtensionConfiguration extensions(1, extension_names);
4157 v8::Handle<Context> context = Context::New(&extensions);
4158 Context::Scope lock(context);
4159 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4160 CHECK_EQ(result, v8::Integer::New(3));
4161}
4162
4163
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004164static void CheckDependencies(const char* name, const char* expected) {
4165 v8::HandleScope handle_scope;
4166 v8::ExtensionConfiguration config(1, &name);
4167 LocalContext context(&config);
4168 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4169}
4170
4171
4172/*
4173 * Configuration:
4174 *
4175 * /-- B <--\
4176 * A <- -- D <-- E
4177 * \-- C <--/
4178 */
4179THREADED_TEST(ExtensionDependency) {
4180 static const char* kEDeps[] = { "D" };
4181 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4182 static const char* kDDeps[] = { "B", "C" };
4183 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4184 static const char* kBCDeps[] = { "A" };
4185 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4186 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4187 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4188 CheckDependencies("A", "undefinedA");
4189 CheckDependencies("B", "undefinedAB");
4190 CheckDependencies("C", "undefinedAC");
4191 CheckDependencies("D", "undefinedABCD");
4192 CheckDependencies("E", "undefinedABCDE");
4193 v8::HandleScope handle_scope;
4194 static const char* exts[2] = { "C", "E" };
4195 v8::ExtensionConfiguration config(2, exts);
4196 LocalContext context(&config);
4197 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4198}
4199
4200
4201static const char* kExtensionTestScript =
4202 "native function A();"
4203 "native function B();"
4204 "native function C();"
4205 "function Foo(i) {"
4206 " if (i == 0) return A();"
4207 " if (i == 1) return B();"
4208 " if (i == 2) return C();"
4209 "}";
4210
4211
4212static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4213 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004214 if (args.IsConstructCall()) {
4215 args.This()->Set(v8_str("data"), args.Data());
4216 return v8::Null();
4217 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004218 return args.Data();
4219}
4220
4221
4222class FunctionExtension : public Extension {
4223 public:
4224 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4225 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4226 v8::Handle<String> name);
4227};
4228
4229
4230static int lookup_count = 0;
4231v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4232 v8::Handle<String> name) {
4233 lookup_count++;
4234 if (name->Equals(v8_str("A"))) {
4235 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4236 } else if (name->Equals(v8_str("B"))) {
4237 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4238 } else if (name->Equals(v8_str("C"))) {
4239 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4240 } else {
4241 return v8::Handle<v8::FunctionTemplate>();
4242 }
4243}
4244
4245
4246THREADED_TEST(FunctionLookup) {
4247 v8::RegisterExtension(new FunctionExtension());
4248 v8::HandleScope handle_scope;
4249 static const char* exts[1] = { "functiontest" };
4250 v8::ExtensionConfiguration config(1, exts);
4251 LocalContext context(&config);
4252 CHECK_EQ(3, lookup_count);
4253 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4254 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4255 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4256}
4257
4258
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004259THREADED_TEST(NativeFunctionConstructCall) {
4260 v8::RegisterExtension(new FunctionExtension());
4261 v8::HandleScope handle_scope;
4262 static const char* exts[1] = { "functiontest" };
4263 v8::ExtensionConfiguration config(1, exts);
4264 LocalContext context(&config);
4265 for (int i = 0; i < 10; i++) {
4266 // Run a few times to ensure that allocation of objects doesn't
4267 // change behavior of a constructor function.
4268 CHECK_EQ(v8::Integer::New(8),
4269 Script::Compile(v8_str("(new A()).data"))->Run());
4270 CHECK_EQ(v8::Integer::New(7),
4271 Script::Compile(v8_str("(new B()).data"))->Run());
4272 CHECK_EQ(v8::Integer::New(6),
4273 Script::Compile(v8_str("(new C()).data"))->Run());
4274 }
4275}
4276
4277
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004278static const char* last_location;
4279static const char* last_message;
4280void StoringErrorCallback(const char* location, const char* message) {
4281 if (last_location == NULL) {
4282 last_location = location;
4283 last_message = message;
4284 }
4285}
4286
4287
4288// ErrorReporting creates a circular extensions configuration and
4289// tests that the fatal error handler gets called. This renders V8
4290// unusable and therefore this test cannot be run in parallel.
4291TEST(ErrorReporting) {
4292 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4293 static const char* aDeps[] = { "B" };
4294 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4295 static const char* bDeps[] = { "A" };
4296 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4297 last_location = NULL;
4298 v8::ExtensionConfiguration config(1, bDeps);
4299 v8::Handle<Context> context = Context::New(&config);
4300 CHECK(context.IsEmpty());
4301 CHECK_NE(last_location, NULL);
4302}
4303
4304
ager@chromium.org7c537e22008-10-16 08:43:32 +00004305static const char* js_code_causing_huge_string_flattening =
4306 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004307 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004308 " str = str + str;"
4309 "}"
4310 "str.match(/X/);";
4311
4312
4313void OOMCallback(const char* location, const char* message) {
4314 exit(0);
4315}
4316
4317
4318TEST(RegexpOutOfMemory) {
4319 // Execute a script that causes out of memory when flattening a string.
4320 v8::HandleScope scope;
4321 v8::V8::SetFatalErrorHandler(OOMCallback);
4322 LocalContext context;
4323 Local<Script> script =
4324 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4325 last_location = NULL;
4326 Local<Value> result = script->Run();
4327
4328 CHECK(false); // Should not return.
4329}
4330
4331
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004332static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4333 v8::Handle<Value> data) {
4334 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004335 CHECK(message->GetScriptResourceName()->IsUndefined());
4336 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004337 message->GetLineNumber();
4338 message->GetSourceLine();
4339}
4340
4341
4342THREADED_TEST(ErrorWithMissingScriptInfo) {
4343 v8::HandleScope scope;
4344 LocalContext context;
4345 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4346 Script::Compile(v8_str("throw Error()"))->Run();
4347 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4348}
4349
4350
4351int global_index = 0;
4352
4353class Snorkel {
4354 public:
4355 Snorkel() { index_ = global_index++; }
4356 int index_;
4357};
4358
4359class Whammy {
4360 public:
4361 Whammy() {
4362 cursor_ = 0;
4363 }
4364 ~Whammy() {
4365 script_.Dispose();
4366 }
4367 v8::Handle<Script> getScript() {
4368 if (script_.IsEmpty())
4369 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4370 return Local<Script>(*script_);
4371 }
4372
4373 public:
4374 static const int kObjectCount = 256;
4375 int cursor_;
4376 v8::Persistent<v8::Object> objects_[kObjectCount];
4377 v8::Persistent<Script> script_;
4378};
4379
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004380static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004381 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4382 delete snorkel;
4383 obj.ClearWeak();
4384}
4385
4386v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4387 const AccessorInfo& info) {
4388 Whammy* whammy =
4389 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4390
4391 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4392
4393 v8::Handle<v8::Object> obj = v8::Object::New();
4394 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4395 if (!prev.IsEmpty()) {
4396 prev->Set(v8_str("next"), obj);
4397 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4398 whammy->objects_[whammy->cursor_].Clear();
4399 }
4400 whammy->objects_[whammy->cursor_] = global;
4401 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4402 return whammy->getScript()->Run();
4403}
4404
4405THREADED_TEST(WeakReference) {
4406 v8::HandleScope handle_scope;
4407 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004408 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004409 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4410 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004411 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004412 const char* extension_list[] = { "v8/gc" };
4413 v8::ExtensionConfiguration extensions(1, extension_list);
4414 v8::Persistent<Context> context = Context::New(&extensions);
4415 Context::Scope context_scope(context);
4416
4417 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4418 context->Global()->Set(v8_str("whammy"), interceptor);
4419 const char* code =
4420 "var last;"
4421 "for (var i = 0; i < 10000; i++) {"
4422 " var obj = whammy.length;"
4423 " if (last) last.next = obj;"
4424 " last = obj;"
4425 "}"
4426 "gc();"
4427 "4";
4428 v8::Handle<Value> result = CompileRun(code);
4429 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004430 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431 context.Dispose();
4432}
4433
4434
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004435static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004436 obj.Dispose();
4437 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004438 *(reinterpret_cast<bool*>(data)) = true;
4439}
4440
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004441
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004442THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004443 v8::Persistent<Context> context = Context::New();
4444 Context::Scope context_scope(context);
4445
4446 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004447
4448 {
4449 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004450 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4451 }
4452
4453 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004454 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4455 object_a.MarkIndependent();
4456 HEAP->PerformScavenge();
4457 CHECK(object_a_disposed);
4458}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004459
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004460
4461static void InvokeScavenge() {
4462 HEAP->PerformScavenge();
4463}
4464
4465
4466static void InvokeMarkSweep() {
4467 HEAP->CollectAllGarbage(false);
4468}
4469
4470
4471static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4472 obj.Dispose();
4473 obj.Clear();
4474 *(reinterpret_cast<bool*>(data)) = true;
4475 InvokeScavenge();
4476}
4477
4478
4479static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4480 obj.Dispose();
4481 obj.Clear();
4482 *(reinterpret_cast<bool*>(data)) = true;
4483 InvokeMarkSweep();
4484}
4485
4486
4487THREADED_TEST(GCFromWeakCallbacks) {
4488 v8::Persistent<Context> context = Context::New();
4489 Context::Scope context_scope(context);
4490
4491 static const int kNumberOfGCTypes = 2;
4492 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4493 {&ForceScavenge, &ForceMarkSweep};
4494
4495 typedef void (*GCInvoker)();
4496 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4497
4498 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4499 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4500 v8::Persistent<v8::Object> object;
4501 {
4502 v8::HandleScope handle_scope;
4503 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4504 }
4505 bool disposed = false;
4506 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4507 object.MarkIndependent();
4508 invoke_gc[outer_gc]();
4509 CHECK(disposed);
4510 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004511 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004512}
4513
4514
4515static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4516 obj.ClearWeak();
4517 *(reinterpret_cast<bool*>(data)) = true;
4518}
4519
4520
4521THREADED_TEST(IndependentHandleRevival) {
4522 v8::Persistent<Context> context = Context::New();
4523 Context::Scope context_scope(context);
4524
4525 v8::Persistent<v8::Object> object;
4526 {
4527 v8::HandleScope handle_scope;
4528 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4529 object->Set(v8_str("x"), v8::Integer::New(1));
4530 v8::Local<String> y_str = v8_str("y");
4531 object->Set(y_str, y_str);
4532 }
4533 bool revived = false;
4534 object.MakeWeak(&revived, &RevivingCallback);
4535 object.MarkIndependent();
4536 HEAP->PerformScavenge();
4537 CHECK(revived);
4538 HEAP->CollectAllGarbage(true);
4539 {
4540 v8::HandleScope handle_scope;
4541 v8::Local<String> y_str = v8_str("y");
4542 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4543 CHECK(object->Get(y_str)->Equals(y_str));
4544 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004545}
4546
4547
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004548v8::Handle<Function> args_fun;
4549
4550
4551static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4552 ApiTestFuzzer::Fuzz();
4553 CHECK_EQ(args_fun, args.Callee());
4554 CHECK_EQ(3, args.Length());
4555 CHECK_EQ(v8::Integer::New(1), args[0]);
4556 CHECK_EQ(v8::Integer::New(2), args[1]);
4557 CHECK_EQ(v8::Integer::New(3), args[2]);
4558 CHECK_EQ(v8::Undefined(), args[3]);
4559 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004560 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004561 return v8::Undefined();
4562}
4563
4564
4565THREADED_TEST(Arguments) {
4566 v8::HandleScope scope;
4567 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4568 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4569 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004570 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004571 v8_compile("f(1, 2, 3)")->Run();
4572}
4573
4574
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004575static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4576 const AccessorInfo&) {
4577 return v8::Handle<Value>();
4578}
4579
4580
4581static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4582 const AccessorInfo&) {
4583 return v8::Handle<Value>();
4584}
4585
4586
4587static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4588 const AccessorInfo&) {
4589 if (!name->Equals(v8_str("foo"))) {
4590 return v8::Handle<v8::Boolean>(); // not intercepted
4591 }
4592
4593 return v8::False(); // intercepted, and don't delete the property
4594}
4595
4596
4597static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4598 if (index != 2) {
4599 return v8::Handle<v8::Boolean>(); // not intercepted
4600 }
4601
4602 return v8::False(); // intercepted, and don't delete the property
4603}
4604
4605
4606THREADED_TEST(Deleter) {
4607 v8::HandleScope scope;
4608 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4609 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4610 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4611 LocalContext context;
4612 context->Global()->Set(v8_str("k"), obj->NewInstance());
4613 CompileRun(
4614 "k.foo = 'foo';"
4615 "k.bar = 'bar';"
4616 "k[2] = 2;"
4617 "k[4] = 4;");
4618 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4619 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4620
4621 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4622 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4623
4624 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4625 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4626
4627 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4628 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4629}
4630
4631
4632static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4633 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004634 if (name->Equals(v8_str("foo")) ||
4635 name->Equals(v8_str("bar")) ||
4636 name->Equals(v8_str("baz"))) {
4637 return v8::Undefined();
4638 }
4639 return v8::Handle<Value>();
4640}
4641
4642
4643static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4644 ApiTestFuzzer::Fuzz();
4645 if (index == 0 || index == 1) return v8::Undefined();
4646 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004647}
4648
4649
4650static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4651 ApiTestFuzzer::Fuzz();
4652 v8::Handle<v8::Array> result = v8::Array::New(3);
4653 result->Set(v8::Integer::New(0), v8_str("foo"));
4654 result->Set(v8::Integer::New(1), v8_str("bar"));
4655 result->Set(v8::Integer::New(2), v8_str("baz"));
4656 return result;
4657}
4658
4659
4660static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4661 ApiTestFuzzer::Fuzz();
4662 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004663 result->Set(v8::Integer::New(0), v8_str("0"));
4664 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004665 return result;
4666}
4667
4668
4669THREADED_TEST(Enumerators) {
4670 v8::HandleScope scope;
4671 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4672 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004673 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004674 LocalContext context;
4675 context->Global()->Set(v8_str("k"), obj->NewInstance());
4676 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004677 "k[10] = 0;"
4678 "k.a = 0;"
4679 "k[5] = 0;"
4680 "k.b = 0;"
4681 "k[4294967295] = 0;"
4682 "k.c = 0;"
4683 "k[4294967296] = 0;"
4684 "k.d = 0;"
4685 "k[140000] = 0;"
4686 "k.e = 0;"
4687 "k[30000000000] = 0;"
4688 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004689 "var result = [];"
4690 "for (var prop in k) {"
4691 " result.push(prop);"
4692 "}"
4693 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004694 // Check that we get all the property names returned including the
4695 // ones from the enumerators in the right order: indexed properties
4696 // in numerical order, indexed interceptor properties, named
4697 // properties in insertion order, named interceptor properties.
4698 // This order is not mandated by the spec, so this test is just
4699 // documenting our behavior.
4700 CHECK_EQ(17, result->Length());
4701 // Indexed properties in numerical order.
4702 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4703 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4704 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4705 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4706 // Indexed interceptor properties in the order they are returned
4707 // from the enumerator interceptor.
4708 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4709 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4710 // Named properties in insertion order.
4711 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4712 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4713 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4714 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4715 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4716 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4717 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4718 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4719 // Named interceptor properties.
4720 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4721 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4722 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004723}
4724
4725
4726int p_getter_count;
4727int p_getter_count2;
4728
4729
4730static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4731 ApiTestFuzzer::Fuzz();
4732 p_getter_count++;
4733 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4734 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4735 if (name->Equals(v8_str("p1"))) {
4736 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4737 } else if (name->Equals(v8_str("p2"))) {
4738 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4739 } else if (name->Equals(v8_str("p3"))) {
4740 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4741 } else if (name->Equals(v8_str("p4"))) {
4742 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4743 }
4744 return v8::Undefined();
4745}
4746
4747
4748static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4749 ApiTestFuzzer::Fuzz();
4750 LocalContext context;
4751 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4752 CompileRun(
4753 "o1.__proto__ = { };"
4754 "var o2 = { __proto__: o1 };"
4755 "var o3 = { __proto__: o2 };"
4756 "var o4 = { __proto__: o3 };"
4757 "for (var i = 0; i < 10; i++) o4.p4;"
4758 "for (var i = 0; i < 10; i++) o3.p3;"
4759 "for (var i = 0; i < 10; i++) o2.p2;"
4760 "for (var i = 0; i < 10; i++) o1.p1;");
4761}
4762
4763
4764static v8::Handle<Value> PGetter2(Local<String> name,
4765 const AccessorInfo& info) {
4766 ApiTestFuzzer::Fuzz();
4767 p_getter_count2++;
4768 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4769 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4770 if (name->Equals(v8_str("p1"))) {
4771 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4772 } else if (name->Equals(v8_str("p2"))) {
4773 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4774 } else if (name->Equals(v8_str("p3"))) {
4775 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4776 } else if (name->Equals(v8_str("p4"))) {
4777 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4778 }
4779 return v8::Undefined();
4780}
4781
4782
4783THREADED_TEST(GetterHolders) {
4784 v8::HandleScope scope;
4785 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4786 obj->SetAccessor(v8_str("p1"), PGetter);
4787 obj->SetAccessor(v8_str("p2"), PGetter);
4788 obj->SetAccessor(v8_str("p3"), PGetter);
4789 obj->SetAccessor(v8_str("p4"), PGetter);
4790 p_getter_count = 0;
4791 RunHolderTest(obj);
4792 CHECK_EQ(40, p_getter_count);
4793}
4794
4795
4796THREADED_TEST(PreInterceptorHolders) {
4797 v8::HandleScope scope;
4798 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4799 obj->SetNamedPropertyHandler(PGetter2);
4800 p_getter_count2 = 0;
4801 RunHolderTest(obj);
4802 CHECK_EQ(40, p_getter_count2);
4803}
4804
4805
4806THREADED_TEST(ObjectInstantiation) {
4807 v8::HandleScope scope;
4808 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4809 templ->SetAccessor(v8_str("t"), PGetter2);
4810 LocalContext context;
4811 context->Global()->Set(v8_str("o"), templ->NewInstance());
4812 for (int i = 0; i < 100; i++) {
4813 v8::HandleScope inner_scope;
4814 v8::Handle<v8::Object> obj = templ->NewInstance();
4815 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4816 context->Global()->Set(v8_str("o2"), obj);
4817 v8::Handle<Value> value =
4818 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4819 CHECK_EQ(v8::True(), value);
4820 context->Global()->Set(v8_str("o"), obj);
4821 }
4822}
4823
4824
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004825static int StrCmp16(uint16_t* a, uint16_t* b) {
4826 while (true) {
4827 if (*a == 0 && *b == 0) return 0;
4828 if (*a != *b) return 0 + *a - *b;
4829 a++;
4830 b++;
4831 }
4832}
4833
4834
4835static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4836 while (true) {
4837 if (n-- == 0) return 0;
4838 if (*a == 0 && *b == 0) return 0;
4839 if (*a != *b) return 0 + *a - *b;
4840 a++;
4841 b++;
4842 }
4843}
4844
4845
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004846THREADED_TEST(StringWrite) {
4847 v8::HandleScope scope;
4848 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004849 // abc<Icelandic eth><Unicode snowman>.
4850 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4851
4852 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004853
4854 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004855 char utf8buf[100];
4856 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004857 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004858 int charlen;
4859
4860 memset(utf8buf, 0x1, sizeof(utf8buf));
4861 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004862 CHECK_EQ(9, len);
4863 CHECK_EQ(5, charlen);
4864 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004865
4866 memset(utf8buf, 0x1, sizeof(utf8buf));
4867 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004868 CHECK_EQ(8, len);
4869 CHECK_EQ(5, charlen);
4870 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004871
4872 memset(utf8buf, 0x1, sizeof(utf8buf));
4873 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004874 CHECK_EQ(5, len);
4875 CHECK_EQ(4, charlen);
4876 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004877
4878 memset(utf8buf, 0x1, sizeof(utf8buf));
4879 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004880 CHECK_EQ(5, len);
4881 CHECK_EQ(4, charlen);
4882 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004883
4884 memset(utf8buf, 0x1, sizeof(utf8buf));
4885 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004886 CHECK_EQ(5, len);
4887 CHECK_EQ(4, charlen);
4888 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004889
4890 memset(utf8buf, 0x1, sizeof(utf8buf));
4891 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004892 CHECK_EQ(3, len);
4893 CHECK_EQ(3, charlen);
4894 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004895
4896 memset(utf8buf, 0x1, sizeof(utf8buf));
4897 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004898 CHECK_EQ(3, len);
4899 CHECK_EQ(3, charlen);
4900 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004901
4902 memset(utf8buf, 0x1, sizeof(utf8buf));
4903 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004904 CHECK_EQ(2, len);
4905 CHECK_EQ(2, charlen);
4906 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004907
4908 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004909 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004910 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004911 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004912 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004913 CHECK_EQ(5, len);
4914 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004915 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004916 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004917
4918 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004919 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004920 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004921 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004922 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004923 CHECK_EQ(4, len);
4924 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004925 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004926 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004927
4928 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004929 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004930 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004931 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004932 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004933 CHECK_EQ(5, len);
4934 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004935 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004936 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004937
4938 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004939 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004940 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004941 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004942 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004943 CHECK_EQ(5, len);
4944 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004945 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004946 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004947
4948 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004949 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004950 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004951 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004952 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004953 CHECK_EQ(1, len);
4954 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004955 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004956 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004957
4958 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004959 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004960 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004961 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004962 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004963 CHECK_EQ(1, len);
4964 CHECK_EQ(0, strcmp("e", buf));
4965 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004966
4967 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004968 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004969 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004970 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004971 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004972 CHECK_EQ(1, len);
4973 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004974 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004975 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004976
4977 memset(buf, 0x1, sizeof(buf));
4978 memset(wbuf, 0x1, sizeof(wbuf));
4979 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004980 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004981 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004982 CHECK_EQ(1, len);
4983 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004984 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004985 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004986}
4987
4988
4989THREADED_TEST(ToArrayIndex) {
4990 v8::HandleScope scope;
4991 LocalContext context;
4992
4993 v8::Handle<String> str = v8_str("42");
4994 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4995 CHECK(!index.IsEmpty());
4996 CHECK_EQ(42.0, index->Uint32Value());
4997 str = v8_str("42asdf");
4998 index = str->ToArrayIndex();
4999 CHECK(index.IsEmpty());
5000 str = v8_str("-42");
5001 index = str->ToArrayIndex();
5002 CHECK(index.IsEmpty());
5003 str = v8_str("4294967295");
5004 index = str->ToArrayIndex();
5005 CHECK(!index.IsEmpty());
5006 CHECK_EQ(4294967295.0, index->Uint32Value());
5007 v8::Handle<v8::Number> num = v8::Number::New(1);
5008 index = num->ToArrayIndex();
5009 CHECK(!index.IsEmpty());
5010 CHECK_EQ(1.0, index->Uint32Value());
5011 num = v8::Number::New(-1);
5012 index = num->ToArrayIndex();
5013 CHECK(index.IsEmpty());
5014 v8::Handle<v8::Object> obj = v8::Object::New();
5015 index = obj->ToArrayIndex();
5016 CHECK(index.IsEmpty());
5017}
5018
5019
5020THREADED_TEST(ErrorConstruction) {
5021 v8::HandleScope scope;
5022 LocalContext context;
5023
5024 v8::Handle<String> foo = v8_str("foo");
5025 v8::Handle<String> message = v8_str("message");
5026 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5027 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005028 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5029 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005030 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5031 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005032 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005033 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5034 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005035 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005036 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5037 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005038 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005039 v8::Handle<Value> error = v8::Exception::Error(foo);
5040 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005041 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005042}
5043
5044
5045static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5046 ApiTestFuzzer::Fuzz();
5047 return v8_num(10);
5048}
5049
5050
5051static void YSetter(Local<String> name,
5052 Local<Value> value,
5053 const AccessorInfo& info) {
5054 if (info.This()->Has(name)) {
5055 info.This()->Delete(name);
5056 }
5057 info.This()->Set(name, value);
5058}
5059
5060
5061THREADED_TEST(DeleteAccessor) {
5062 v8::HandleScope scope;
5063 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5064 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5065 LocalContext context;
5066 v8::Handle<v8::Object> holder = obj->NewInstance();
5067 context->Global()->Set(v8_str("holder"), holder);
5068 v8::Handle<Value> result = CompileRun(
5069 "holder.y = 11; holder.y = 12; holder.y");
5070 CHECK_EQ(12, result->Uint32Value());
5071}
5072
5073
5074THREADED_TEST(TypeSwitch) {
5075 v8::HandleScope scope;
5076 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5077 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5078 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5079 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5080 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5081 LocalContext context;
5082 v8::Handle<v8::Object> obj0 = v8::Object::New();
5083 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5084 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5085 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5086 for (int i = 0; i < 10; i++) {
5087 CHECK_EQ(0, type_switch->match(obj0));
5088 CHECK_EQ(1, type_switch->match(obj1));
5089 CHECK_EQ(2, type_switch->match(obj2));
5090 CHECK_EQ(3, type_switch->match(obj3));
5091 CHECK_EQ(3, type_switch->match(obj3));
5092 CHECK_EQ(2, type_switch->match(obj2));
5093 CHECK_EQ(1, type_switch->match(obj1));
5094 CHECK_EQ(0, type_switch->match(obj0));
5095 }
5096}
5097
5098
5099// For use within the TestSecurityHandler() test.
5100static bool g_security_callback_result = false;
5101static bool NamedSecurityTestCallback(Local<v8::Object> global,
5102 Local<Value> name,
5103 v8::AccessType type,
5104 Local<Value> data) {
5105 // Always allow read access.
5106 if (type == v8::ACCESS_GET)
5107 return true;
5108
5109 // Sometimes allow other access.
5110 return g_security_callback_result;
5111}
5112
5113
5114static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5115 uint32_t key,
5116 v8::AccessType type,
5117 Local<Value> data) {
5118 // Always allow read access.
5119 if (type == v8::ACCESS_GET)
5120 return true;
5121
5122 // Sometimes allow other access.
5123 return g_security_callback_result;
5124}
5125
5126
5127static int trouble_nesting = 0;
5128static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5129 ApiTestFuzzer::Fuzz();
5130 trouble_nesting++;
5131
5132 // Call a JS function that throws an uncaught exception.
5133 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5134 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5135 arg_this->Get(v8_str("trouble_callee")) :
5136 arg_this->Get(v8_str("trouble_caller"));
5137 CHECK(trouble_callee->IsFunction());
5138 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5139}
5140
5141
5142static int report_count = 0;
5143static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5144 v8::Handle<Value>) {
5145 report_count++;
5146}
5147
5148
5149// Counts uncaught exceptions, but other tests running in parallel
5150// also have uncaught exceptions.
5151TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005152 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005153 v8::HandleScope scope;
5154 LocalContext env;
5155 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5156
5157 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5158 v8::Local<v8::Object> global = env->Global();
5159 global->Set(v8_str("trouble"), fun->GetFunction());
5160
5161 Script::Compile(v8_str("function trouble_callee() {"
5162 " var x = null;"
5163 " return x.foo;"
5164 "};"
5165 "function trouble_caller() {"
5166 " trouble();"
5167 "};"))->Run();
5168 Local<Value> trouble = global->Get(v8_str("trouble"));
5169 CHECK(trouble->IsFunction());
5170 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5171 CHECK(trouble_callee->IsFunction());
5172 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5173 CHECK(trouble_caller->IsFunction());
5174 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5175 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005176 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5177}
5178
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005179static const char* script_resource_name = "ExceptionInNativeScript.js";
5180static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5181 v8::Handle<Value>) {
5182 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5183 CHECK(!name_val.IsEmpty() && name_val->IsString());
5184 v8::String::AsciiValue name(message->GetScriptResourceName());
5185 CHECK_EQ(script_resource_name, *name);
5186 CHECK_EQ(3, message->GetLineNumber());
5187 v8::String::AsciiValue source_line(message->GetSourceLine());
5188 CHECK_EQ(" new o.foo();", *source_line);
5189}
5190
5191TEST(ExceptionInNativeScript) {
5192 v8::HandleScope scope;
5193 LocalContext env;
5194 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5195
5196 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5197 v8::Local<v8::Object> global = env->Global();
5198 global->Set(v8_str("trouble"), fun->GetFunction());
5199
5200 Script::Compile(v8_str("function trouble() {\n"
5201 " var o = {};\n"
5202 " new o.foo();\n"
5203 "};"), v8::String::New(script_resource_name))->Run();
5204 Local<Value> trouble = global->Get(v8_str("trouble"));
5205 CHECK(trouble->IsFunction());
5206 Function::Cast(*trouble)->Call(global, 0, NULL);
5207 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5208}
5209
ager@chromium.org8bb60582008-12-11 12:02:20 +00005210
5211TEST(CompilationErrorUsingTryCatchHandler) {
5212 v8::HandleScope scope;
5213 LocalContext env;
5214 v8::TryCatch try_catch;
5215 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5216 CHECK_NE(NULL, *try_catch.Exception());
5217 CHECK(try_catch.HasCaught());
5218}
5219
5220
5221TEST(TryCatchFinallyUsingTryCatchHandler) {
5222 v8::HandleScope scope;
5223 LocalContext env;
5224 v8::TryCatch try_catch;
5225 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5226 CHECK(!try_catch.HasCaught());
5227 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5228 CHECK(try_catch.HasCaught());
5229 try_catch.Reset();
5230 Script::Compile(v8_str("(function() {"
5231 "try { throw ''; } finally { return; }"
5232 "})()"))->Run();
5233 CHECK(!try_catch.HasCaught());
5234 Script::Compile(v8_str("(function()"
5235 " { try { throw ''; } finally { throw 0; }"
5236 "})()"))->Run();
5237 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005238}
5239
5240
5241// SecurityHandler can't be run twice
5242TEST(SecurityHandler) {
5243 v8::HandleScope scope0;
5244 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5245 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5246 IndexedSecurityTestCallback);
5247 // Create an environment
5248 v8::Persistent<Context> context0 =
5249 Context::New(NULL, global_template);
5250 context0->Enter();
5251
5252 v8::Handle<v8::Object> global0 = context0->Global();
5253 v8::Handle<Script> script0 = v8_compile("foo = 111");
5254 script0->Run();
5255 global0->Set(v8_str("0"), v8_num(999));
5256 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5257 CHECK_EQ(111, foo0->Int32Value());
5258 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5259 CHECK_EQ(999, z0->Int32Value());
5260
5261 // Create another environment, should fail security checks.
5262 v8::HandleScope scope1;
5263
5264 v8::Persistent<Context> context1 =
5265 Context::New(NULL, global_template);
5266 context1->Enter();
5267
5268 v8::Handle<v8::Object> global1 = context1->Global();
5269 global1->Set(v8_str("othercontext"), global0);
5270 // This set will fail the security check.
5271 v8::Handle<Script> script1 =
5272 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5273 script1->Run();
5274 // This read will pass the security check.
5275 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5276 CHECK_EQ(111, foo1->Int32Value());
5277 // This read will pass the security check.
5278 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5279 CHECK_EQ(999, z1->Int32Value());
5280
5281 // Create another environment, should pass security checks.
5282 { g_security_callback_result = true; // allow security handler to pass.
5283 v8::HandleScope scope2;
5284 LocalContext context2;
5285 v8::Handle<v8::Object> global2 = context2->Global();
5286 global2->Set(v8_str("othercontext"), global0);
5287 v8::Handle<Script> script2 =
5288 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5289 script2->Run();
5290 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5291 CHECK_EQ(333, foo2->Int32Value());
5292 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5293 CHECK_EQ(888, z2->Int32Value());
5294 }
5295
5296 context1->Exit();
5297 context1.Dispose();
5298
5299 context0->Exit();
5300 context0.Dispose();
5301}
5302
5303
5304THREADED_TEST(SecurityChecks) {
5305 v8::HandleScope handle_scope;
5306 LocalContext env1;
5307 v8::Persistent<Context> env2 = Context::New();
5308
5309 Local<Value> foo = v8_str("foo");
5310 Local<Value> bar = v8_str("bar");
5311
5312 // Set to the same domain.
5313 env1->SetSecurityToken(foo);
5314
5315 // Create a function in env1.
5316 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5317 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5318 CHECK(spy->IsFunction());
5319
5320 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005321 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005322 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5323 CHECK(spy2->IsFunction());
5324
5325 // Switch to env2 in the same domain and invoke spy on env2.
5326 {
5327 env2->SetSecurityToken(foo);
5328 // Enter env2
5329 Context::Scope scope_env2(env2);
5330 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5331 CHECK(result->IsFunction());
5332 }
5333
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005334 {
5335 env2->SetSecurityToken(bar);
5336 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005337
5338 // Call cross_domain_call, it should throw an exception
5339 v8::TryCatch try_catch;
5340 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5341 CHECK(try_catch.HasCaught());
5342 }
5343
5344 env2.Dispose();
5345}
5346
5347
5348// Regression test case for issue 1183439.
5349THREADED_TEST(SecurityChecksForPrototypeChain) {
5350 v8::HandleScope scope;
5351 LocalContext current;
5352 v8::Persistent<Context> other = Context::New();
5353
5354 // Change context to be able to get to the Object function in the
5355 // other context without hitting the security checks.
5356 v8::Local<Value> other_object;
5357 { Context::Scope scope(other);
5358 other_object = other->Global()->Get(v8_str("Object"));
5359 other->Global()->Set(v8_num(42), v8_num(87));
5360 }
5361
5362 current->Global()->Set(v8_str("other"), other->Global());
5363 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5364
5365 // Make sure the security check fails here and we get an undefined
5366 // result instead of getting the Object function. Repeat in a loop
5367 // to make sure to exercise the IC code.
5368 v8::Local<Script> access_other0 = v8_compile("other.Object");
5369 v8::Local<Script> access_other1 = v8_compile("other[42]");
5370 for (int i = 0; i < 5; i++) {
5371 CHECK(!access_other0->Run()->Equals(other_object));
5372 CHECK(access_other0->Run()->IsUndefined());
5373 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5374 CHECK(access_other1->Run()->IsUndefined());
5375 }
5376
5377 // Create an object that has 'other' in its prototype chain and make
5378 // sure we cannot access the Object function indirectly through
5379 // that. Repeat in a loop to make sure to exercise the IC code.
5380 v8_compile("function F() { };"
5381 "F.prototype = other;"
5382 "var f = new F();")->Run();
5383 v8::Local<Script> access_f0 = v8_compile("f.Object");
5384 v8::Local<Script> access_f1 = v8_compile("f[42]");
5385 for (int j = 0; j < 5; j++) {
5386 CHECK(!access_f0->Run()->Equals(other_object));
5387 CHECK(access_f0->Run()->IsUndefined());
5388 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5389 CHECK(access_f1->Run()->IsUndefined());
5390 }
5391
5392 // Now it gets hairy: Set the prototype for the other global object
5393 // to be the current global object. The prototype chain for 'f' now
5394 // goes through 'other' but ends up in the current global object.
5395 { Context::Scope scope(other);
5396 other->Global()->Set(v8_str("__proto__"), current->Global());
5397 }
5398 // Set a named and an index property on the current global
5399 // object. To force the lookup to go through the other global object,
5400 // the properties must not exist in the other global object.
5401 current->Global()->Set(v8_str("foo"), v8_num(100));
5402 current->Global()->Set(v8_num(99), v8_num(101));
5403 // Try to read the properties from f and make sure that the access
5404 // gets stopped by the security checks on the other global object.
5405 Local<Script> access_f2 = v8_compile("f.foo");
5406 Local<Script> access_f3 = v8_compile("f[99]");
5407 for (int k = 0; k < 5; k++) {
5408 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5409 CHECK(access_f2->Run()->IsUndefined());
5410 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5411 CHECK(access_f3->Run()->IsUndefined());
5412 }
5413 other.Dispose();
5414}
5415
5416
5417THREADED_TEST(CrossDomainDelete) {
5418 v8::HandleScope handle_scope;
5419 LocalContext env1;
5420 v8::Persistent<Context> env2 = Context::New();
5421
5422 Local<Value> foo = v8_str("foo");
5423 Local<Value> bar = v8_str("bar");
5424
5425 // Set to the same domain.
5426 env1->SetSecurityToken(foo);
5427 env2->SetSecurityToken(foo);
5428
5429 env1->Global()->Set(v8_str("prop"), v8_num(3));
5430 env2->Global()->Set(v8_str("env1"), env1->Global());
5431
5432 // Change env2 to a different domain and delete env1.prop.
5433 env2->SetSecurityToken(bar);
5434 {
5435 Context::Scope scope_env2(env2);
5436 Local<Value> result =
5437 Script::Compile(v8_str("delete env1.prop"))->Run();
5438 CHECK(result->IsFalse());
5439 }
5440
5441 // Check that env1.prop still exists.
5442 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5443 CHECK(v->IsNumber());
5444 CHECK_EQ(3, v->Int32Value());
5445
5446 env2.Dispose();
5447}
5448
5449
ager@chromium.org870a0b62008-11-04 11:43:05 +00005450THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5451 v8::HandleScope handle_scope;
5452 LocalContext env1;
5453 v8::Persistent<Context> env2 = Context::New();
5454
5455 Local<Value> foo = v8_str("foo");
5456 Local<Value> bar = v8_str("bar");
5457
5458 // Set to the same domain.
5459 env1->SetSecurityToken(foo);
5460 env2->SetSecurityToken(foo);
5461
5462 env1->Global()->Set(v8_str("prop"), v8_num(3));
5463 env2->Global()->Set(v8_str("env1"), env1->Global());
5464
5465 // env1.prop is enumerable in env2.
5466 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5467 {
5468 Context::Scope scope_env2(env2);
5469 Local<Value> result = Script::Compile(test)->Run();
5470 CHECK(result->IsTrue());
5471 }
5472
5473 // Change env2 to a different domain and test again.
5474 env2->SetSecurityToken(bar);
5475 {
5476 Context::Scope scope_env2(env2);
5477 Local<Value> result = Script::Compile(test)->Run();
5478 CHECK(result->IsFalse());
5479 }
5480
5481 env2.Dispose();
5482}
5483
5484
ager@chromium.org236ad962008-09-25 09:45:57 +00005485THREADED_TEST(CrossDomainForIn) {
5486 v8::HandleScope handle_scope;
5487 LocalContext env1;
5488 v8::Persistent<Context> env2 = Context::New();
5489
5490 Local<Value> foo = v8_str("foo");
5491 Local<Value> bar = v8_str("bar");
5492
5493 // Set to the same domain.
5494 env1->SetSecurityToken(foo);
5495 env2->SetSecurityToken(foo);
5496
5497 env1->Global()->Set(v8_str("prop"), v8_num(3));
5498 env2->Global()->Set(v8_str("env1"), env1->Global());
5499
5500 // Change env2 to a different domain and set env1's global object
5501 // as the __proto__ of an object in env2 and enumerate properties
5502 // in for-in. It shouldn't enumerate properties on env1's global
5503 // object.
5504 env2->SetSecurityToken(bar);
5505 {
5506 Context::Scope scope_env2(env2);
5507 Local<Value> result =
5508 CompileRun("(function(){var obj = {'__proto__':env1};"
5509 "for (var p in obj)"
5510 " if (p == 'prop') return false;"
5511 "return true;})()");
5512 CHECK(result->IsTrue());
5513 }
5514 env2.Dispose();
5515}
5516
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005517
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005518TEST(ContextDetachGlobal) {
5519 v8::HandleScope handle_scope;
5520 LocalContext env1;
5521 v8::Persistent<Context> env2 = Context::New();
5522
5523 Local<v8::Object> global1 = env1->Global();
5524
5525 Local<Value> foo = v8_str("foo");
5526
5527 // Set to the same domain.
5528 env1->SetSecurityToken(foo);
5529 env2->SetSecurityToken(foo);
5530
5531 // Enter env2
5532 env2->Enter();
5533
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005534 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005535 Local<v8::Object> global2 = env2->Global();
5536 global2->Set(v8_str("prop"), v8::Integer::New(1));
5537 CompileRun("function getProp() {return prop;}");
5538
5539 env1->Global()->Set(v8_str("getProp"),
5540 global2->Get(v8_str("getProp")));
5541
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005542 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005543 env2->Exit();
5544 env2->DetachGlobal();
5545 // env2 has a new global object.
5546 CHECK(!env2->Global()->Equals(global2));
5547
5548 v8::Persistent<Context> env3 =
5549 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5550 env3->SetSecurityToken(v8_str("bar"));
5551 env3->Enter();
5552
5553 Local<v8::Object> global3 = env3->Global();
5554 CHECK_EQ(global2, global3);
5555 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5556 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5557 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5558 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5559 env3->Exit();
5560
5561 // Call getProp in env1, and it should return the value 1
5562 {
5563 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5564 CHECK(get_prop->IsFunction());
5565 v8::TryCatch try_catch;
5566 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5567 CHECK(!try_catch.HasCaught());
5568 CHECK_EQ(1, r->Int32Value());
5569 }
5570
5571 // Check that env3 is not accessible from env1
5572 {
5573 Local<Value> r = global3->Get(v8_str("prop2"));
5574 CHECK(r->IsUndefined());
5575 }
5576
5577 env2.Dispose();
5578 env3.Dispose();
5579}
5580
5581
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005582TEST(DetachAndReattachGlobal) {
5583 v8::HandleScope scope;
5584 LocalContext env1;
5585
5586 // Create second environment.
5587 v8::Persistent<Context> env2 = Context::New();
5588
5589 Local<Value> foo = v8_str("foo");
5590
5591 // Set same security token for env1 and env2.
5592 env1->SetSecurityToken(foo);
5593 env2->SetSecurityToken(foo);
5594
5595 // Create a property on the global object in env2.
5596 {
5597 v8::Context::Scope scope(env2);
5598 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5599 }
5600
5601 // Create a reference to env2 global from env1 global.
5602 env1->Global()->Set(v8_str("other"), env2->Global());
5603
5604 // Check that we have access to other.p in env2 from env1.
5605 Local<Value> result = CompileRun("other.p");
5606 CHECK(result->IsInt32());
5607 CHECK_EQ(42, result->Int32Value());
5608
5609 // Hold on to global from env2 and detach global from env2.
5610 Local<v8::Object> global2 = env2->Global();
5611 env2->DetachGlobal();
5612
5613 // Check that the global has been detached. No other.p property can
5614 // be found.
5615 result = CompileRun("other.p");
5616 CHECK(result->IsUndefined());
5617
5618 // Reuse global2 for env3.
5619 v8::Persistent<Context> env3 =
5620 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5621 CHECK_EQ(global2, env3->Global());
5622
5623 // Start by using the same security token for env3 as for env1 and env2.
5624 env3->SetSecurityToken(foo);
5625
5626 // Create a property on the global object in env3.
5627 {
5628 v8::Context::Scope scope(env3);
5629 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5630 }
5631
5632 // Check that other.p is now the property in env3 and that we have access.
5633 result = CompileRun("other.p");
5634 CHECK(result->IsInt32());
5635 CHECK_EQ(24, result->Int32Value());
5636
5637 // Change security token for env3 to something different from env1 and env2.
5638 env3->SetSecurityToken(v8_str("bar"));
5639
5640 // Check that we do not have access to other.p in env1. |other| is now
5641 // the global object for env3 which has a different security token,
5642 // so access should be blocked.
5643 result = CompileRun("other.p");
5644 CHECK(result->IsUndefined());
5645
5646 // Detach the global for env3 and reattach it to env2.
5647 env3->DetachGlobal();
5648 env2->ReattachGlobal(global2);
5649
5650 // Check that we have access to other.p again in env1. |other| is now
5651 // the global object for env2 which has the same security token as env1.
5652 result = CompileRun("other.p");
5653 CHECK(result->IsInt32());
5654 CHECK_EQ(42, result->Int32Value());
5655
5656 env2.Dispose();
5657 env3.Dispose();
5658}
5659
5660
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005661static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005662static bool NamedAccessBlocker(Local<v8::Object> global,
5663 Local<Value> name,
5664 v8::AccessType type,
5665 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005666 return Context::GetCurrent()->Global()->Equals(global) ||
5667 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005668}
5669
5670
5671static bool IndexedAccessBlocker(Local<v8::Object> global,
5672 uint32_t key,
5673 v8::AccessType type,
5674 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005675 return Context::GetCurrent()->Global()->Equals(global) ||
5676 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005677}
5678
5679
5680static int g_echo_value = -1;
5681static v8::Handle<Value> EchoGetter(Local<String> name,
5682 const AccessorInfo& info) {
5683 return v8_num(g_echo_value);
5684}
5685
5686
5687static void EchoSetter(Local<String> name,
5688 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005689 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005690 if (value->IsNumber())
5691 g_echo_value = value->Int32Value();
5692}
5693
5694
5695static v8::Handle<Value> UnreachableGetter(Local<String> name,
5696 const AccessorInfo& info) {
5697 CHECK(false); // This function should not be called..
5698 return v8::Undefined();
5699}
5700
5701
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005702static void UnreachableSetter(Local<String>, Local<Value>,
5703 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005704 CHECK(false); // This function should nto be called.
5705}
5706
5707
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005708TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005709 v8::HandleScope handle_scope;
5710 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5711
5712 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5713 IndexedAccessBlocker);
5714
5715 // Add an accessor accessible by cross-domain JS code.
5716 global_template->SetAccessor(
5717 v8_str("accessible_prop"),
5718 EchoGetter, EchoSetter,
5719 v8::Handle<Value>(),
5720 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5721
5722 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005723 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005724 UnreachableGetter, UnreachableSetter,
5725 v8::Handle<Value>(),
5726 v8::DEFAULT);
5727
5728 // Create an environment
5729 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5730 context0->Enter();
5731
5732 v8::Handle<v8::Object> global0 = context0->Global();
5733
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005734 // Define a property with JS getter and setter.
5735 CompileRun(
5736 "function getter() { return 'getter'; };\n"
5737 "function setter() { return 'setter'; }\n"
5738 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
5739
5740 Local<Value> getter = global0->Get(v8_str("getter"));
5741 Local<Value> setter = global0->Get(v8_str("setter"));
5742
5743 // And define normal element.
5744 global0->Set(239, v8_str("239"));
5745
5746 // Define an element with JS getter and setter.
5747 CompileRun(
5748 "function el_getter() { return 'el_getter'; };\n"
5749 "function el_setter() { return 'el_setter'; };\n"
5750 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
5751
5752 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
5753 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
5754
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005755 v8::HandleScope scope1;
5756
5757 v8::Persistent<Context> context1 = Context::New();
5758 context1->Enter();
5759
5760 v8::Handle<v8::Object> global1 = context1->Global();
5761 global1->Set(v8_str("other"), global0);
5762
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005763 // Access blocked property.
5764 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005765
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005766 ExpectUndefined("other.blocked_prop");
5767 ExpectUndefined(
5768 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5769 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005770
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005771 // Enable ACCESS_HAS
5772 allowed_access_type[v8::ACCESS_HAS] = true;
5773 ExpectUndefined("other.blocked_prop");
5774 // ... and now we can get the descriptor...
5775 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005776 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005777 // ... and enumerate the property.
5778 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
5779 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005780
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005781 // Access blocked element.
5782 CompileRun("other[239] = 1");
5783
5784 ExpectUndefined("other[239]");
5785 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
5786 ExpectFalse("propertyIsEnumerable.call(other, '239')");
5787
5788 // Enable ACCESS_HAS
5789 allowed_access_type[v8::ACCESS_HAS] = true;
5790 ExpectUndefined("other[239]");
5791 // ... and now we can get the descriptor...
5792 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
5793 // ... and enumerate the property.
5794 ExpectTrue("propertyIsEnumerable.call(other, '239')");
5795 allowed_access_type[v8::ACCESS_HAS] = false;
5796
5797 // Access a property with JS accessor.
5798 CompileRun("other.js_accessor_p = 2");
5799
5800 ExpectUndefined("other.js_accessor_p");
5801 ExpectUndefined(
5802 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
5803
5804 // Enable ACCESS_HAS.
5805 allowed_access_type[v8::ACCESS_HAS] = true;
5806 ExpectUndefined("other.js_accessor_p");
5807 ExpectUndefined(
5808 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5809 ExpectUndefined(
5810 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5811 ExpectUndefined(
5812 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5813 allowed_access_type[v8::ACCESS_HAS] = false;
5814
5815 // Enable both ACCESS_HAS and ACCESS_GET.
5816 allowed_access_type[v8::ACCESS_HAS] = true;
5817 allowed_access_type[v8::ACCESS_GET] = true;
5818
5819 ExpectString("other.js_accessor_p", "getter");
5820 ExpectObject(
5821 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5822 ExpectUndefined(
5823 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
5824 ExpectUndefined(
5825 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5826
5827 allowed_access_type[v8::ACCESS_GET] = false;
5828 allowed_access_type[v8::ACCESS_HAS] = false;
5829
5830 // Enable both ACCESS_HAS and ACCESS_SET.
5831 allowed_access_type[v8::ACCESS_HAS] = true;
5832 allowed_access_type[v8::ACCESS_SET] = true;
5833
5834 ExpectUndefined("other.js_accessor_p");
5835 ExpectUndefined(
5836 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
5837 ExpectObject(
5838 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5839 ExpectUndefined(
5840 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5841
5842 allowed_access_type[v8::ACCESS_SET] = false;
5843 allowed_access_type[v8::ACCESS_HAS] = false;
5844
5845 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5846 allowed_access_type[v8::ACCESS_HAS] = true;
5847 allowed_access_type[v8::ACCESS_GET] = true;
5848 allowed_access_type[v8::ACCESS_SET] = true;
5849
5850 ExpectString("other.js_accessor_p", "getter");
5851 ExpectObject(
5852 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
5853 ExpectObject(
5854 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
5855 ExpectUndefined(
5856 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
5857
5858 allowed_access_type[v8::ACCESS_SET] = false;
5859 allowed_access_type[v8::ACCESS_GET] = false;
5860 allowed_access_type[v8::ACCESS_HAS] = false;
5861
5862 // Access an element with JS accessor.
5863 CompileRun("other[42] = 2");
5864
5865 ExpectUndefined("other[42]");
5866 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
5867
5868 // Enable ACCESS_HAS.
5869 allowed_access_type[v8::ACCESS_HAS] = true;
5870 ExpectUndefined("other[42]");
5871 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5872 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5873 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5874 allowed_access_type[v8::ACCESS_HAS] = false;
5875
5876 // Enable both ACCESS_HAS and ACCESS_GET.
5877 allowed_access_type[v8::ACCESS_HAS] = true;
5878 allowed_access_type[v8::ACCESS_GET] = true;
5879
5880 ExpectString("other[42]", "el_getter");
5881 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5882 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
5883 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5884
5885 allowed_access_type[v8::ACCESS_GET] = false;
5886 allowed_access_type[v8::ACCESS_HAS] = false;
5887
5888 // Enable both ACCESS_HAS and ACCESS_SET.
5889 allowed_access_type[v8::ACCESS_HAS] = true;
5890 allowed_access_type[v8::ACCESS_SET] = true;
5891
5892 ExpectUndefined("other[42]");
5893 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
5894 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5895 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5896
5897 allowed_access_type[v8::ACCESS_SET] = false;
5898 allowed_access_type[v8::ACCESS_HAS] = false;
5899
5900 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
5901 allowed_access_type[v8::ACCESS_HAS] = true;
5902 allowed_access_type[v8::ACCESS_GET] = true;
5903 allowed_access_type[v8::ACCESS_SET] = true;
5904
5905 ExpectString("other[42]", "el_getter");
5906 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
5907 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
5908 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
5909
5910 allowed_access_type[v8::ACCESS_SET] = false;
5911 allowed_access_type[v8::ACCESS_GET] = false;
5912 allowed_access_type[v8::ACCESS_HAS] = false;
5913
5914 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005915
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005916 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005917 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005918 CHECK(value->IsNumber());
5919 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00005920 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005921
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005922 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005923 CHECK(value->IsNumber());
5924 CHECK_EQ(3, value->Int32Value());
5925
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005926 value = CompileRun(
5927 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
5928 CHECK(value->IsNumber());
5929 CHECK_EQ(3, value->Int32Value());
5930
5931 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00005932 CHECK(value->IsTrue());
5933
5934 // Enumeration doesn't enumerate accessors from inaccessible objects in
5935 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005936 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00005937 CompileRun("(function(){var obj = {'__proto__':other};"
5938 "for (var p in obj)"
5939 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5940 " return false;"
5941 " }"
5942 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00005943 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00005944
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005945 context1->Exit();
5946 context0->Exit();
5947 context1.Dispose();
5948 context0.Dispose();
5949}
5950
5951
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005952TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005953 v8::HandleScope handle_scope;
5954 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5955
5956 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5957 IndexedAccessBlocker);
5958
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00005959 // Add accessible accessor.
5960 global_template->SetAccessor(
5961 v8_str("accessible_prop"),
5962 EchoGetter, EchoSetter,
5963 v8::Handle<Value>(),
5964 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5965
5966
ricow@chromium.org65001782011-02-15 13:36:41 +00005967 // Add an accessor that is not accessible by cross-domain JS code.
5968 global_template->SetAccessor(v8_str("blocked_prop"),
5969 UnreachableGetter, UnreachableSetter,
5970 v8::Handle<Value>(),
5971 v8::DEFAULT);
5972
5973 // Create an environment
5974 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5975 context0->Enter();
5976
5977 v8::Handle<v8::Object> global0 = context0->Global();
5978
5979 v8::Persistent<Context> context1 = Context::New();
5980 context1->Enter();
5981 v8::Handle<v8::Object> global1 = context1->Global();
5982 global1->Set(v8_str("other"), global0);
5983
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005984 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00005985 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005986
5987 ExpectUndefined("other.blocked_prop");
5988
5989 // Regression test for issue 1027.
5990 CompileRun("Object.defineProperty(\n"
5991 " other, 'blocked_prop', {configurable: false})");
5992 ExpectUndefined("other.blocked_prop");
5993 ExpectUndefined(
5994 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
5995
5996 // Regression test for issue 1171.
5997 ExpectTrue("Object.isExtensible(other)");
5998 CompileRun("Object.preventExtensions(other)");
5999 ExpectTrue("Object.isExtensible(other)");
6000
6001 // Object.seal and Object.freeze.
6002 CompileRun("Object.freeze(other)");
6003 ExpectTrue("Object.isExtensible(other)");
6004
6005 CompileRun("Object.seal(other)");
6006 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006007
6008 // Regression test for issue 1250.
6009 // Make sure that we can set the accessible accessors value using normal
6010 // assignment.
6011 CompileRun("other.accessible_prop = 42");
6012 CHECK_EQ(42, g_echo_value);
6013
6014 v8::Handle<Value> value;
6015 // We follow Safari in ignoring assignments to host object accessors.
6016 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6017 value = CompileRun("other.accessible_prop == 42");
6018 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006019}
6020
6021
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006022static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6023 Local<Value> name,
6024 v8::AccessType type,
6025 Local<Value> data) {
6026 return false;
6027}
6028
6029
6030static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6031 uint32_t key,
6032 v8::AccessType type,
6033 Local<Value> data) {
6034 return false;
6035}
6036
6037
6038THREADED_TEST(AccessControlGetOwnPropertyNames) {
6039 v8::HandleScope handle_scope;
6040 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6041
6042 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6043 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6044 GetOwnPropertyNamesIndexedBlocker);
6045
6046 // Create an environment
6047 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6048 context0->Enter();
6049
6050 v8::Handle<v8::Object> global0 = context0->Global();
6051
6052 v8::HandleScope scope1;
6053
6054 v8::Persistent<Context> context1 = Context::New();
6055 context1->Enter();
6056
6057 v8::Handle<v8::Object> global1 = context1->Global();
6058 global1->Set(v8_str("other"), global0);
6059 global1->Set(v8_str("object"), obj_template->NewInstance());
6060
6061 v8::Handle<Value> value;
6062
6063 // Attempt to get the property names of the other global object and
6064 // of an object that requires access checks. Accessing the other
6065 // global object should be blocked by access checks on the global
6066 // proxy object. Accessing the object that requires access checks
6067 // is blocked by the access checks on the object itself.
6068 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6069 CHECK(value->IsTrue());
6070
6071 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6072 CHECK(value->IsTrue());
6073
6074 context1->Exit();
6075 context0->Exit();
6076 context1.Dispose();
6077 context0.Dispose();
6078}
6079
6080
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006081static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6082 v8::Handle<v8::Array> result = v8::Array::New(1);
6083 result->Set(0, v8_str("x"));
6084 return result;
6085}
6086
6087
6088THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6089 v8::HandleScope handle_scope;
6090 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6091
6092 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6093 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6094 NamedPropertyEnumerator);
6095
6096 LocalContext context;
6097 v8::Handle<v8::Object> global = context->Global();
6098 global->Set(v8_str("object"), obj_template->NewInstance());
6099
6100 v8::Handle<Value> value =
6101 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6102 CHECK_EQ(v8_str("x"), value);
6103}
6104
6105
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006106static v8::Handle<Value> ConstTenGetter(Local<String> name,
6107 const AccessorInfo& info) {
6108 return v8_num(10);
6109}
6110
6111
6112THREADED_TEST(CrossDomainAccessors) {
6113 v8::HandleScope handle_scope;
6114
6115 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6116
6117 v8::Handle<v8::ObjectTemplate> global_template =
6118 func_template->InstanceTemplate();
6119
6120 v8::Handle<v8::ObjectTemplate> proto_template =
6121 func_template->PrototypeTemplate();
6122
6123 // Add an accessor to proto that's accessible by cross-domain JS code.
6124 proto_template->SetAccessor(v8_str("accessible"),
6125 ConstTenGetter, 0,
6126 v8::Handle<Value>(),
6127 v8::ALL_CAN_READ);
6128
6129 // Add an accessor that is not accessible by cross-domain JS code.
6130 global_template->SetAccessor(v8_str("unreachable"),
6131 UnreachableGetter, 0,
6132 v8::Handle<Value>(),
6133 v8::DEFAULT);
6134
6135 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6136 context0->Enter();
6137
6138 Local<v8::Object> global = context0->Global();
6139 // Add a normal property that shadows 'accessible'
6140 global->Set(v8_str("accessible"), v8_num(11));
6141
6142 // Enter a new context.
6143 v8::HandleScope scope1;
6144 v8::Persistent<Context> context1 = Context::New();
6145 context1->Enter();
6146
6147 v8::Handle<v8::Object> global1 = context1->Global();
6148 global1->Set(v8_str("other"), global);
6149
6150 // Should return 10, instead of 11
6151 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6152 CHECK(value->IsNumber());
6153 CHECK_EQ(10, value->Int32Value());
6154
6155 value = v8_compile("other.unreachable")->Run();
6156 CHECK(value->IsUndefined());
6157
6158 context1->Exit();
6159 context0->Exit();
6160 context1.Dispose();
6161 context0.Dispose();
6162}
6163
6164
6165static int named_access_count = 0;
6166static int indexed_access_count = 0;
6167
6168static bool NamedAccessCounter(Local<v8::Object> global,
6169 Local<Value> name,
6170 v8::AccessType type,
6171 Local<Value> data) {
6172 named_access_count++;
6173 return true;
6174}
6175
6176
6177static bool IndexedAccessCounter(Local<v8::Object> global,
6178 uint32_t key,
6179 v8::AccessType type,
6180 Local<Value> data) {
6181 indexed_access_count++;
6182 return true;
6183}
6184
6185
6186// This one is too easily disturbed by other tests.
6187TEST(AccessControlIC) {
6188 named_access_count = 0;
6189 indexed_access_count = 0;
6190
6191 v8::HandleScope handle_scope;
6192
6193 // Create an environment.
6194 v8::Persistent<Context> context0 = Context::New();
6195 context0->Enter();
6196
6197 // Create an object that requires access-check functions to be
6198 // called for cross-domain access.
6199 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6200 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6201 IndexedAccessCounter);
6202 Local<v8::Object> object = object_template->NewInstance();
6203
6204 v8::HandleScope scope1;
6205
6206 // Create another environment.
6207 v8::Persistent<Context> context1 = Context::New();
6208 context1->Enter();
6209
6210 // Make easy access to the object from the other environment.
6211 v8::Handle<v8::Object> global1 = context1->Global();
6212 global1->Set(v8_str("obj"), object);
6213
6214 v8::Handle<Value> value;
6215
6216 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006217 CompileRun("function testProp(obj) {"
6218 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6219 " for (var j = 0; j < 10; j++) obj.prop;"
6220 " return obj.prop"
6221 "}");
6222 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006223 CHECK(value->IsNumber());
6224 CHECK_EQ(1, value->Int32Value());
6225 CHECK_EQ(21, named_access_count);
6226
6227 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006228 CompileRun("var p = 'prop';"
6229 "function testKeyed(obj) {"
6230 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6231 " for (var j = 0; j < 10; j++) obj[p];"
6232 " return obj[p];"
6233 "}");
6234 // Use obj which requires access checks. No inline caching is used
6235 // in that case.
6236 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006237 CHECK(value->IsNumber());
6238 CHECK_EQ(1, value->Int32Value());
6239 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006240 // Force the inline caches into generic state and try again.
6241 CompileRun("testKeyed({ a: 0 })");
6242 CompileRun("testKeyed({ b: 0 })");
6243 value = CompileRun("testKeyed(obj)");
6244 CHECK(value->IsNumber());
6245 CHECK_EQ(1, value->Int32Value());
6246 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006247
6248 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006249 CompileRun("function testIndexed(obj) {"
6250 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6251 " for (var j = 0; j < 10; j++) obj[0];"
6252 " return obj[0]"
6253 "}");
6254 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006255 CHECK(value->IsNumber());
6256 CHECK_EQ(1, value->Int32Value());
6257 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006258 // Force the inline caches into generic state.
6259 CompileRun("testIndexed(new Array(1))");
6260 // Test that the indexed access check is called.
6261 value = CompileRun("testIndexed(obj)");
6262 CHECK(value->IsNumber());
6263 CHECK_EQ(1, value->Int32Value());
6264 CHECK_EQ(42, indexed_access_count);
6265
6266 // Check that the named access check is called when invoking
6267 // functions on an object that requires access checks.
6268 CompileRun("obj.f = function() {}");
6269 CompileRun("function testCallNormal(obj) {"
6270 " for (var i = 0; i < 10; i++) obj.f();"
6271 "}");
6272 CompileRun("testCallNormal(obj)");
6273 CHECK_EQ(74, named_access_count);
6274
6275 // Force obj into slow case.
6276 value = CompileRun("delete obj.prop");
6277 CHECK(value->BooleanValue());
6278 // Force inline caches into dictionary probing mode.
6279 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6280 // Test that the named access check is called.
6281 value = CompileRun("testProp(obj);");
6282 CHECK(value->IsNumber());
6283 CHECK_EQ(1, value->Int32Value());
6284 CHECK_EQ(96, named_access_count);
6285
6286 // Force the call inline cache into dictionary probing mode.
6287 CompileRun("o.f = function() {}; testCallNormal(o)");
6288 // Test that the named access check is still called for each
6289 // invocation of the function.
6290 value = CompileRun("testCallNormal(obj)");
6291 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006292
6293 context1->Exit();
6294 context0->Exit();
6295 context1.Dispose();
6296 context0.Dispose();
6297}
6298
6299
6300static bool NamedAccessFlatten(Local<v8::Object> global,
6301 Local<Value> name,
6302 v8::AccessType type,
6303 Local<Value> data) {
6304 char buf[100];
6305 int len;
6306
6307 CHECK(name->IsString());
6308
6309 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006310 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006311 CHECK_EQ(4, len);
6312
6313 uint16_t buf2[100];
6314
6315 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006316 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006317 CHECK_EQ(4, len);
6318
6319 return true;
6320}
6321
6322
6323static bool IndexedAccessFlatten(Local<v8::Object> global,
6324 uint32_t key,
6325 v8::AccessType type,
6326 Local<Value> data) {
6327 return true;
6328}
6329
6330
6331// Regression test. In access checks, operations that may cause
6332// garbage collection are not allowed. It used to be the case that
6333// using the Write operation on a string could cause a garbage
6334// collection due to flattening of the string. This is no longer the
6335// case.
6336THREADED_TEST(AccessControlFlatten) {
6337 named_access_count = 0;
6338 indexed_access_count = 0;
6339
6340 v8::HandleScope handle_scope;
6341
6342 // Create an environment.
6343 v8::Persistent<Context> context0 = Context::New();
6344 context0->Enter();
6345
6346 // Create an object that requires access-check functions to be
6347 // called for cross-domain access.
6348 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6349 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6350 IndexedAccessFlatten);
6351 Local<v8::Object> object = object_template->NewInstance();
6352
6353 v8::HandleScope scope1;
6354
6355 // Create another environment.
6356 v8::Persistent<Context> context1 = Context::New();
6357 context1->Enter();
6358
6359 // Make easy access to the object from the other environment.
6360 v8::Handle<v8::Object> global1 = context1->Global();
6361 global1->Set(v8_str("obj"), object);
6362
6363 v8::Handle<Value> value;
6364
6365 value = v8_compile("var p = 'as' + 'df';")->Run();
6366 value = v8_compile("obj[p];")->Run();
6367
6368 context1->Exit();
6369 context0->Exit();
6370 context1.Dispose();
6371 context0.Dispose();
6372}
6373
6374
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006375static v8::Handle<Value> AccessControlNamedGetter(
6376 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006377 return v8::Integer::New(42);
6378}
6379
6380
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006381static v8::Handle<Value> AccessControlNamedSetter(
6382 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006383 return value;
6384}
6385
6386
6387static v8::Handle<Value> AccessControlIndexedGetter(
6388 uint32_t index,
6389 const AccessorInfo& info) {
6390 return v8_num(42);
6391}
6392
6393
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006394static v8::Handle<Value> AccessControlIndexedSetter(
6395 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006396 return value;
6397}
6398
6399
6400THREADED_TEST(AccessControlInterceptorIC) {
6401 named_access_count = 0;
6402 indexed_access_count = 0;
6403
6404 v8::HandleScope handle_scope;
6405
6406 // Create an environment.
6407 v8::Persistent<Context> context0 = Context::New();
6408 context0->Enter();
6409
6410 // Create an object that requires access-check functions to be
6411 // called for cross-domain access. The object also has interceptors
6412 // interceptor.
6413 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6414 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6415 IndexedAccessCounter);
6416 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6417 AccessControlNamedSetter);
6418 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6419 AccessControlIndexedSetter);
6420 Local<v8::Object> object = object_template->NewInstance();
6421
6422 v8::HandleScope scope1;
6423
6424 // Create another environment.
6425 v8::Persistent<Context> context1 = Context::New();
6426 context1->Enter();
6427
6428 // Make easy access to the object from the other environment.
6429 v8::Handle<v8::Object> global1 = context1->Global();
6430 global1->Set(v8_str("obj"), object);
6431
6432 v8::Handle<Value> value;
6433
6434 // Check that the named access-control function is called every time
6435 // eventhough there is an interceptor on the object.
6436 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6437 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6438 "obj.x")->Run();
6439 CHECK(value->IsNumber());
6440 CHECK_EQ(42, value->Int32Value());
6441 CHECK_EQ(21, named_access_count);
6442
6443 value = v8_compile("var p = 'x';")->Run();
6444 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6445 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6446 "obj[p]")->Run();
6447 CHECK(value->IsNumber());
6448 CHECK_EQ(42, value->Int32Value());
6449 CHECK_EQ(42, named_access_count);
6450
6451 // Check that the indexed access-control function is called every
6452 // time eventhough there is an interceptor on the object.
6453 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6454 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6455 "obj[0]")->Run();
6456 CHECK(value->IsNumber());
6457 CHECK_EQ(42, value->Int32Value());
6458 CHECK_EQ(21, indexed_access_count);
6459
6460 context1->Exit();
6461 context0->Exit();
6462 context1.Dispose();
6463 context0.Dispose();
6464}
6465
6466
6467THREADED_TEST(Version) {
6468 v8::V8::GetVersion();
6469}
6470
6471
6472static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6473 ApiTestFuzzer::Fuzz();
6474 return v8_num(12);
6475}
6476
6477
6478THREADED_TEST(InstanceProperties) {
6479 v8::HandleScope handle_scope;
6480 LocalContext context;
6481
6482 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6483 Local<ObjectTemplate> instance = t->InstanceTemplate();
6484
6485 instance->Set(v8_str("x"), v8_num(42));
6486 instance->Set(v8_str("f"),
6487 v8::FunctionTemplate::New(InstanceFunctionCallback));
6488
6489 Local<Value> o = t->GetFunction()->NewInstance();
6490
6491 context->Global()->Set(v8_str("i"), o);
6492 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6493 CHECK_EQ(42, value->Int32Value());
6494
6495 value = Script::Compile(v8_str("i.f()"))->Run();
6496 CHECK_EQ(12, value->Int32Value());
6497}
6498
6499
6500static v8::Handle<Value>
6501GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6502 ApiTestFuzzer::Fuzz();
6503 return v8::Handle<Value>();
6504}
6505
6506
6507THREADED_TEST(GlobalObjectInstanceProperties) {
6508 v8::HandleScope handle_scope;
6509
6510 Local<Value> global_object;
6511
6512 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6513 t->InstanceTemplate()->SetNamedPropertyHandler(
6514 GlobalObjectInstancePropertiesGet);
6515 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6516 instance_template->Set(v8_str("x"), v8_num(42));
6517 instance_template->Set(v8_str("f"),
6518 v8::FunctionTemplate::New(InstanceFunctionCallback));
6519
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006520 // The script to check how Crankshaft compiles missing global function
6521 // invocations. function g is not defined and should throw on call.
6522 const char* script =
6523 "function wrapper(call) {"
6524 " var x = 0, y = 1;"
6525 " for (var i = 0; i < 1000; i++) {"
6526 " x += i * 100;"
6527 " y += i * 100;"
6528 " }"
6529 " if (call) g();"
6530 "}"
6531 "for (var i = 0; i < 17; i++) wrapper(false);"
6532 "var thrown = 0;"
6533 "try { wrapper(true); } catch (e) { thrown = 1; };"
6534 "thrown";
6535
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006536 {
6537 LocalContext env(NULL, instance_template);
6538 // Hold on to the global object so it can be used again in another
6539 // environment initialization.
6540 global_object = env->Global();
6541
6542 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6543 CHECK_EQ(42, value->Int32Value());
6544 value = Script::Compile(v8_str("f()"))->Run();
6545 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006546 value = Script::Compile(v8_str(script))->Run();
6547 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006548 }
6549
6550 {
6551 // Create new environment reusing the global object.
6552 LocalContext env(NULL, instance_template, global_object);
6553 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6554 CHECK_EQ(42, value->Int32Value());
6555 value = Script::Compile(v8_str("f()"))->Run();
6556 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006557 value = Script::Compile(v8_str(script))->Run();
6558 CHECK_EQ(1, value->Int32Value());
6559 }
6560}
6561
6562
6563THREADED_TEST(CallKnownGlobalReceiver) {
6564 v8::HandleScope handle_scope;
6565
6566 Local<Value> global_object;
6567
6568 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6569 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6570
6571 // The script to check that we leave global object not
6572 // global object proxy on stack when we deoptimize from inside
6573 // arguments evaluation.
6574 // To provoke error we need to both force deoptimization
6575 // from arguments evaluation and to force CallIC to take
6576 // CallIC_Miss code path that can't cope with global proxy.
6577 const char* script =
6578 "function bar(x, y) { try { } finally { } }"
6579 "function baz(x) { try { } finally { } }"
6580 "function bom(x) { try { } finally { } }"
6581 "function foo(x) { bar([x], bom(2)); }"
6582 "for (var i = 0; i < 10000; i++) foo(1);"
6583 "foo";
6584
6585 Local<Value> foo;
6586 {
6587 LocalContext env(NULL, instance_template);
6588 // Hold on to the global object so it can be used again in another
6589 // environment initialization.
6590 global_object = env->Global();
6591 foo = Script::Compile(v8_str(script))->Run();
6592 }
6593
6594 {
6595 // Create new environment reusing the global object.
6596 LocalContext env(NULL, instance_template, global_object);
6597 env->Global()->Set(v8_str("foo"), foo);
6598 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006599 }
6600}
6601
6602
6603static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6604 ApiTestFuzzer::Fuzz();
6605 return v8_num(42);
6606}
6607
6608
6609static int shadow_y;
6610static int shadow_y_setter_call_count;
6611static int shadow_y_getter_call_count;
6612
6613
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006614static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006615 shadow_y_setter_call_count++;
6616 shadow_y = 42;
6617}
6618
6619
6620static v8::Handle<Value> ShadowYGetter(Local<String> name,
6621 const AccessorInfo& info) {
6622 ApiTestFuzzer::Fuzz();
6623 shadow_y_getter_call_count++;
6624 return v8_num(shadow_y);
6625}
6626
6627
6628static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6629 const AccessorInfo& info) {
6630 return v8::Handle<Value>();
6631}
6632
6633
6634static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6635 const AccessorInfo&) {
6636 return v8::Handle<Value>();
6637}
6638
6639
6640THREADED_TEST(ShadowObject) {
6641 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6642 v8::HandleScope handle_scope;
6643
6644 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6645 LocalContext context(NULL, global_template);
6646
6647 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6648 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6649 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6650 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6651 Local<ObjectTemplate> instance = t->InstanceTemplate();
6652
6653 // Only allow calls of f on instances of t.
6654 Local<v8::Signature> signature = v8::Signature::New(t);
6655 proto->Set(v8_str("f"),
6656 v8::FunctionTemplate::New(ShadowFunctionCallback,
6657 Local<Value>(),
6658 signature));
6659 proto->Set(v8_str("x"), v8_num(12));
6660
6661 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6662
6663 Local<Value> o = t->GetFunction()->NewInstance();
6664 context->Global()->Set(v8_str("__proto__"), o);
6665
6666 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006667 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006668 CHECK(value->IsBoolean());
6669 CHECK(!value->BooleanValue());
6670
6671 value = Script::Compile(v8_str("x"))->Run();
6672 CHECK_EQ(12, value->Int32Value());
6673
6674 value = Script::Compile(v8_str("f()"))->Run();
6675 CHECK_EQ(42, value->Int32Value());
6676
6677 Script::Compile(v8_str("y = 42"))->Run();
6678 CHECK_EQ(1, shadow_y_setter_call_count);
6679 value = Script::Compile(v8_str("y"))->Run();
6680 CHECK_EQ(1, shadow_y_getter_call_count);
6681 CHECK_EQ(42, value->Int32Value());
6682}
6683
6684
6685THREADED_TEST(HiddenPrototype) {
6686 v8::HandleScope handle_scope;
6687 LocalContext context;
6688
6689 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6690 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6691 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6692 t1->SetHiddenPrototype(true);
6693 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6694 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6695 t2->SetHiddenPrototype(true);
6696 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6697 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6698 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6699
6700 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6701 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6702 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6703 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6704
6705 // Setting the prototype on an object skips hidden prototypes.
6706 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6707 o0->Set(v8_str("__proto__"), o1);
6708 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6709 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6710 o0->Set(v8_str("__proto__"), o2);
6711 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6712 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6713 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6714 o0->Set(v8_str("__proto__"), o3);
6715 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6716 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6717 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6718 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6719
6720 // Getting the prototype of o0 should get the first visible one
6721 // which is o3. Therefore, z should not be defined on the prototype
6722 // object.
6723 Local<Value> proto = o0->Get(v8_str("__proto__"));
6724 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006725 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006726}
6727
6728
ager@chromium.org5c838252010-02-19 08:53:10 +00006729THREADED_TEST(SetPrototype) {
6730 v8::HandleScope handle_scope;
6731 LocalContext context;
6732
6733 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6734 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6735 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6736 t1->SetHiddenPrototype(true);
6737 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6738 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6739 t2->SetHiddenPrototype(true);
6740 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6741 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6742 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6743
6744 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6745 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6746 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6747 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6748
6749 // Setting the prototype on an object does not skip hidden prototypes.
6750 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6751 CHECK(o0->SetPrototype(o1));
6752 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6753 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6754 CHECK(o1->SetPrototype(o2));
6755 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6756 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6757 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6758 CHECK(o2->SetPrototype(o3));
6759 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6760 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6761 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6762 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6763
6764 // Getting the prototype of o0 should get the first visible one
6765 // which is o3. Therefore, z should not be defined on the prototype
6766 // object.
6767 Local<Value> proto = o0->Get(v8_str("__proto__"));
6768 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006769 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006770
6771 // However, Object::GetPrototype ignores hidden prototype.
6772 Local<Value> proto0 = o0->GetPrototype();
6773 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006774 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00006775
6776 Local<Value> proto1 = o1->GetPrototype();
6777 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006778 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00006779
6780 Local<Value> proto2 = o2->GetPrototype();
6781 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006782 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00006783}
6784
6785
6786THREADED_TEST(SetPrototypeThrows) {
6787 v8::HandleScope handle_scope;
6788 LocalContext context;
6789
6790 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6791
6792 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6793 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6794
6795 CHECK(o0->SetPrototype(o1));
6796 // If setting the prototype leads to the cycle, SetPrototype should
6797 // return false and keep VM in sane state.
6798 v8::TryCatch try_catch;
6799 CHECK(!o1->SetPrototype(o0));
6800 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00006802
6803 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6804}
6805
6806
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006807THREADED_TEST(GetterSetterExceptions) {
6808 v8::HandleScope handle_scope;
6809 LocalContext context;
6810 CompileRun(
6811 "function Foo() { };"
6812 "function Throw() { throw 5; };"
6813 "var x = { };"
6814 "x.__defineSetter__('set', Throw);"
6815 "x.__defineGetter__('get', Throw);");
6816 Local<v8::Object> x =
6817 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6818 v8::TryCatch try_catch;
6819 x->Set(v8_str("set"), v8::Integer::New(8));
6820 x->Get(v8_str("get"));
6821 x->Set(v8_str("set"), v8::Integer::New(8));
6822 x->Get(v8_str("get"));
6823 x->Set(v8_str("set"), v8::Integer::New(8));
6824 x->Get(v8_str("get"));
6825 x->Set(v8_str("set"), v8::Integer::New(8));
6826 x->Get(v8_str("get"));
6827}
6828
6829
6830THREADED_TEST(Constructor) {
6831 v8::HandleScope handle_scope;
6832 LocalContext context;
6833 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6834 templ->SetClassName(v8_str("Fun"));
6835 Local<Function> cons = templ->GetFunction();
6836 context->Global()->Set(v8_str("Fun"), cons);
6837 Local<v8::Object> inst = cons->NewInstance();
6838 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6839 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6840 CHECK(value->BooleanValue());
6841}
6842
lrn@chromium.org1c092762011-05-09 09:42:16 +00006843
6844static Handle<Value> ConstructorCallback(const Arguments& args) {
6845 ApiTestFuzzer::Fuzz();
6846 Local<Object> This;
6847
6848 if (args.IsConstructCall()) {
6849 Local<Object> Holder = args.Holder();
6850 This = Object::New();
6851 Local<Value> proto = Holder->GetPrototype();
6852 if (proto->IsObject()) {
6853 This->SetPrototype(proto);
6854 }
6855 } else {
6856 This = args.This();
6857 }
6858
6859 This->Set(v8_str("a"), args[0]);
6860 return This;
6861}
6862
6863
6864static Handle<Value> FakeConstructorCallback(const Arguments& args) {
6865 ApiTestFuzzer::Fuzz();
6866 return args[0];
6867}
6868
6869
6870THREADED_TEST(ConstructorForObject) {
6871 v8::HandleScope handle_scope;
6872 LocalContext context;
6873
6874 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
6875 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
6876 Local<Object> instance = instance_template->NewInstance();
6877 context->Global()->Set(v8_str("obj"), instance);
6878 v8::TryCatch try_catch;
6879 Local<Value> value;
6880 CHECK(!try_catch.HasCaught());
6881
6882 // Call the Object's constructor with a 32-bit signed integer.
6883 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
6884 CHECK(!try_catch.HasCaught());
6885 CHECK(value->IsInt32());
6886 CHECK_EQ(28, value->Int32Value());
6887
6888 Local<Value> args1[] = { v8_num(28) };
6889 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
6890 CHECK(value_obj1->IsObject());
6891 Local<Object> object1 = Local<Object>::Cast(value_obj1);
6892 value = object1->Get(v8_str("a"));
6893 CHECK(value->IsInt32());
6894 CHECK(!try_catch.HasCaught());
6895 CHECK_EQ(28, value->Int32Value());
6896
6897 // Call the Object's constructor with a String.
6898 value = CompileRun(
6899 "(function() { var o = new obj('tipli'); return o.a; })()");
6900 CHECK(!try_catch.HasCaught());
6901 CHECK(value->IsString());
6902 String::AsciiValue string_value1(value->ToString());
6903 CHECK_EQ("tipli", *string_value1);
6904
6905 Local<Value> args2[] = { v8_str("tipli") };
6906 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
6907 CHECK(value_obj2->IsObject());
6908 Local<Object> object2 = Local<Object>::Cast(value_obj2);
6909 value = object2->Get(v8_str("a"));
6910 CHECK(!try_catch.HasCaught());
6911 CHECK(value->IsString());
6912 String::AsciiValue string_value2(value->ToString());
6913 CHECK_EQ("tipli", *string_value2);
6914
6915 // Call the Object's constructor with a Boolean.
6916 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
6917 CHECK(!try_catch.HasCaught());
6918 CHECK(value->IsBoolean());
6919 CHECK_EQ(true, value->BooleanValue());
6920
6921 Handle<Value> args3[] = { v8::Boolean::New(true) };
6922 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
6923 CHECK(value_obj3->IsObject());
6924 Local<Object> object3 = Local<Object>::Cast(value_obj3);
6925 value = object3->Get(v8_str("a"));
6926 CHECK(!try_catch.HasCaught());
6927 CHECK(value->IsBoolean());
6928 CHECK_EQ(true, value->BooleanValue());
6929
6930 // Call the Object's constructor with undefined.
6931 Handle<Value> args4[] = { v8::Undefined() };
6932 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
6933 CHECK(value_obj4->IsObject());
6934 Local<Object> object4 = Local<Object>::Cast(value_obj4);
6935 value = object4->Get(v8_str("a"));
6936 CHECK(!try_catch.HasCaught());
6937 CHECK(value->IsUndefined());
6938
6939 // Call the Object's constructor with null.
6940 Handle<Value> args5[] = { v8::Null() };
6941 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
6942 CHECK(value_obj5->IsObject());
6943 Local<Object> object5 = Local<Object>::Cast(value_obj5);
6944 value = object5->Get(v8_str("a"));
6945 CHECK(!try_catch.HasCaught());
6946 CHECK(value->IsNull());
6947 }
6948
6949 // Check exception handling when there is no constructor set for the Object.
6950 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
6951 Local<Object> instance = instance_template->NewInstance();
6952 context->Global()->Set(v8_str("obj2"), instance);
6953 v8::TryCatch try_catch;
6954 Local<Value> value;
6955 CHECK(!try_catch.HasCaught());
6956
6957 value = CompileRun("new obj2(28)");
6958 CHECK(try_catch.HasCaught());
6959 String::AsciiValue exception_value1(try_catch.Exception());
6960 CHECK_EQ("TypeError: object is not a function", *exception_value1);
6961 try_catch.Reset();
6962
6963 Local<Value> args[] = { v8_num(29) };
6964 value = instance->CallAsConstructor(1, args);
6965 CHECK(try_catch.HasCaught());
6966 String::AsciiValue exception_value2(try_catch.Exception());
6967 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
6968 try_catch.Reset();
6969 }
6970
6971 // Check the case when constructor throws exception.
6972 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
6973 instance_template->SetCallAsFunctionHandler(ThrowValue);
6974 Local<Object> instance = instance_template->NewInstance();
6975 context->Global()->Set(v8_str("obj3"), instance);
6976 v8::TryCatch try_catch;
6977 Local<Value> value;
6978 CHECK(!try_catch.HasCaught());
6979
6980 value = CompileRun("new obj3(22)");
6981 CHECK(try_catch.HasCaught());
6982 String::AsciiValue exception_value1(try_catch.Exception());
6983 CHECK_EQ("22", *exception_value1);
6984 try_catch.Reset();
6985
6986 Local<Value> args[] = { v8_num(23) };
6987 value = instance->CallAsConstructor(1, args);
6988 CHECK(try_catch.HasCaught());
6989 String::AsciiValue exception_value2(try_catch.Exception());
6990 CHECK_EQ("23", *exception_value2);
6991 try_catch.Reset();
6992 }
6993
6994 // Check whether constructor returns with an object or non-object.
6995 { Local<FunctionTemplate> function_template =
6996 FunctionTemplate::New(FakeConstructorCallback);
6997 Local<Function> function = function_template->GetFunction();
6998 Local<Object> instance1 = function;
6999 context->Global()->Set(v8_str("obj4"), instance1);
7000 v8::TryCatch try_catch;
7001 Local<Value> value;
7002 CHECK(!try_catch.HasCaught());
7003
7004 CHECK(instance1->IsObject());
7005 CHECK(instance1->IsFunction());
7006
7007 value = CompileRun("new obj4(28)");
7008 CHECK(!try_catch.HasCaught());
7009 CHECK(value->IsObject());
7010
7011 Local<Value> args1[] = { v8_num(28) };
7012 value = instance1->CallAsConstructor(1, args1);
7013 CHECK(!try_catch.HasCaught());
7014 CHECK(value->IsObject());
7015
7016 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7017 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7018 Local<Object> instance2 = instance_template->NewInstance();
7019 context->Global()->Set(v8_str("obj5"), instance2);
7020 CHECK(!try_catch.HasCaught());
7021
7022 CHECK(instance2->IsObject());
7023 CHECK(!instance2->IsFunction());
7024
7025 value = CompileRun("new obj5(28)");
7026 CHECK(!try_catch.HasCaught());
7027 CHECK(!value->IsObject());
7028
7029 Local<Value> args2[] = { v8_num(28) };
7030 value = instance2->CallAsConstructor(1, args2);
7031 CHECK(!try_catch.HasCaught());
7032 CHECK(!value->IsObject());
7033 }
7034}
7035
7036
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007037THREADED_TEST(FunctionDescriptorException) {
7038 v8::HandleScope handle_scope;
7039 LocalContext context;
7040 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7041 templ->SetClassName(v8_str("Fun"));
7042 Local<Function> cons = templ->GetFunction();
7043 context->Global()->Set(v8_str("Fun"), cons);
7044 Local<Value> value = CompileRun(
7045 "function test() {"
7046 " try {"
7047 " (new Fun()).blah()"
7048 " } catch (e) {"
7049 " var str = String(e);"
7050 " if (str.indexOf('TypeError') == -1) return 1;"
7051 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007052 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007053 " return 0;"
7054 " }"
7055 " return 4;"
7056 "}"
7057 "test();");
7058 CHECK_EQ(0, value->Int32Value());
7059}
7060
7061
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007062THREADED_TEST(EvalAliasedDynamic) {
7063 v8::HandleScope scope;
7064 LocalContext current;
7065
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007066 // Tests where aliased eval can only be resolved dynamically.
7067 Local<Script> script =
7068 Script::Compile(v8_str("function f(x) { "
7069 " var foo = 2;"
7070 " with (x) { return eval('foo'); }"
7071 "}"
7072 "foo = 0;"
7073 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007074 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007075 "var x = new Object();"
7076 "x.eval = function(x) { return 1; };"
7077 "result3 = f(x);"));
7078 script->Run();
7079 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7080 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7081 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7082
7083 v8::TryCatch try_catch;
7084 script =
7085 Script::Compile(v8_str("function f(x) { "
7086 " var bar = 2;"
7087 " with (x) { return eval('bar'); }"
7088 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007089 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007090 script->Run();
7091 CHECK(try_catch.HasCaught());
7092 try_catch.Reset();
7093}
7094
7095
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007096THREADED_TEST(CrossEval) {
7097 v8::HandleScope scope;
7098 LocalContext other;
7099 LocalContext current;
7100
7101 Local<String> token = v8_str("<security token>");
7102 other->SetSecurityToken(token);
7103 current->SetSecurityToken(token);
7104
7105 // Setup reference from current to other.
7106 current->Global()->Set(v8_str("other"), other->Global());
7107
7108 // Check that new variables are introduced in other context.
7109 Local<Script> script =
7110 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7111 script->Run();
7112 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7113 CHECK_EQ(1234, foo->Int32Value());
7114 CHECK(!current->Global()->Has(v8_str("foo")));
7115
7116 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007117 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007118 script =
7119 Script::Compile(v8_str("other.eval('na = 1234')"));
7120 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007121 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7122 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007123
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007124 // Check that global variables in current context are not visible in other
7125 // context.
7126 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007127 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007128 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007129 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007130 CHECK(try_catch.HasCaught());
7131 try_catch.Reset();
7132
7133 // Check that local variables in current context are not visible in other
7134 // context.
7135 script =
7136 Script::Compile(v8_str("(function() { "
7137 " var baz = 87;"
7138 " return other.eval('baz');"
7139 "})();"));
7140 result = script->Run();
7141 CHECK(try_catch.HasCaught());
7142 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007143
7144 // Check that global variables in the other environment are visible
7145 // when evaluting code.
7146 other->Global()->Set(v8_str("bis"), v8_num(1234));
7147 script = Script::Compile(v8_str("other.eval('bis')"));
7148 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007149 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007150
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007151 // Check that the 'this' pointer points to the global object evaluating
7152 // code.
7153 other->Global()->Set(v8_str("t"), other->Global());
7154 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007155 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007156 CHECK(result->IsTrue());
7157 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007158
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007159 // Check that variables introduced in with-statement are not visible in
7160 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007161 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007162 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007163 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007164 CHECK(try_catch.HasCaught());
7165 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007166
7167 // Check that you cannot use 'eval.call' with another object than the
7168 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007169 script =
7170 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7171 result = script->Run();
7172 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007173}
7174
7175
ager@chromium.orge2902be2009-06-08 12:21:35 +00007176// Test that calling eval in a context which has been detached from
7177// its global throws an exception. This behavior is consistent with
7178// other JavaScript implementations.
7179THREADED_TEST(EvalInDetachedGlobal) {
7180 v8::HandleScope scope;
7181
7182 v8::Persistent<Context> context0 = Context::New();
7183 v8::Persistent<Context> context1 = Context::New();
7184
7185 // Setup function in context0 that uses eval from context0.
7186 context0->Enter();
7187 v8::Handle<v8::Value> fun =
7188 CompileRun("var x = 42;"
7189 "(function() {"
7190 " var e = eval;"
7191 " return function(s) { return e(s); }"
7192 "})()");
7193 context0->Exit();
7194
7195 // Put the function into context1 and call it before and after
7196 // detaching the global. Before detaching, the call succeeds and
7197 // after detaching and exception is thrown.
7198 context1->Enter();
7199 context1->Global()->Set(v8_str("fun"), fun);
7200 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7201 CHECK_EQ(42, x_value->Int32Value());
7202 context0->DetachGlobal();
7203 v8::TryCatch catcher;
7204 x_value = CompileRun("fun('x')");
7205 CHECK(x_value.IsEmpty());
7206 CHECK(catcher.HasCaught());
7207 context1->Exit();
7208
7209 context1.Dispose();
7210 context0.Dispose();
7211}
7212
7213
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007214THREADED_TEST(CrossLazyLoad) {
7215 v8::HandleScope scope;
7216 LocalContext other;
7217 LocalContext current;
7218
7219 Local<String> token = v8_str("<security token>");
7220 other->SetSecurityToken(token);
7221 current->SetSecurityToken(token);
7222
7223 // Setup reference from current to other.
7224 current->Global()->Set(v8_str("other"), other->Global());
7225
7226 // Trigger lazy loading in other context.
7227 Local<Script> script =
7228 Script::Compile(v8_str("other.eval('new Date(42)')"));
7229 Local<Value> value = script->Run();
7230 CHECK_EQ(42.0, value->NumberValue());
7231}
7232
7233
7234static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7235 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007236 if (args.IsConstructCall()) {
7237 if (args[0]->IsInt32()) {
7238 return v8_num(-args[0]->Int32Value());
7239 }
7240 }
7241
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007242 return args[0];
7243}
7244
7245
7246// Test that a call handler can be set for objects which will allow
7247// non-function objects created through the API to be called as
7248// functions.
7249THREADED_TEST(CallAsFunction) {
7250 v8::HandleScope scope;
7251 LocalContext context;
7252
lrn@chromium.org1c092762011-05-09 09:42:16 +00007253 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7254 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7255 instance_template->SetCallAsFunctionHandler(call_as_function);
7256 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7257 context->Global()->Set(v8_str("obj"), instance);
7258 v8::TryCatch try_catch;
7259 Local<Value> value;
7260 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007261
lrn@chromium.org1c092762011-05-09 09:42:16 +00007262 value = CompileRun("obj(42)");
7263 CHECK(!try_catch.HasCaught());
7264 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007265
lrn@chromium.org1c092762011-05-09 09:42:16 +00007266 value = CompileRun("(function(o){return o(49)})(obj)");
7267 CHECK(!try_catch.HasCaught());
7268 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007269
lrn@chromium.org1c092762011-05-09 09:42:16 +00007270 // test special case of call as function
7271 value = CompileRun("[obj]['0'](45)");
7272 CHECK(!try_catch.HasCaught());
7273 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007274
lrn@chromium.org1c092762011-05-09 09:42:16 +00007275 value = CompileRun("obj.call = Function.prototype.call;"
7276 "obj.call(null, 87)");
7277 CHECK(!try_catch.HasCaught());
7278 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007279
lrn@chromium.org1c092762011-05-09 09:42:16 +00007280 // Regression tests for bug #1116356: Calling call through call/apply
7281 // must work for non-function receivers.
7282 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7283 value = CompileRun(apply_99);
7284 CHECK(!try_catch.HasCaught());
7285 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007286
lrn@chromium.org1c092762011-05-09 09:42:16 +00007287 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7288 value = CompileRun(call_17);
7289 CHECK(!try_catch.HasCaught());
7290 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007291
lrn@chromium.org1c092762011-05-09 09:42:16 +00007292 // Check that the call-as-function handler can be called through
7293 // new.
7294 value = CompileRun("new obj(43)");
7295 CHECK(!try_catch.HasCaught());
7296 CHECK_EQ(-43, value->Int32Value());
7297
7298 // Check that the call-as-function handler can be called through
7299 // the API.
7300 v8::Handle<Value> args[] = { v8_num(28) };
7301 value = instance->CallAsFunction(instance, 1, args);
7302 CHECK(!try_catch.HasCaught());
7303 CHECK_EQ(28, value->Int32Value());
7304 }
7305
7306 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7307 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7308 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7309 context->Global()->Set(v8_str("obj2"), instance);
7310 v8::TryCatch try_catch;
7311 Local<Value> value;
7312 CHECK(!try_catch.HasCaught());
7313
7314 // Call an object without call-as-function handler through the JS
7315 value = CompileRun("obj2(28)");
7316 CHECK(value.IsEmpty());
7317 CHECK(try_catch.HasCaught());
7318 String::AsciiValue exception_value1(try_catch.Exception());
7319 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7320 *exception_value1);
7321 try_catch.Reset();
7322
7323 // Call an object without call-as-function handler through the API
7324 value = CompileRun("obj2(28)");
7325 v8::Handle<Value> args[] = { v8_num(28) };
7326 value = instance->CallAsFunction(instance, 1, args);
7327 CHECK(value.IsEmpty());
7328 CHECK(try_catch.HasCaught());
7329 String::AsciiValue exception_value2(try_catch.Exception());
7330 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7331 try_catch.Reset();
7332 }
7333
7334 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7335 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7336 instance_template->SetCallAsFunctionHandler(ThrowValue);
7337 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7338 context->Global()->Set(v8_str("obj3"), instance);
7339 v8::TryCatch try_catch;
7340 Local<Value> value;
7341 CHECK(!try_catch.HasCaught());
7342
7343 // Catch the exception which is thrown by call-as-function handler
7344 value = CompileRun("obj3(22)");
7345 CHECK(try_catch.HasCaught());
7346 String::AsciiValue exception_value1(try_catch.Exception());
7347 CHECK_EQ("22", *exception_value1);
7348 try_catch.Reset();
7349
7350 v8::Handle<Value> args[] = { v8_num(23) };
7351 value = instance->CallAsFunction(instance, 1, args);
7352 CHECK(try_catch.HasCaught());
7353 String::AsciiValue exception_value2(try_catch.Exception());
7354 CHECK_EQ("23", *exception_value2);
7355 try_catch.Reset();
7356 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007357}
7358
7359
karlklose@chromium.org83a47282011-05-11 11:54:09 +00007360// Check whether a non-function object is callable.
7361THREADED_TEST(CallableObject) {
7362 v8::HandleScope scope;
7363 LocalContext context;
7364
7365 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7366 instance_template->SetCallAsFunctionHandler(call_as_function);
7367 Local<Object> instance = instance_template->NewInstance();
7368 v8::TryCatch try_catch;
7369
7370 CHECK(instance->IsCallable());
7371 CHECK(!try_catch.HasCaught());
7372 }
7373
7374 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7375 Local<Object> instance = instance_template->NewInstance();
7376 v8::TryCatch try_catch;
7377
7378 CHECK(!instance->IsCallable());
7379 CHECK(!try_catch.HasCaught());
7380 }
7381
7382 { Local<FunctionTemplate> function_template =
7383 FunctionTemplate::New(call_as_function);
7384 Local<Function> function = function_template->GetFunction();
7385 Local<Object> instance = function;
7386 v8::TryCatch try_catch;
7387
7388 CHECK(instance->IsCallable());
7389 CHECK(!try_catch.HasCaught());
7390 }
7391
7392 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7393 Local<Function> function = function_template->GetFunction();
7394 Local<Object> instance = function;
7395 v8::TryCatch try_catch;
7396
7397 CHECK(instance->IsCallable());
7398 CHECK(!try_catch.HasCaught());
7399 }
7400}
7401
7402
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007403static int CountHandles() {
7404 return v8::HandleScope::NumberOfHandles();
7405}
7406
7407
7408static int Recurse(int depth, int iterations) {
7409 v8::HandleScope scope;
7410 if (depth == 0) return CountHandles();
7411 for (int i = 0; i < iterations; i++) {
7412 Local<v8::Number> n = v8::Integer::New(42);
7413 }
7414 return Recurse(depth - 1, iterations);
7415}
7416
7417
7418THREADED_TEST(HandleIteration) {
7419 static const int kIterations = 500;
7420 static const int kNesting = 200;
7421 CHECK_EQ(0, CountHandles());
7422 {
7423 v8::HandleScope scope1;
7424 CHECK_EQ(0, CountHandles());
7425 for (int i = 0; i < kIterations; i++) {
7426 Local<v8::Number> n = v8::Integer::New(42);
7427 CHECK_EQ(i + 1, CountHandles());
7428 }
7429
7430 CHECK_EQ(kIterations, CountHandles());
7431 {
7432 v8::HandleScope scope2;
7433 for (int j = 0; j < kIterations; j++) {
7434 Local<v8::Number> n = v8::Integer::New(42);
7435 CHECK_EQ(j + 1 + kIterations, CountHandles());
7436 }
7437 }
7438 CHECK_EQ(kIterations, CountHandles());
7439 }
7440 CHECK_EQ(0, CountHandles());
7441 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7442}
7443
7444
7445static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7446 Local<String> name,
7447 const AccessorInfo& info) {
7448 ApiTestFuzzer::Fuzz();
7449 return v8::Handle<Value>();
7450}
7451
7452
7453THREADED_TEST(InterceptorHasOwnProperty) {
7454 v8::HandleScope scope;
7455 LocalContext context;
7456 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7457 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7458 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7459 Local<Function> function = fun_templ->GetFunction();
7460 context->Global()->Set(v8_str("constructor"), function);
7461 v8::Handle<Value> value = CompileRun(
7462 "var o = new constructor();"
7463 "o.hasOwnProperty('ostehaps');");
7464 CHECK_EQ(false, value->BooleanValue());
7465 value = CompileRun(
7466 "o.ostehaps = 42;"
7467 "o.hasOwnProperty('ostehaps');");
7468 CHECK_EQ(true, value->BooleanValue());
7469 value = CompileRun(
7470 "var p = new constructor();"
7471 "p.hasOwnProperty('ostehaps');");
7472 CHECK_EQ(false, value->BooleanValue());
7473}
7474
7475
ager@chromium.org9085a012009-05-11 19:22:57 +00007476static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7477 Local<String> name,
7478 const AccessorInfo& info) {
7479 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007481 return v8::Handle<Value>();
7482}
7483
7484
7485THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7486 v8::HandleScope scope;
7487 LocalContext context;
7488 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7489 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7490 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7491 Local<Function> function = fun_templ->GetFunction();
7492 context->Global()->Set(v8_str("constructor"), function);
7493 // Let's first make some stuff so we can be sure to get a good GC.
7494 CompileRun(
7495 "function makestr(size) {"
7496 " switch (size) {"
7497 " case 1: return 'f';"
7498 " case 2: return 'fo';"
7499 " case 3: return 'foo';"
7500 " }"
7501 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7502 "}"
7503 "var x = makestr(12345);"
7504 "x = makestr(31415);"
7505 "x = makestr(23456);");
7506 v8::Handle<Value> value = CompileRun(
7507 "var o = new constructor();"
7508 "o.__proto__ = new String(x);"
7509 "o.hasOwnProperty('ostehaps');");
7510 CHECK_EQ(false, value->BooleanValue());
7511}
7512
7513
ager@chromium.orge2902be2009-06-08 12:21:35 +00007514typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7515 const AccessorInfo& info);
7516
7517
7518static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7519 const char* source,
7520 int expected) {
7521 v8::HandleScope scope;
7522 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007523 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007524 LocalContext context;
7525 context->Global()->Set(v8_str("o"), templ->NewInstance());
7526 v8::Handle<Value> value = CompileRun(source);
7527 CHECK_EQ(expected, value->Int32Value());
7528}
7529
7530
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007531static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7532 const AccessorInfo& info) {
7533 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007534 CHECK_EQ(v8_str("data"), info.Data());
7535 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007536 return v8::Integer::New(42);
7537}
7538
7539
7540// This test should hit the load IC for the interceptor case.
7541THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007542 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007543 "var result = 0;"
7544 "for (var i = 0; i < 1000; i++) {"
7545 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007546 "}",
7547 42);
7548}
7549
7550
7551// Below go several tests which verify that JITing for various
7552// configurations of interceptor and explicit fields works fine
7553// (those cases are special cased to get better performance).
7554
7555static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7556 const AccessorInfo& info) {
7557 ApiTestFuzzer::Fuzz();
7558 return v8_str("x")->Equals(name)
7559 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7560}
7561
7562
7563THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7564 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7565 "var result = 0;"
7566 "o.y = 239;"
7567 "for (var i = 0; i < 1000; i++) {"
7568 " result = o.y;"
7569 "}",
7570 239);
7571}
7572
7573
7574THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7575 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7576 "var result = 0;"
7577 "o.__proto__ = { 'y': 239 };"
7578 "for (var i = 0; i < 1000; i++) {"
7579 " result = o.y + o.x;"
7580 "}",
7581 239 + 42);
7582}
7583
7584
7585THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7586 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7587 "var result = 0;"
7588 "o.__proto__.y = 239;"
7589 "for (var i = 0; i < 1000; i++) {"
7590 " result = o.y + o.x;"
7591 "}",
7592 239 + 42);
7593}
7594
7595
7596THREADED_TEST(InterceptorLoadICUndefined) {
7597 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7598 "var result = 0;"
7599 "for (var i = 0; i < 1000; i++) {"
7600 " result = (o.y == undefined) ? 239 : 42;"
7601 "}",
7602 239);
7603}
7604
7605
7606THREADED_TEST(InterceptorLoadICWithOverride) {
7607 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7608 "fst = new Object(); fst.__proto__ = o;"
7609 "snd = new Object(); snd.__proto__ = fst;"
7610 "var result1 = 0;"
7611 "for (var i = 0; i < 1000; i++) {"
7612 " result1 = snd.x;"
7613 "}"
7614 "fst.x = 239;"
7615 "var result = 0;"
7616 "for (var i = 0; i < 1000; i++) {"
7617 " result = snd.x;"
7618 "}"
7619 "result + result1",
7620 239 + 42);
7621}
7622
7623
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007624// Test the case when we stored field into
7625// a stub, but interceptor produced value on its own.
7626THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7627 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7628 "proto = new Object();"
7629 "o.__proto__ = proto;"
7630 "proto.x = 239;"
7631 "for (var i = 0; i < 1000; i++) {"
7632 " o.x;"
7633 // Now it should be ICed and keep a reference to x defined on proto
7634 "}"
7635 "var result = 0;"
7636 "for (var i = 0; i < 1000; i++) {"
7637 " result += o.x;"
7638 "}"
7639 "result;",
7640 42 * 1000);
7641}
7642
7643
7644// Test the case when we stored field into
7645// a stub, but it got invalidated later on.
7646THREADED_TEST(InterceptorLoadICInvalidatedField) {
7647 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7648 "proto1 = new Object();"
7649 "proto2 = new Object();"
7650 "o.__proto__ = proto1;"
7651 "proto1.__proto__ = proto2;"
7652 "proto2.y = 239;"
7653 "for (var i = 0; i < 1000; i++) {"
7654 " o.y;"
7655 // Now it should be ICed and keep a reference to y defined on proto2
7656 "}"
7657 "proto1.y = 42;"
7658 "var result = 0;"
7659 "for (var i = 0; i < 1000; i++) {"
7660 " result += o.y;"
7661 "}"
7662 "result;",
7663 42 * 1000);
7664}
7665
7666
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007667static int interceptor_load_not_handled_calls = 0;
7668static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7669 const AccessorInfo& info) {
7670 ++interceptor_load_not_handled_calls;
7671 return v8::Handle<v8::Value>();
7672}
7673
7674
7675// Test how post-interceptor lookups are done in the non-cacheable
7676// case: the interceptor should not be invoked during this lookup.
7677THREADED_TEST(InterceptorLoadICPostInterceptor) {
7678 interceptor_load_not_handled_calls = 0;
7679 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7680 "receiver = new Object();"
7681 "receiver.__proto__ = o;"
7682 "proto = new Object();"
7683 "/* Make proto a slow-case object. */"
7684 "for (var i = 0; i < 1000; i++) {"
7685 " proto[\"xxxxxxxx\" + i] = [];"
7686 "}"
7687 "proto.x = 17;"
7688 "o.__proto__ = proto;"
7689 "var result = 0;"
7690 "for (var i = 0; i < 1000; i++) {"
7691 " result += receiver.x;"
7692 "}"
7693 "result;",
7694 17 * 1000);
7695 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7696}
7697
7698
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007699// Test the case when we stored field into
7700// a stub, but it got invalidated later on due to override on
7701// global object which is between interceptor and fields' holders.
7702THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
7703 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7704 "o.__proto__ = this;" // set a global to be a proto of o.
7705 "this.__proto__.y = 239;"
7706 "for (var i = 0; i < 10; i++) {"
7707 " if (o.y != 239) throw 'oops: ' + o.y;"
7708 // Now it should be ICed and keep a reference to y defined on field_holder.
7709 "}"
7710 "this.y = 42;" // Assign on a global.
7711 "var result = 0;"
7712 "for (var i = 0; i < 10; i++) {"
7713 " result += o.y;"
7714 "}"
7715 "result;",
7716 42 * 10);
7717}
7718
7719
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007720static void SetOnThis(Local<String> name,
7721 Local<Value> value,
7722 const AccessorInfo& info) {
7723 info.This()->ForceSet(name, value);
7724}
7725
7726
7727THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
7728 v8::HandleScope scope;
7729 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7730 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7731 templ->SetAccessor(v8_str("y"), Return239);
7732 LocalContext context;
7733 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007734
7735 // Check the case when receiver and interceptor's holder
7736 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007737 v8::Handle<Value> value = CompileRun(
7738 "var result = 0;"
7739 "for (var i = 0; i < 7; i++) {"
7740 " result = o.y;"
7741 "}");
7742 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007743
7744 // Check the case when interceptor's holder is in proto chain
7745 // of receiver.
7746 value = CompileRun(
7747 "r = { __proto__: o };"
7748 "var result = 0;"
7749 "for (var i = 0; i < 7; i++) {"
7750 " result = r.y;"
7751 "}");
7752 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007753}
7754
7755
7756THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
7757 v8::HandleScope scope;
7758 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7759 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7760 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7761 templ_p->SetAccessor(v8_str("y"), Return239);
7762
7763 LocalContext context;
7764 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7765 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7766
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007767 // Check the case when receiver and interceptor's holder
7768 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007769 v8::Handle<Value> value = CompileRun(
7770 "o.__proto__ = p;"
7771 "var result = 0;"
7772 "for (var i = 0; i < 7; i++) {"
7773 " result = o.x + o.y;"
7774 "}");
7775 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007776
7777 // Check the case when interceptor's holder is in proto chain
7778 // of receiver.
7779 value = CompileRun(
7780 "r = { __proto__: o };"
7781 "var result = 0;"
7782 "for (var i = 0; i < 7; i++) {"
7783 " result = r.x + r.y;"
7784 "}");
7785 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007786}
7787
7788
7789THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
7790 v8::HandleScope scope;
7791 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7792 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7793 templ->SetAccessor(v8_str("y"), Return239);
7794
7795 LocalContext context;
7796 context->Global()->Set(v8_str("o"), templ->NewInstance());
7797
7798 v8::Handle<Value> value = CompileRun(
7799 "fst = new Object(); fst.__proto__ = o;"
7800 "snd = new Object(); snd.__proto__ = fst;"
7801 "var result1 = 0;"
7802 "for (var i = 0; i < 7; i++) {"
7803 " result1 = snd.x;"
7804 "}"
7805 "fst.x = 239;"
7806 "var result = 0;"
7807 "for (var i = 0; i < 7; i++) {"
7808 " result = snd.x;"
7809 "}"
7810 "result + result1");
7811 CHECK_EQ(239 + 42, value->Int32Value());
7812}
7813
7814
7815// Test the case when we stored callback into
7816// a stub, but interceptor produced value on its own.
7817THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
7818 v8::HandleScope scope;
7819 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7820 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7821 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7822 templ_p->SetAccessor(v8_str("y"), Return239);
7823
7824 LocalContext context;
7825 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7826 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7827
7828 v8::Handle<Value> value = CompileRun(
7829 "o.__proto__ = p;"
7830 "for (var i = 0; i < 7; i++) {"
7831 " o.x;"
7832 // Now it should be ICed and keep a reference to x defined on p
7833 "}"
7834 "var result = 0;"
7835 "for (var i = 0; i < 7; i++) {"
7836 " result += o.x;"
7837 "}"
7838 "result");
7839 CHECK_EQ(42 * 7, value->Int32Value());
7840}
7841
7842
7843// Test the case when we stored callback into
7844// a stub, but it got invalidated later on.
7845THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
7846 v8::HandleScope scope;
7847 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7848 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7849 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7850 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7851
7852 LocalContext context;
7853 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7854 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7855
7856 v8::Handle<Value> value = CompileRun(
7857 "inbetween = new Object();"
7858 "o.__proto__ = inbetween;"
7859 "inbetween.__proto__ = p;"
7860 "for (var i = 0; i < 10; i++) {"
7861 " o.y;"
7862 // Now it should be ICed and keep a reference to y defined on p
7863 "}"
7864 "inbetween.y = 42;"
7865 "var result = 0;"
7866 "for (var i = 0; i < 10; i++) {"
7867 " result += o.y;"
7868 "}"
7869 "result");
7870 CHECK_EQ(42 * 10, value->Int32Value());
7871}
7872
7873
7874// Test the case when we stored callback into
7875// a stub, but it got invalidated later on due to override on
7876// global object which is between interceptor and callbacks' holders.
7877THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
7878 v8::HandleScope scope;
7879 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7880 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7881 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
7882 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
7883
7884 LocalContext context;
7885 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7886 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
7887
7888 v8::Handle<Value> value = CompileRun(
7889 "o.__proto__ = this;"
7890 "this.__proto__ = p;"
7891 "for (var i = 0; i < 10; i++) {"
7892 " if (o.y != 239) throw 'oops: ' + o.y;"
7893 // Now it should be ICed and keep a reference to y defined on p
7894 "}"
7895 "this.y = 42;"
7896 "var result = 0;"
7897 "for (var i = 0; i < 10; i++) {"
7898 " result += o.y;"
7899 "}"
7900 "result");
7901 CHECK_EQ(42 * 10, value->Int32Value());
7902}
7903
7904
ager@chromium.orge2902be2009-06-08 12:21:35 +00007905static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
7906 const AccessorInfo& info) {
7907 ApiTestFuzzer::Fuzz();
7908 CHECK(v8_str("x")->Equals(name));
7909 return v8::Integer::New(0);
7910}
7911
7912
7913THREADED_TEST(InterceptorReturningZero) {
7914 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
7915 "o.x == undefined ? 1 : 0",
7916 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007917}
7918
7919
7920static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007921 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007922 CHECK(v8_str("x")->Equals(key));
7923 CHECK_EQ(42, value->Int32Value());
7924 return value;
7925}
7926
7927
7928// This test should hit the store IC for the interceptor case.
7929THREADED_TEST(InterceptorStoreIC) {
7930 v8::HandleScope scope;
7931 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7932 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007933 InterceptorStoreICSetter,
7934 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007935 LocalContext context;
7936 context->Global()->Set(v8_str("o"), templ->NewInstance());
7937 v8::Handle<Value> value = CompileRun(
7938 "for (var i = 0; i < 1000; i++) {"
7939 " o.x = 42;"
7940 "}");
7941}
7942
7943
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007944THREADED_TEST(InterceptorStoreICWithNoSetter) {
7945 v8::HandleScope scope;
7946 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7947 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7948 LocalContext context;
7949 context->Global()->Set(v8_str("o"), templ->NewInstance());
7950 v8::Handle<Value> value = CompileRun(
7951 "for (var i = 0; i < 1000; i++) {"
7952 " o.y = 239;"
7953 "}"
7954 "42 + o.y");
7955 CHECK_EQ(239 + 42, value->Int32Value());
7956}
7957
7958
7959
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007960
7961v8::Handle<Value> call_ic_function;
7962v8::Handle<Value> call_ic_function2;
7963v8::Handle<Value> call_ic_function3;
7964
7965static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
7966 const AccessorInfo& info) {
7967 ApiTestFuzzer::Fuzz();
7968 CHECK(v8_str("x")->Equals(name));
7969 return call_ic_function;
7970}
7971
7972
7973// This test should hit the call IC for the interceptor case.
7974THREADED_TEST(InterceptorCallIC) {
7975 v8::HandleScope scope;
7976 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7977 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
7978 LocalContext context;
7979 context->Global()->Set(v8_str("o"), templ->NewInstance());
7980 call_ic_function =
7981 v8_compile("function f(x) { return x + 1; }; f")->Run();
7982 v8::Handle<Value> value = CompileRun(
7983 "var result = 0;"
7984 "for (var i = 0; i < 1000; i++) {"
7985 " result = o.x(41);"
7986 "}");
7987 CHECK_EQ(42, value->Int32Value());
7988}
7989
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007990
7991// This test checks that if interceptor doesn't provide
7992// a value, we can fetch regular value.
7993THREADED_TEST(InterceptorCallICSeesOthers) {
7994 v8::HandleScope scope;
7995 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7996 templ->SetNamedPropertyHandler(NoBlockGetterX);
7997 LocalContext context;
7998 context->Global()->Set(v8_str("o"), templ->NewInstance());
7999 v8::Handle<Value> value = CompileRun(
8000 "o.x = function f(x) { return x + 1; };"
8001 "var result = 0;"
8002 "for (var i = 0; i < 7; i++) {"
8003 " result = o.x(41);"
8004 "}");
8005 CHECK_EQ(42, value->Int32Value());
8006}
8007
8008
8009static v8::Handle<Value> call_ic_function4;
8010static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8011 const AccessorInfo& info) {
8012 ApiTestFuzzer::Fuzz();
8013 CHECK(v8_str("x")->Equals(name));
8014 return call_ic_function4;
8015}
8016
8017
8018// This test checks that if interceptor provides a function,
8019// even if we cached shadowed variant, interceptor's function
8020// is invoked
8021THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8022 v8::HandleScope scope;
8023 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8024 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8025 LocalContext context;
8026 context->Global()->Set(v8_str("o"), templ->NewInstance());
8027 call_ic_function4 =
8028 v8_compile("function f(x) { return x - 1; }; f")->Run();
8029 v8::Handle<Value> value = CompileRun(
8030 "o.__proto__.x = function(x) { return x + 1; };"
8031 "var result = 0;"
8032 "for (var i = 0; i < 1000; i++) {"
8033 " result = o.x(42);"
8034 "}");
8035 CHECK_EQ(41, value->Int32Value());
8036}
8037
8038
8039// Test the case when we stored cacheable lookup into
8040// a stub, but it got invalidated later on
8041THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8042 v8::HandleScope scope;
8043 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8044 templ->SetNamedPropertyHandler(NoBlockGetterX);
8045 LocalContext context;
8046 context->Global()->Set(v8_str("o"), templ->NewInstance());
8047 v8::Handle<Value> value = CompileRun(
8048 "proto1 = new Object();"
8049 "proto2 = new Object();"
8050 "o.__proto__ = proto1;"
8051 "proto1.__proto__ = proto2;"
8052 "proto2.y = function(x) { return x + 1; };"
8053 // Invoke it many times to compile a stub
8054 "for (var i = 0; i < 7; i++) {"
8055 " o.y(42);"
8056 "}"
8057 "proto1.y = function(x) { return x - 1; };"
8058 "var result = 0;"
8059 "for (var i = 0; i < 7; i++) {"
8060 " result += o.y(42);"
8061 "}");
8062 CHECK_EQ(41 * 7, value->Int32Value());
8063}
8064
8065
8066static v8::Handle<Value> call_ic_function5;
8067static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8068 const AccessorInfo& info) {
8069 ApiTestFuzzer::Fuzz();
8070 if (v8_str("x")->Equals(name))
8071 return call_ic_function5;
8072 else
8073 return Local<Value>();
8074}
8075
8076
8077// This test checks that if interceptor doesn't provide a function,
8078// cached constant function is used
8079THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8080 v8::HandleScope scope;
8081 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8082 templ->SetNamedPropertyHandler(NoBlockGetterX);
8083 LocalContext context;
8084 context->Global()->Set(v8_str("o"), templ->NewInstance());
8085 v8::Handle<Value> value = CompileRun(
8086 "function inc(x) { return x + 1; };"
8087 "inc(1);"
8088 "o.x = inc;"
8089 "var result = 0;"
8090 "for (var i = 0; i < 1000; i++) {"
8091 " result = o.x(42);"
8092 "}");
8093 CHECK_EQ(43, value->Int32Value());
8094}
8095
8096
8097// This test checks that if interceptor provides a function,
8098// even if we cached constant function, interceptor's function
8099// is invoked
8100THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8101 v8::HandleScope scope;
8102 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8103 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8104 LocalContext context;
8105 context->Global()->Set(v8_str("o"), templ->NewInstance());
8106 call_ic_function5 =
8107 v8_compile("function f(x) { return x - 1; }; f")->Run();
8108 v8::Handle<Value> value = CompileRun(
8109 "function inc(x) { return x + 1; };"
8110 "inc(1);"
8111 "o.x = inc;"
8112 "var result = 0;"
8113 "for (var i = 0; i < 1000; i++) {"
8114 " result = o.x(42);"
8115 "}");
8116 CHECK_EQ(41, value->Int32Value());
8117}
8118
8119
8120// Test the case when we stored constant function into
8121// a stub, but it got invalidated later on
8122THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8123 v8::HandleScope scope;
8124 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8125 templ->SetNamedPropertyHandler(NoBlockGetterX);
8126 LocalContext context;
8127 context->Global()->Set(v8_str("o"), templ->NewInstance());
8128 v8::Handle<Value> value = CompileRun(
8129 "function inc(x) { return x + 1; };"
8130 "inc(1);"
8131 "proto1 = new Object();"
8132 "proto2 = new Object();"
8133 "o.__proto__ = proto1;"
8134 "proto1.__proto__ = proto2;"
8135 "proto2.y = inc;"
8136 // Invoke it many times to compile a stub
8137 "for (var i = 0; i < 7; i++) {"
8138 " o.y(42);"
8139 "}"
8140 "proto1.y = function(x) { return x - 1; };"
8141 "var result = 0;"
8142 "for (var i = 0; i < 7; i++) {"
8143 " result += o.y(42);"
8144 "}");
8145 CHECK_EQ(41 * 7, value->Int32Value());
8146}
8147
8148
8149// Test the case when we stored constant function into
8150// a stub, but it got invalidated later on due to override on
8151// global object which is between interceptor and constant function' holders.
8152THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8153 v8::HandleScope scope;
8154 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8155 templ->SetNamedPropertyHandler(NoBlockGetterX);
8156 LocalContext context;
8157 context->Global()->Set(v8_str("o"), templ->NewInstance());
8158 v8::Handle<Value> value = CompileRun(
8159 "function inc(x) { return x + 1; };"
8160 "inc(1);"
8161 "o.__proto__ = this;"
8162 "this.__proto__.y = inc;"
8163 // Invoke it many times to compile a stub
8164 "for (var i = 0; i < 7; i++) {"
8165 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8166 "}"
8167 "this.y = function(x) { return x - 1; };"
8168 "var result = 0;"
8169 "for (var i = 0; i < 7; i++) {"
8170 " result += o.y(42);"
8171 "}");
8172 CHECK_EQ(41 * 7, value->Int32Value());
8173}
8174
8175
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008176// Test the case when actual function to call sits on global object.
8177THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8178 v8::HandleScope scope;
8179 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8180 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8181
8182 LocalContext context;
8183 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8184
8185 v8::Handle<Value> value = CompileRun(
8186 "try {"
8187 " o.__proto__ = this;"
8188 " for (var i = 0; i < 10; i++) {"
8189 " var v = o.parseFloat('239');"
8190 " if (v != 239) throw v;"
8191 // Now it should be ICed and keep a reference to parseFloat.
8192 " }"
8193 " var result = 0;"
8194 " for (var i = 0; i < 10; i++) {"
8195 " result += o.parseFloat('239');"
8196 " }"
8197 " result"
8198 "} catch(e) {"
8199 " e"
8200 "};");
8201 CHECK_EQ(239 * 10, value->Int32Value());
8202}
8203
ager@chromium.org5c838252010-02-19 08:53:10 +00008204static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8205 const AccessorInfo& info) {
8206 ApiTestFuzzer::Fuzz();
8207 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8208 ++(*call_count);
8209 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00008211 }
8212 return v8::Handle<Value>();
8213}
8214
8215static v8::Handle<Value> FastApiCallback_TrivialSignature(
8216 const v8::Arguments& args) {
8217 ApiTestFuzzer::Fuzz();
8218 CHECK_EQ(args.This(), args.Holder());
8219 CHECK(args.Data()->Equals(v8_str("method_data")));
8220 return v8::Integer::New(args[0]->Int32Value() + 1);
8221}
8222
8223static v8::Handle<Value> FastApiCallback_SimpleSignature(
8224 const v8::Arguments& args) {
8225 ApiTestFuzzer::Fuzz();
8226 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8227 CHECK(args.Data()->Equals(v8_str("method_data")));
8228 // Note, we're using HasRealNamedProperty instead of Has to avoid
8229 // invoking the interceptor again.
8230 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8231 return v8::Integer::New(args[0]->Int32Value() + 1);
8232}
8233
8234// Helper to maximize the odds of object moving.
8235static void GenerateSomeGarbage() {
8236 CompileRun(
8237 "var garbage;"
8238 "for (var i = 0; i < 1000; i++) {"
8239 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8240 "}"
8241 "garbage = undefined;");
8242}
8243
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008244
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008245v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8246 static int count = 0;
8247 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008248 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008249 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8250 }
8251 return v8::Handle<v8::Value>();
8252}
8253
8254
8255THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8256 v8::HandleScope scope;
8257 LocalContext context;
8258 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8259 nativeobject_templ->Set("callback",
8260 v8::FunctionTemplate::New(DirectApiCallback));
8261 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8262 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8263 // call the api function multiple times to ensure direct call stub creation.
8264 CompileRun(
8265 "function f() {"
8266 " for (var i = 1; i <= 30; i++) {"
8267 " nativeobject.callback();"
8268 " }"
8269 "}"
8270 "f();");
8271}
8272
8273
8274v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8275 return v8::ThrowException(v8_str("g"));
8276}
8277
8278
8279THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8280 v8::HandleScope scope;
8281 LocalContext context;
8282 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8283 nativeobject_templ->Set("callback",
8284 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8285 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8286 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8287 // call the api function multiple times to ensure direct call stub creation.
8288 v8::Handle<Value> result = CompileRun(
8289 "var result = '';"
8290 "function f() {"
8291 " for (var i = 1; i <= 5; i++) {"
8292 " try { nativeobject.callback(); } catch (e) { result += e; }"
8293 " }"
8294 "}"
8295 "f(); result;");
8296 CHECK_EQ(v8_str("ggggg"), result);
8297}
8298
8299
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008300v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8301 const v8::AccessorInfo& info) {
8302 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008304 GenerateSomeGarbage();
8305 }
8306 return v8::Handle<v8::Value>();
8307}
8308
8309
8310THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8311 v8::HandleScope scope;
8312 LocalContext context;
8313 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8314 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8315 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8316 p_getter_count = 0;
8317 CompileRun(
8318 "function f() {"
8319 " for (var i = 0; i < 30; i++) o1.p1;"
8320 "}"
8321 "f();");
8322 CHECK_EQ(30, p_getter_count);
8323}
8324
8325
8326v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8327 Local<String> name, const v8::AccessorInfo& info) {
8328 return v8::ThrowException(v8_str("g"));
8329}
8330
8331
8332THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8333 v8::HandleScope scope;
8334 LocalContext context;
8335 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8336 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8337 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8338 v8::Handle<Value> result = CompileRun(
8339 "var result = '';"
8340 "for (var i = 0; i < 5; i++) {"
8341 " try { o1.p1; } catch (e) { result += e; }"
8342 "}"
8343 "result;");
8344 CHECK_EQ(v8_str("ggggg"), result);
8345}
8346
8347
ager@chromium.org5c838252010-02-19 08:53:10 +00008348THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8349 int interceptor_call_count = 0;
8350 v8::HandleScope scope;
8351 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8352 v8::Handle<v8::FunctionTemplate> method_templ =
8353 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8354 v8_str("method_data"),
8355 v8::Handle<v8::Signature>());
8356 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8357 proto_templ->Set(v8_str("method"), method_templ);
8358 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8359 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8360 NULL, NULL, NULL, NULL,
8361 v8::External::Wrap(&interceptor_call_count));
8362 LocalContext context;
8363 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8364 GenerateSomeGarbage();
8365 context->Global()->Set(v8_str("o"), fun->NewInstance());
8366 v8::Handle<Value> value = CompileRun(
8367 "var result = 0;"
8368 "for (var i = 0; i < 100; i++) {"
8369 " result = o.method(41);"
8370 "}");
8371 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8372 CHECK_EQ(100, interceptor_call_count);
8373}
8374
8375THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8376 int interceptor_call_count = 0;
8377 v8::HandleScope scope;
8378 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8379 v8::Handle<v8::FunctionTemplate> method_templ =
8380 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8381 v8_str("method_data"),
8382 v8::Signature::New(fun_templ));
8383 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8384 proto_templ->Set(v8_str("method"), method_templ);
8385 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8386 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8387 NULL, NULL, NULL, NULL,
8388 v8::External::Wrap(&interceptor_call_count));
8389 LocalContext context;
8390 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8391 GenerateSomeGarbage();
8392 context->Global()->Set(v8_str("o"), fun->NewInstance());
8393 v8::Handle<Value> value = CompileRun(
8394 "o.foo = 17;"
8395 "var receiver = {};"
8396 "receiver.__proto__ = o;"
8397 "var result = 0;"
8398 "for (var i = 0; i < 100; i++) {"
8399 " result = receiver.method(41);"
8400 "}");
8401 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8402 CHECK_EQ(100, interceptor_call_count);
8403}
8404
8405THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8406 int interceptor_call_count = 0;
8407 v8::HandleScope scope;
8408 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8409 v8::Handle<v8::FunctionTemplate> method_templ =
8410 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8411 v8_str("method_data"),
8412 v8::Signature::New(fun_templ));
8413 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8414 proto_templ->Set(v8_str("method"), method_templ);
8415 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8416 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8417 NULL, NULL, NULL, NULL,
8418 v8::External::Wrap(&interceptor_call_count));
8419 LocalContext context;
8420 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8421 GenerateSomeGarbage();
8422 context->Global()->Set(v8_str("o"), fun->NewInstance());
8423 v8::Handle<Value> value = CompileRun(
8424 "o.foo = 17;"
8425 "var receiver = {};"
8426 "receiver.__proto__ = o;"
8427 "var result = 0;"
8428 "var saved_result = 0;"
8429 "for (var i = 0; i < 100; i++) {"
8430 " result = receiver.method(41);"
8431 " if (i == 50) {"
8432 " saved_result = result;"
8433 " receiver = {method: function(x) { return x - 1 }};"
8434 " }"
8435 "}");
8436 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8437 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8438 CHECK_GE(interceptor_call_count, 50);
8439}
8440
8441THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8442 int interceptor_call_count = 0;
8443 v8::HandleScope scope;
8444 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8445 v8::Handle<v8::FunctionTemplate> method_templ =
8446 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8447 v8_str("method_data"),
8448 v8::Signature::New(fun_templ));
8449 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8450 proto_templ->Set(v8_str("method"), method_templ);
8451 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8452 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8453 NULL, NULL, NULL, NULL,
8454 v8::External::Wrap(&interceptor_call_count));
8455 LocalContext context;
8456 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8457 GenerateSomeGarbage();
8458 context->Global()->Set(v8_str("o"), fun->NewInstance());
8459 v8::Handle<Value> value = CompileRun(
8460 "o.foo = 17;"
8461 "var receiver = {};"
8462 "receiver.__proto__ = o;"
8463 "var result = 0;"
8464 "var saved_result = 0;"
8465 "for (var i = 0; i < 100; i++) {"
8466 " result = receiver.method(41);"
8467 " if (i == 50) {"
8468 " saved_result = result;"
8469 " o.method = function(x) { return x - 1 };"
8470 " }"
8471 "}");
8472 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8473 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8474 CHECK_GE(interceptor_call_count, 50);
8475}
8476
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008477THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8478 int interceptor_call_count = 0;
8479 v8::HandleScope scope;
8480 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8481 v8::Handle<v8::FunctionTemplate> method_templ =
8482 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8483 v8_str("method_data"),
8484 v8::Signature::New(fun_templ));
8485 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8486 proto_templ->Set(v8_str("method"), method_templ);
8487 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8488 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8489 NULL, NULL, NULL, NULL,
8490 v8::External::Wrap(&interceptor_call_count));
8491 LocalContext context;
8492 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8493 GenerateSomeGarbage();
8494 context->Global()->Set(v8_str("o"), fun->NewInstance());
8495 v8::TryCatch try_catch;
8496 v8::Handle<Value> value = CompileRun(
8497 "o.foo = 17;"
8498 "var receiver = {};"
8499 "receiver.__proto__ = o;"
8500 "var result = 0;"
8501 "var saved_result = 0;"
8502 "for (var i = 0; i < 100; i++) {"
8503 " result = receiver.method(41);"
8504 " if (i == 50) {"
8505 " saved_result = result;"
8506 " receiver = 333;"
8507 " }"
8508 "}");
8509 CHECK(try_catch.HasCaught());
8510 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8511 try_catch.Exception()->ToString());
8512 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8513 CHECK_GE(interceptor_call_count, 50);
8514}
8515
ager@chromium.org5c838252010-02-19 08:53:10 +00008516THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8517 int interceptor_call_count = 0;
8518 v8::HandleScope scope;
8519 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8520 v8::Handle<v8::FunctionTemplate> method_templ =
8521 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8522 v8_str("method_data"),
8523 v8::Signature::New(fun_templ));
8524 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8525 proto_templ->Set(v8_str("method"), method_templ);
8526 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8527 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8528 NULL, NULL, NULL, NULL,
8529 v8::External::Wrap(&interceptor_call_count));
8530 LocalContext context;
8531 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8532 GenerateSomeGarbage();
8533 context->Global()->Set(v8_str("o"), fun->NewInstance());
8534 v8::TryCatch try_catch;
8535 v8::Handle<Value> value = CompileRun(
8536 "o.foo = 17;"
8537 "var receiver = {};"
8538 "receiver.__proto__ = o;"
8539 "var result = 0;"
8540 "var saved_result = 0;"
8541 "for (var i = 0; i < 100; i++) {"
8542 " result = receiver.method(41);"
8543 " if (i == 50) {"
8544 " saved_result = result;"
8545 " receiver = {method: receiver.method};"
8546 " }"
8547 "}");
8548 CHECK(try_catch.HasCaught());
8549 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8550 try_catch.Exception()->ToString());
8551 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8552 CHECK_GE(interceptor_call_count, 50);
8553}
8554
8555THREADED_TEST(CallICFastApi_TrivialSignature) {
8556 v8::HandleScope scope;
8557 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8558 v8::Handle<v8::FunctionTemplate> method_templ =
8559 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8560 v8_str("method_data"),
8561 v8::Handle<v8::Signature>());
8562 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8563 proto_templ->Set(v8_str("method"), method_templ);
8564 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8565 LocalContext context;
8566 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8567 GenerateSomeGarbage();
8568 context->Global()->Set(v8_str("o"), fun->NewInstance());
8569 v8::Handle<Value> value = CompileRun(
8570 "var result = 0;"
8571 "for (var i = 0; i < 100; i++) {"
8572 " result = o.method(41);"
8573 "}");
8574
8575 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8576}
8577
8578THREADED_TEST(CallICFastApi_SimpleSignature) {
8579 v8::HandleScope scope;
8580 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8581 v8::Handle<v8::FunctionTemplate> method_templ =
8582 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8583 v8_str("method_data"),
8584 v8::Signature::New(fun_templ));
8585 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8586 proto_templ->Set(v8_str("method"), method_templ);
8587 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8588 LocalContext context;
8589 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8590 GenerateSomeGarbage();
8591 context->Global()->Set(v8_str("o"), fun->NewInstance());
8592 v8::Handle<Value> value = CompileRun(
8593 "o.foo = 17;"
8594 "var receiver = {};"
8595 "receiver.__proto__ = o;"
8596 "var result = 0;"
8597 "for (var i = 0; i < 100; i++) {"
8598 " result = receiver.method(41);"
8599 "}");
8600
8601 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8602}
8603
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008604THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008605 v8::HandleScope scope;
8606 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8607 v8::Handle<v8::FunctionTemplate> method_templ =
8608 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8609 v8_str("method_data"),
8610 v8::Signature::New(fun_templ));
8611 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8612 proto_templ->Set(v8_str("method"), method_templ);
8613 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8614 LocalContext context;
8615 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8616 GenerateSomeGarbage();
8617 context->Global()->Set(v8_str("o"), fun->NewInstance());
8618 v8::Handle<Value> value = CompileRun(
8619 "o.foo = 17;"
8620 "var receiver = {};"
8621 "receiver.__proto__ = o;"
8622 "var result = 0;"
8623 "var saved_result = 0;"
8624 "for (var i = 0; i < 100; i++) {"
8625 " result = receiver.method(41);"
8626 " if (i == 50) {"
8627 " saved_result = result;"
8628 " receiver = {method: function(x) { return x - 1 }};"
8629 " }"
8630 "}");
8631 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8632 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8633}
8634
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008635THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8636 v8::HandleScope scope;
8637 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8638 v8::Handle<v8::FunctionTemplate> method_templ =
8639 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8640 v8_str("method_data"),
8641 v8::Signature::New(fun_templ));
8642 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8643 proto_templ->Set(v8_str("method"), method_templ);
8644 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8645 LocalContext context;
8646 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8647 GenerateSomeGarbage();
8648 context->Global()->Set(v8_str("o"), fun->NewInstance());
8649 v8::TryCatch try_catch;
8650 v8::Handle<Value> value = CompileRun(
8651 "o.foo = 17;"
8652 "var receiver = {};"
8653 "receiver.__proto__ = o;"
8654 "var result = 0;"
8655 "var saved_result = 0;"
8656 "for (var i = 0; i < 100; i++) {"
8657 " result = receiver.method(41);"
8658 " if (i == 50) {"
8659 " saved_result = result;"
8660 " receiver = 333;"
8661 " }"
8662 "}");
8663 CHECK(try_catch.HasCaught());
8664 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8665 try_catch.Exception()->ToString());
8666 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8667}
8668
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008669
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008670v8::Handle<Value> keyed_call_ic_function;
8671
8672static v8::Handle<Value> InterceptorKeyedCallICGetter(
8673 Local<String> name, const AccessorInfo& info) {
8674 ApiTestFuzzer::Fuzz();
8675 if (v8_str("x")->Equals(name)) {
8676 return keyed_call_ic_function;
8677 }
8678 return v8::Handle<Value>();
8679}
8680
8681
8682// Test the case when we stored cacheable lookup into
8683// a stub, but the function name changed (to another cacheable function).
8684THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8685 v8::HandleScope scope;
8686 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8687 templ->SetNamedPropertyHandler(NoBlockGetterX);
8688 LocalContext context;
8689 context->Global()->Set(v8_str("o"), templ->NewInstance());
8690 v8::Handle<Value> value = CompileRun(
8691 "proto = new Object();"
8692 "proto.y = function(x) { return x + 1; };"
8693 "proto.z = function(x) { return x - 1; };"
8694 "o.__proto__ = proto;"
8695 "var result = 0;"
8696 "var method = 'y';"
8697 "for (var i = 0; i < 10; i++) {"
8698 " if (i == 5) { method = 'z'; };"
8699 " result += o[method](41);"
8700 "}");
8701 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8702}
8703
8704
8705// Test the case when we stored cacheable lookup into
8706// a stub, but the function name changed (and the new function is present
8707// both before and after the interceptor in the prototype chain).
8708THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
8709 v8::HandleScope scope;
8710 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8711 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
8712 LocalContext context;
8713 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
8714 keyed_call_ic_function =
8715 v8_compile("function f(x) { return x - 1; }; f")->Run();
8716 v8::Handle<Value> value = CompileRun(
8717 "o = new Object();"
8718 "proto2 = new Object();"
8719 "o.y = function(x) { return x + 1; };"
8720 "proto2.y = function(x) { return x + 2; };"
8721 "o.__proto__ = proto1;"
8722 "proto1.__proto__ = proto2;"
8723 "var result = 0;"
8724 "var method = 'x';"
8725 "for (var i = 0; i < 10; i++) {"
8726 " if (i == 5) { method = 'y'; };"
8727 " result += o[method](41);"
8728 "}");
8729 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8730}
8731
8732
8733// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
8734// on the global object.
8735THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
8736 v8::HandleScope scope;
8737 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8738 templ->SetNamedPropertyHandler(NoBlockGetterX);
8739 LocalContext context;
8740 context->Global()->Set(v8_str("o"), templ->NewInstance());
8741 v8::Handle<Value> value = CompileRun(
8742 "function inc(x) { return x + 1; };"
8743 "inc(1);"
8744 "function dec(x) { return x - 1; };"
8745 "dec(1);"
8746 "o.__proto__ = this;"
8747 "this.__proto__.x = inc;"
8748 "this.__proto__.y = dec;"
8749 "var result = 0;"
8750 "var method = 'x';"
8751 "for (var i = 0; i < 10; i++) {"
8752 " if (i == 5) { method = 'y'; };"
8753 " result += o[method](41);"
8754 "}");
8755 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8756}
8757
8758
8759// Test the case when actual function to call sits on global object.
8760THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
8761 v8::HandleScope scope;
8762 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8763 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8764 LocalContext context;
8765 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8766
8767 v8::Handle<Value> value = CompileRun(
8768 "function len(x) { return x.length; };"
8769 "o.__proto__ = this;"
8770 "var m = 'parseFloat';"
8771 "var result = 0;"
8772 "for (var i = 0; i < 10; i++) {"
8773 " if (i == 5) {"
8774 " m = 'len';"
8775 " saved_result = result;"
8776 " };"
8777 " result = o[m]('239');"
8778 "}");
8779 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
8780 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8781}
8782
8783// Test the map transition before the interceptor.
8784THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
8785 v8::HandleScope scope;
8786 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8787 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8788 LocalContext context;
8789 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
8790
8791 v8::Handle<Value> value = CompileRun(
8792 "var o = new Object();"
8793 "o.__proto__ = proto;"
8794 "o.method = function(x) { return x + 1; };"
8795 "var m = 'method';"
8796 "var result = 0;"
8797 "for (var i = 0; i < 10; i++) {"
8798 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
8799 " result += o[m](41);"
8800 "}");
8801 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8802}
8803
8804
8805// Test the map transition after the interceptor.
8806THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
8807 v8::HandleScope scope;
8808 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8809 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8810 LocalContext context;
8811 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8812
8813 v8::Handle<Value> value = CompileRun(
8814 "var proto = new Object();"
8815 "o.__proto__ = proto;"
8816 "proto.method = function(x) { return x + 1; };"
8817 "var m = 'method';"
8818 "var result = 0;"
8819 "for (var i = 0; i < 10; i++) {"
8820 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
8821 " result += o[m](41);"
8822 "}");
8823 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
8824}
8825
8826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008827static int interceptor_call_count = 0;
8828
8829static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
8830 const AccessorInfo& info) {
8831 ApiTestFuzzer::Fuzz();
8832 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
8833 return call_ic_function2;
8834 }
8835 return v8::Handle<Value>();
8836}
8837
8838
8839// This test should hit load and call ICs for the interceptor case.
8840// Once in a while, the interceptor will reply that a property was not
8841// found in which case we should get a reference error.
8842THREADED_TEST(InterceptorICReferenceErrors) {
8843 v8::HandleScope scope;
8844 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8845 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
8846 LocalContext context(0, templ, v8::Handle<Value>());
8847 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
8848 v8::Handle<Value> value = CompileRun(
8849 "function f() {"
8850 " for (var i = 0; i < 1000; i++) {"
8851 " try { x; } catch(e) { return true; }"
8852 " }"
8853 " return false;"
8854 "};"
8855 "f();");
8856 CHECK_EQ(true, value->BooleanValue());
8857 interceptor_call_count = 0;
8858 value = CompileRun(
8859 "function g() {"
8860 " for (var i = 0; i < 1000; i++) {"
8861 " try { x(42); } catch(e) { return true; }"
8862 " }"
8863 " return false;"
8864 "};"
8865 "g();");
8866 CHECK_EQ(true, value->BooleanValue());
8867}
8868
8869
8870static int interceptor_ic_exception_get_count = 0;
8871
8872static v8::Handle<Value> InterceptorICExceptionGetter(
8873 Local<String> name,
8874 const AccessorInfo& info) {
8875 ApiTestFuzzer::Fuzz();
8876 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
8877 return call_ic_function3;
8878 }
8879 if (interceptor_ic_exception_get_count == 20) {
8880 return v8::ThrowException(v8_num(42));
8881 }
8882 // Do not handle get for properties other than x.
8883 return v8::Handle<Value>();
8884}
8885
8886// Test interceptor load/call IC where the interceptor throws an
8887// exception once in a while.
8888THREADED_TEST(InterceptorICGetterExceptions) {
8889 interceptor_ic_exception_get_count = 0;
8890 v8::HandleScope scope;
8891 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8892 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
8893 LocalContext context(0, templ, v8::Handle<Value>());
8894 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
8895 v8::Handle<Value> value = CompileRun(
8896 "function f() {"
8897 " for (var i = 0; i < 100; i++) {"
8898 " try { x; } catch(e) { return true; }"
8899 " }"
8900 " return false;"
8901 "};"
8902 "f();");
8903 CHECK_EQ(true, value->BooleanValue());
8904 interceptor_ic_exception_get_count = 0;
8905 value = CompileRun(
8906 "function f() {"
8907 " for (var i = 0; i < 100; i++) {"
8908 " try { x(42); } catch(e) { return true; }"
8909 " }"
8910 " return false;"
8911 "};"
8912 "f();");
8913 CHECK_EQ(true, value->BooleanValue());
8914}
8915
8916
8917static int interceptor_ic_exception_set_count = 0;
8918
8919static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008920 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008921 ApiTestFuzzer::Fuzz();
8922 if (++interceptor_ic_exception_set_count > 20) {
8923 return v8::ThrowException(v8_num(42));
8924 }
8925 // Do not actually handle setting.
8926 return v8::Handle<Value>();
8927}
8928
8929// Test interceptor store IC where the interceptor throws an exception
8930// once in a while.
8931THREADED_TEST(InterceptorICSetterExceptions) {
8932 interceptor_ic_exception_set_count = 0;
8933 v8::HandleScope scope;
8934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8935 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
8936 LocalContext context(0, templ, v8::Handle<Value>());
8937 v8::Handle<Value> value = CompileRun(
8938 "function f() {"
8939 " for (var i = 0; i < 100; i++) {"
8940 " try { x = 42; } catch(e) { return true; }"
8941 " }"
8942 " return false;"
8943 "};"
8944 "f();");
8945 CHECK_EQ(true, value->BooleanValue());
8946}
8947
8948
8949// Test that we ignore null interceptors.
8950THREADED_TEST(NullNamedInterceptor) {
8951 v8::HandleScope scope;
8952 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8953 templ->SetNamedPropertyHandler(0);
8954 LocalContext context;
8955 templ->Set("x", v8_num(42));
8956 v8::Handle<v8::Object> obj = templ->NewInstance();
8957 context->Global()->Set(v8_str("obj"), obj);
8958 v8::Handle<Value> value = CompileRun("obj.x");
8959 CHECK(value->IsInt32());
8960 CHECK_EQ(42, value->Int32Value());
8961}
8962
8963
8964// Test that we ignore null interceptors.
8965THREADED_TEST(NullIndexedInterceptor) {
8966 v8::HandleScope scope;
8967 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8968 templ->SetIndexedPropertyHandler(0);
8969 LocalContext context;
8970 templ->Set("42", v8_num(42));
8971 v8::Handle<v8::Object> obj = templ->NewInstance();
8972 context->Global()->Set(v8_str("obj"), obj);
8973 v8::Handle<Value> value = CompileRun("obj[42]");
8974 CHECK(value->IsInt32());
8975 CHECK_EQ(42, value->Int32Value());
8976}
8977
8978
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008979THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
8980 v8::HandleScope scope;
8981 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8982 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8983 LocalContext env;
8984 env->Global()->Set(v8_str("obj"),
8985 templ->GetFunction()->NewInstance());
8986 ExpectTrue("obj.x === 42");
8987 ExpectTrue("!obj.propertyIsEnumerable('x')");
8988}
8989
8990
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008991static Handle<Value> ThrowingGetter(Local<String> name,
8992 const AccessorInfo& info) {
8993 ApiTestFuzzer::Fuzz();
8994 ThrowException(Handle<Value>());
8995 return Undefined();
8996}
8997
8998
8999THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9000 HandleScope scope;
9001 LocalContext context;
9002
9003 Local<FunctionTemplate> templ = FunctionTemplate::New();
9004 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9005 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9006
9007 Local<Object> instance = templ->GetFunction()->NewInstance();
9008
9009 Local<Object> another = Object::New();
9010 another->SetPrototype(instance);
9011
9012 Local<Object> with_js_getter = CompileRun(
9013 "o = {};\n"
9014 "o.__defineGetter__('f', function() { throw undefined; });\n"
9015 "o\n").As<Object>();
9016 CHECK(!with_js_getter.IsEmpty());
9017
9018 TryCatch try_catch;
9019
9020 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9021 CHECK(try_catch.HasCaught());
9022 try_catch.Reset();
9023 CHECK(result.IsEmpty());
9024
9025 result = another->GetRealNamedProperty(v8_str("f"));
9026 CHECK(try_catch.HasCaught());
9027 try_catch.Reset();
9028 CHECK(result.IsEmpty());
9029
9030 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9031 CHECK(try_catch.HasCaught());
9032 try_catch.Reset();
9033 CHECK(result.IsEmpty());
9034
9035 result = another->Get(v8_str("f"));
9036 CHECK(try_catch.HasCaught());
9037 try_catch.Reset();
9038 CHECK(result.IsEmpty());
9039
9040 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9041 CHECK(try_catch.HasCaught());
9042 try_catch.Reset();
9043 CHECK(result.IsEmpty());
9044
9045 result = with_js_getter->Get(v8_str("f"));
9046 CHECK(try_catch.HasCaught());
9047 try_catch.Reset();
9048 CHECK(result.IsEmpty());
9049}
9050
9051
9052static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9053 TryCatch try_catch;
9054 // Verboseness is important: it triggers message delivery which can call into
9055 // external code.
9056 try_catch.SetVerbose(true);
9057 CompileRun("throw 'from JS';");
9058 CHECK(try_catch.HasCaught());
9059 CHECK(!i::Isolate::Current()->has_pending_exception());
9060 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9061 return Undefined();
9062}
9063
9064
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009065static int call_depth;
9066
9067
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009068static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9069 TryCatch try_catch;
9070}
9071
9072
9073static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009074 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009075}
9076
9077
9078static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009079 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009080}
9081
9082
9083static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9084 Handle<String> errorMessageString = message->Get();
9085 CHECK(!errorMessageString.IsEmpty());
9086 message->GetStackTrace();
9087 message->GetScriptResourceName();
9088}
9089
9090THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9091 HandleScope scope;
9092 LocalContext context;
9093
9094 Local<Function> func =
9095 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9096 context->Global()->Set(v8_str("func"), func);
9097
9098 MessageCallback callbacks[] =
9099 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9100 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9101 MessageCallback callback = callbacks[i];
9102 if (callback != NULL) {
9103 V8::AddMessageListener(callback);
9104 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009105 // Some small number to control number of times message handler should
9106 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009107 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009108 ExpectFalse(
9109 "var thrown = false;\n"
9110 "try { func(); } catch(e) { thrown = true; }\n"
9111 "thrown\n");
9112 if (callback != NULL) {
9113 V8::RemoveMessageListeners(callback);
9114 }
9115 }
9116}
9117
9118
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009119static v8::Handle<Value> ParentGetter(Local<String> name,
9120 const AccessorInfo& info) {
9121 ApiTestFuzzer::Fuzz();
9122 return v8_num(1);
9123}
9124
9125
9126static v8::Handle<Value> ChildGetter(Local<String> name,
9127 const AccessorInfo& info) {
9128 ApiTestFuzzer::Fuzz();
9129 return v8_num(42);
9130}
9131
9132
9133THREADED_TEST(Overriding) {
9134 v8::HandleScope scope;
9135 LocalContext context;
9136
9137 // Parent template.
9138 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9139 Local<ObjectTemplate> parent_instance_templ =
9140 parent_templ->InstanceTemplate();
9141 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9142
9143 // Template that inherits from the parent template.
9144 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9145 Local<ObjectTemplate> child_instance_templ =
9146 child_templ->InstanceTemplate();
9147 child_templ->Inherit(parent_templ);
9148 // Override 'f'. The child version of 'f' should get called for child
9149 // instances.
9150 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9151 // Add 'g' twice. The 'g' added last should get called for instances.
9152 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9153 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9154
9155 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9156 // so 'h' can be shadowed on the instance object.
9157 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9158 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9159 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9160
9161 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9162 // but the attribute does not have effect because it is duplicated with
9163 // NULL setter.
9164 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9165 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9166
9167
9168
9169 // Instantiate the child template.
9170 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9171
9172 // Check that the child function overrides the parent one.
9173 context->Global()->Set(v8_str("o"), instance);
9174 Local<Value> value = v8_compile("o.f")->Run();
9175 // Check that the 'g' that was added last is hit.
9176 CHECK_EQ(42, value->Int32Value());
9177 value = v8_compile("o.g")->Run();
9178 CHECK_EQ(42, value->Int32Value());
9179
9180 // Check 'h' can be shadowed.
9181 value = v8_compile("o.h = 3; o.h")->Run();
9182 CHECK_EQ(3, value->Int32Value());
9183
9184 // Check 'i' is cannot be shadowed or changed.
9185 value = v8_compile("o.i = 3; o.i")->Run();
9186 CHECK_EQ(42, value->Int32Value());
9187}
9188
9189
9190static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9191 ApiTestFuzzer::Fuzz();
9192 if (args.IsConstructCall()) {
9193 return v8::Boolean::New(true);
9194 }
9195 return v8::Boolean::New(false);
9196}
9197
9198
9199THREADED_TEST(IsConstructCall) {
9200 v8::HandleScope scope;
9201
9202 // Function template with call handler.
9203 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9204 templ->SetCallHandler(IsConstructHandler);
9205
9206 LocalContext context;
9207
9208 context->Global()->Set(v8_str("f"), templ->GetFunction());
9209 Local<Value> value = v8_compile("f()")->Run();
9210 CHECK(!value->BooleanValue());
9211 value = v8_compile("new f()")->Run();
9212 CHECK(value->BooleanValue());
9213}
9214
9215
9216THREADED_TEST(ObjectProtoToString) {
9217 v8::HandleScope scope;
9218 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9219 templ->SetClassName(v8_str("MyClass"));
9220
9221 LocalContext context;
9222
9223 Local<String> customized_tostring = v8_str("customized toString");
9224
9225 // Replace Object.prototype.toString
9226 v8_compile("Object.prototype.toString = function() {"
9227 " return 'customized toString';"
9228 "}")->Run();
9229
9230 // Normal ToString call should call replaced Object.prototype.toString
9231 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9232 Local<String> value = instance->ToString();
9233 CHECK(value->IsString() && value->Equals(customized_tostring));
9234
9235 // ObjectProtoToString should not call replace toString function.
9236 value = instance->ObjectProtoToString();
9237 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9238
9239 // Check global
9240 value = context->Global()->ObjectProtoToString();
9241 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9242
9243 // Check ordinary object
9244 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009245 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009246 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9247}
9248
9249
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009250THREADED_TEST(ObjectGetConstructorName) {
9251 v8::HandleScope scope;
9252 LocalContext context;
9253 v8_compile("function Parent() {};"
9254 "function Child() {};"
9255 "Child.prototype = new Parent();"
9256 "var outer = { inner: function() { } };"
9257 "var p = new Parent();"
9258 "var c = new Child();"
9259 "var x = new outer.inner();")->Run();
9260
9261 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9262 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9263 v8_str("Parent")));
9264
9265 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9266 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9267 v8_str("Child")));
9268
9269 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9270 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9271 v8_str("outer.inner")));
9272}
9273
9274
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009275bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009276i::Semaphore* ApiTestFuzzer::all_tests_done_=
9277 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009278int ApiTestFuzzer::active_tests_;
9279int ApiTestFuzzer::tests_being_run_;
9280int ApiTestFuzzer::current_;
9281
9282
9283// We are in a callback and want to switch to another thread (if we
9284// are currently running the thread fuzzing test).
9285void ApiTestFuzzer::Fuzz() {
9286 if (!fuzzing_) return;
9287 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9288 test->ContextSwitch();
9289}
9290
9291
9292// Let the next thread go. Since it is also waiting on the V8 lock it may
9293// not start immediately.
9294bool ApiTestFuzzer::NextThread() {
9295 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009296 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009297 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009298 if (kLogThreading)
9299 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009300 return false;
9301 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009302 if (kLogThreading) {
9303 printf("Switch from %s to %s\n",
9304 test_name,
9305 RegisterThreadedTest::nth(test_position)->name());
9306 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009307 current_ = test_position;
9308 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9309 return true;
9310}
9311
9312
9313void ApiTestFuzzer::Run() {
9314 // When it is our turn...
9315 gate_->Wait();
9316 {
9317 // ... get the V8 lock and start running the test.
9318 v8::Locker locker;
9319 CallTest();
9320 }
9321 // This test finished.
9322 active_ = false;
9323 active_tests_--;
9324 // If it was the last then signal that fact.
9325 if (active_tests_ == 0) {
9326 all_tests_done_->Signal();
9327 } else {
9328 // Otherwise select a new test and start that.
9329 NextThread();
9330 }
9331}
9332
9333
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009334static unsigned linear_congruential_generator;
9335
9336
9337void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009338 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009339 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +00009340 int count = RegisterThreadedTest::count();
9341 int start = count * part / (LAST_PART + 1);
9342 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9343 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009344 for (int i = 0; i < tests_being_run_; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(
9346 i::Isolate::Current(), i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009347 }
9348 for (int i = 0; i < active_tests_; i++) {
9349 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9350 }
9351}
9352
9353
9354static void CallTestNumber(int test_number) {
9355 (RegisterThreadedTest::nth(test_number)->callback())();
9356}
9357
9358
9359void ApiTestFuzzer::RunAllTests() {
9360 // Set off the first test.
9361 current_ = -1;
9362 NextThread();
9363 // Wait till they are all done.
9364 all_tests_done_->Wait();
9365}
9366
9367
9368int ApiTestFuzzer::GetNextTestNumber() {
9369 int next_test;
9370 do {
9371 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9372 linear_congruential_generator *= 1664525u;
9373 linear_congruential_generator += 1013904223u;
9374 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9375 return next_test;
9376}
9377
9378
9379void ApiTestFuzzer::ContextSwitch() {
9380 // If the new thread is the same as the current thread there is nothing to do.
9381 if (NextThread()) {
9382 // Now it can start.
9383 v8::Unlocker unlocker;
9384 // Wait till someone starts us again.
9385 gate_->Wait();
9386 // And we're off.
9387 }
9388}
9389
9390
9391void ApiTestFuzzer::TearDown() {
9392 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009393 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9394 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9395 if (fuzzer != NULL) fuzzer->Join();
9396 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009397}
9398
9399
9400// Lets not be needlessly self-referential.
9401TEST(Threading) {
9402 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9403 ApiTestFuzzer::RunAllTests();
9404 ApiTestFuzzer::TearDown();
9405}
9406
9407TEST(Threading2) {
9408 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9409 ApiTestFuzzer::RunAllTests();
9410 ApiTestFuzzer::TearDown();
9411}
9412
lrn@chromium.org1c092762011-05-09 09:42:16 +00009413TEST(Threading3) {
9414 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9415 ApiTestFuzzer::RunAllTests();
9416 ApiTestFuzzer::TearDown();
9417}
9418
9419TEST(Threading4) {
9420 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9421 ApiTestFuzzer::RunAllTests();
9422 ApiTestFuzzer::TearDown();
9423}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009424
9425void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009426 if (kLogThreading)
9427 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009428 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009429 if (kLogThreading)
9430 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009431}
9432
9433
9434static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009435 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009436 ApiTestFuzzer::Fuzz();
9437 v8::Unlocker unlocker;
9438 const char* code = "throw 7;";
9439 {
9440 v8::Locker nested_locker;
9441 v8::HandleScope scope;
9442 v8::Handle<Value> exception;
9443 { v8::TryCatch try_catch;
9444 v8::Handle<Value> value = CompileRun(code);
9445 CHECK(value.IsEmpty());
9446 CHECK(try_catch.HasCaught());
9447 // Make sure to wrap the exception in a new handle because
9448 // the handle returned from the TryCatch is destroyed
9449 // when the TryCatch is destroyed.
9450 exception = Local<Value>::New(try_catch.Exception());
9451 }
9452 return v8::ThrowException(exception);
9453 }
9454}
9455
9456
9457static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009458 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009459 ApiTestFuzzer::Fuzz();
9460 v8::Unlocker unlocker;
9461 const char* code = "throw 7;";
9462 {
9463 v8::Locker nested_locker;
9464 v8::HandleScope scope;
9465 v8::Handle<Value> value = CompileRun(code);
9466 CHECK(value.IsEmpty());
9467 return v8_str("foo");
9468 }
9469}
9470
9471
9472// These are locking tests that don't need to be run again
9473// as part of the locking aggregation tests.
9474TEST(NestedLockers) {
9475 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009476 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009477 v8::HandleScope scope;
9478 LocalContext env;
9479 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9480 Local<Function> fun = fun_templ->GetFunction();
9481 env->Global()->Set(v8_str("throw_in_js"), fun);
9482 Local<Script> script = v8_compile("(function () {"
9483 " try {"
9484 " throw_in_js();"
9485 " return 42;"
9486 " } catch (e) {"
9487 " return e * 13;"
9488 " }"
9489 "})();");
9490 CHECK_EQ(91, script->Run()->Int32Value());
9491}
9492
9493
9494// These are locking tests that don't need to be run again
9495// as part of the locking aggregation tests.
9496TEST(NestedLockersNoTryCatch) {
9497 v8::Locker locker;
9498 v8::HandleScope scope;
9499 LocalContext env;
9500 Local<v8::FunctionTemplate> fun_templ =
9501 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9502 Local<Function> fun = fun_templ->GetFunction();
9503 env->Global()->Set(v8_str("throw_in_js"), fun);
9504 Local<Script> script = v8_compile("(function () {"
9505 " try {"
9506 " throw_in_js();"
9507 " return 42;"
9508 " } catch (e) {"
9509 " return e * 13;"
9510 " }"
9511 "})();");
9512 CHECK_EQ(91, script->Run()->Int32Value());
9513}
9514
9515
9516THREADED_TEST(RecursiveLocking) {
9517 v8::Locker locker;
9518 {
9519 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009520 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009521 }
9522}
9523
9524
9525static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9526 ApiTestFuzzer::Fuzz();
9527 v8::Unlocker unlocker;
9528 return v8::Undefined();
9529}
9530
9531
9532THREADED_TEST(LockUnlockLock) {
9533 {
9534 v8::Locker locker;
9535 v8::HandleScope scope;
9536 LocalContext env;
9537 Local<v8::FunctionTemplate> fun_templ =
9538 v8::FunctionTemplate::New(UnlockForAMoment);
9539 Local<Function> fun = fun_templ->GetFunction();
9540 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9541 Local<Script> script = v8_compile("(function () {"
9542 " unlock_for_a_moment();"
9543 " return 42;"
9544 "})();");
9545 CHECK_EQ(42, script->Run()->Int32Value());
9546 }
9547 {
9548 v8::Locker locker;
9549 v8::HandleScope scope;
9550 LocalContext env;
9551 Local<v8::FunctionTemplate> fun_templ =
9552 v8::FunctionTemplate::New(UnlockForAMoment);
9553 Local<Function> fun = fun_templ->GetFunction();
9554 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9555 Local<Script> script = v8_compile("(function () {"
9556 " unlock_for_a_moment();"
9557 " return 42;"
9558 "})();");
9559 CHECK_EQ(42, script->Run()->Int32Value());
9560 }
9561}
9562
9563
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009564static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009565 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009566 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009567 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9568 if (object->IsJSGlobalObject()) count++;
9569 return count;
9570}
9571
9572
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009573static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009574 // We need to collect all garbage twice to be sure that everything
9575 // has been collected. This is because inline caches are cleared in
9576 // the first garbage collection but some of the maps have already
9577 // been marked at that point. Therefore some of the maps are not
9578 // collected until the second garbage collection.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009579 HEAP->CollectAllGarbage(false);
9580 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009581 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009582#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009583 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009584#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009585 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009586}
9587
9588
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009589TEST(DontLeakGlobalObjects) {
9590 // Regression test for issues 1139850 and 1174891.
9591
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009592 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009593
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009594 for (int i = 0; i < 5; i++) {
9595 { v8::HandleScope scope;
9596 LocalContext context;
9597 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009598 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009599
9600 { v8::HandleScope scope;
9601 LocalContext context;
9602 v8_compile("Date")->Run();
9603 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009604 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009605
9606 { v8::HandleScope scope;
9607 LocalContext context;
9608 v8_compile("/aaa/")->Run();
9609 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009610 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009611
9612 { v8::HandleScope scope;
9613 const char* extension_list[] = { "v8/gc" };
9614 v8::ExtensionConfiguration extensions(1, extension_list);
9615 LocalContext context(&extensions);
9616 v8_compile("gc();")->Run();
9617 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009618 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009619 }
9620}
9621
9622
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009623v8::Persistent<v8::Object> some_object;
9624v8::Persistent<v8::Object> bad_handle;
9625
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009626void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009627 v8::HandleScope scope;
9628 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009629 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009630}
9631
9632
9633THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9634 LocalContext context;
9635
9636 v8::Persistent<v8::Object> handle1, handle2;
9637 {
9638 v8::HandleScope scope;
9639 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9640 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9641 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9642 }
9643 // Note: order is implementation dependent alas: currently
9644 // global handle nodes are processed by PostGarbageCollectionProcessing
9645 // in reverse allocation order, so if second allocated handle is deleted,
9646 // weak callback of the first handle would be able to 'reallocate' it.
9647 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9648 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009650}
9651
9652
9653v8::Persistent<v8::Object> to_be_disposed;
9654
9655void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9656 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009657 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009658 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009659}
9660
9661
9662THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9663 LocalContext context;
9664
9665 v8::Persistent<v8::Object> handle1, handle2;
9666 {
9667 v8::HandleScope scope;
9668 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9669 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9670 }
9671 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9672 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009673 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009674}
9675
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009676void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9677 handle.Dispose();
9678}
9679
9680void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9681 v8::HandleScope scope;
9682 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009683 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009684}
9685
9686
9687THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9688 LocalContext context;
9689
9690 v8::Persistent<v8::Object> handle1, handle2, handle3;
9691 {
9692 v8::HandleScope scope;
9693 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9694 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9695 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9696 }
9697 handle2.MakeWeak(NULL, DisposingCallback);
9698 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009700}
9701
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009702
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009703THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009704 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009705
9706 const int nof = 2;
9707 const char* sources[nof] = {
9708 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
9709 "Object()"
9710 };
9711
9712 for (int i = 0; i < nof; i++) {
9713 const char* source = sources[i];
9714 { v8::HandleScope scope;
9715 LocalContext context;
9716 CompileRun(source);
9717 }
9718 { v8::HandleScope scope;
9719 LocalContext context;
9720 CompileRun(source);
9721 }
9722 }
9723}
9724
9725
9726static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
9727 v8::HandleScope inner;
9728 env->Enter();
9729 v8::Handle<Value> three = v8_num(3);
9730 v8::Handle<Value> value = inner.Close(three);
9731 env->Exit();
9732 return value;
9733}
9734
9735
9736THREADED_TEST(NestedHandleScopeAndContexts) {
9737 v8::HandleScope outer;
9738 v8::Persistent<Context> env = Context::New();
9739 env->Enter();
9740 v8::Handle<Value> value = NestedScope(env);
9741 v8::Handle<String> str = value->ToString();
9742 env->Exit();
9743 env.Dispose();
9744}
9745
9746
9747THREADED_TEST(ExternalAllocatedMemory) {
9748 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009749 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009750 const int kSize = 1024*1024;
9751 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
9752 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
9753}
9754
9755
9756THREADED_TEST(DisposeEnteredContext) {
9757 v8::HandleScope scope;
9758 LocalContext outer;
9759 { v8::Persistent<v8::Context> inner = v8::Context::New();
9760 inner->Enter();
9761 inner.Dispose();
9762 inner.Clear();
9763 inner->Exit();
9764 }
9765}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009766
9767
9768// Regression test for issue 54, object templates with internal fields
9769// but no accessors or interceptors did not get their internal field
9770// count set on instances.
9771THREADED_TEST(Regress54) {
9772 v8::HandleScope outer;
9773 LocalContext context;
9774 static v8::Persistent<v8::ObjectTemplate> templ;
9775 if (templ.IsEmpty()) {
9776 v8::HandleScope inner;
9777 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
9778 local->SetInternalFieldCount(1);
9779 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
9780 }
9781 v8::Handle<v8::Object> result = templ->NewInstance();
9782 CHECK_EQ(1, result->InternalFieldCount());
9783}
9784
9785
9786// If part of the threaded tests, this test makes ThreadingTest fail
9787// on mac.
9788TEST(CatchStackOverflow) {
9789 v8::HandleScope scope;
9790 LocalContext context;
9791 v8::TryCatch try_catch;
9792 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
9793 "function f() {"
9794 " return f();"
9795 "}"
9796 ""
9797 "f();"));
9798 v8::Handle<v8::Value> result = script->Run();
9799 CHECK(result.IsEmpty());
9800}
9801
9802
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009803static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
9804 const char* resource_name,
9805 int line_offset) {
9806 v8::HandleScope scope;
9807 v8::TryCatch try_catch;
9808 v8::Handle<v8::Value> result = script->Run();
9809 CHECK(result.IsEmpty());
9810 CHECK(try_catch.HasCaught());
9811 v8::Handle<v8::Message> message = try_catch.Message();
9812 CHECK(!message.IsEmpty());
9813 CHECK_EQ(10 + line_offset, message->GetLineNumber());
9814 CHECK_EQ(91, message->GetStartPosition());
9815 CHECK_EQ(92, message->GetEndPosition());
9816 CHECK_EQ(2, message->GetStartColumn());
9817 CHECK_EQ(3, message->GetEndColumn());
9818 v8::String::AsciiValue line(message->GetSourceLine());
9819 CHECK_EQ(" throw 'nirk';", *line);
9820 v8::String::AsciiValue name(message->GetScriptResourceName());
9821 CHECK_EQ(resource_name, *name);
9822}
9823
9824
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009825THREADED_TEST(TryCatchSourceInfo) {
9826 v8::HandleScope scope;
9827 LocalContext context;
9828 v8::Handle<v8::String> source = v8::String::New(
9829 "function Foo() {\n"
9830 " return Bar();\n"
9831 "}\n"
9832 "\n"
9833 "function Bar() {\n"
9834 " return Baz();\n"
9835 "}\n"
9836 "\n"
9837 "function Baz() {\n"
9838 " throw 'nirk';\n"
9839 "}\n"
9840 "\n"
9841 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009842
9843 const char* resource_name;
9844 v8::Handle<v8::Script> script;
9845 resource_name = "test.js";
9846 script = v8::Script::Compile(source, v8::String::New(resource_name));
9847 CheckTryCatchSourceInfo(script, resource_name, 0);
9848
9849 resource_name = "test1.js";
9850 v8::ScriptOrigin origin1(v8::String::New(resource_name));
9851 script = v8::Script::Compile(source, &origin1);
9852 CheckTryCatchSourceInfo(script, resource_name, 0);
9853
9854 resource_name = "test2.js";
9855 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
9856 script = v8::Script::Compile(source, &origin2);
9857 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009858}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009859
9860
9861THREADED_TEST(CompilationCache) {
9862 v8::HandleScope scope;
9863 LocalContext context;
9864 v8::Handle<v8::String> source0 = v8::String::New("1234");
9865 v8::Handle<v8::String> source1 = v8::String::New("1234");
9866 v8::Handle<v8::Script> script0 =
9867 v8::Script::Compile(source0, v8::String::New("test.js"));
9868 v8::Handle<v8::Script> script1 =
9869 v8::Script::Compile(source1, v8::String::New("test.js"));
9870 v8::Handle<v8::Script> script2 =
9871 v8::Script::Compile(source0); // different origin
9872 CHECK_EQ(1234, script0->Run()->Int32Value());
9873 CHECK_EQ(1234, script1->Run()->Int32Value());
9874 CHECK_EQ(1234, script2->Run()->Int32Value());
9875}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00009876
9877
9878static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
9879 ApiTestFuzzer::Fuzz();
9880 return v8_num(42);
9881}
9882
9883
9884THREADED_TEST(CallbackFunctionName) {
9885 v8::HandleScope scope;
9886 LocalContext context;
9887 Local<ObjectTemplate> t = ObjectTemplate::New();
9888 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
9889 context->Global()->Set(v8_str("obj"), t->NewInstance());
9890 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
9891 CHECK(value->IsString());
9892 v8::String::AsciiValue name(value);
9893 CHECK_EQ("asdf", *name);
9894}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009895
9896
9897THREADED_TEST(DateAccess) {
9898 v8::HandleScope scope;
9899 LocalContext context;
9900 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
9901 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009902 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009903}
9904
9905
9906void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009907 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009908 v8::Handle<v8::Array> props = obj->GetPropertyNames();
9909 CHECK_EQ(elmc, props->Length());
9910 for (int i = 0; i < elmc; i++) {
9911 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
9912 CHECK_EQ(elmv[i], *elm);
9913 }
9914}
9915
9916
9917THREADED_TEST(PropertyEnumeration) {
9918 v8::HandleScope scope;
9919 LocalContext context;
9920 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9921 "var result = [];"
9922 "result[0] = {};"
9923 "result[1] = {a: 1, b: 2};"
9924 "result[2] = [1, 2, 3];"
9925 "var proto = {x: 1, y: 2, z: 3};"
9926 "var x = { __proto__: proto, w: 0, z: 1 };"
9927 "result[3] = x;"
9928 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009929 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009930 CHECK_EQ(4, elms->Length());
9931 int elmc0 = 0;
9932 const char** elmv0 = NULL;
9933 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9934 int elmc1 = 2;
9935 const char* elmv1[] = {"a", "b"};
9936 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
9937 int elmc2 = 3;
9938 const char* elmv2[] = {"0", "1", "2"};
9939 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
9940 int elmc3 = 4;
9941 const char* elmv3[] = {"w", "z", "x", "y"};
9942 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
9943}
ager@chromium.org870a0b62008-11-04 11:43:05 +00009944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945THREADED_TEST(PropertyEnumeration2) {
9946 v8::HandleScope scope;
9947 LocalContext context;
9948 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
9949 "var result = [];"
9950 "result[0] = {};"
9951 "result[1] = {a: 1, b: 2};"
9952 "result[2] = [1, 2, 3];"
9953 "var proto = {x: 1, y: 2, z: 3};"
9954 "var x = { __proto__: proto, w: 0, z: 1 };"
9955 "result[3] = x;"
9956 "result;"))->Run();
9957 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
9958 CHECK_EQ(4, elms->Length());
9959 int elmc0 = 0;
9960 const char** elmv0 = NULL;
9961 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
9962
9963 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
9964 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
9965 CHECK_EQ(0, props->Length());
9966 for (uint32_t i = 0; i < props->Length(); i++) {
9967 printf("p[%d]\n", i);
9968 }
9969}
ager@chromium.org870a0b62008-11-04 11:43:05 +00009970
ager@chromium.org870a0b62008-11-04 11:43:05 +00009971static bool NamedSetAccessBlocker(Local<v8::Object> obj,
9972 Local<Value> name,
9973 v8::AccessType type,
9974 Local<Value> data) {
9975 return type != v8::ACCESS_SET;
9976}
9977
9978
9979static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
9980 uint32_t key,
9981 v8::AccessType type,
9982 Local<Value> data) {
9983 return type != v8::ACCESS_SET;
9984}
9985
9986
9987THREADED_TEST(DisableAccessChecksWhileConfiguring) {
9988 v8::HandleScope scope;
9989 LocalContext context;
9990 Local<ObjectTemplate> templ = ObjectTemplate::New();
9991 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
9992 IndexedSetAccessBlocker);
9993 templ->Set(v8_str("x"), v8::True());
9994 Local<v8::Object> instance = templ->NewInstance();
9995 context->Global()->Set(v8_str("obj"), instance);
9996 Local<Value> value = CompileRun("obj.x");
9997 CHECK(value->BooleanValue());
9998}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009999
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010000
ager@chromium.org32912102009-01-16 10:38:43 +000010001static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10002 Local<Value> name,
10003 v8::AccessType type,
10004 Local<Value> data) {
10005 return false;
10006}
10007
10008
10009static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10010 uint32_t key,
10011 v8::AccessType type,
10012 Local<Value> data) {
10013 return false;
10014}
10015
10016
10017
10018THREADED_TEST(AccessChecksReenabledCorrectly) {
10019 v8::HandleScope scope;
10020 LocalContext context;
10021 Local<ObjectTemplate> templ = ObjectTemplate::New();
10022 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10023 IndexedGetAccessBlocker);
10024 templ->Set(v8_str("a"), v8_str("a"));
10025 // Add more than 8 (see kMaxFastProperties) properties
10026 // so that the constructor will force copying map.
10027 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010028 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010029 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010030 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010031 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010032 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010033 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010034 buf[2] = k;
10035 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010036 templ->Set(v8_str(buf), v8::Number::New(k));
10037 }
10038 }
10039 }
10040
10041 Local<v8::Object> instance_1 = templ->NewInstance();
10042 context->Global()->Set(v8_str("obj_1"), instance_1);
10043
10044 Local<Value> value_1 = CompileRun("obj_1.a");
10045 CHECK(value_1->IsUndefined());
10046
10047 Local<v8::Object> instance_2 = templ->NewInstance();
10048 context->Global()->Set(v8_str("obj_2"), instance_2);
10049
10050 Local<Value> value_2 = CompileRun("obj_2.a");
10051 CHECK(value_2->IsUndefined());
10052}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010053
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010054
ager@chromium.org8bb60582008-12-11 12:02:20 +000010055// This tests that access check information remains on the global
10056// object template when creating contexts.
10057THREADED_TEST(AccessControlRepeatedContextCreation) {
10058 v8::HandleScope handle_scope;
10059 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10060 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10061 IndexedSetAccessBlocker);
10062 i::Handle<i::ObjectTemplateInfo> internal_template =
10063 v8::Utils::OpenHandle(*global_template);
10064 CHECK(!internal_template->constructor()->IsUndefined());
10065 i::Handle<i::FunctionTemplateInfo> constructor(
10066 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10067 CHECK(!constructor->access_check_info()->IsUndefined());
10068 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10069 CHECK(!constructor->access_check_info()->IsUndefined());
10070}
10071
10072
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010073THREADED_TEST(TurnOnAccessCheck) {
10074 v8::HandleScope handle_scope;
10075
10076 // Create an environment with access check to the global object disabled by
10077 // default.
10078 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10079 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10080 IndexedGetAccessBlocker,
10081 v8::Handle<v8::Value>(),
10082 false);
10083 v8::Persistent<Context> context = Context::New(NULL, global_template);
10084 Context::Scope context_scope(context);
10085
10086 // Set up a property and a number of functions.
10087 context->Global()->Set(v8_str("a"), v8_num(1));
10088 CompileRun("function f1() {return a;}"
10089 "function f2() {return a;}"
10090 "function g1() {return h();}"
10091 "function g2() {return h();}"
10092 "function h() {return 1;}");
10093 Local<Function> f1 =
10094 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10095 Local<Function> f2 =
10096 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10097 Local<Function> g1 =
10098 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10099 Local<Function> g2 =
10100 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10101 Local<Function> h =
10102 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10103
10104 // Get the global object.
10105 v8::Handle<v8::Object> global = context->Global();
10106
10107 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10108 // uses the runtime system to retreive property a whereas f2 uses global load
10109 // inline cache.
10110 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10111 for (int i = 0; i < 4; i++) {
10112 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10113 }
10114
10115 // Same for g1 and g2.
10116 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10117 for (int i = 0; i < 4; i++) {
10118 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10119 }
10120
10121 // Detach the global and turn on access check.
10122 context->DetachGlobal();
10123 context->Global()->TurnOnAccessCheck();
10124
10125 // Failing access check to property get results in undefined.
10126 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10127 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10128
10129 // Failing access check to function call results in exception.
10130 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10131 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10132
10133 // No failing access check when just returning a constant.
10134 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10135}
10136
10137
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010138v8::Handle<v8::String> a;
10139v8::Handle<v8::String> h;
10140
10141static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10142 Local<Value> name,
10143 v8::AccessType type,
10144 Local<Value> data) {
10145 return !(name->Equals(a) || name->Equals(h));
10146}
10147
10148
10149THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10150 v8::HandleScope handle_scope;
10151
10152 // Create an environment with access check to the global object disabled by
10153 // default. When the registered access checker will block access to properties
10154 // a and h
10155 a = v8_str("a");
10156 h = v8_str("h");
10157 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10158 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10159 IndexedGetAccessBlocker,
10160 v8::Handle<v8::Value>(),
10161 false);
10162 v8::Persistent<Context> context = Context::New(NULL, global_template);
10163 Context::Scope context_scope(context);
10164
10165 // Set up a property and a number of functions.
10166 context->Global()->Set(v8_str("a"), v8_num(1));
10167 static const char* source = "function f1() {return a;}"
10168 "function f2() {return a;}"
10169 "function g1() {return h();}"
10170 "function g2() {return h();}"
10171 "function h() {return 1;}";
10172
10173 CompileRun(source);
10174 Local<Function> f1;
10175 Local<Function> f2;
10176 Local<Function> g1;
10177 Local<Function> g2;
10178 Local<Function> h;
10179 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10180 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10181 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10182 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10183 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10184
10185 // Get the global object.
10186 v8::Handle<v8::Object> global = context->Global();
10187
10188 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10189 // uses the runtime system to retreive property a whereas f2 uses global load
10190 // inline cache.
10191 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10192 for (int i = 0; i < 4; i++) {
10193 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10194 }
10195
10196 // Same for g1 and g2.
10197 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10198 for (int i = 0; i < 4; i++) {
10199 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10200 }
10201
10202 // Detach the global and turn on access check now blocking access to property
10203 // a and function h.
10204 context->DetachGlobal();
10205 context->Global()->TurnOnAccessCheck();
10206
10207 // Failing access check to property get results in undefined.
10208 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10209 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10210
10211 // Failing access check to function call results in exception.
10212 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10213 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10214
10215 // No failing access check when just returning a constant.
10216 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10217
10218 // Now compile the source again. And get the newly compiled functions, except
10219 // for h for which access is blocked.
10220 CompileRun(source);
10221 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10222 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10223 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10224 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10225 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10226
10227 // Failing access check to property get results in undefined.
10228 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10229 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10230
10231 // Failing access check to function call results in exception.
10232 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10233 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10234}
10235
10236
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010237// This test verifies that pre-compilation (aka preparsing) can be called
10238// without initializing the whole VM. Thus we cannot run this test in a
10239// multi-threaded setup.
10240TEST(PreCompile) {
10241 // TODO(155): This test would break without the initialization of V8. This is
10242 // a workaround for now to make this test not fail.
10243 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010244 const char* script = "function foo(a) { return a+1; }";
10245 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010246 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010247 CHECK_NE(sd->Length(), 0);
10248 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010249 CHECK(!sd->HasError());
10250 delete sd;
10251}
10252
10253
10254TEST(PreCompileWithError) {
10255 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010256 const char* script = "function foo(a) { return 1 * * 2; }";
10257 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010258 v8::ScriptData::PreCompile(script, i::StrLength(script));
10259 CHECK(sd->HasError());
10260 delete sd;
10261}
10262
10263
10264TEST(Regress31661) {
10265 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010266 const char* script = " The Definintive Guide";
10267 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010268 v8::ScriptData::PreCompile(script, i::StrLength(script));
10269 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010270 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010271}
10272
10273
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010274// Tests that ScriptData can be serialized and deserialized.
10275TEST(PreCompileSerialization) {
10276 v8::V8::Initialize();
10277 const char* script = "function foo(a) { return a+1; }";
10278 v8::ScriptData* sd =
10279 v8::ScriptData::PreCompile(script, i::StrLength(script));
10280
10281 // Serialize.
10282 int serialized_data_length = sd->Length();
10283 char* serialized_data = i::NewArray<char>(serialized_data_length);
10284 memcpy(serialized_data, sd->Data(), serialized_data_length);
10285
10286 // Deserialize.
10287 v8::ScriptData* deserialized_sd =
10288 v8::ScriptData::New(serialized_data, serialized_data_length);
10289
10290 // Verify that the original is the same as the deserialized.
10291 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10292 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10293 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10294
10295 delete sd;
10296 delete deserialized_sd;
10297}
10298
10299
10300// Attempts to deserialize bad data.
10301TEST(PreCompileDeserializationError) {
10302 v8::V8::Initialize();
10303 const char* data = "DONT CARE";
10304 int invalid_size = 3;
10305 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10306
10307 CHECK_EQ(0, sd->Length());
10308
10309 delete sd;
10310}
10311
10312
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010313// Attempts to deserialize bad data.
10314TEST(PreCompileInvalidPreparseDataError) {
10315 v8::V8::Initialize();
10316 v8::HandleScope scope;
10317 LocalContext context;
10318
10319 const char* script = "function foo(){ return 5;}\n"
10320 "function bar(){ return 6 + 7;} foo();";
10321 v8::ScriptData* sd =
10322 v8::ScriptData::PreCompile(script, i::StrLength(script));
10323 CHECK(!sd->HasError());
10324 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010325 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000010326 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010327 const int kFunctionEntryStartOffset = 0;
10328 const int kFunctionEntryEndOffset = 1;
10329 unsigned* sd_data =
10330 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010331
10332 // Overwrite function bar's end position with 0.
10333 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10334 v8::TryCatch try_catch;
10335
10336 Local<String> source = String::New(script);
10337 Local<Script> compiled_script = Script::New(source, NULL, sd);
10338 CHECK(try_catch.HasCaught());
10339 String::AsciiValue exception_value(try_catch.Message()->Get());
10340 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10341 *exception_value);
10342
10343 try_catch.Reset();
10344 // Overwrite function bar's start position with 200. The function entry
10345 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000010346 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10347 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010348 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10349 200;
10350 compiled_script = Script::New(source, NULL, sd);
10351 CHECK(try_catch.HasCaught());
10352 String::AsciiValue second_exception_value(try_catch.Message()->Get());
10353 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10354 *second_exception_value);
10355
10356 delete sd;
10357}
10358
10359
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010360// Verifies that the Handle<String> and const char* versions of the API produce
10361// the same results (at least for one trivial case).
10362TEST(PreCompileAPIVariationsAreSame) {
10363 v8::V8::Initialize();
10364 v8::HandleScope scope;
10365
10366 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010367
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010368 v8::ScriptData* sd_from_cstring =
10369 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10370
10371 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010372 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010373 v8::String::NewExternal(resource));
10374
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010375 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10376 v8::String::New(cstring));
10377
10378 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010379 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010380 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010381 sd_from_cstring->Length()));
10382
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010383 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10384 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10385 sd_from_string->Data(),
10386 sd_from_cstring->Length()));
10387
10388
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010389 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010390 delete sd_from_external_string;
10391 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010392}
10393
10394
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010395// This tests that we do not allow dictionary load/call inline caches
10396// to use functions that have not yet been compiled. The potential
10397// problem of loading a function that has not yet been compiled can
10398// arise because we share code between contexts via the compilation
10399// cache.
10400THREADED_TEST(DictionaryICLoadedFunction) {
10401 v8::HandleScope scope;
10402 // Test LoadIC.
10403 for (int i = 0; i < 2; i++) {
10404 LocalContext context;
10405 context->Global()->Set(v8_str("tmp"), v8::True());
10406 context->Global()->Delete(v8_str("tmp"));
10407 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10408 }
10409 // Test CallIC.
10410 for (int i = 0; i < 2; i++) {
10411 LocalContext context;
10412 context->Global()->Set(v8_str("tmp"), v8::True());
10413 context->Global()->Delete(v8_str("tmp"));
10414 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10415 }
10416}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010417
10418
10419// Test that cross-context new calls use the context of the callee to
10420// create the new JavaScript object.
10421THREADED_TEST(CrossContextNew) {
10422 v8::HandleScope scope;
10423 v8::Persistent<Context> context0 = Context::New();
10424 v8::Persistent<Context> context1 = Context::New();
10425
10426 // Allow cross-domain access.
10427 Local<String> token = v8_str("<security token>");
10428 context0->SetSecurityToken(token);
10429 context1->SetSecurityToken(token);
10430
10431 // Set an 'x' property on the Object prototype and define a
10432 // constructor function in context0.
10433 context0->Enter();
10434 CompileRun("Object.prototype.x = 42; function C() {};");
10435 context0->Exit();
10436
10437 // Call the constructor function from context0 and check that the
10438 // result has the 'x' property.
10439 context1->Enter();
10440 context1->Global()->Set(v8_str("other"), context0->Global());
10441 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10442 CHECK(value->IsInt32());
10443 CHECK_EQ(42, value->Int32Value());
10444 context1->Exit();
10445
10446 // Dispose the contexts to allow them to be garbage collected.
10447 context0.Dispose();
10448 context1.Dispose();
10449}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010450
10451
10452class RegExpInterruptTest {
10453 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010454 RegExpInterruptTest() : block_(NULL) {}
10455 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010456 void RunTest() {
10457 block_ = i::OS::CreateSemaphore(0);
10458 gc_count_ = 0;
10459 gc_during_regexp_ = 0;
10460 regexp_success_ = false;
10461 gc_success_ = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 GCThread gc_thread(i::Isolate::Current(), this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010463 gc_thread.Start();
10464 v8::Locker::StartPreemption(1);
10465
10466 LongRunningRegExp();
10467 {
10468 v8::Unlocker unlock;
10469 gc_thread.Join();
10470 }
10471 v8::Locker::StopPreemption();
10472 CHECK(regexp_success_);
10473 CHECK(gc_success_);
10474 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010475
ager@chromium.org381abbb2009-02-25 13:23:22 +000010476 private:
10477 // Number of garbage collections required.
10478 static const int kRequiredGCs = 5;
10479
10480 class GCThread : public i::Thread {
10481 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010482 explicit GCThread(i::Isolate* isolate, RegExpInterruptTest* test)
10483 : Thread(isolate, "GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010484 virtual void Run() {
10485 test_->CollectGarbage();
10486 }
10487 private:
10488 RegExpInterruptTest* test_;
10489 };
10490
10491 void CollectGarbage() {
10492 block_->Wait();
10493 while (gc_during_regexp_ < kRequiredGCs) {
10494 {
10495 v8::Locker lock;
10496 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010498 gc_count_++;
10499 }
10500 i::OS::Sleep(1);
10501 }
10502 gc_success_ = true;
10503 }
10504
10505 void LongRunningRegExp() {
10506 block_->Signal(); // Enable garbage collection thread on next preemption.
10507 int rounds = 0;
10508 while (gc_during_regexp_ < kRequiredGCs) {
10509 int gc_before = gc_count_;
10510 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010511 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010512 const char* c_source =
10513 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10514 ".exec('aaaaaaaaaaaaaaab') === null";
10515 Local<String> source = String::New(c_source);
10516 Local<Script> script = Script::Compile(source);
10517 Local<Value> result = script->Run();
10518 if (!result->BooleanValue()) {
10519 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10520 return;
10521 }
10522 }
10523 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010524 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010525 const char* c_source =
10526 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10527 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10528 Local<String> source = String::New(c_source);
10529 Local<Script> script = Script::Compile(source);
10530 Local<Value> result = script->Run();
10531 if (!result->BooleanValue()) {
10532 gc_during_regexp_ = kRequiredGCs;
10533 return;
10534 }
10535 }
10536 int gc_after = gc_count_;
10537 gc_during_regexp_ += gc_after - gc_before;
10538 rounds++;
10539 i::OS::Sleep(1);
10540 }
10541 regexp_success_ = true;
10542 }
10543
10544 i::Semaphore* block_;
10545 int gc_count_;
10546 int gc_during_regexp_;
10547 bool regexp_success_;
10548 bool gc_success_;
10549};
10550
10551
10552// Test that a regular expression execution can be interrupted and
10553// survive a garbage collection.
10554TEST(RegExpInterruption) {
10555 v8::Locker lock;
10556 v8::V8::Initialize();
10557 v8::HandleScope scope;
10558 Local<Context> local_env;
10559 {
10560 LocalContext env;
10561 local_env = env.local();
10562 }
10563
10564 // Local context should still be live.
10565 CHECK(!local_env.IsEmpty());
10566 local_env->Enter();
10567
10568 // Should complete without problems.
10569 RegExpInterruptTest().RunTest();
10570
10571 local_env->Exit();
10572}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010573
10574
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010575class ApplyInterruptTest {
10576 public:
10577 ApplyInterruptTest() : block_(NULL) {}
10578 ~ApplyInterruptTest() { delete block_; }
10579 void RunTest() {
10580 block_ = i::OS::CreateSemaphore(0);
10581 gc_count_ = 0;
10582 gc_during_apply_ = 0;
10583 apply_success_ = false;
10584 gc_success_ = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010585 GCThread gc_thread(i::Isolate::Current(), this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010586 gc_thread.Start();
10587 v8::Locker::StartPreemption(1);
10588
10589 LongRunningApply();
10590 {
10591 v8::Unlocker unlock;
10592 gc_thread.Join();
10593 }
10594 v8::Locker::StopPreemption();
10595 CHECK(apply_success_);
10596 CHECK(gc_success_);
10597 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010598
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010599 private:
10600 // Number of garbage collections required.
10601 static const int kRequiredGCs = 2;
10602
10603 class GCThread : public i::Thread {
10604 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 explicit GCThread(i::Isolate* isolate, ApplyInterruptTest* test)
10606 : Thread(isolate, "GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010607 virtual void Run() {
10608 test_->CollectGarbage();
10609 }
10610 private:
10611 ApplyInterruptTest* test_;
10612 };
10613
10614 void CollectGarbage() {
10615 block_->Wait();
10616 while (gc_during_apply_ < kRequiredGCs) {
10617 {
10618 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010620 gc_count_++;
10621 }
10622 i::OS::Sleep(1);
10623 }
10624 gc_success_ = true;
10625 }
10626
10627 void LongRunningApply() {
10628 block_->Signal();
10629 int rounds = 0;
10630 while (gc_during_apply_ < kRequiredGCs) {
10631 int gc_before = gc_count_;
10632 {
10633 const char* c_source =
10634 "function do_very_little(bar) {"
10635 " this.foo = bar;"
10636 "}"
10637 "for (var i = 0; i < 100000; i++) {"
10638 " do_very_little.apply(this, ['bar']);"
10639 "}";
10640 Local<String> source = String::New(c_source);
10641 Local<Script> script = Script::Compile(source);
10642 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010643 // Check that no exception was thrown.
10644 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010645 }
10646 int gc_after = gc_count_;
10647 gc_during_apply_ += gc_after - gc_before;
10648 rounds++;
10649 }
10650 apply_success_ = true;
10651 }
10652
10653 i::Semaphore* block_;
10654 int gc_count_;
10655 int gc_during_apply_;
10656 bool apply_success_;
10657 bool gc_success_;
10658};
10659
10660
10661// Test that nothing bad happens if we get a preemption just when we were
10662// about to do an apply().
10663TEST(ApplyInterruption) {
10664 v8::Locker lock;
10665 v8::V8::Initialize();
10666 v8::HandleScope scope;
10667 Local<Context> local_env;
10668 {
10669 LocalContext env;
10670 local_env = env.local();
10671 }
10672
10673 // Local context should still be live.
10674 CHECK(!local_env.IsEmpty());
10675 local_env->Enter();
10676
10677 // Should complete without problems.
10678 ApplyInterruptTest().RunTest();
10679
10680 local_env->Exit();
10681}
10682
10683
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010684// Verify that we can clone an object
10685TEST(ObjectClone) {
10686 v8::HandleScope scope;
10687 LocalContext env;
10688
10689 const char* sample =
10690 "var rv = {};" \
10691 "rv.alpha = 'hello';" \
10692 "rv.beta = 123;" \
10693 "rv;";
10694
10695 // Create an object, verify basics.
10696 Local<Value> val = CompileRun(sample);
10697 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010698 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010699 obj->Set(v8_str("gamma"), v8_str("cloneme"));
10700
10701 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
10702 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10703 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
10704
10705 // Clone it.
10706 Local<v8::Object> clone = obj->Clone();
10707 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
10708 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
10709 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
10710
10711 // Set a property on the clone, verify each object.
10712 clone->Set(v8_str("beta"), v8::Integer::New(456));
10713 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
10714 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
10715}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010716
10717
ager@chromium.org5ec48922009-05-05 07:25:34 +000010718class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
10719 public:
10720 explicit AsciiVectorResource(i::Vector<const char> vector)
10721 : data_(vector) {}
10722 virtual ~AsciiVectorResource() {}
10723 virtual size_t length() const { return data_.length(); }
10724 virtual const char* data() const { return data_.start(); }
10725 private:
10726 i::Vector<const char> data_;
10727};
10728
10729
10730class UC16VectorResource : public v8::String::ExternalStringResource {
10731 public:
10732 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
10733 : data_(vector) {}
10734 virtual ~UC16VectorResource() {}
10735 virtual size_t length() const { return data_.length(); }
10736 virtual const i::uc16* data() const { return data_.start(); }
10737 private:
10738 i::Vector<const i::uc16> data_;
10739};
10740
10741
10742static void MorphAString(i::String* string,
10743 AsciiVectorResource* ascii_resource,
10744 UC16VectorResource* uc16_resource) {
10745 CHECK(i::StringShape(string).IsExternal());
10746 if (string->IsAsciiRepresentation()) {
10747 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010749 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010751 i::ExternalTwoByteString* morphed =
10752 i::ExternalTwoByteString::cast(string);
10753 morphed->set_resource(uc16_resource);
10754 } else {
10755 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010756 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010757 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010759 i::ExternalAsciiString* morphed =
10760 i::ExternalAsciiString::cast(string);
10761 morphed->set_resource(ascii_resource);
10762 }
10763}
10764
10765
10766// Test that we can still flatten a string if the components it is built up
10767// from have been turned into 16 bit strings in the mean time.
10768THREADED_TEST(MorphCompositeStringTest) {
10769 const char* c_string = "Now is the time for all good men"
10770 " to come to the aid of the party";
10771 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
10772 {
10773 v8::HandleScope scope;
10774 LocalContext env;
10775 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010776 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010777 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010778 i::Vector<const uint16_t>(two_byte_string,
10779 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010780
10781 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010782 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010783 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010784 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000010785
10786 env->Global()->Set(v8_str("lhs"), lhs);
10787 env->Global()->Set(v8_str("rhs"), rhs);
10788
10789 CompileRun(
10790 "var cons = lhs + rhs;"
10791 "var slice = lhs.substring(1, lhs.length - 1);"
10792 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
10793
10794 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
10795 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
10796
10797 // Now do some stuff to make sure the strings are flattened, etc.
10798 CompileRun(
10799 "/[^a-z]/.test(cons);"
10800 "/[^a-z]/.test(slice);"
10801 "/[^a-z]/.test(slice_on_cons);");
10802 const char* expected_cons =
10803 "Now is the time for all good men to come to the aid of the party"
10804 "Now is the time for all good men to come to the aid of the party";
10805 const char* expected_slice =
10806 "ow is the time for all good men to come to the aid of the part";
10807 const char* expected_slice_on_cons =
10808 "ow is the time for all good men to come to the aid of the party"
10809 "Now is the time for all good men to come to the aid of the part";
10810 CHECK_EQ(String::New(expected_cons),
10811 env->Global()->Get(v8_str("cons")));
10812 CHECK_EQ(String::New(expected_slice),
10813 env->Global()->Get(v8_str("slice")));
10814 CHECK_EQ(String::New(expected_slice_on_cons),
10815 env->Global()->Get(v8_str("slice_on_cons")));
10816 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010817 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010818}
10819
10820
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010821TEST(CompileExternalTwoByteSource) {
10822 v8::HandleScope scope;
10823 LocalContext context;
10824
10825 // This is a very short list of sources, which currently is to check for a
10826 // regression caused by r2703.
10827 const char* ascii_sources[] = {
10828 "0.5",
10829 "-0.5", // This mainly testes PushBack in the Scanner.
10830 "--0.5", // This mainly testes PushBack in the Scanner.
10831 NULL
10832 };
10833
10834 // Compile the sources as external two byte strings.
10835 for (int i = 0; ascii_sources[i] != NULL; i++) {
10836 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
10837 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010838 i::Vector<const uint16_t>(two_byte_string,
10839 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010840 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
10841 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010842 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010843 }
10844}
10845
10846
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010847class RegExpStringModificationTest {
10848 public:
10849 RegExpStringModificationTest()
10850 : block_(i::OS::CreateSemaphore(0)),
10851 morphs_(0),
10852 morphs_during_regexp_(0),
10853 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
10854 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
10855 ~RegExpStringModificationTest() { delete block_; }
10856 void RunTest() {
10857 regexp_success_ = false;
10858 morph_success_ = false;
10859
10860 // Initialize the contents of two_byte_content_ to be a uc16 representation
10861 // of "aaaaaaaaaaaaaab".
10862 for (int i = 0; i < 14; i++) {
10863 two_byte_content_[i] = 'a';
10864 }
10865 two_byte_content_[14] = 'b';
10866
10867 // Create the input string for the regexp - the one we are going to change
10868 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010869 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010870
10871 // Inject the input as a global variable.
10872 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
10874 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010875 *input_name,
10876 *input_,
10877 NONE,
10878 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010880 MorphThread morph_thread(i::Isolate::Current(), this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010881 morph_thread.Start();
10882 v8::Locker::StartPreemption(1);
10883 LongRunningRegExp();
10884 {
10885 v8::Unlocker unlock;
10886 morph_thread.Join();
10887 }
10888 v8::Locker::StopPreemption();
10889 CHECK(regexp_success_);
10890 CHECK(morph_success_);
10891 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010892
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010893 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010894 // Number of string modifications required.
10895 static const int kRequiredModifications = 5;
10896 static const int kMaxModifications = 100;
10897
10898 class MorphThread : public i::Thread {
10899 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 explicit MorphThread(i::Isolate* isolate,
10901 RegExpStringModificationTest* test)
10902 : Thread(isolate, "MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010903 virtual void Run() {
10904 test_->MorphString();
10905 }
10906 private:
10907 RegExpStringModificationTest* test_;
10908 };
10909
10910 void MorphString() {
10911 block_->Wait();
10912 while (morphs_during_regexp_ < kRequiredModifications &&
10913 morphs_ < kMaxModifications) {
10914 {
10915 v8::Locker lock;
10916 // Swap string between ascii and two-byte representation.
10917 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000010918 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010919 morphs_++;
10920 }
10921 i::OS::Sleep(1);
10922 }
10923 morph_success_ = true;
10924 }
10925
10926 void LongRunningRegExp() {
10927 block_->Signal(); // Enable morphing thread on next preemption.
10928 while (morphs_during_regexp_ < kRequiredModifications &&
10929 morphs_ < kMaxModifications) {
10930 int morphs_before = morphs_;
10931 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000010932 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010933 // Match 15-30 "a"'s against 14 and a "b".
10934 const char* c_source =
10935 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10936 ".exec(input) === null";
10937 Local<String> source = String::New(c_source);
10938 Local<Script> script = Script::Compile(source);
10939 Local<Value> result = script->Run();
10940 CHECK(result->IsTrue());
10941 }
10942 int morphs_after = morphs_;
10943 morphs_during_regexp_ += morphs_after - morphs_before;
10944 }
10945 regexp_success_ = true;
10946 }
10947
10948 i::uc16 two_byte_content_[15];
10949 i::Semaphore* block_;
10950 int morphs_;
10951 int morphs_during_regexp_;
10952 bool regexp_success_;
10953 bool morph_success_;
10954 i::Handle<i::String> input_;
10955 AsciiVectorResource ascii_resource_;
10956 UC16VectorResource uc16_resource_;
10957};
10958
10959
10960// Test that a regular expression execution can be interrupted and
10961// the string changed without failing.
10962TEST(RegExpStringModification) {
10963 v8::Locker lock;
10964 v8::V8::Initialize();
10965 v8::HandleScope scope;
10966 Local<Context> local_env;
10967 {
10968 LocalContext env;
10969 local_env = env.local();
10970 }
10971
10972 // Local context should still be live.
10973 CHECK(!local_env.IsEmpty());
10974 local_env->Enter();
10975
10976 // Should complete without problems.
10977 RegExpStringModificationTest().RunTest();
10978
10979 local_env->Exit();
10980}
10981
10982
10983// Test that we can set a property on the global object even if there
10984// is a read-only property in the prototype chain.
10985TEST(ReadOnlyPropertyInGlobalProto) {
10986 v8::HandleScope scope;
10987 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
10988 LocalContext context(0, templ);
10989 v8::Handle<v8::Object> global = context->Global();
10990 v8::Handle<v8::Object> global_proto =
10991 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
10992 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
10993 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
10994 // Check without 'eval' or 'with'.
10995 v8::Handle<v8::Value> res =
10996 CompileRun("function f() { x = 42; return x; }; f()");
10997 // Check with 'eval'.
10998 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
10999 CHECK_EQ(v8::Integer::New(42), res);
11000 // Check with 'with'.
11001 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11002 CHECK_EQ(v8::Integer::New(42), res);
11003}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011004
11005static int force_set_set_count = 0;
11006static int force_set_get_count = 0;
11007bool pass_on_get = false;
11008
11009static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11010 const v8::AccessorInfo& info) {
11011 force_set_get_count++;
11012 if (pass_on_get) {
11013 return v8::Handle<v8::Value>();
11014 } else {
11015 return v8::Int32::New(3);
11016 }
11017}
11018
11019static void ForceSetSetter(v8::Local<v8::String> name,
11020 v8::Local<v8::Value> value,
11021 const v8::AccessorInfo& info) {
11022 force_set_set_count++;
11023}
11024
11025static v8::Handle<v8::Value> ForceSetInterceptSetter(
11026 v8::Local<v8::String> name,
11027 v8::Local<v8::Value> value,
11028 const v8::AccessorInfo& info) {
11029 force_set_set_count++;
11030 return v8::Undefined();
11031}
11032
11033TEST(ForceSet) {
11034 force_set_get_count = 0;
11035 force_set_set_count = 0;
11036 pass_on_get = false;
11037
11038 v8::HandleScope scope;
11039 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11040 v8::Handle<v8::String> access_property = v8::String::New("a");
11041 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11042 LocalContext context(NULL, templ);
11043 v8::Handle<v8::Object> global = context->Global();
11044
11045 // Ordinary properties
11046 v8::Handle<v8::String> simple_property = v8::String::New("p");
11047 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11048 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11049 // This should fail because the property is read-only
11050 global->Set(simple_property, v8::Int32::New(5));
11051 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11052 // This should succeed even though the property is read-only
11053 global->ForceSet(simple_property, v8::Int32::New(6));
11054 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11055
11056 // Accessors
11057 CHECK_EQ(0, force_set_set_count);
11058 CHECK_EQ(0, force_set_get_count);
11059 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11060 // CHECK_EQ the property shouldn't override it, just call the setter
11061 // which in this case does nothing.
11062 global->Set(access_property, v8::Int32::New(7));
11063 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11064 CHECK_EQ(1, force_set_set_count);
11065 CHECK_EQ(2, force_set_get_count);
11066 // Forcing the property to be set should override the accessor without
11067 // calling it
11068 global->ForceSet(access_property, v8::Int32::New(8));
11069 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11070 CHECK_EQ(1, force_set_set_count);
11071 CHECK_EQ(2, force_set_get_count);
11072}
11073
11074TEST(ForceSetWithInterceptor) {
11075 force_set_get_count = 0;
11076 force_set_set_count = 0;
11077 pass_on_get = false;
11078
11079 v8::HandleScope scope;
11080 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11081 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11082 LocalContext context(NULL, templ);
11083 v8::Handle<v8::Object> global = context->Global();
11084
11085 v8::Handle<v8::String> some_property = v8::String::New("a");
11086 CHECK_EQ(0, force_set_set_count);
11087 CHECK_EQ(0, force_set_get_count);
11088 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11089 // Setting the property shouldn't override it, just call the setter
11090 // which in this case does nothing.
11091 global->Set(some_property, v8::Int32::New(7));
11092 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11093 CHECK_EQ(1, force_set_set_count);
11094 CHECK_EQ(2, force_set_get_count);
11095 // Getting the property when the interceptor returns an empty handle
11096 // should yield undefined, since the property isn't present on the
11097 // object itself yet.
11098 pass_on_get = true;
11099 CHECK(global->Get(some_property)->IsUndefined());
11100 CHECK_EQ(1, force_set_set_count);
11101 CHECK_EQ(3, force_set_get_count);
11102 // Forcing the property to be set should cause the value to be
11103 // set locally without calling the interceptor.
11104 global->ForceSet(some_property, v8::Int32::New(8));
11105 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11106 CHECK_EQ(1, force_set_set_count);
11107 CHECK_EQ(4, force_set_get_count);
11108 // Reenabling the interceptor should cause it to take precedence over
11109 // the property
11110 pass_on_get = false;
11111 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11112 CHECK_EQ(1, force_set_set_count);
11113 CHECK_EQ(5, force_set_get_count);
11114 // The interceptor should also work for other properties
11115 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11116 CHECK_EQ(1, force_set_set_count);
11117 CHECK_EQ(6, force_set_get_count);
11118}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011119
11120
ager@chromium.orge2902be2009-06-08 12:21:35 +000011121THREADED_TEST(ForceDelete) {
11122 v8::HandleScope scope;
11123 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11124 LocalContext context(NULL, templ);
11125 v8::Handle<v8::Object> global = context->Global();
11126
11127 // Ordinary properties
11128 v8::Handle<v8::String> simple_property = v8::String::New("p");
11129 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11130 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11131 // This should fail because the property is dont-delete.
11132 CHECK(!global->Delete(simple_property));
11133 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11134 // This should succeed even though the property is dont-delete.
11135 CHECK(global->ForceDelete(simple_property));
11136 CHECK(global->Get(simple_property)->IsUndefined());
11137}
11138
11139
11140static int force_delete_interceptor_count = 0;
11141static bool pass_on_delete = false;
11142
11143
11144static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11145 v8::Local<v8::String> name,
11146 const v8::AccessorInfo& info) {
11147 force_delete_interceptor_count++;
11148 if (pass_on_delete) {
11149 return v8::Handle<v8::Boolean>();
11150 } else {
11151 return v8::True();
11152 }
11153}
11154
11155
11156THREADED_TEST(ForceDeleteWithInterceptor) {
11157 force_delete_interceptor_count = 0;
11158 pass_on_delete = false;
11159
11160 v8::HandleScope scope;
11161 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11162 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11163 LocalContext context(NULL, templ);
11164 v8::Handle<v8::Object> global = context->Global();
11165
11166 v8::Handle<v8::String> some_property = v8::String::New("a");
11167 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11168
11169 // Deleting a property should get intercepted and nothing should
11170 // happen.
11171 CHECK_EQ(0, force_delete_interceptor_count);
11172 CHECK(global->Delete(some_property));
11173 CHECK_EQ(1, force_delete_interceptor_count);
11174 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11175 // Deleting the property when the interceptor returns an empty
11176 // handle should not delete the property since it is DontDelete.
11177 pass_on_delete = true;
11178 CHECK(!global->Delete(some_property));
11179 CHECK_EQ(2, force_delete_interceptor_count);
11180 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11181 // Forcing the property to be deleted should delete the value
11182 // without calling the interceptor.
11183 CHECK(global->ForceDelete(some_property));
11184 CHECK(global->Get(some_property)->IsUndefined());
11185 CHECK_EQ(2, force_delete_interceptor_count);
11186}
11187
11188
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011189// Make sure that forcing a delete invalidates any IC stubs, so we
11190// don't read the hole value.
11191THREADED_TEST(ForceDeleteIC) {
11192 v8::HandleScope scope;
11193 LocalContext context;
11194 // Create a DontDelete variable on the global object.
11195 CompileRun("this.__proto__ = { foo: 'horse' };"
11196 "var foo = 'fish';"
11197 "function f() { return foo.length; }");
11198 // Initialize the IC for foo in f.
11199 CompileRun("for (var i = 0; i < 4; i++) f();");
11200 // Make sure the value of foo is correct before the deletion.
11201 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11202 // Force the deletion of foo.
11203 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11204 // Make sure the value for foo is read from the prototype, and that
11205 // we don't get in trouble with reading the deleted cell value
11206 // sentinel.
11207 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11208}
11209
11210
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011211v8::Persistent<Context> calling_context0;
11212v8::Persistent<Context> calling_context1;
11213v8::Persistent<Context> calling_context2;
11214
11215
11216// Check that the call to the callback is initiated in
11217// calling_context2, the directly calling context is calling_context1
11218// and the callback itself is in calling_context0.
11219static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11220 ApiTestFuzzer::Fuzz();
11221 CHECK(Context::GetCurrent() == calling_context0);
11222 CHECK(Context::GetCalling() == calling_context1);
11223 CHECK(Context::GetEntered() == calling_context2);
11224 return v8::Integer::New(42);
11225}
11226
11227
11228THREADED_TEST(GetCallingContext) {
11229 v8::HandleScope scope;
11230
11231 calling_context0 = Context::New();
11232 calling_context1 = Context::New();
11233 calling_context2 = Context::New();
11234
11235 // Allow cross-domain access.
11236 Local<String> token = v8_str("<security token>");
11237 calling_context0->SetSecurityToken(token);
11238 calling_context1->SetSecurityToken(token);
11239 calling_context2->SetSecurityToken(token);
11240
11241 // Create an object with a C++ callback in context0.
11242 calling_context0->Enter();
11243 Local<v8::FunctionTemplate> callback_templ =
11244 v8::FunctionTemplate::New(GetCallingContextCallback);
11245 calling_context0->Global()->Set(v8_str("callback"),
11246 callback_templ->GetFunction());
11247 calling_context0->Exit();
11248
11249 // Expose context0 in context1 and setup a function that calls the
11250 // callback function.
11251 calling_context1->Enter();
11252 calling_context1->Global()->Set(v8_str("context0"),
11253 calling_context0->Global());
11254 CompileRun("function f() { context0.callback() }");
11255 calling_context1->Exit();
11256
11257 // Expose context1 in context2 and call the callback function in
11258 // context0 indirectly through f in context1.
11259 calling_context2->Enter();
11260 calling_context2->Global()->Set(v8_str("context1"),
11261 calling_context1->Global());
11262 CompileRun("context1.f()");
11263 calling_context2->Exit();
11264
11265 // Dispose the contexts to allow them to be garbage collected.
11266 calling_context0.Dispose();
11267 calling_context1.Dispose();
11268 calling_context2.Dispose();
11269 calling_context0.Clear();
11270 calling_context1.Clear();
11271 calling_context2.Clear();
11272}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011273
11274
11275// Check that a variable declaration with no explicit initialization
11276// value does not shadow an existing property in the prototype chain.
11277//
11278// This is consistent with Firefox and Safari.
11279//
11280// See http://crbug.com/12548.
11281THREADED_TEST(InitGlobalVarInProtoChain) {
11282 v8::HandleScope scope;
11283 LocalContext context;
11284 // Introduce a variable in the prototype chain.
11285 CompileRun("__proto__.x = 42");
11286 v8::Handle<v8::Value> result = CompileRun("var x; x");
11287 CHECK(!result->IsUndefined());
11288 CHECK_EQ(42, result->Int32Value());
11289}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011290
11291
11292// Regression test for issue 398.
11293// If a function is added to an object, creating a constant function
11294// field, and the result is cloned, replacing the constant function on the
11295// original should not affect the clone.
11296// See http://code.google.com/p/v8/issues/detail?id=398
11297THREADED_TEST(ReplaceConstantFunction) {
11298 v8::HandleScope scope;
11299 LocalContext context;
11300 v8::Handle<v8::Object> obj = v8::Object::New();
11301 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11302 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11303 obj->Set(foo_string, func_templ->GetFunction());
11304 v8::Handle<v8::Object> obj_clone = obj->Clone();
11305 obj_clone->Set(foo_string, v8::String::New("Hello"));
11306 CHECK(!obj->Get(foo_string)->IsUndefined());
11307}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000011308
11309
11310// Regression test for http://crbug.com/16276.
11311THREADED_TEST(Regress16276) {
11312 v8::HandleScope scope;
11313 LocalContext context;
11314 // Force the IC in f to be a dictionary load IC.
11315 CompileRun("function f(obj) { return obj.x; }\n"
11316 "var obj = { x: { foo: 42 }, y: 87 };\n"
11317 "var x = obj.x;\n"
11318 "delete obj.y;\n"
11319 "for (var i = 0; i < 5; i++) f(obj);");
11320 // Detach the global object to make 'this' refer directly to the
11321 // global object (not the proxy), and make sure that the dictionary
11322 // load IC doesn't mess up loading directly from the global object.
11323 context->DetachGlobal();
11324 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11325}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011326
11327
11328THREADED_TEST(PixelArray) {
11329 v8::HandleScope scope;
11330 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011331 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011332 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011333 i::Handle<i::ExternalPixelArray> pixels =
11334 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011336 v8::kExternalPixelArray,
11337 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011338 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011339 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011340 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011341 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011342 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011343 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011344 CHECK_EQ(i % 256, pixels->get(i));
11345 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011346 }
11347
11348 v8::Handle<v8::Object> obj = v8::Object::New();
11349 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11350 // Set the elements to be the pixels.
11351 // jsobj->set_elements(*pixels);
11352 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011353 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011354 obj->Set(v8_str("field"), v8::Int32::New(1503));
11355 context->Global()->Set(v8_str("pixels"), obj);
11356 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11357 CHECK_EQ(1503, result->Int32Value());
11358 result = CompileRun("pixels[1]");
11359 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011360
11361 result = CompileRun("var sum = 0;"
11362 "for (var i = 0; i < 8; i++) {"
11363 " sum += pixels[i] = pixels[i] = -i;"
11364 "}"
11365 "sum;");
11366 CHECK_EQ(-28, result->Int32Value());
11367
11368 result = CompileRun("var sum = 0;"
11369 "for (var i = 0; i < 8; i++) {"
11370 " sum += pixels[i] = pixels[i] = 0;"
11371 "}"
11372 "sum;");
11373 CHECK_EQ(0, result->Int32Value());
11374
11375 result = CompileRun("var sum = 0;"
11376 "for (var i = 0; i < 8; i++) {"
11377 " sum += pixels[i] = pixels[i] = 255;"
11378 "}"
11379 "sum;");
11380 CHECK_EQ(8 * 255, result->Int32Value());
11381
11382 result = CompileRun("var sum = 0;"
11383 "for (var i = 0; i < 8; i++) {"
11384 " sum += pixels[i] = pixels[i] = 256 + i;"
11385 "}"
11386 "sum;");
11387 CHECK_EQ(2076, result->Int32Value());
11388
11389 result = CompileRun("var sum = 0;"
11390 "for (var i = 0; i < 8; i++) {"
11391 " sum += pixels[i] = pixels[i] = i;"
11392 "}"
11393 "sum;");
11394 CHECK_EQ(28, result->Int32Value());
11395
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011396 result = CompileRun("var sum = 0;"
11397 "for (var i = 0; i < 8; i++) {"
11398 " sum += pixels[i];"
11399 "}"
11400 "sum;");
11401 CHECK_EQ(28, result->Int32Value());
11402
11403 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011404 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011405 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011406 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011407 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011408 CHECK_EQ(255,
11409 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011410 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011411 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011412 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011413
11414 result = CompileRun("for (var i = 0; i < 8; i++) {"
11415 " pixels[i] = (i * 65) - 109;"
11416 "}"
11417 "pixels[1] + pixels[6];");
11418 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011419 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11420 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11421 CHECK_EQ(21,
11422 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11423 CHECK_EQ(86,
11424 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11425 CHECK_EQ(151,
11426 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11427 CHECK_EQ(216,
11428 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11429 CHECK_EQ(255,
11430 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11431 CHECK_EQ(255,
11432 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011433 result = CompileRun("var sum = 0;"
11434 "for (var i = 0; i < 8; i++) {"
11435 " sum += pixels[i];"
11436 "}"
11437 "sum;");
11438 CHECK_EQ(984, result->Int32Value());
11439
11440 result = CompileRun("for (var i = 0; i < 8; i++) {"
11441 " pixels[i] = (i * 1.1);"
11442 "}"
11443 "pixels[1] + pixels[6];");
11444 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11446 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11447 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11448 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11449 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11450 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11451 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11452 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011453
11454 result = CompileRun("for (var i = 0; i < 8; i++) {"
11455 " pixels[7] = undefined;"
11456 "}"
11457 "pixels[7];");
11458 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011459 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011460
11461 result = CompileRun("for (var i = 0; i < 8; i++) {"
11462 " pixels[6] = '2.3';"
11463 "}"
11464 "pixels[6];");
11465 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011466 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011467
11468 result = CompileRun("for (var i = 0; i < 8; i++) {"
11469 " pixels[5] = NaN;"
11470 "}"
11471 "pixels[5];");
11472 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011473 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011474
11475 result = CompileRun("for (var i = 0; i < 8; i++) {"
11476 " pixels[8] = Infinity;"
11477 "}"
11478 "pixels[8];");
11479 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011480 CHECK_EQ(255,
11481 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011482
11483 result = CompileRun("for (var i = 0; i < 8; i++) {"
11484 " pixels[9] = -Infinity;"
11485 "}"
11486 "pixels[9];");
11487 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011488 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011489
11490 result = CompileRun("pixels[3] = 33;"
11491 "delete pixels[3];"
11492 "pixels[3];");
11493 CHECK_EQ(33, result->Int32Value());
11494
11495 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11496 "pixels[2] = 12; pixels[3] = 13;"
11497 "pixels.__defineGetter__('2',"
11498 "function() { return 120; });"
11499 "pixels[2];");
11500 CHECK_EQ(12, result->Int32Value());
11501
11502 result = CompileRun("var js_array = new Array(40);"
11503 "js_array[0] = 77;"
11504 "js_array;");
11505 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11506
11507 result = CompileRun("pixels[1] = 23;"
11508 "pixels.__proto__ = [];"
11509 "js_array.__proto__ = pixels;"
11510 "js_array.concat(pixels);");
11511 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11512 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11513
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011514 result = CompileRun("pixels[1] = 23;");
11515 CHECK_EQ(23, result->Int32Value());
11516
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011517 // Test for index greater than 255. Regression test for:
11518 // http://code.google.com/p/chromium/issues/detail?id=26337.
11519 result = CompileRun("pixels[256] = 255;");
11520 CHECK_EQ(255, result->Int32Value());
11521 result = CompileRun("var i = 0;"
11522 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11523 "i");
11524 CHECK_EQ(255, result->Int32Value());
11525
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011526 // Make sure that pixel array ICs recognize when a non-pixel array
11527 // is passed to it.
11528 result = CompileRun("function pa_load(p) {"
11529 " var sum = 0;"
11530 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11531 " return sum;"
11532 "}"
11533 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11534 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11535 "just_ints = new Object();"
11536 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11537 "for (var i = 0; i < 10; ++i) {"
11538 " result = pa_load(just_ints);"
11539 "}"
11540 "result");
11541 CHECK_EQ(32640, result->Int32Value());
11542
11543 // Make sure that pixel array ICs recognize out-of-bound accesses.
11544 result = CompileRun("function pa_load(p, start) {"
11545 " var sum = 0;"
11546 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11547 " return sum;"
11548 "}"
11549 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11550 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11551 "for (var i = 0; i < 10; ++i) {"
11552 " result = pa_load(pixels,-10);"
11553 "}"
11554 "result");
11555 CHECK_EQ(0, result->Int32Value());
11556
11557 // Make sure that generic ICs properly handles a pixel array.
11558 result = CompileRun("function pa_load(p) {"
11559 " var sum = 0;"
11560 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11561 " return sum;"
11562 "}"
11563 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11564 "just_ints = new Object();"
11565 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11566 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11567 "for (var i = 0; i < 10; ++i) {"
11568 " result = pa_load(pixels);"
11569 "}"
11570 "result");
11571 CHECK_EQ(32640, result->Int32Value());
11572
11573 // Make sure that generic load ICs recognize out-of-bound accesses in
11574 // pixel arrays.
11575 result = CompileRun("function pa_load(p, start) {"
11576 " var sum = 0;"
11577 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11578 " return sum;"
11579 "}"
11580 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11581 "just_ints = new Object();"
11582 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11583 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11584 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11585 "for (var i = 0; i < 10; ++i) {"
11586 " result = pa_load(pixels,-10);"
11587 "}"
11588 "result");
11589 CHECK_EQ(0, result->Int32Value());
11590
11591 // Make sure that generic ICs properly handles other types than pixel
11592 // arrays (that the inlined fast pixel array test leaves the right information
11593 // in the right registers).
11594 result = CompileRun("function pa_load(p) {"
11595 " var sum = 0;"
11596 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11597 " return sum;"
11598 "}"
11599 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11600 "just_ints = new Object();"
11601 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11602 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11603 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11604 "sparse_array = new Object();"
11605 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11606 "sparse_array[1000000] = 3;"
11607 "for (var i = 0; i < 10; ++i) {"
11608 " result = pa_load(sparse_array);"
11609 "}"
11610 "result");
11611 CHECK_EQ(32640, result->Int32Value());
11612
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011613 // Make sure that pixel array store ICs clamp values correctly.
11614 result = CompileRun("function pa_store(p) {"
11615 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11616 "}"
11617 "pa_store(pixels);"
11618 "var sum = 0;"
11619 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11620 "sum");
11621 CHECK_EQ(48896, result->Int32Value());
11622
11623 // Make sure that pixel array stores correctly handle accesses outside
11624 // of the pixel array..
11625 result = CompileRun("function pa_store(p,start) {"
11626 " for (var j = 0; j < 256; j++) {"
11627 " p[j+start] = j * 2;"
11628 " }"
11629 "}"
11630 "pa_store(pixels,0);"
11631 "pa_store(pixels,-128);"
11632 "var sum = 0;"
11633 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11634 "sum");
11635 CHECK_EQ(65280, result->Int32Value());
11636
11637 // Make sure that the generic store stub correctly handle accesses outside
11638 // of the pixel array..
11639 result = CompileRun("function pa_store(p,start) {"
11640 " for (var j = 0; j < 256; j++) {"
11641 " p[j+start] = j * 2;"
11642 " }"
11643 "}"
11644 "pa_store(pixels,0);"
11645 "just_ints = new Object();"
11646 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11647 "pa_store(just_ints, 0);"
11648 "pa_store(pixels,-128);"
11649 "var sum = 0;"
11650 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11651 "sum");
11652 CHECK_EQ(65280, result->Int32Value());
11653
11654 // Make sure that the generic keyed store stub clamps pixel array values
11655 // correctly.
11656 result = CompileRun("function pa_store(p) {"
11657 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11658 "}"
11659 "pa_store(pixels);"
11660 "just_ints = new Object();"
11661 "pa_store(just_ints);"
11662 "pa_store(pixels);"
11663 "var sum = 0;"
11664 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11665 "sum");
11666 CHECK_EQ(48896, result->Int32Value());
11667
11668 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011669 result = CompileRun("function pa_load(p) {"
11670 " var sum = 0;"
11671 " for (var i=0; i<256; ++i) {"
11672 " sum += p[i];"
11673 " }"
11674 " return sum; "
11675 "}"
11676 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011677 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011678 " result = pa_load(pixels);"
11679 "}"
11680 "result");
11681 CHECK_EQ(32640, result->Int32Value());
11682
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011683 // Make sure that pixel array stores are optimized by crankshaft.
11684 result = CompileRun("function pa_init(p) {"
11685 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
11686 "}"
11687 "function pa_load(p) {"
11688 " var sum = 0;"
11689 " for (var i=0; i<256; ++i) {"
11690 " sum += p[i];"
11691 " }"
11692 " return sum; "
11693 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011694 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011695 " pa_init(pixels);"
11696 "}"
11697 "result = pa_load(pixels);"
11698 "result");
11699 CHECK_EQ(32640, result->Int32Value());
11700
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011701 free(pixel_data);
11702}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000011703
ager@chromium.org96c75b52009-08-26 09:13:16 +000011704
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011705THREADED_TEST(PixelArrayInfo) {
11706 v8::HandleScope scope;
11707 LocalContext context;
11708 for (int size = 0; size < 100; size += 10) {
11709 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
11710 v8::Handle<v8::Object> obj = v8::Object::New();
11711 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
11712 CHECK(obj->HasIndexedPropertiesInPixelData());
11713 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
11714 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
11715 free(pixel_data);
11716 }
11717}
11718
11719
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011720static v8::Handle<Value> NotHandledIndexedPropertyGetter(
11721 uint32_t index,
11722 const AccessorInfo& info) {
11723 ApiTestFuzzer::Fuzz();
11724 return v8::Handle<Value>();
11725}
11726
11727
11728static v8::Handle<Value> NotHandledIndexedPropertySetter(
11729 uint32_t index,
11730 Local<Value> value,
11731 const AccessorInfo& info) {
11732 ApiTestFuzzer::Fuzz();
11733 return v8::Handle<Value>();
11734}
11735
11736
11737THREADED_TEST(PixelArrayWithInterceptor) {
11738 v8::HandleScope scope;
11739 LocalContext context;
11740 const int kElementCount = 260;
11741 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011742 i::Handle<i::ExternalPixelArray> pixels =
11743 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 FACTORY->NewExternalArray(kElementCount,
11745 v8::kExternalPixelArray,
11746 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000011747 for (int i = 0; i < kElementCount; i++) {
11748 pixels->set(i, i % 256);
11749 }
11750 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11751 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
11752 NotHandledIndexedPropertySetter);
11753 v8::Handle<v8::Object> obj = templ->NewInstance();
11754 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
11755 context->Global()->Set(v8_str("pixels"), obj);
11756 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
11757 CHECK_EQ(1, result->Int32Value());
11758 result = CompileRun("var sum = 0;"
11759 "for (var i = 0; i < 8; i++) {"
11760 " sum += pixels[i] = pixels[i] = -i;"
11761 "}"
11762 "sum;");
11763 CHECK_EQ(-28, result->Int32Value());
11764 result = CompileRun("pixels.hasOwnProperty('1')");
11765 CHECK(result->BooleanValue());
11766 free(pixel_data);
11767}
11768
11769
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011770static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
11771 switch (array_type) {
11772 case v8::kExternalByteArray:
11773 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011774 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011775 return 1;
11776 break;
11777 case v8::kExternalShortArray:
11778 case v8::kExternalUnsignedShortArray:
11779 return 2;
11780 break;
11781 case v8::kExternalIntArray:
11782 case v8::kExternalUnsignedIntArray:
11783 case v8::kExternalFloatArray:
11784 return 4;
11785 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011786 case v8::kExternalDoubleArray:
11787 return 8;
11788 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011789 default:
11790 UNREACHABLE();
11791 return -1;
11792 }
11793 UNREACHABLE();
11794 return -1;
11795}
11796
11797
ager@chromium.org3811b432009-10-28 14:53:37 +000011798template <class ExternalArrayClass, class ElementType>
11799static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
11800 int64_t low,
11801 int64_t high) {
11802 v8::HandleScope scope;
11803 LocalContext context;
11804 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011805 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000011806 ElementType* array_data =
11807 static_cast<ElementType*>(malloc(kElementCount * element_size));
11808 i::Handle<ExternalArrayClass> array =
11809 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
11811 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011812 for (int i = 0; i < kElementCount; i++) {
11813 array->set(i, static_cast<ElementType>(i));
11814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011816 for (int i = 0; i < kElementCount; i++) {
11817 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
11818 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
11819 }
11820
11821 v8::Handle<v8::Object> obj = v8::Object::New();
11822 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11823 // Set the elements to be the external array.
11824 obj->SetIndexedPropertiesToExternalArrayData(array_data,
11825 array_type,
11826 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011827 CHECK_EQ(
11828 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011829 obj->Set(v8_str("field"), v8::Int32::New(1503));
11830 context->Global()->Set(v8_str("ext_array"), obj);
11831 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
11832 CHECK_EQ(1503, result->Int32Value());
11833 result = CompileRun("ext_array[1]");
11834 CHECK_EQ(1, result->Int32Value());
11835
11836 // Check pass through of assigned smis
11837 result = CompileRun("var sum = 0;"
11838 "for (var i = 0; i < 8; i++) {"
11839 " sum += ext_array[i] = ext_array[i] = -i;"
11840 "}"
11841 "sum;");
11842 CHECK_EQ(-28, result->Int32Value());
11843
11844 // Check assigned smis
11845 result = CompileRun("for (var i = 0; i < 8; i++) {"
11846 " ext_array[i] = i;"
11847 "}"
11848 "var sum = 0;"
11849 "for (var i = 0; i < 8; i++) {"
11850 " sum += ext_array[i];"
11851 "}"
11852 "sum;");
11853 CHECK_EQ(28, result->Int32Value());
11854
11855 // Check assigned smis in reverse order
11856 result = CompileRun("for (var i = 8; --i >= 0; ) {"
11857 " ext_array[i] = i;"
11858 "}"
11859 "var sum = 0;"
11860 "for (var i = 0; i < 8; i++) {"
11861 " sum += ext_array[i];"
11862 "}"
11863 "sum;");
11864 CHECK_EQ(28, result->Int32Value());
11865
11866 // Check pass through of assigned HeapNumbers
11867 result = CompileRun("var sum = 0;"
11868 "for (var i = 0; i < 16; i+=2) {"
11869 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
11870 "}"
11871 "sum;");
11872 CHECK_EQ(-28, result->Int32Value());
11873
11874 // Check assigned HeapNumbers
11875 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
11876 " ext_array[i] = (i * 0.5);"
11877 "}"
11878 "var sum = 0;"
11879 "for (var i = 0; i < 16; i+=2) {"
11880 " sum += ext_array[i];"
11881 "}"
11882 "sum;");
11883 CHECK_EQ(28, result->Int32Value());
11884
11885 // Check assigned HeapNumbers in reverse order
11886 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
11887 " ext_array[i] = (i * 0.5);"
11888 "}"
11889 "var sum = 0;"
11890 "for (var i = 0; i < 16; i+=2) {"
11891 " sum += ext_array[i];"
11892 "}"
11893 "sum;");
11894 CHECK_EQ(28, result->Int32Value());
11895
11896 i::ScopedVector<char> test_buf(1024);
11897
11898 // Check legal boundary conditions.
11899 // The repeated loads and stores ensure the ICs are exercised.
11900 const char* boundary_program =
11901 "var res = 0;"
11902 "for (var i = 0; i < 16; i++) {"
11903 " ext_array[i] = %lld;"
11904 " if (i > 8) {"
11905 " res = ext_array[i];"
11906 " }"
11907 "}"
11908 "res;";
11909 i::OS::SNPrintF(test_buf,
11910 boundary_program,
11911 low);
11912 result = CompileRun(test_buf.start());
11913 CHECK_EQ(low, result->IntegerValue());
11914
11915 i::OS::SNPrintF(test_buf,
11916 boundary_program,
11917 high);
11918 result = CompileRun(test_buf.start());
11919 CHECK_EQ(high, result->IntegerValue());
11920
11921 // Check misprediction of type in IC.
11922 result = CompileRun("var tmp_array = ext_array;"
11923 "var sum = 0;"
11924 "for (var i = 0; i < 8; i++) {"
11925 " tmp_array[i] = i;"
11926 " sum += tmp_array[i];"
11927 " if (i == 4) {"
11928 " tmp_array = {};"
11929 " }"
11930 "}"
11931 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000011933 CHECK_EQ(28, result->Int32Value());
11934
11935 // Make sure out-of-range loads do not throw.
11936 i::OS::SNPrintF(test_buf,
11937 "var caught_exception = false;"
11938 "try {"
11939 " ext_array[%d];"
11940 "} catch (e) {"
11941 " caught_exception = true;"
11942 "}"
11943 "caught_exception;",
11944 kElementCount);
11945 result = CompileRun(test_buf.start());
11946 CHECK_EQ(false, result->BooleanValue());
11947
11948 // Make sure out-of-range stores do not throw.
11949 i::OS::SNPrintF(test_buf,
11950 "var caught_exception = false;"
11951 "try {"
11952 " ext_array[%d] = 1;"
11953 "} catch (e) {"
11954 " caught_exception = true;"
11955 "}"
11956 "caught_exception;",
11957 kElementCount);
11958 result = CompileRun(test_buf.start());
11959 CHECK_EQ(false, result->BooleanValue());
11960
11961 // Check other boundary conditions, values and operations.
11962 result = CompileRun("for (var i = 0; i < 8; i++) {"
11963 " ext_array[7] = undefined;"
11964 "}"
11965 "ext_array[7];");
11966 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011967 CHECK_EQ(
11968 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011969
11970 result = CompileRun("for (var i = 0; i < 8; i++) {"
11971 " ext_array[6] = '2.3';"
11972 "}"
11973 "ext_array[6];");
11974 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011975 CHECK_EQ(
11976 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000011977
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011978 if (array_type != v8::kExternalFloatArray &&
11979 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011980 // Though the specification doesn't state it, be explicit about
11981 // converting NaNs and +/-Infinity to zero.
11982 result = CompileRun("for (var i = 0; i < 8; i++) {"
11983 " ext_array[i] = 5;"
11984 "}"
11985 "for (var i = 0; i < 8; i++) {"
11986 " ext_array[i] = NaN;"
11987 "}"
11988 "ext_array[5];");
11989 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011990 CHECK_EQ(0,
11991 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000011992
11993 result = CompileRun("for (var i = 0; i < 8; i++) {"
11994 " ext_array[i] = 5;"
11995 "}"
11996 "for (var i = 0; i < 8; i++) {"
11997 " ext_array[i] = Infinity;"
11998 "}"
11999 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012000 int expected_value =
12001 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12002 CHECK_EQ(expected_value, result->Int32Value());
12003 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012004 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012005
12006 result = CompileRun("for (var i = 0; i < 8; i++) {"
12007 " ext_array[i] = 5;"
12008 "}"
12009 "for (var i = 0; i < 8; i++) {"
12010 " ext_array[i] = -Infinity;"
12011 "}"
12012 "ext_array[5];");
12013 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012014 CHECK_EQ(0,
12015 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012016
12017 // Check truncation behavior of integral arrays.
12018 const char* unsigned_data =
12019 "var source_data = [0.6, 10.6];"
12020 "var expected_results = [0, 10];";
12021 const char* signed_data =
12022 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12023 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012024 const char* pixel_data =
12025 "var source_data = [0.6, 10.6];"
12026 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012027 bool is_unsigned =
12028 (array_type == v8::kExternalUnsignedByteArray ||
12029 array_type == v8::kExternalUnsignedShortArray ||
12030 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012031 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012032
12033 i::OS::SNPrintF(test_buf,
12034 "%s"
12035 "var all_passed = true;"
12036 "for (var i = 0; i < source_data.length; i++) {"
12037 " for (var j = 0; j < 8; j++) {"
12038 " ext_array[j] = source_data[i];"
12039 " }"
12040 " all_passed = all_passed &&"
12041 " (ext_array[5] == expected_results[i]);"
12042 "}"
12043 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012044 (is_unsigned ?
12045 unsigned_data :
12046 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012047 result = CompileRun(test_buf.start());
12048 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012049 }
12050
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012051 for (int i = 0; i < kElementCount; i++) {
12052 array->set(i, static_cast<ElementType>(i));
12053 }
12054 // Test complex assignments
12055 result = CompileRun("function ee_op_test_complex_func(sum) {"
12056 " for (var i = 0; i < 40; ++i) {"
12057 " sum += (ext_array[i] += 1);"
12058 " sum += (ext_array[i] -= 1);"
12059 " } "
12060 " return sum;"
12061 "}"
12062 "sum=0;"
12063 "for (var i=0;i<10000;++i) {"
12064 " sum=ee_op_test_complex_func(sum);"
12065 "}"
12066 "sum;");
12067 CHECK_EQ(16000000, result->Int32Value());
12068
12069 // Test count operations
12070 result = CompileRun("function ee_op_test_count_func(sum) {"
12071 " for (var i = 0; i < 40; ++i) {"
12072 " sum += (++ext_array[i]);"
12073 " sum += (--ext_array[i]);"
12074 " } "
12075 " return sum;"
12076 "}"
12077 "sum=0;"
12078 "for (var i=0;i<10000;++i) {"
12079 " sum=ee_op_test_count_func(sum);"
12080 "}"
12081 "sum;");
12082 CHECK_EQ(16000000, result->Int32Value());
12083
ager@chromium.org3811b432009-10-28 14:53:37 +000012084 result = CompileRun("ext_array[3] = 33;"
12085 "delete ext_array[3];"
12086 "ext_array[3];");
12087 CHECK_EQ(33, result->Int32Value());
12088
12089 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12090 "ext_array[2] = 12; ext_array[3] = 13;"
12091 "ext_array.__defineGetter__('2',"
12092 "function() { return 120; });"
12093 "ext_array[2];");
12094 CHECK_EQ(12, result->Int32Value());
12095
12096 result = CompileRun("var js_array = new Array(40);"
12097 "js_array[0] = 77;"
12098 "js_array;");
12099 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12100
12101 result = CompileRun("ext_array[1] = 23;"
12102 "ext_array.__proto__ = [];"
12103 "js_array.__proto__ = ext_array;"
12104 "js_array.concat(ext_array);");
12105 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12106 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12107
12108 result = CompileRun("ext_array[1] = 23;");
12109 CHECK_EQ(23, result->Int32Value());
12110
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012111 // Test more complex manipulations which cause eax to contain values
12112 // that won't be completely overwritten by loads from the arrays.
12113 // This catches bugs in the instructions used for the KeyedLoadIC
12114 // for byte and word types.
12115 {
12116 const int kXSize = 300;
12117 const int kYSize = 300;
12118 const int kLargeElementCount = kXSize * kYSize * 4;
12119 ElementType* large_array_data =
12120 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12121 i::Handle<ExternalArrayClass> large_array =
12122 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012124 array_type,
12125 array_data));
12126 v8::Handle<v8::Object> large_obj = v8::Object::New();
12127 // Set the elements to be the external array.
12128 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12129 array_type,
12130 kLargeElementCount);
12131 context->Global()->Set(v8_str("large_array"), large_obj);
12132 // Initialize contents of a few rows.
12133 for (int x = 0; x < 300; x++) {
12134 int row = 0;
12135 int offset = row * 300 * 4;
12136 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12137 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12138 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12139 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12140 row = 150;
12141 offset = row * 300 * 4;
12142 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12143 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12144 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12145 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12146 row = 298;
12147 offset = row * 300 * 4;
12148 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12149 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12150 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12151 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12152 }
12153 // The goal of the code below is to make "offset" large enough
12154 // that the computation of the index (which goes into eax) has
12155 // high bits set which will not be overwritten by a byte or short
12156 // load.
12157 result = CompileRun("var failed = false;"
12158 "var offset = 0;"
12159 "for (var i = 0; i < 300; i++) {"
12160 " if (large_array[4 * i] != 127 ||"
12161 " large_array[4 * i + 1] != 0 ||"
12162 " large_array[4 * i + 2] != 0 ||"
12163 " large_array[4 * i + 3] != 127) {"
12164 " failed = true;"
12165 " }"
12166 "}"
12167 "offset = 150 * 300 * 4;"
12168 "for (var i = 0; i < 300; i++) {"
12169 " if (large_array[offset + 4 * i] != 127 ||"
12170 " large_array[offset + 4 * i + 1] != 0 ||"
12171 " large_array[offset + 4 * i + 2] != 0 ||"
12172 " large_array[offset + 4 * i + 3] != 127) {"
12173 " failed = true;"
12174 " }"
12175 "}"
12176 "offset = 298 * 300 * 4;"
12177 "for (var i = 0; i < 300; i++) {"
12178 " if (large_array[offset + 4 * i] != 127 ||"
12179 " large_array[offset + 4 * i + 1] != 0 ||"
12180 " large_array[offset + 4 * i + 2] != 0 ||"
12181 " large_array[offset + 4 * i + 3] != 127) {"
12182 " failed = true;"
12183 " }"
12184 "}"
12185 "!failed;");
12186 CHECK_EQ(true, result->BooleanValue());
12187 free(large_array_data);
12188 }
12189
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012190 // The "" property descriptor is overloaded to store information about
12191 // the external array. Ensure that setting and accessing the "" property
12192 // works (it should overwrite the information cached about the external
12193 // array in the DescriptorArray) in various situations.
12194 result = CompileRun("ext_array[''] = 23; ext_array['']");
12195 CHECK_EQ(23, result->Int32Value());
12196
12197 // Property "" set after the external array is associated with the object.
12198 {
12199 v8::Handle<v8::Object> obj2 = v8::Object::New();
12200 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12201 obj2->Set(v8_str(""), v8::Int32::New(1503));
12202 // Set the elements to be the external array.
12203 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12204 array_type,
12205 kElementCount);
12206 context->Global()->Set(v8_str("ext_array"), obj2);
12207 result = CompileRun("ext_array['']");
12208 CHECK_EQ(1503, result->Int32Value());
12209 }
12210
12211 // Property "" set after the external array is associated with the object.
12212 {
12213 v8::Handle<v8::Object> obj2 = v8::Object::New();
12214 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12215 // Set the elements to be the external array.
12216 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12217 array_type,
12218 kElementCount);
12219 obj2->Set(v8_str(""), v8::Int32::New(1503));
12220 context->Global()->Set(v8_str("ext_array"), obj2);
12221 result = CompileRun("ext_array['']");
12222 CHECK_EQ(1503, result->Int32Value());
12223 }
12224
12225 // Should reuse the map from previous test.
12226 {
12227 v8::Handle<v8::Object> obj2 = v8::Object::New();
12228 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12229 // Set the elements to be the external array. Should re-use the map
12230 // from previous test.
12231 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12232 array_type,
12233 kElementCount);
12234 context->Global()->Set(v8_str("ext_array"), obj2);
12235 result = CompileRun("ext_array['']");
12236 }
12237
12238 // Property "" is a constant function that shouldn't not be interfered with
12239 // when an external array is set.
12240 {
12241 v8::Handle<v8::Object> obj2 = v8::Object::New();
12242 // Start
12243 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12244
12245 // Add a constant function to an object.
12246 context->Global()->Set(v8_str("ext_array"), obj2);
12247 result = CompileRun("ext_array[''] = function() {return 1503;};"
12248 "ext_array['']();");
12249
12250 // Add an external array transition to the same map that
12251 // has the constant transition.
12252 v8::Handle<v8::Object> obj3 = v8::Object::New();
12253 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12254 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12255 array_type,
12256 kElementCount);
12257 context->Global()->Set(v8_str("ext_array"), obj3);
12258 }
12259
12260 // If a external array transition is in the map, it should get clobbered
12261 // by a constant function.
12262 {
12263 // Add an external array transition.
12264 v8::Handle<v8::Object> obj3 = v8::Object::New();
12265 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12266 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12267 array_type,
12268 kElementCount);
12269
12270 // Add a constant function to the same map that just got an external array
12271 // transition.
12272 v8::Handle<v8::Object> obj2 = v8::Object::New();
12273 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12274 context->Global()->Set(v8_str("ext_array"), obj2);
12275 result = CompileRun("ext_array[''] = function() {return 1503;};"
12276 "ext_array['']();");
12277 }
12278
ager@chromium.org3811b432009-10-28 14:53:37 +000012279 free(array_data);
12280}
12281
12282
12283THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012284 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012285 v8::kExternalByteArray,
12286 -128,
12287 127);
12288}
12289
12290
12291THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012292 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012293 v8::kExternalUnsignedByteArray,
12294 0,
12295 255);
12296}
12297
12298
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012299THREADED_TEST(ExternalPixelArray) {
12300 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12301 v8::kExternalPixelArray,
12302 0,
12303 255);
12304}
12305
12306
ager@chromium.org3811b432009-10-28 14:53:37 +000012307THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012308 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012309 v8::kExternalShortArray,
12310 -32768,
12311 32767);
12312}
12313
12314
12315THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012316 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012317 v8::kExternalUnsignedShortArray,
12318 0,
12319 65535);
12320}
12321
12322
12323THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012324 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012325 v8::kExternalIntArray,
12326 INT_MIN, // -2147483648
12327 INT_MAX); // 2147483647
12328}
12329
12330
12331THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012332 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012333 v8::kExternalUnsignedIntArray,
12334 0,
12335 UINT_MAX); // 4294967295
12336}
12337
12338
12339THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012340 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012341 v8::kExternalFloatArray,
12342 -500,
12343 500);
12344}
12345
12346
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012347THREADED_TEST(ExternalDoubleArray) {
12348 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12349 v8::kExternalDoubleArray,
12350 -500,
12351 500);
12352}
12353
12354
ager@chromium.org3811b432009-10-28 14:53:37 +000012355THREADED_TEST(ExternalArrays) {
12356 TestExternalByteArray();
12357 TestExternalUnsignedByteArray();
12358 TestExternalShortArray();
12359 TestExternalUnsignedShortArray();
12360 TestExternalIntArray();
12361 TestExternalUnsignedIntArray();
12362 TestExternalFloatArray();
12363}
12364
12365
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012366void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12367 v8::HandleScope scope;
12368 LocalContext context;
12369 for (int size = 0; size < 100; size += 10) {
12370 int element_size = ExternalArrayElementSize(array_type);
12371 void* external_data = malloc(size * element_size);
12372 v8::Handle<v8::Object> obj = v8::Object::New();
12373 obj->SetIndexedPropertiesToExternalArrayData(
12374 external_data, array_type, size);
12375 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12376 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12377 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12378 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12379 free(external_data);
12380 }
12381}
12382
12383
12384THREADED_TEST(ExternalArrayInfo) {
12385 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12386 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12387 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12388 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12389 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12390 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12391 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012392 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012393 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012394}
12395
12396
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012397THREADED_TEST(ScriptContextDependence) {
12398 v8::HandleScope scope;
12399 LocalContext c1;
12400 const char *source = "foo";
12401 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12402 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12403 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12404 CHECK_EQ(dep->Run()->Int32Value(), 100);
12405 CHECK_EQ(indep->Run()->Int32Value(), 100);
12406 LocalContext c2;
12407 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12408 CHECK_EQ(dep->Run()->Int32Value(), 100);
12409 CHECK_EQ(indep->Run()->Int32Value(), 101);
12410}
12411
ager@chromium.org96c75b52009-08-26 09:13:16 +000012412
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012413THREADED_TEST(StackTrace) {
12414 v8::HandleScope scope;
12415 LocalContext context;
12416 v8::TryCatch try_catch;
12417 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12418 v8::Handle<v8::String> src = v8::String::New(source);
12419 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12420 v8::Script::New(src, origin)->Run();
12421 CHECK(try_catch.HasCaught());
12422 v8::String::Utf8Value stack(try_catch.StackTrace());
12423 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12424}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012425
12426
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012427// Checks that a StackFrame has certain expected values.
12428void checkStackFrame(const char* expected_script_name,
12429 const char* expected_func_name, int expected_line_number,
12430 int expected_column, bool is_eval, bool is_constructor,
12431 v8::Handle<v8::StackFrame> frame) {
12432 v8::HandleScope scope;
12433 v8::String::Utf8Value func_name(frame->GetFunctionName());
12434 v8::String::Utf8Value script_name(frame->GetScriptName());
12435 if (*script_name == NULL) {
12436 // The situation where there is no associated script, like for evals.
12437 CHECK(expected_script_name == NULL);
12438 } else {
12439 CHECK(strstr(*script_name, expected_script_name) != NULL);
12440 }
12441 CHECK(strstr(*func_name, expected_func_name) != NULL);
12442 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12443 CHECK_EQ(expected_column, frame->GetColumn());
12444 CHECK_EQ(is_eval, frame->IsEval());
12445 CHECK_EQ(is_constructor, frame->IsConstructor());
12446}
12447
12448
12449v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12450 v8::HandleScope scope;
12451 const char* origin = "capture-stack-trace-test";
12452 const int kOverviewTest = 1;
12453 const int kDetailedTest = 2;
12454
12455 ASSERT(args.Length() == 1);
12456
12457 int testGroup = args[0]->Int32Value();
12458 if (testGroup == kOverviewTest) {
12459 v8::Handle<v8::StackTrace> stackTrace =
12460 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12461 CHECK_EQ(4, stackTrace->GetFrameCount());
12462 checkStackFrame(origin, "bar", 2, 10, false, false,
12463 stackTrace->GetFrame(0));
12464 checkStackFrame(origin, "foo", 6, 3, false, false,
12465 stackTrace->GetFrame(1));
12466 checkStackFrame(NULL, "", 1, 1, false, false,
12467 stackTrace->GetFrame(2));
12468 // The last frame is an anonymous function that has the initial call.
12469 checkStackFrame(origin, "", 8, 7, false, false,
12470 stackTrace->GetFrame(3));
12471
12472 CHECK(stackTrace->AsArray()->IsArray());
12473 } else if (testGroup == kDetailedTest) {
12474 v8::Handle<v8::StackTrace> stackTrace =
12475 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12476 CHECK_EQ(4, stackTrace->GetFrameCount());
12477 checkStackFrame(origin, "bat", 4, 22, false, false,
12478 stackTrace->GetFrame(0));
12479 checkStackFrame(origin, "baz", 8, 3, false, true,
12480 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012481#ifdef ENABLE_DEBUGGER_SUPPORT
12482 bool is_eval = true;
12483#else // ENABLE_DEBUGGER_SUPPORT
12484 bool is_eval = false;
12485#endif // ENABLE_DEBUGGER_SUPPORT
12486
12487 checkStackFrame(NULL, "", 1, 1, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012488 stackTrace->GetFrame(2));
12489 // The last frame is an anonymous function that has the initial call to foo.
12490 checkStackFrame(origin, "", 10, 1, false, false,
12491 stackTrace->GetFrame(3));
12492
12493 CHECK(stackTrace->AsArray()->IsArray());
12494 }
12495 return v8::Undefined();
12496}
12497
12498
12499// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012500// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12501// THREADED_TEST(CaptureStackTrace) {
12502TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012503 v8::HandleScope scope;
12504 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12505 Local<ObjectTemplate> templ = ObjectTemplate::New();
12506 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12507 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12508 LocalContext context(0, templ);
12509
12510 // Test getting OVERVIEW information. Should ignore information that is not
12511 // script name, function name, line number, and column offset.
12512 const char *overview_source =
12513 "function bar() {\n"
12514 " var y; AnalyzeStackInNativeCode(1);\n"
12515 "}\n"
12516 "function foo() {\n"
12517 "\n"
12518 " bar();\n"
12519 "}\n"
12520 "var x;eval('new foo();');";
12521 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12522 v8::Handle<Value> overview_result =
12523 v8::Script::New(overview_src, origin)->Run();
12524 ASSERT(!overview_result.IsEmpty());
12525 ASSERT(overview_result->IsObject());
12526
12527 // Test getting DETAILED information.
12528 const char *detailed_source =
12529 "function bat() {AnalyzeStackInNativeCode(2);\n"
12530 "}\n"
12531 "\n"
12532 "function baz() {\n"
12533 " bat();\n"
12534 "}\n"
12535 "eval('new baz();');";
12536 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12537 // Make the script using a non-zero line and column offset.
12538 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12539 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12540 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12541 v8::Handle<v8::Script> detailed_script(
12542 v8::Script::New(detailed_src, &detailed_origin));
12543 v8::Handle<Value> detailed_result = detailed_script->Run();
12544 ASSERT(!detailed_result.IsEmpty());
12545 ASSERT(detailed_result->IsObject());
12546}
12547
12548
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012549static void StackTraceForUncaughtExceptionListener(
12550 v8::Handle<v8::Message> message,
12551 v8::Handle<Value>) {
12552 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12553 CHECK_EQ(2, stack_trace->GetFrameCount());
12554 checkStackFrame("origin", "foo", 2, 3, false, false,
12555 stack_trace->GetFrame(0));
12556 checkStackFrame("origin", "bar", 5, 3, false, false,
12557 stack_trace->GetFrame(1));
12558}
12559
12560TEST(CaptureStackTraceForUncaughtException) {
12561 report_count = 0;
12562 v8::HandleScope scope;
12563 LocalContext env;
12564 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12565 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12566
12567 Script::Compile(v8_str("function foo() {\n"
12568 " throw 1;\n"
12569 "};\n"
12570 "function bar() {\n"
12571 " foo();\n"
12572 "};"),
12573 v8_str("origin"))->Run();
12574 v8::Local<v8::Object> global = env->Global();
12575 Local<Value> trouble = global->Get(v8_str("bar"));
12576 CHECK(trouble->IsFunction());
12577 Function::Cast(*trouble)->Call(global, 0, NULL);
12578 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12579 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12580}
12581
12582
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012583TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12584 v8::HandleScope scope;
12585 LocalContext env;
12586 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12587 1024,
12588 v8::StackTrace::kDetailed);
12589
12590 CompileRun(
12591 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12592 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12593 " 'isConstructor'];\n"
12594 "for (var i = 0; i < setters.length; i++) {\n"
12595 " var prop = setters[i];\n"
12596 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12597 "}\n");
12598 CompileRun("throw 'exception';");
12599 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12600}
12601
12602
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012603v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12604 v8::HandleScope scope;
12605 v8::Handle<v8::StackTrace> stackTrace =
12606 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12607 CHECK_EQ(5, stackTrace->GetFrameCount());
12608 v8::Handle<v8::String> url = v8_str("eval_url");
12609 for (int i = 0; i < 3; i++) {
12610 v8::Handle<v8::String> name =
12611 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12612 CHECK(!name.IsEmpty());
12613 CHECK_EQ(url, name);
12614 }
12615 return v8::Undefined();
12616}
12617
12618
12619TEST(SourceURLInStackTrace) {
12620 v8::HandleScope scope;
12621 Local<ObjectTemplate> templ = ObjectTemplate::New();
12622 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12623 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12624 LocalContext context(0, templ);
12625
12626 const char *source =
12627 "function outer() {\n"
12628 "function bar() {\n"
12629 " AnalyzeStackOfEvalWithSourceURL();\n"
12630 "}\n"
12631 "function foo() {\n"
12632 "\n"
12633 " bar();\n"
12634 "}\n"
12635 "foo();\n"
12636 "}\n"
12637 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12638 CHECK(CompileRun(source)->IsUndefined());
12639}
12640
12641
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012642// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012643THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012644 bool rv = false;
12645 for (int i = 0; i < 100; i++) {
12646 rv = v8::V8::IdleNotification();
12647 if (rv)
12648 break;
12649 }
12650 CHECK(rv == true);
12651}
12652
12653
12654static uint32_t* stack_limit;
12655
12656static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 stack_limit = reinterpret_cast<uint32_t*>(
12658 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012659 return v8::Undefined();
12660}
12661
12662
12663// Uses the address of a local variable to determine the stack top now.
12664// Given a size, returns an address that is that far from the current
12665// top of stack.
12666static uint32_t* ComputeStackLimit(uint32_t size) {
12667 uint32_t* answer = &size - (size / sizeof(size));
12668 // If the size is very large and the stack is very near the bottom of
12669 // memory then the calculation above may wrap around and give an address
12670 // that is above the (downwards-growing) stack. In that case we return
12671 // a very low address.
12672 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12673 return answer;
12674}
12675
12676
12677TEST(SetResourceConstraints) {
12678 static const int K = 1024;
12679 uint32_t* set_limit = ComputeStackLimit(128 * K);
12680
12681 // Set stack limit.
12682 v8::ResourceConstraints constraints;
12683 constraints.set_stack_limit(set_limit);
12684 CHECK(v8::SetResourceConstraints(&constraints));
12685
12686 // Execute a script.
12687 v8::HandleScope scope;
12688 LocalContext env;
12689 Local<v8::FunctionTemplate> fun_templ =
12690 v8::FunctionTemplate::New(GetStackLimitCallback);
12691 Local<Function> fun = fun_templ->GetFunction();
12692 env->Global()->Set(v8_str("get_stack_limit"), fun);
12693 CompileRun("get_stack_limit();");
12694
12695 CHECK(stack_limit == set_limit);
12696}
12697
12698
12699TEST(SetResourceConstraintsInThread) {
12700 uint32_t* set_limit;
12701 {
12702 v8::Locker locker;
12703 static const int K = 1024;
12704 set_limit = ComputeStackLimit(128 * K);
12705
12706 // Set stack limit.
12707 v8::ResourceConstraints constraints;
12708 constraints.set_stack_limit(set_limit);
12709 CHECK(v8::SetResourceConstraints(&constraints));
12710
12711 // Execute a script.
12712 v8::HandleScope scope;
12713 LocalContext env;
12714 Local<v8::FunctionTemplate> fun_templ =
12715 v8::FunctionTemplate::New(GetStackLimitCallback);
12716 Local<Function> fun = fun_templ->GetFunction();
12717 env->Global()->Set(v8_str("get_stack_limit"), fun);
12718 CompileRun("get_stack_limit();");
12719
12720 CHECK(stack_limit == set_limit);
12721 }
12722 {
12723 v8::Locker locker;
12724 CHECK(stack_limit == set_limit);
12725 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000012726}
ager@chromium.org3811b432009-10-28 14:53:37 +000012727
12728
12729THREADED_TEST(GetHeapStatistics) {
12730 v8::HandleScope scope;
12731 LocalContext c1;
12732 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012733 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
12734 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000012735 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012736 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
12737 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000012738}
12739
12740
12741static double DoubleFromBits(uint64_t value) {
12742 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000012743 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000012744 return target;
12745}
12746
12747
12748static uint64_t DoubleToBits(double value) {
12749 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000012750 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000012751 return target;
12752}
12753
12754
12755static double DoubleToDateTime(double input) {
12756 double date_limit = 864e13;
12757 if (IsNaN(input) || input < -date_limit || input > date_limit) {
12758 return i::OS::nan_value();
12759 }
12760 return (input < 0) ? -(floor(-input)) : floor(input);
12761}
12762
12763// We don't have a consistent way to write 64-bit constants syntactically, so we
12764// split them into two 32-bit constants and combine them programmatically.
12765static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
12766 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
12767}
12768
12769
12770THREADED_TEST(QuietSignalingNaNs) {
12771 v8::HandleScope scope;
12772 LocalContext context;
12773 v8::TryCatch try_catch;
12774
12775 // Special double values.
12776 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
12777 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
12778 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
12779 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
12780 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
12781 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
12782 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
12783
12784 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
12785 // on either side of the epoch.
12786 double date_limit = 864e13;
12787
12788 double test_values[] = {
12789 snan,
12790 qnan,
12791 infinity,
12792 max_normal,
12793 date_limit + 1,
12794 date_limit,
12795 min_normal,
12796 max_denormal,
12797 min_denormal,
12798 0,
12799 -0,
12800 -min_denormal,
12801 -max_denormal,
12802 -min_normal,
12803 -date_limit,
12804 -date_limit - 1,
12805 -max_normal,
12806 -infinity,
12807 -qnan,
12808 -snan
12809 };
12810 int num_test_values = 20;
12811
12812 for (int i = 0; i < num_test_values; i++) {
12813 double test_value = test_values[i];
12814
12815 // Check that Number::New preserves non-NaNs and quiets SNaNs.
12816 v8::Handle<v8::Value> number = v8::Number::New(test_value);
12817 double stored_number = number->NumberValue();
12818 if (!IsNaN(test_value)) {
12819 CHECK_EQ(test_value, stored_number);
12820 } else {
12821 uint64_t stored_bits = DoubleToBits(stored_number);
12822 // Check if quiet nan (bits 51..62 all set).
12823 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12824 }
12825
12826 // Check that Date::New preserves non-NaNs in the date range and
12827 // quiets SNaNs.
12828 v8::Handle<v8::Value> date = v8::Date::New(test_value);
12829 double expected_stored_date = DoubleToDateTime(test_value);
12830 double stored_date = date->NumberValue();
12831 if (!IsNaN(expected_stored_date)) {
12832 CHECK_EQ(expected_stored_date, stored_date);
12833 } else {
12834 uint64_t stored_bits = DoubleToBits(stored_date);
12835 // Check if quiet nan (bits 51..62 all set).
12836 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
12837 }
12838 }
12839}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000012840
12841
12842static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
12843 v8::HandleScope scope;
12844 v8::TryCatch tc;
12845 v8::Handle<v8::String> str = args[0]->ToString();
12846 if (tc.HasCaught())
12847 return tc.ReThrow();
12848 return v8::Undefined();
12849}
12850
12851
12852// Test that an exception can be propagated down through a spaghetti
12853// stack using ReThrow.
12854THREADED_TEST(SpaghettiStackReThrow) {
12855 v8::HandleScope scope;
12856 LocalContext context;
12857 context->Global()->Set(
12858 v8::String::New("s"),
12859 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
12860 v8::TryCatch try_catch;
12861 CompileRun(
12862 "var i = 0;"
12863 "var o = {"
12864 " toString: function () {"
12865 " if (i == 10) {"
12866 " throw 'Hey!';"
12867 " } else {"
12868 " i++;"
12869 " return s(o);"
12870 " }"
12871 " }"
12872 "};"
12873 "s(o);");
12874 CHECK(try_catch.HasCaught());
12875 v8::String::Utf8Value value(try_catch.Exception());
12876 CHECK_EQ(0, strcmp(*value, "Hey!"));
12877}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012878
12879
sgjesse@chromium.org98180592009-12-02 08:17:28 +000012880TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012881 v8::V8::Initialize();
12882
12883 v8::HandleScope scope;
12884 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000012885 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012886 int gc_count;
12887
ager@chromium.org60121232009-12-03 11:25:37 +000012888 // Create a context used to keep the code from aging in the compilation
12889 // cache.
12890 other_context = Context::New();
12891
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012892 // Context-dependent context data creates reference from the compilation
12893 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012894 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012895 context = Context::New();
12896 {
12897 v8::HandleScope scope;
12898
12899 context->Enter();
12900 Local<v8::String> obj = v8::String::New("");
12901 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000012902 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012903 context->Exit();
12904 }
12905 context.Dispose();
12906 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012907 other_context->Enter();
12908 CompileRun(source_simple);
12909 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012911 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012912 }
ager@chromium.org60121232009-12-03 11:25:37 +000012913 CHECK_GE(2, gc_count);
12914 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012915
12916 // Eval in a function creates reference from the compilation cache to the
12917 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012918 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012919 context = Context::New();
12920 {
12921 v8::HandleScope scope;
12922
12923 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000012924 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012925 context->Exit();
12926 }
12927 context.Dispose();
12928 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012929 other_context->Enter();
12930 CompileRun(source_eval);
12931 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012932 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012933 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012934 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012935 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000012936 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012937
12938 // Looking up the line number for an exception creates reference from the
12939 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000012940 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012941 context = Context::New();
12942 {
12943 v8::HandleScope scope;
12944
12945 context->Enter();
12946 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000012947 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012948 CHECK(try_catch.HasCaught());
12949 v8::Handle<v8::Message> message = try_catch.Message();
12950 CHECK(!message.IsEmpty());
12951 CHECK_EQ(1, message->GetLineNumber());
12952 context->Exit();
12953 }
12954 context.Dispose();
12955 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000012956 other_context->Enter();
12957 CompileRun(source_exception);
12958 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012959 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000012960 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012961 }
ager@chromium.org60121232009-12-03 11:25:37 +000012962 CHECK_GE(2, gc_count);
12963 CHECK_EQ(1, GetGlobalObjectsCount());
12964
12965 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000012966}
ager@chromium.org5c838252010-02-19 08:53:10 +000012967
12968
12969THREADED_TEST(ScriptOrigin) {
12970 v8::HandleScope scope;
12971 LocalContext env;
12972 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12973 v8::Handle<v8::String> script = v8::String::New(
12974 "function f() {}\n\nfunction g() {}");
12975 v8::Script::Compile(script, &origin)->Run();
12976 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12977 env->Global()->Get(v8::String::New("f")));
12978 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
12979 env->Global()->Get(v8::String::New("g")));
12980
12981 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
12982 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
12983 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
12984
12985 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
12986 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
12987 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
12988}
12989
12990
12991THREADED_TEST(ScriptLineNumber) {
12992 v8::HandleScope scope;
12993 LocalContext env;
12994 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
12995 v8::Handle<v8::String> script = v8::String::New(
12996 "function f() {}\n\nfunction g() {}");
12997 v8::Script::Compile(script, &origin)->Run();
12998 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
12999 env->Global()->Get(v8::String::New("f")));
13000 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13001 env->Global()->Get(v8::String::New("g")));
13002 CHECK_EQ(0, f->GetScriptLineNumber());
13003 CHECK_EQ(2, g->GetScriptLineNumber());
13004}
13005
13006
13007static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13008 const AccessorInfo& info) {
13009 return v8_num(42);
13010}
13011
13012
13013static void SetterWhichSetsYOnThisTo23(Local<String> name,
13014 Local<Value> value,
13015 const AccessorInfo& info) {
13016 info.This()->Set(v8_str("y"), v8_num(23));
13017}
13018
13019
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013020TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013021 v8::HandleScope scope;
13022 Local<ObjectTemplate> templ = ObjectTemplate::New();
13023 templ->SetAccessor(v8_str("x"),
13024 GetterWhichReturns42,
13025 SetterWhichSetsYOnThisTo23);
13026 LocalContext context;
13027 context->Global()->Set(v8_str("P"), templ->NewInstance());
13028 CompileRun("function C1() {"
13029 " this.x = 23;"
13030 "};"
13031 "C1.prototype = P;"
13032 "function C2() {"
13033 " this.x = 23"
13034 "};"
13035 "C2.prototype = { };"
13036 "C2.prototype.__proto__ = P;");
13037
13038 v8::Local<v8::Script> script;
13039 script = v8::Script::Compile(v8_str("new C1();"));
13040 for (int i = 0; i < 10; i++) {
13041 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13042 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13043 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13044 }
13045
13046 script = v8::Script::Compile(v8_str("new C2();"));
13047 for (int i = 0; i < 10; i++) {
13048 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13049 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13050 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13051 }
13052}
13053
13054
13055static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13056 Local<String> name, const AccessorInfo& info) {
13057 return v8_num(42);
13058}
13059
13060
13061static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13062 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13063 if (name->Equals(v8_str("x"))) {
13064 info.This()->Set(v8_str("y"), v8_num(23));
13065 }
13066 return v8::Handle<Value>();
13067}
13068
13069
13070THREADED_TEST(InterceptorOnConstructorPrototype) {
13071 v8::HandleScope scope;
13072 Local<ObjectTemplate> templ = ObjectTemplate::New();
13073 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13074 NamedPropertySetterWhichSetsYOnThisTo23);
13075 LocalContext context;
13076 context->Global()->Set(v8_str("P"), templ->NewInstance());
13077 CompileRun("function C1() {"
13078 " this.x = 23;"
13079 "};"
13080 "C1.prototype = P;"
13081 "function C2() {"
13082 " this.x = 23"
13083 "};"
13084 "C2.prototype = { };"
13085 "C2.prototype.__proto__ = P;");
13086
13087 v8::Local<v8::Script> script;
13088 script = v8::Script::Compile(v8_str("new C1();"));
13089 for (int i = 0; i < 10; i++) {
13090 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13091 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13092 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13093 }
13094
13095 script = v8::Script::Compile(v8_str("new C2();"));
13096 for (int i = 0; i < 10; i++) {
13097 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13098 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13099 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13100 }
13101}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013102
13103
13104TEST(Bug618) {
13105 const char* source = "function C1() {"
13106 " this.x = 23;"
13107 "};"
13108 "C1.prototype = P;";
13109
13110 v8::HandleScope scope;
13111 LocalContext context;
13112 v8::Local<v8::Script> script;
13113
13114 // Use a simple object as prototype.
13115 v8::Local<v8::Object> prototype = v8::Object::New();
13116 prototype->Set(v8_str("y"), v8_num(42));
13117 context->Global()->Set(v8_str("P"), prototype);
13118
13119 // This compile will add the code to the compilation cache.
13120 CompileRun(source);
13121
13122 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000013123 // Allow enough iterations for the inobject slack tracking logic
13124 // to finalize instance size and install the fast construct stub.
13125 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013126 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13127 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13128 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13129 }
13130
13131 // Use an API object with accessors as prototype.
13132 Local<ObjectTemplate> templ = ObjectTemplate::New();
13133 templ->SetAccessor(v8_str("x"),
13134 GetterWhichReturns42,
13135 SetterWhichSetsYOnThisTo23);
13136 context->Global()->Set(v8_str("P"), templ->NewInstance());
13137
13138 // This compile will get the code from the compilation cache.
13139 CompileRun(source);
13140
13141 script = v8::Script::Compile(v8_str("new C1();"));
13142 for (int i = 0; i < 10; i++) {
13143 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13144 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13145 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13146 }
13147}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013148
13149int prologue_call_count = 0;
13150int epilogue_call_count = 0;
13151int prologue_call_count_second = 0;
13152int epilogue_call_count_second = 0;
13153
13154void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13155 ++prologue_call_count;
13156}
13157
13158void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13159 ++epilogue_call_count;
13160}
13161
13162void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13163 ++prologue_call_count_second;
13164}
13165
13166void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13167 ++epilogue_call_count_second;
13168}
13169
13170TEST(GCCallbacks) {
13171 LocalContext context;
13172
13173 v8::V8::AddGCPrologueCallback(PrologueCallback);
13174 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13175 CHECK_EQ(0, prologue_call_count);
13176 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013177 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013178 CHECK_EQ(1, prologue_call_count);
13179 CHECK_EQ(1, epilogue_call_count);
13180 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13181 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013182 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013183 CHECK_EQ(2, prologue_call_count);
13184 CHECK_EQ(2, epilogue_call_count);
13185 CHECK_EQ(1, prologue_call_count_second);
13186 CHECK_EQ(1, epilogue_call_count_second);
13187 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13188 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013189 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013190 CHECK_EQ(2, prologue_call_count);
13191 CHECK_EQ(2, epilogue_call_count);
13192 CHECK_EQ(2, prologue_call_count_second);
13193 CHECK_EQ(2, epilogue_call_count_second);
13194 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13195 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013196 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013197 CHECK_EQ(2, prologue_call_count);
13198 CHECK_EQ(2, epilogue_call_count);
13199 CHECK_EQ(2, prologue_call_count_second);
13200 CHECK_EQ(2, epilogue_call_count_second);
13201}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013202
13203
13204THREADED_TEST(AddToJSFunctionResultCache) {
13205 i::FLAG_allow_natives_syntax = true;
13206 v8::HandleScope scope;
13207
13208 LocalContext context;
13209
13210 const char* code =
13211 "(function() {"
13212 " var key0 = 'a';"
13213 " var key1 = 'b';"
13214 " var r0 = %_GetFromCache(0, key0);"
13215 " var r1 = %_GetFromCache(0, key1);"
13216 " var r0_ = %_GetFromCache(0, key0);"
13217 " if (r0 !== r0_)"
13218 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13219 " var r1_ = %_GetFromCache(0, key1);"
13220 " if (r1 !== r1_)"
13221 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13222 " return 'PASSED';"
13223 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013224 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013225 ExpectString(code, "PASSED");
13226}
13227
13228
13229static const int k0CacheSize = 16;
13230
13231THREADED_TEST(FillJSFunctionResultCache) {
13232 i::FLAG_allow_natives_syntax = true;
13233 v8::HandleScope scope;
13234
13235 LocalContext context;
13236
13237 const char* code =
13238 "(function() {"
13239 " var k = 'a';"
13240 " var r = %_GetFromCache(0, k);"
13241 " for (var i = 0; i < 16; i++) {"
13242 " %_GetFromCache(0, 'a' + i);"
13243 " };"
13244 " if (r === %_GetFromCache(0, k))"
13245 " return 'FAILED: k0CacheSize is too small';"
13246 " return 'PASSED';"
13247 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013248 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013249 ExpectString(code, "PASSED");
13250}
13251
13252
13253THREADED_TEST(RoundRobinGetFromCache) {
13254 i::FLAG_allow_natives_syntax = true;
13255 v8::HandleScope scope;
13256
13257 LocalContext context;
13258
13259 const char* code =
13260 "(function() {"
13261 " var keys = [];"
13262 " for (var i = 0; i < 16; i++) keys.push(i);"
13263 " var values = [];"
13264 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13265 " for (var i = 0; i < 16; i++) {"
13266 " var v = %_GetFromCache(0, keys[i]);"
13267 " if (v !== values[i])"
13268 " return 'Wrong value for ' + "
13269 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13270 " };"
13271 " return 'PASSED';"
13272 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013273 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013274 ExpectString(code, "PASSED");
13275}
13276
13277
13278THREADED_TEST(ReverseGetFromCache) {
13279 i::FLAG_allow_natives_syntax = true;
13280 v8::HandleScope scope;
13281
13282 LocalContext context;
13283
13284 const char* code =
13285 "(function() {"
13286 " var keys = [];"
13287 " for (var i = 0; i < 16; i++) keys.push(i);"
13288 " var values = [];"
13289 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13290 " for (var i = 15; i >= 16; i--) {"
13291 " var v = %_GetFromCache(0, keys[i]);"
13292 " if (v !== values[i])"
13293 " return 'Wrong value for ' + "
13294 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13295 " };"
13296 " return 'PASSED';"
13297 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013298 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013299 ExpectString(code, "PASSED");
13300}
13301
13302
13303THREADED_TEST(TestEviction) {
13304 i::FLAG_allow_natives_syntax = true;
13305 v8::HandleScope scope;
13306
13307 LocalContext context;
13308
13309 const char* code =
13310 "(function() {"
13311 " for (var i = 0; i < 2*16; i++) {"
13312 " %_GetFromCache(0, 'a' + i);"
13313 " };"
13314 " return 'PASSED';"
13315 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013316 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013317 ExpectString(code, "PASSED");
13318}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013319
13320
13321THREADED_TEST(TwoByteStringInAsciiCons) {
13322 // See Chromium issue 47824.
13323 v8::HandleScope scope;
13324
13325 LocalContext context;
13326 const char* init_code =
13327 "var str1 = 'abelspendabel';"
13328 "var str2 = str1 + str1 + str1;"
13329 "str2;";
13330 Local<Value> result = CompileRun(init_code);
13331
13332 CHECK(result->IsString());
13333 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13334 int length = string->length();
13335 CHECK(string->IsAsciiRepresentation());
13336
13337 FlattenString(string);
13338 i::Handle<i::String> flat_string = FlattenGetString(string);
13339
13340 CHECK(string->IsAsciiRepresentation());
13341 CHECK(flat_string->IsAsciiRepresentation());
13342
13343 // Create external resource.
13344 uint16_t* uc16_buffer = new uint16_t[length + 1];
13345
13346 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13347 uc16_buffer[length] = 0;
13348
13349 TestResource resource(uc16_buffer);
13350
13351 flat_string->MakeExternal(&resource);
13352
13353 CHECK(flat_string->IsTwoByteRepresentation());
13354
13355 // At this point, we should have a Cons string which is flat and ASCII,
13356 // with a first half that is a two-byte string (although it only contains
13357 // ASCII characters). This is a valid sequence of steps, and it can happen
13358 // in real pages.
13359
13360 CHECK(string->IsAsciiRepresentation());
13361 i::ConsString* cons = i::ConsString::cast(*string);
13362 CHECK_EQ(0, cons->second()->length());
13363 CHECK(cons->first()->IsTwoByteRepresentation());
13364
13365 // Check that some string operations work.
13366
13367 // Atom RegExp.
13368 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13369 CHECK_EQ(6, reresult->Int32Value());
13370
13371 // Nonatom RegExp.
13372 reresult = CompileRun("str2.match(/abe./g).length;");
13373 CHECK_EQ(6, reresult->Int32Value());
13374
13375 reresult = CompileRun("str2.search(/bel/g);");
13376 CHECK_EQ(1, reresult->Int32Value());
13377
13378 reresult = CompileRun("str2.search(/be./g);");
13379 CHECK_EQ(1, reresult->Int32Value());
13380
13381 ExpectTrue("/bel/g.test(str2);");
13382
13383 ExpectTrue("/be./g.test(str2);");
13384
13385 reresult = CompileRun("/bel/g.exec(str2);");
13386 CHECK(!reresult->IsNull());
13387
13388 reresult = CompileRun("/be./g.exec(str2);");
13389 CHECK(!reresult->IsNull());
13390
13391 ExpectString("str2.substring(2, 10);", "elspenda");
13392
13393 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13394
13395 ExpectString("str2.charAt(2);", "e");
13396
13397 reresult = CompileRun("str2.charCodeAt(2);");
13398 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13399}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013400
13401
13402// Failed access check callback that performs a GC on each invocation.
13403void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13404 v8::AccessType type,
13405 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013406 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013407}
13408
13409
13410TEST(GCInFailedAccessCheckCallback) {
13411 // Install a failed access check callback that performs a GC on each
13412 // invocation. Then force the callback to be called from va
13413
13414 v8::V8::Initialize();
13415 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13416
13417 v8::HandleScope scope;
13418
13419 // Create an ObjectTemplate for global objects and install access
13420 // check callbacks that will block access.
13421 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13422 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13423 IndexedGetAccessBlocker,
13424 v8::Handle<v8::Value>(),
13425 false);
13426
13427 // Create a context and set an x property on it's global object.
13428 LocalContext context0(NULL, global_template);
13429 context0->Global()->Set(v8_str("x"), v8_num(42));
13430 v8::Handle<v8::Object> global0 = context0->Global();
13431
13432 // Create a context with a different security token so that the
13433 // failed access check callback will be called on each access.
13434 LocalContext context1(NULL, global_template);
13435 context1->Global()->Set(v8_str("other"), global0);
13436
13437 // Get property with failed access check.
13438 ExpectUndefined("other.x");
13439
13440 // Get element with failed access check.
13441 ExpectUndefined("other[0]");
13442
13443 // Set property with failed access check.
13444 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13445 CHECK(result->IsObject());
13446
13447 // Set element with failed access check.
13448 result = CompileRun("other[0] = new Object()");
13449 CHECK(result->IsObject());
13450
13451 // Get property attribute with failed access check.
13452 ExpectFalse("\'x\' in other");
13453
13454 // Get property attribute for element with failed access check.
13455 ExpectFalse("0 in other");
13456
13457 // Delete property.
13458 ExpectFalse("delete other.x");
13459
13460 // Delete element.
13461 CHECK_EQ(false, global0->Delete(0));
13462
13463 // DefineAccessor.
13464 CHECK_EQ(false,
13465 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13466
13467 // Define JavaScript accessor.
13468 ExpectUndefined("Object.prototype.__defineGetter__.call("
13469 " other, \'x\', function() { return 42; })");
13470
13471 // LookupAccessor.
13472 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13473 " other, \'x\')");
13474
13475 // HasLocalElement.
13476 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13477
13478 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13479 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13480 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13481
13482 // Reset the failed access check callback so it does not influence
13483 // the other tests.
13484 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13485}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013487TEST(DefaultIsolateGetCurrent) {
13488 CHECK(v8::Isolate::GetCurrent() != NULL);
13489 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13490 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13491 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13492}
13493
13494TEST(IsolateNewDispose) {
13495 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13496 v8::Isolate* isolate = v8::Isolate::New();
13497 CHECK(isolate != NULL);
13498 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13499 CHECK(current_isolate != isolate);
13500 CHECK(current_isolate == v8::Isolate::GetCurrent());
13501
13502 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13503 last_location = last_message = NULL;
13504 isolate->Dispose();
13505 CHECK_EQ(last_location, NULL);
13506 CHECK_EQ(last_message, NULL);
13507}
13508
13509TEST(IsolateEnterExitDefault) {
13510 v8::HandleScope scope;
13511 LocalContext context;
13512 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13513 CHECK(current_isolate != NULL); // Default isolate.
13514 ExpectString("'hello'", "hello");
13515 current_isolate->Enter();
13516 ExpectString("'still working'", "still working");
13517 current_isolate->Exit();
13518 ExpectString("'still working 2'", "still working 2");
13519 current_isolate->Exit();
13520 // Default isolate is always, well, 'default current'.
13521 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13522 // Still working since default isolate is auto-entering any thread
13523 // that has no isolate and attempts to execute V8 APIs.
13524 ExpectString("'still working 3'", "still working 3");
13525}
13526
13527TEST(DisposeDefaultIsolate) {
13528 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13529
13530 // Run some V8 code to trigger default isolate to become 'current'.
13531 v8::HandleScope scope;
13532 LocalContext context;
13533 ExpectString("'run some V8'", "run some V8");
13534
13535 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13536 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13537 last_location = last_message = NULL;
13538 isolate->Dispose();
13539 // It is not possible to dispose default isolate via Isolate API.
13540 CHECK_NE(last_location, NULL);
13541 CHECK_NE(last_message, NULL);
13542}
13543
13544TEST(RunDefaultAndAnotherIsolate) {
13545 v8::HandleScope scope;
13546 LocalContext context;
13547
13548 // Enter new isolate.
13549 v8::Isolate* isolate = v8::Isolate::New();
13550 CHECK(isolate);
13551 isolate->Enter();
13552 { // Need this block because subsequent Exit() will deallocate Heap,
13553 // so we need all scope objects to be deconstructed when it happens.
13554 v8::HandleScope scope_new;
13555 LocalContext context_new;
13556
13557 // Run something in new isolate.
13558 CompileRun("var foo = 153;");
13559 ExpectTrue("function f() { return foo == 153; }; f()");
13560 }
13561 isolate->Exit();
13562
13563 // This runs automatically in default isolate.
13564 // Variables in another isolate should be not available.
13565 ExpectTrue("function f() {"
13566 " try {"
13567 " foo;"
13568 " return false;"
13569 " } catch(e) {"
13570 " return true;"
13571 " }"
13572 "};"
13573 "var bar = 371;"
13574 "f()");
13575
13576 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13577 last_location = last_message = NULL;
13578 isolate->Dispose();
13579 CHECK_EQ(last_location, NULL);
13580 CHECK_EQ(last_message, NULL);
13581
13582 // Check that default isolate still runs.
13583 ExpectTrue("function f() { return bar == 371; }; f()");
13584}
13585
13586TEST(DisposeIsolateWhenInUse) {
13587 v8::Isolate* isolate = v8::Isolate::New();
13588 CHECK(isolate);
13589 isolate->Enter();
13590 v8::HandleScope scope;
13591 LocalContext context;
13592 // Run something in this isolate.
13593 ExpectTrue("true");
13594 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13595 last_location = last_message = NULL;
13596 // Still entered, should fail.
13597 isolate->Dispose();
13598 CHECK_NE(last_location, NULL);
13599 CHECK_NE(last_message, NULL);
13600}
13601
13602TEST(RunTwoIsolatesOnSingleThread) {
13603 // Run isolate 1.
13604 v8::Isolate* isolate1 = v8::Isolate::New();
13605 isolate1->Enter();
13606 v8::Persistent<v8::Context> context1 = v8::Context::New();
13607
13608 {
13609 v8::Context::Scope cscope(context1);
13610 v8::HandleScope scope;
13611 // Run something in new isolate.
13612 CompileRun("var foo = 'isolate 1';");
13613 ExpectString("function f() { return foo; }; f()", "isolate 1");
13614 }
13615
13616 // Run isolate 2.
13617 v8::Isolate* isolate2 = v8::Isolate::New();
13618 v8::Persistent<v8::Context> context2;
13619
13620 {
13621 v8::Isolate::Scope iscope(isolate2);
13622 context2 = v8::Context::New();
13623 v8::Context::Scope cscope(context2);
13624 v8::HandleScope scope;
13625
13626 // Run something in new isolate.
13627 CompileRun("var foo = 'isolate 2';");
13628 ExpectString("function f() { return foo; }; f()", "isolate 2");
13629 }
13630
13631 {
13632 v8::Context::Scope cscope(context1);
13633 v8::HandleScope scope;
13634 // Now again in isolate 1
13635 ExpectString("function f() { return foo; }; f()", "isolate 1");
13636 }
13637
13638 isolate1->Exit();
13639
13640 // Run some stuff in default isolate.
13641 v8::Persistent<v8::Context> context_default = v8::Context::New();
13642
13643 {
13644 v8::Context::Scope cscope(context_default);
13645 v8::HandleScope scope;
13646 // Variables in other isolates should be not available, verify there
13647 // is an exception.
13648 ExpectTrue("function f() {"
13649 " try {"
13650 " foo;"
13651 " return false;"
13652 " } catch(e) {"
13653 " return true;"
13654 " }"
13655 "};"
13656 "var isDefaultIsolate = true;"
13657 "f()");
13658 }
13659
13660 isolate1->Enter();
13661
13662 {
13663 v8::Isolate::Scope iscope(isolate2);
13664 v8::Context::Scope cscope(context2);
13665 v8::HandleScope scope;
13666 ExpectString("function f() { return foo; }; f()", "isolate 2");
13667 }
13668
13669 {
13670 v8::Context::Scope cscope(context1);
13671 v8::HandleScope scope;
13672 ExpectString("function f() { return foo; }; f()", "isolate 1");
13673 }
13674
13675 {
13676 v8::Isolate::Scope iscope(isolate2);
13677 context2.Dispose();
13678 }
13679
13680 context1.Dispose();
13681 isolate1->Exit();
13682
13683 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13684 last_location = last_message = NULL;
13685
13686 isolate1->Dispose();
13687 CHECK_EQ(last_location, NULL);
13688 CHECK_EQ(last_message, NULL);
13689
13690 isolate2->Dispose();
13691 CHECK_EQ(last_location, NULL);
13692 CHECK_EQ(last_message, NULL);
13693
13694 // Check that default isolate still runs.
13695 {
13696 v8::Context::Scope cscope(context_default);
13697 v8::HandleScope scope;
13698 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
13699 }
13700}
13701
13702static int CalcFibonacci(v8::Isolate* isolate, int limit) {
13703 v8::Isolate::Scope isolate_scope(isolate);
13704 v8::HandleScope scope;
13705 LocalContext context;
13706 i::ScopedVector<char> code(1024);
13707 i::OS::SNPrintF(code, "function fib(n) {"
13708 " if (n <= 2) return 1;"
13709 " return fib(n-1) + fib(n-2);"
13710 "}"
13711 "fib(%d)", limit);
13712 Local<Value> value = CompileRun(code.start());
13713 CHECK(value->IsNumber());
13714 return static_cast<int>(value->NumberValue());
13715}
13716
13717class IsolateThread : public v8::internal::Thread {
13718 public:
13719 explicit IsolateThread(v8::Isolate* isolate, int fib_limit)
13720 : Thread(NULL, "IsolateThread"),
13721 isolate_(isolate),
13722 fib_limit_(fib_limit),
13723 result_(0) { }
13724
13725 void Run() {
13726 result_ = CalcFibonacci(isolate_, fib_limit_);
13727 }
13728
13729 int result() { return result_; }
13730
13731 private:
13732 v8::Isolate* isolate_;
13733 int fib_limit_;
13734 int result_;
13735};
13736
13737TEST(MultipleIsolatesOnIndividualThreads) {
13738 v8::Isolate* isolate1 = v8::Isolate::New();
13739 v8::Isolate* isolate2 = v8::Isolate::New();
13740
13741 IsolateThread thread1(isolate1, 21);
13742 IsolateThread thread2(isolate2, 12);
13743
13744 // Compute some fibonacci numbers on 3 threads in 3 isolates.
13745 thread1.Start();
13746 thread2.Start();
13747
13748 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
13749 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
13750
13751 thread1.Join();
13752 thread2.Join();
13753
13754 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
13755 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
13756 CHECK_EQ(result1, 10946);
13757 CHECK_EQ(result2, 144);
13758 CHECK_EQ(result1, thread1.result());
13759 CHECK_EQ(result2, thread2.result());
13760
13761 isolate1->Dispose();
13762 isolate2->Dispose();
13763}
13764
lrn@chromium.org1c092762011-05-09 09:42:16 +000013765TEST(IsolateDifferentContexts) {
13766 v8::Isolate* isolate = v8::Isolate::New();
13767 Persistent<v8::Context> context;
13768 {
13769 v8::Isolate::Scope isolate_scope(isolate);
13770 v8::HandleScope handle_scope;
13771 context = v8::Context::New();
13772 v8::Context::Scope context_scope(context);
13773 Local<Value> v = CompileRun("2");
13774 CHECK(v->IsNumber());
13775 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
13776 }
13777 {
13778 v8::Isolate::Scope isolate_scope(isolate);
13779 v8::HandleScope handle_scope;
13780 context = v8::Context::New();
13781 v8::Context::Scope context_scope(context);
13782 Local<Value> v = CompileRun("22");
13783 CHECK(v->IsNumber());
13784 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
13785 }
13786}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013787
13788class InitDefaultIsolateThread : public v8::internal::Thread {
13789 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013790 enum TestCase {
13791 IgnoreOOM,
13792 SetResourceConstraints,
13793 SetFatalHandler,
13794 SetCounterFunction,
13795 SetCreateHistogramFunction,
13796 SetAddHistogramSampleFunction
13797 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013798
13799 explicit InitDefaultIsolateThread(TestCase testCase)
13800 : Thread(NULL, "InitDefaultIsolateThread"),
13801 testCase_(testCase),
13802 result_(false) { }
13803
13804 void Run() {
13805 switch (testCase_) {
13806 case IgnoreOOM:
13807 v8::V8::IgnoreOutOfMemoryException();
13808 break;
13809
13810 case SetResourceConstraints: {
13811 static const int K = 1024;
13812 v8::ResourceConstraints constraints;
13813 constraints.set_max_young_space_size(256 * K);
13814 constraints.set_max_old_space_size(4 * K * K);
13815 v8::SetResourceConstraints(&constraints);
13816 break;
13817 }
13818
13819 case SetFatalHandler:
13820 v8::V8::SetFatalErrorHandler(NULL);
13821 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013822
13823 case SetCounterFunction:
13824 v8::V8::SetCounterFunction(NULL);
13825 break;
13826
13827 case SetCreateHistogramFunction:
13828 v8::V8::SetCreateHistogramFunction(NULL);
13829 break;
13830
13831 case SetAddHistogramSampleFunction:
13832 v8::V8::SetAddHistogramSampleFunction(NULL);
13833 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013834 }
13835 result_ = true;
13836 }
13837
13838 bool result() { return result_; }
13839
13840 private:
13841 TestCase testCase_;
13842 bool result_;
13843};
13844
13845
13846static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
13847 InitDefaultIsolateThread thread(testCase);
13848 thread.Start();
13849 thread.Join();
13850 CHECK_EQ(thread.result(), true);
13851}
13852
13853TEST(InitializeDefaultIsolateOnSecondaryThread1) {
13854 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
13855}
13856
13857TEST(InitializeDefaultIsolateOnSecondaryThread2) {
13858 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
13859}
13860
13861TEST(InitializeDefaultIsolateOnSecondaryThread3) {
13862 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
13863}
13864
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000013865TEST(InitializeDefaultIsolateOnSecondaryThread4) {
13866 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
13867}
13868
13869TEST(InitializeDefaultIsolateOnSecondaryThread5) {
13870 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
13871}
13872
13873TEST(InitializeDefaultIsolateOnSecondaryThread6) {
13874 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
13875}
13876
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013877
13878TEST(StringCheckMultipleContexts) {
13879 const char* code =
13880 "(function() { return \"a\".charAt(0); })()";
13881
13882 {
13883 // Run the code twice in the first context to initialize the call IC.
13884 v8::HandleScope scope;
13885 LocalContext context1;
13886 ExpectString(code, "a");
13887 ExpectString(code, "a");
13888 }
13889
13890 {
13891 // Change the String.prototype in the second context and check
13892 // that the right function gets called.
13893 v8::HandleScope scope;
13894 LocalContext context2;
13895 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
13896 ExpectString(code, "not a");
13897 }
13898}
13899
13900
13901TEST(NumberCheckMultipleContexts) {
13902 const char* code =
13903 "(function() { return (42).toString(); })()";
13904
13905 {
13906 // Run the code twice in the first context to initialize the call IC.
13907 v8::HandleScope scope;
13908 LocalContext context1;
13909 ExpectString(code, "42");
13910 ExpectString(code, "42");
13911 }
13912
13913 {
13914 // Change the Number.prototype in the second context and check
13915 // that the right function gets called.
13916 v8::HandleScope scope;
13917 LocalContext context2;
13918 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
13919 ExpectString(code, "not 42");
13920 }
13921}
13922
13923
13924TEST(BooleanCheckMultipleContexts) {
13925 const char* code =
13926 "(function() { return true.toString(); })()";
13927
13928 {
13929 // Run the code twice in the first context to initialize the call IC.
13930 v8::HandleScope scope;
13931 LocalContext context1;
13932 ExpectString(code, "true");
13933 ExpectString(code, "true");
13934 }
13935
13936 {
13937 // Change the Boolean.prototype in the second context and check
13938 // that the right function gets called.
13939 v8::HandleScope scope;
13940 LocalContext context2;
13941 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
13942 ExpectString(code, "");
13943 }
13944}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000013945
13946
13947TEST(DontDeleteCellLoadIC) {
13948 const char* function_code =
13949 "function readCell() { while (true) { return cell; } }";
13950
13951 {
13952 // Run the code twice in the first context to initialize the load
13953 // IC for a don't delete cell.
13954 v8::HandleScope scope;
13955 LocalContext context1;
13956 CompileRun("var cell = \"first\";");
13957 ExpectBoolean("delete cell", false);
13958 CompileRun(function_code);
13959 ExpectString("readCell()", "first");
13960 ExpectString("readCell()", "first");
13961 }
13962
13963 {
13964 // Use a deletable cell in the second context.
13965 v8::HandleScope scope;
13966 LocalContext context2;
13967 CompileRun("cell = \"second\";");
13968 CompileRun(function_code);
13969 ExpectString("readCell()", "second");
13970 ExpectBoolean("delete cell", true);
13971 ExpectString("(function() {"
13972 " try {"
13973 " return readCell();"
13974 " } catch(e) {"
13975 " return e.toString();"
13976 " }"
13977 "})()",
13978 "ReferenceError: cell is not defined");
13979 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013980 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000013981 ExpectString("readCell()", "new_second");
13982 ExpectString("readCell()", "new_second");
13983 }
13984}
13985
13986
13987TEST(DontDeleteCellLoadICForceDelete) {
13988 const char* function_code =
13989 "function readCell() { while (true) { return cell; } }";
13990
13991 // Run the code twice to initialize the load IC for a don't delete
13992 // cell.
13993 v8::HandleScope scope;
13994 LocalContext context;
13995 CompileRun("var cell = \"value\";");
13996 ExpectBoolean("delete cell", false);
13997 CompileRun(function_code);
13998 ExpectString("readCell()", "value");
13999 ExpectString("readCell()", "value");
14000
14001 // Delete the cell using the API and check the inlined code works
14002 // correctly.
14003 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14004 ExpectString("(function() {"
14005 " try {"
14006 " return readCell();"
14007 " } catch(e) {"
14008 " return e.toString();"
14009 " }"
14010 "})()",
14011 "ReferenceError: cell is not defined");
14012}
14013
14014
14015TEST(DontDeleteCellLoadICAPI) {
14016 const char* function_code =
14017 "function readCell() { while (true) { return cell; } }";
14018
14019 // Run the code twice to initialize the load IC for a don't delete
14020 // cell created using the API.
14021 v8::HandleScope scope;
14022 LocalContext context;
14023 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14024 ExpectBoolean("delete cell", false);
14025 CompileRun(function_code);
14026 ExpectString("readCell()", "value");
14027 ExpectString("readCell()", "value");
14028
14029 // Delete the cell using the API and check the inlined code works
14030 // correctly.
14031 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14032 ExpectString("(function() {"
14033 " try {"
14034 " return readCell();"
14035 " } catch(e) {"
14036 " return e.toString();"
14037 " }"
14038 "})()",
14039 "ReferenceError: cell is not defined");
14040}
14041
14042
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014043TEST(RegExp) {
14044 v8::HandleScope scope;
14045 LocalContext context;
14046
14047 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14048 CHECK(re->IsRegExp());
14049 CHECK(re->GetSource()->Equals(v8_str("foo")));
14050 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14051
14052 re = v8::RegExp::New(v8_str("bar"),
14053 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14054 v8::RegExp::kGlobal));
14055 CHECK(re->IsRegExp());
14056 CHECK(re->GetSource()->Equals(v8_str("bar")));
14057 CHECK_EQ(static_cast<int>(re->GetFlags()),
14058 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14059
14060 re = v8::RegExp::New(v8_str("baz"),
14061 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14062 v8::RegExp::kMultiline));
14063 CHECK(re->IsRegExp());
14064 CHECK(re->GetSource()->Equals(v8_str("baz")));
14065 CHECK_EQ(static_cast<int>(re->GetFlags()),
14066 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14067
14068 re = CompileRun("/quux/").As<v8::RegExp>();
14069 CHECK(re->IsRegExp());
14070 CHECK(re->GetSource()->Equals(v8_str("quux")));
14071 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14072
14073 re = CompileRun("/quux/gm").As<v8::RegExp>();
14074 CHECK(re->IsRegExp());
14075 CHECK(re->GetSource()->Equals(v8_str("quux")));
14076 CHECK_EQ(static_cast<int>(re->GetFlags()),
14077 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14078
14079 // Override the RegExp constructor and check the API constructor
14080 // still works.
14081 CompileRun("RegExp = function() {}");
14082
14083 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14084 CHECK(re->IsRegExp());
14085 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14086 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14087
14088 re = v8::RegExp::New(v8_str("foobarbaz"),
14089 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14090 v8::RegExp::kMultiline));
14091 CHECK(re->IsRegExp());
14092 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14093 CHECK_EQ(static_cast<int>(re->GetFlags()),
14094 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14095
14096 context->Global()->Set(v8_str("re"), re);
14097 ExpectTrue("re.test('FoobarbaZ')");
14098
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014099 // RegExps are objects on which you can set properties.
14100 re->Set(v8_str("property"), v8::Integer::New(32));
14101 v8::Handle<v8::Value> value = CompileRun("re.property");
14102 ASSERT_EQ(32, value->Int32Value());
14103
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014104 v8::TryCatch try_catch;
14105 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14106 CHECK(re.IsEmpty());
14107 CHECK(try_catch.HasCaught());
14108 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14109 ExpectTrue("ex instanceof SyntaxError");
14110}
14111
14112
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014113THREADED_TEST(Equals) {
14114 v8::HandleScope handleScope;
14115 LocalContext localContext;
14116
14117 v8::Handle<v8::Object> globalProxy = localContext->Global();
14118 v8::Handle<Value> global = globalProxy->GetPrototype();
14119
14120 CHECK(global->StrictEquals(global));
14121 CHECK(!global->StrictEquals(globalProxy));
14122 CHECK(!globalProxy->StrictEquals(global));
14123 CHECK(globalProxy->StrictEquals(globalProxy));
14124
14125 CHECK(global->Equals(global));
14126 CHECK(!global->Equals(globalProxy));
14127 CHECK(!globalProxy->Equals(global));
14128 CHECK(globalProxy->Equals(globalProxy));
14129}
14130
14131
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014132static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14133 const v8::AccessorInfo& info ) {
14134 return v8_str("42!");
14135}
14136
14137
14138static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14139 v8::Handle<v8::Array> result = v8::Array::New();
14140 result->Set(0, v8_str("universalAnswer"));
14141 return result;
14142}
14143
14144
14145TEST(NamedEnumeratorAndForIn) {
14146 v8::HandleScope handle_scope;
14147 LocalContext context;
14148 v8::Context::Scope context_scope(context.local());
14149
14150 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14151 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14152 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14153 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14154 "var result = []; for (var k in o) result.push(k); result"));
14155 CHECK_EQ(1, result->Length());
14156 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14157}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000014158
14159
14160TEST(DefinePropertyPostDetach) {
14161 v8::HandleScope scope;
14162 LocalContext context;
14163 v8::Handle<v8::Object> proxy = context->Global();
14164 v8::Handle<v8::Function> define_property =
14165 CompileRun("(function() {"
14166 " Object.defineProperty("
14167 " this,"
14168 " 1,"
14169 " { configurable: true, enumerable: true, value: 3 });"
14170 "})").As<Function>();
14171 context->DetachGlobal();
14172 define_property->Call(proxy, 0, NULL);
14173}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014174
14175
14176static void InstallContextId(v8::Handle<Context> context, int id) {
14177 Context::Scope scope(context);
14178 CompileRun("Object.prototype").As<Object>()->
14179 Set(v8_str("context_id"), v8::Integer::New(id));
14180}
14181
14182
14183static void CheckContextId(v8::Handle<Object> object, int expected) {
14184 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14185}
14186
14187
14188THREADED_TEST(CreationContext) {
14189 HandleScope handle_scope;
14190 Persistent<Context> context1 = Context::New();
14191 InstallContextId(context1, 1);
14192 Persistent<Context> context2 = Context::New();
14193 InstallContextId(context2, 2);
14194 Persistent<Context> context3 = Context::New();
14195 InstallContextId(context3, 3);
14196
14197 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14198
14199 Local<Object> object1;
14200 Local<Function> func1;
14201 {
14202 Context::Scope scope(context1);
14203 object1 = Object::New();
14204 func1 = tmpl->GetFunction();
14205 }
14206
14207 Local<Object> object2;
14208 Local<Function> func2;
14209 {
14210 Context::Scope scope(context2);
14211 object2 = Object::New();
14212 func2 = tmpl->GetFunction();
14213 }
14214
14215 Local<Object> instance1;
14216 Local<Object> instance2;
14217
14218 {
14219 Context::Scope scope(context3);
14220 instance1 = func1->NewInstance();
14221 instance2 = func2->NewInstance();
14222 }
14223
14224 CHECK(object1->CreationContext() == context1);
14225 CheckContextId(object1, 1);
14226 CHECK(func1->CreationContext() == context1);
14227 CheckContextId(func1, 1);
14228 CHECK(instance1->CreationContext() == context1);
14229 CheckContextId(instance1, 1);
14230 CHECK(object2->CreationContext() == context2);
14231 CheckContextId(object2, 2);
14232 CHECK(func2->CreationContext() == context2);
14233 CheckContextId(func2, 2);
14234 CHECK(instance2->CreationContext() == context2);
14235 CheckContextId(instance2, 2);
14236
14237 {
14238 Context::Scope scope(context1);
14239 CHECK(object1->CreationContext() == context1);
14240 CheckContextId(object1, 1);
14241 CHECK(func1->CreationContext() == context1);
14242 CheckContextId(func1, 1);
14243 CHECK(instance1->CreationContext() == context1);
14244 CheckContextId(instance1, 1);
14245 CHECK(object2->CreationContext() == context2);
14246 CheckContextId(object2, 2);
14247 CHECK(func2->CreationContext() == context2);
14248 CheckContextId(func2, 2);
14249 CHECK(instance2->CreationContext() == context2);
14250 CheckContextId(instance2, 2);
14251 }
14252
14253 {
14254 Context::Scope scope(context2);
14255 CHECK(object1->CreationContext() == context1);
14256 CheckContextId(object1, 1);
14257 CHECK(func1->CreationContext() == context1);
14258 CheckContextId(func1, 1);
14259 CHECK(instance1->CreationContext() == context1);
14260 CheckContextId(instance1, 1);
14261 CHECK(object2->CreationContext() == context2);
14262 CheckContextId(object2, 2);
14263 CHECK(func2->CreationContext() == context2);
14264 CheckContextId(func2, 2);
14265 CHECK(instance2->CreationContext() == context2);
14266 CheckContextId(instance2, 2);
14267 }
14268
14269 context1.Dispose();
14270 context2.Dispose();
14271 context3.Dispose();
14272}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014273
14274
14275Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14276 const AccessorInfo& info) {
14277 if (index == 42) return v8_str("yes");
14278 return Handle<v8::Integer>();
14279}
14280
14281
14282Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14283 const AccessorInfo& info) {
14284 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14285 return Handle<Value>();
14286}
14287
14288
14289Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14290 uint32_t index, const AccessorInfo& info) {
14291 if (index == 42) return v8_num(1).As<v8::Integer>();
14292 return Handle<v8::Integer>();
14293}
14294
14295
14296Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14297 Local<String> property, const AccessorInfo& info) {
14298 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14299 return Handle<v8::Integer>();
14300}
14301
14302
14303Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14304 Local<String> property, const AccessorInfo& info) {
14305 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14306 return Handle<v8::Integer>();
14307}
14308
14309
14310Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14311 const AccessorInfo& info) {
14312 return v8_str("yes");
14313}
14314
14315
14316TEST(HasOwnProperty) {
14317 v8::HandleScope scope;
14318 LocalContext env;
14319 { // Check normal properties and defined getters.
14320 Handle<Value> value = CompileRun(
14321 "function Foo() {"
14322 " this.foo = 11;"
14323 " this.__defineGetter__('baz', function() { return 1; });"
14324 "};"
14325 "function Bar() { "
14326 " this.bar = 13;"
14327 " this.__defineGetter__('bla', function() { return 2; });"
14328 "};"
14329 "Bar.prototype = new Foo();"
14330 "new Bar();");
14331 CHECK(value->IsObject());
14332 Handle<Object> object = value->ToObject();
14333 CHECK(object->Has(v8_str("foo")));
14334 CHECK(!object->HasOwnProperty(v8_str("foo")));
14335 CHECK(object->HasOwnProperty(v8_str("bar")));
14336 CHECK(object->Has(v8_str("baz")));
14337 CHECK(!object->HasOwnProperty(v8_str("baz")));
14338 CHECK(object->HasOwnProperty(v8_str("bla")));
14339 }
14340 { // Check named getter interceptors.
14341 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14342 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14343 Handle<Object> instance = templ->NewInstance();
14344 CHECK(!instance->HasOwnProperty(v8_str("42")));
14345 CHECK(instance->HasOwnProperty(v8_str("foo")));
14346 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14347 }
14348 { // Check indexed getter interceptors.
14349 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14350 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14351 Handle<Object> instance = templ->NewInstance();
14352 CHECK(instance->HasOwnProperty(v8_str("42")));
14353 CHECK(!instance->HasOwnProperty(v8_str("43")));
14354 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14355 }
14356 { // Check named query interceptors.
14357 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14358 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14359 Handle<Object> instance = templ->NewInstance();
14360 CHECK(instance->HasOwnProperty(v8_str("foo")));
14361 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14362 }
14363 { // Check indexed query interceptors.
14364 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14365 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14366 Handle<Object> instance = templ->NewInstance();
14367 CHECK(instance->HasOwnProperty(v8_str("42")));
14368 CHECK(!instance->HasOwnProperty(v8_str("41")));
14369 }
14370 { // Check callbacks.
14371 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14372 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14373 Handle<Object> instance = templ->NewInstance();
14374 CHECK(instance->HasOwnProperty(v8_str("foo")));
14375 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14376 }
14377 { // Check that query wins on disagreement.
14378 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14379 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14380 0,
14381 HasOwnPropertyNamedPropertyQuery2);
14382 Handle<Object> instance = templ->NewInstance();
14383 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14384 CHECK(instance->HasOwnProperty(v8_str("bar")));
14385 }
14386}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014387
14388
14389void CheckCodeGenerationAllowed() {
14390 Handle<Value> result = CompileRun("eval('42')");
14391 CHECK_EQ(42, result->Int32Value());
14392 result = CompileRun("(function(e) { return e('42'); })(eval)");
14393 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014394 result = CompileRun("var f = new Function('return 42'); f()");
14395 CHECK_EQ(42, result->Int32Value());
14396}
14397
14398
14399void CheckCodeGenerationDisallowed() {
14400 TryCatch try_catch;
14401
14402 Handle<Value> result = CompileRun("eval('42')");
14403 CHECK(result.IsEmpty());
14404 CHECK(try_catch.HasCaught());
14405 try_catch.Reset();
14406
14407 result = CompileRun("(function(e) { return e('42'); })(eval)");
14408 CHECK(result.IsEmpty());
14409 CHECK(try_catch.HasCaught());
14410 try_catch.Reset();
14411
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014412 result = CompileRun("var f = new Function('return 42'); f()");
14413 CHECK(result.IsEmpty());
14414 CHECK(try_catch.HasCaught());
14415}
14416
14417
14418bool CodeGenerationAllowed(Local<Context> context) {
14419 ApiTestFuzzer::Fuzz();
14420 return true;
14421}
14422
14423
14424bool CodeGenerationDisallowed(Local<Context> context) {
14425 ApiTestFuzzer::Fuzz();
14426 return false;
14427}
14428
14429
14430THREADED_TEST(AllowCodeGenFromStrings) {
14431 v8::HandleScope scope;
14432 LocalContext context;
14433
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014434 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014435 CheckCodeGenerationAllowed();
14436
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014437 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014438 context->AllowCodeGenerationFromStrings(false);
14439 CheckCodeGenerationDisallowed();
14440
14441 // Allow again.
14442 context->AllowCodeGenerationFromStrings(true);
14443 CheckCodeGenerationAllowed();
14444
14445 // Disallow but setting a global callback that will allow the calls.
14446 context->AllowCodeGenerationFromStrings(false);
14447 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14448 CheckCodeGenerationAllowed();
14449
14450 // Set a callback that disallows the code generation.
14451 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14452 CheckCodeGenerationDisallowed();
14453}
lrn@chromium.org1c092762011-05-09 09:42:16 +000014454
14455
14456static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14457 return v8::Undefined();
14458}
14459
14460
14461THREADED_TEST(CallAPIFunctionOnNonObject) {
14462 v8::HandleScope scope;
14463 LocalContext context;
14464 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14465 Handle<Function> function = templ->GetFunction();
14466 context->Global()->Set(v8_str("f"), function);
14467 TryCatch try_catch;
14468 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000014469}