blob: ed01532303b6231714103942ce1eb30610b828b6 [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
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001029THREADED_TEST(IsNativeError) {
1030 v8::HandleScope scope;
1031 LocalContext env;
1032 v8::Handle<Value> syntax_error = CompileRun(
1033 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034 CHECK(syntax_error->IsNativeError());
1035 v8::Handle<Value> not_error = CompileRun("{a:42}");
1036 CHECK(!not_error->IsNativeError());
1037 v8::Handle<Value> not_object = CompileRun("42");
1038 CHECK(!not_object->IsNativeError());
1039}
1040
1041
1042THREADED_TEST(StringObject) {
1043 v8::HandleScope scope;
1044 LocalContext env;
1045 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046 CHECK(boxed_string->IsStringObject());
1047 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048 CHECK(!unboxed_string->IsStringObject());
1049 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050 CHECK(!boxed_not_string->IsStringObject());
1051 v8::Handle<Value> not_object = CompileRun("0");
1052 CHECK(!not_object->IsStringObject());
1053 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054 CHECK(!as_boxed.IsEmpty());
1055 Local<v8::String> the_string = as_boxed->StringValue();
1056 CHECK(!the_string.IsEmpty());
1057 ExpectObject("\"test\"", the_string);
1058 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059 CHECK(new_boxed_string->IsStringObject());
1060 as_boxed = new_boxed_string.As<v8::StringObject>();
1061 the_string = as_boxed->StringValue();
1062 CHECK(!the_string.IsEmpty());
1063 ExpectObject("\"test\"", the_string);
1064}
1065
1066
1067THREADED_TEST(NumberObject) {
1068 v8::HandleScope scope;
1069 LocalContext env;
1070 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071 CHECK(boxed_number->IsNumberObject());
1072 v8::Handle<Value> unboxed_number = CompileRun("42");
1073 CHECK(!unboxed_number->IsNumberObject());
1074 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075 CHECK(!boxed_not_number->IsNumberObject());
1076 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077 CHECK(!as_boxed.IsEmpty());
1078 double the_number = as_boxed->NumberValue();
1079 CHECK_EQ(42.0, the_number);
1080 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081 CHECK(new_boxed_number->IsNumberObject());
1082 as_boxed = new_boxed_number.As<v8::NumberObject>();
1083 the_number = as_boxed->NumberValue();
1084 CHECK_EQ(43.0, the_number);
1085}
1086
1087
1088THREADED_TEST(BooleanObject) {
1089 v8::HandleScope scope;
1090 LocalContext env;
1091 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092 CHECK(boxed_boolean->IsBooleanObject());
1093 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094 CHECK(!unboxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096 CHECK(!boxed_not_boolean->IsBooleanObject());
1097 v8::Handle<v8::BooleanObject> as_boxed =
1098 boxed_boolean.As<v8::BooleanObject>();
1099 CHECK(!as_boxed.IsEmpty());
1100 bool the_boolean = as_boxed->BooleanValue();
1101 CHECK_EQ(true, the_boolean);
1102 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104 CHECK(boxed_true->IsBooleanObject());
1105 CHECK(boxed_false->IsBooleanObject());
1106 as_boxed = boxed_true.As<v8::BooleanObject>();
1107 CHECK_EQ(true, as_boxed->BooleanValue());
1108 as_boxed = boxed_false.As<v8::BooleanObject>();
1109 CHECK_EQ(false, as_boxed->BooleanValue());
1110}
1111
1112
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001113THREADED_TEST(Number) {
1114 v8::HandleScope scope;
1115 LocalContext env;
1116 double PI = 3.1415926;
1117 Local<v8::Number> pi_obj = v8::Number::New(PI);
1118 CHECK_EQ(PI, pi_obj->NumberValue());
1119}
1120
1121
1122THREADED_TEST(ToNumber) {
1123 v8::HandleScope scope;
1124 LocalContext env;
1125 Local<String> str = v8_str("3.1415926");
1126 CHECK_EQ(3.1415926, str->NumberValue());
1127 v8::Handle<v8::Boolean> t = v8::True();
1128 CHECK_EQ(1.0, t->NumberValue());
1129 v8::Handle<v8::Boolean> f = v8::False();
1130 CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
1135 v8::HandleScope scope;
1136 LocalContext env;
1137 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001138 Local<Value> date = v8::Date::New(PI);
1139 CHECK_EQ(3.0, date->NumberValue());
1140 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001142}
1143
1144
1145THREADED_TEST(Boolean) {
1146 v8::HandleScope scope;
1147 LocalContext env;
1148 v8::Handle<v8::Boolean> t = v8::True();
1149 CHECK(t->Value());
1150 v8::Handle<v8::Boolean> f = v8::False();
1151 CHECK(!f->Value());
1152 v8::Handle<v8::Primitive> u = v8::Undefined();
1153 CHECK(!u->BooleanValue());
1154 v8::Handle<v8::Primitive> n = v8::Null();
1155 CHECK(!n->BooleanValue());
1156 v8::Handle<String> str1 = v8_str("");
1157 CHECK(!str1->BooleanValue());
1158 v8::Handle<String> str2 = v8_str("x");
1159 CHECK(str2->BooleanValue());
1160 CHECK(!v8::Number::New(0)->BooleanValue());
1161 CHECK(v8::Number::New(-1)->BooleanValue());
1162 CHECK(v8::Number::New(1)->BooleanValue());
1163 CHECK(v8::Number::New(42)->BooleanValue());
1164 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165}
1166
1167
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169 ApiTestFuzzer::Fuzz();
1170 return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175 ApiTestFuzzer::Fuzz();
1176 return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181 v8::HandleScope scope;
1182 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1183 func_templ->PrototypeTemplate()->Set(
1184 "dummy",
1185 v8::FunctionTemplate::New(DummyCallHandler));
1186 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187 templ->Set("x", v8_num(200));
1188 templ->SetAccessor(v8_str("m"), GetM);
1189 LocalContext env(0, templ);
1190 v8::Handle<v8::Object> obj = env->Global();
1191 v8::Handle<Script> script = v8_compile("dummy()");
1192 v8::Handle<Value> result = script->Run();
1193 CHECK_EQ(13.4, result->NumberValue());
1194 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1195 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1196}
1197
1198
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199THREADED_TEST(ObjectTemplate) {
1200 v8::HandleScope scope;
1201 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1202 templ1->Set("x", v8_num(10));
1203 templ1->Set("y", v8_num(13));
1204 LocalContext env;
1205 Local<v8::Object> instance1 = templ1->NewInstance();
1206 env->Global()->Set(v8_str("p"), instance1);
1207 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1208 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1209 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1210 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1211 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1212 templ2->Set("a", v8_num(12));
1213 templ2->Set("b", templ1);
1214 Local<v8::Object> instance2 = templ2->NewInstance();
1215 env->Global()->Set(v8_str("q"), instance2);
1216 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1217 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1218 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1220}
1221
1222
1223static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1224 ApiTestFuzzer::Fuzz();
1225 return v8_num(17.2);
1226}
1227
1228
1229static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1230 ApiTestFuzzer::Fuzz();
1231 return v8_num(15.2);
1232}
1233
1234
1235THREADED_TEST(DescriptorInheritance) {
1236 v8::HandleScope scope;
1237 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1238 super->PrototypeTemplate()->Set("flabby",
1239 v8::FunctionTemplate::New(GetFlabby));
1240 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1241
1242 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1243
1244 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1245 base1->Inherit(super);
1246 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1247
1248 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1249 base2->Inherit(super);
1250 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1251
1252 LocalContext env;
1253
1254 env->Global()->Set(v8_str("s"), super->GetFunction());
1255 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1256 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1257
1258 // Checks right __proto__ chain.
1259 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1260 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1261
1262 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1263
1264 // Instance accessor should not be visible on function object or its prototype
1265 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1266 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1267 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1268
1269 env->Global()->Set(v8_str("obj"),
1270 base1->GetFunction()->NewInstance());
1271 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1272 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1273 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1274 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1275 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1276
1277 env->Global()->Set(v8_str("obj2"),
1278 base2->GetFunction()->NewInstance());
1279 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1280 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1281 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1282 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1283 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1284
1285 // base1 and base2 cannot cross reference to each's prototype
1286 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1287 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1288}
1289
1290
1291int echo_named_call_count;
1292
1293
1294static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1295 const AccessorInfo& info) {
1296 ApiTestFuzzer::Fuzz();
1297 CHECK_EQ(v8_str("data"), info.Data());
1298 echo_named_call_count++;
1299 return name;
1300}
1301
1302
1303THREADED_TEST(NamedPropertyHandlerGetter) {
1304 echo_named_call_count = 0;
1305 v8::HandleScope scope;
1306 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1307 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1308 0, 0, 0, 0,
1309 v8_str("data"));
1310 LocalContext env;
1311 env->Global()->Set(v8_str("obj"),
1312 templ->GetFunction()->NewInstance());
1313 CHECK_EQ(echo_named_call_count, 0);
1314 v8_compile("obj.x")->Run();
1315 CHECK_EQ(echo_named_call_count, 1);
1316 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1317 v8::Handle<Value> str = CompileRun(code);
1318 String::AsciiValue value(str);
1319 CHECK_EQ(*value, "oddlepoddle");
1320 // Check default behavior
1321 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1322 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1323 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1324}
1325
1326
1327int echo_indexed_call_count = 0;
1328
1329
1330static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1331 const AccessorInfo& info) {
1332 ApiTestFuzzer::Fuzz();
1333 CHECK_EQ(v8_num(637), info.Data());
1334 echo_indexed_call_count++;
1335 return v8_num(index);
1336}
1337
1338
1339THREADED_TEST(IndexedPropertyHandlerGetter) {
1340 v8::HandleScope scope;
1341 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1342 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1343 0, 0, 0, 0,
1344 v8_num(637));
1345 LocalContext env;
1346 env->Global()->Set(v8_str("obj"),
1347 templ->GetFunction()->NewInstance());
1348 Local<Script> script = v8_compile("obj[900]");
1349 CHECK_EQ(script->Run()->Int32Value(), 900);
1350}
1351
1352
1353v8::Handle<v8::Object> bottom;
1354
1355static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1356 uint32_t index,
1357 const AccessorInfo& info) {
1358 ApiTestFuzzer::Fuzz();
1359 CHECK(info.This()->Equals(bottom));
1360 return v8::Handle<Value>();
1361}
1362
1363static v8::Handle<Value> CheckThisNamedPropertyHandler(
1364 Local<String> name,
1365 const AccessorInfo& info) {
1366 ApiTestFuzzer::Fuzz();
1367 CHECK(info.This()->Equals(bottom));
1368 return v8::Handle<Value>();
1369}
1370
1371
1372v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1373 Local<Value> value,
1374 const AccessorInfo& info) {
1375 ApiTestFuzzer::Fuzz();
1376 CHECK(info.This()->Equals(bottom));
1377 return v8::Handle<Value>();
1378}
1379
1380
1381v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1382 Local<Value> value,
1383 const AccessorInfo& info) {
1384 ApiTestFuzzer::Fuzz();
1385 CHECK(info.This()->Equals(bottom));
1386 return v8::Handle<Value>();
1387}
1388
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001389v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001390 uint32_t index,
1391 const AccessorInfo& info) {
1392 ApiTestFuzzer::Fuzz();
1393 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001394 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001395}
1396
1397
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001398v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001399 const AccessorInfo& info) {
1400 ApiTestFuzzer::Fuzz();
1401 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001402 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001403}
1404
1405
1406v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1407 uint32_t index,
1408 const AccessorInfo& info) {
1409 ApiTestFuzzer::Fuzz();
1410 CHECK(info.This()->Equals(bottom));
1411 return v8::Handle<v8::Boolean>();
1412}
1413
1414
1415v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1416 Local<String> property,
1417 const AccessorInfo& info) {
1418 ApiTestFuzzer::Fuzz();
1419 CHECK(info.This()->Equals(bottom));
1420 return v8::Handle<v8::Boolean>();
1421}
1422
1423
1424v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1425 const AccessorInfo& info) {
1426 ApiTestFuzzer::Fuzz();
1427 CHECK(info.This()->Equals(bottom));
1428 return v8::Handle<v8::Array>();
1429}
1430
1431
1432v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1433 const AccessorInfo& info) {
1434 ApiTestFuzzer::Fuzz();
1435 CHECK(info.This()->Equals(bottom));
1436 return v8::Handle<v8::Array>();
1437}
1438
1439
1440THREADED_TEST(PropertyHandlerInPrototype) {
1441 v8::HandleScope scope;
1442 LocalContext env;
1443
1444 // Set up a prototype chain with three interceptors.
1445 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1446 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1447 CheckThisIndexedPropertyHandler,
1448 CheckThisIndexedPropertySetter,
1449 CheckThisIndexedPropertyQuery,
1450 CheckThisIndexedPropertyDeleter,
1451 CheckThisIndexedPropertyEnumerator);
1452
1453 templ->InstanceTemplate()->SetNamedPropertyHandler(
1454 CheckThisNamedPropertyHandler,
1455 CheckThisNamedPropertySetter,
1456 CheckThisNamedPropertyQuery,
1457 CheckThisNamedPropertyDeleter,
1458 CheckThisNamedPropertyEnumerator);
1459
1460 bottom = templ->GetFunction()->NewInstance();
1461 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1462 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1463
1464 bottom->Set(v8_str("__proto__"), middle);
1465 middle->Set(v8_str("__proto__"), top);
1466 env->Global()->Set(v8_str("obj"), bottom);
1467
1468 // Indexed and named get.
1469 Script::Compile(v8_str("obj[0]"))->Run();
1470 Script::Compile(v8_str("obj.x"))->Run();
1471
1472 // Indexed and named set.
1473 Script::Compile(v8_str("obj[1] = 42"))->Run();
1474 Script::Compile(v8_str("obj.y = 42"))->Run();
1475
1476 // Indexed and named query.
1477 Script::Compile(v8_str("0 in obj"))->Run();
1478 Script::Compile(v8_str("'x' in obj"))->Run();
1479
1480 // Indexed and named deleter.
1481 Script::Compile(v8_str("delete obj[0]"))->Run();
1482 Script::Compile(v8_str("delete obj.x"))->Run();
1483
1484 // Enumerators.
1485 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1486}
1487
1488
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001489static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1490 const AccessorInfo& info) {
1491 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001492 if (v8_str("pre")->Equals(key)) {
1493 return v8_str("PrePropertyHandler: pre");
1494 }
1495 return v8::Handle<String>();
1496}
1497
1498
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001499static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1500 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001501 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001502 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001503 }
1504
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001505 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001506}
1507
1508
1509THREADED_TEST(PrePropertyHandler) {
1510 v8::HandleScope scope;
1511 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1512 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1513 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001514 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001515 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001516 Script::Compile(v8_str(
1517 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1518 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1519 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1520 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1521 CHECK_EQ(v8_str("Object: on"), result_on);
1522 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1523 CHECK(result_post.IsEmpty());
1524}
1525
1526
ager@chromium.org870a0b62008-11-04 11:43:05 +00001527THREADED_TEST(UndefinedIsNotEnumerable) {
1528 v8::HandleScope scope;
1529 LocalContext env;
1530 v8::Handle<Value> result = Script::Compile(v8_str(
1531 "this.propertyIsEnumerable(undefined)"))->Run();
1532 CHECK(result->IsFalse());
1533}
1534
1535
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001536v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001537static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001538
1539
1540static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1541 ApiTestFuzzer::Fuzz();
1542 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1543 if (depth == kTargetRecursionDepth) return v8::Undefined();
1544 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1545 return call_recursively_script->Run();
1546}
1547
1548
1549static v8::Handle<Value> CallFunctionRecursivelyCall(
1550 const v8::Arguments& args) {
1551 ApiTestFuzzer::Fuzz();
1552 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1553 if (depth == kTargetRecursionDepth) {
1554 printf("[depth = %d]\n", depth);
1555 return v8::Undefined();
1556 }
1557 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1558 v8::Handle<Value> function =
1559 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001560 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001561}
1562
1563
1564THREADED_TEST(DeepCrossLanguageRecursion) {
1565 v8::HandleScope scope;
1566 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1567 global->Set(v8_str("callScriptRecursively"),
1568 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1569 global->Set(v8_str("callFunctionRecursively"),
1570 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1571 LocalContext env(NULL, global);
1572
1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574 call_recursively_script = v8_compile("callScriptRecursively()");
1575 v8::Handle<Value> result = call_recursively_script->Run();
1576 call_recursively_script = v8::Handle<Script>();
1577
1578 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1579 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1580}
1581
1582
1583static v8::Handle<Value>
1584 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1585 ApiTestFuzzer::Fuzz();
1586 return v8::ThrowException(key);
1587}
1588
1589
1590static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1591 Local<Value>,
1592 const AccessorInfo&) {
1593 v8::ThrowException(key);
1594 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1595}
1596
1597
1598THREADED_TEST(CallbackExceptionRegression) {
1599 v8::HandleScope scope;
1600 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1601 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1602 ThrowingPropertyHandlerSet);
1603 LocalContext env;
1604 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1605 v8::Handle<Value> otto = Script::Compile(v8_str(
1606 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1607 CHECK_EQ(v8_str("otto"), otto);
1608 v8::Handle<Value> netto = Script::Compile(v8_str(
1609 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1610 CHECK_EQ(v8_str("netto"), netto);
1611}
1612
1613
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001614THREADED_TEST(FunctionPrototype) {
1615 v8::HandleScope scope;
1616 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1617 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1618 LocalContext env;
1619 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1620 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1621 CHECK_EQ(script->Run()->Int32Value(), 321);
1622}
1623
1624
1625THREADED_TEST(InternalFields) {
1626 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001627 LocalContext env;
1628
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001629 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1630 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1631 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001632 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1633 CHECK_EQ(1, obj->InternalFieldCount());
1634 CHECK(obj->GetInternalField(0)->IsUndefined());
1635 obj->SetInternalField(0, v8_num(17));
1636 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1637}
1638
1639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001640THREADED_TEST(GlobalObjectInternalFields) {
1641 v8::HandleScope scope;
1642 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1643 global_template->SetInternalFieldCount(1);
1644 LocalContext env(NULL, global_template);
1645 v8::Handle<v8::Object> global_proxy = env->Global();
1646 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1647 CHECK_EQ(1, global->InternalFieldCount());
1648 CHECK(global->GetInternalField(0)->IsUndefined());
1649 global->SetInternalField(0, v8_num(17));
1650 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1651}
1652
1653
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001654THREADED_TEST(InternalFieldsNativePointers) {
1655 v8::HandleScope scope;
1656 LocalContext env;
1657
1658 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1659 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1660 instance_templ->SetInternalFieldCount(1);
1661 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1662 CHECK_EQ(1, obj->InternalFieldCount());
1663 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1664
1665 char* data = new char[100];
1666
1667 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001668 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001669 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001670 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001671
1672 // Check reading and writing aligned pointers.
1673 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001674 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001675 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1676
1677 // Check reading and writing unaligned pointers.
1678 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001680 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1681
1682 delete[] data;
1683}
1684
1685
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001686THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1687 v8::HandleScope scope;
1688 LocalContext env;
1689
1690 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1691 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1692 instance_templ->SetInternalFieldCount(1);
1693 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1694 CHECK_EQ(1, obj->InternalFieldCount());
1695 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1696
1697 char* data = new char[100];
1698
1699 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001700 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001701 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001702 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001703
1704 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001706 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1707
1708 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001709 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001710 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1711
1712 obj->SetInternalField(0, v8::External::Wrap(aligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001714 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1715
1716 obj->SetInternalField(0, v8::External::Wrap(unaligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001718 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1719
1720 delete[] data;
1721}
1722
1723
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001724THREADED_TEST(IdentityHash) {
1725 v8::HandleScope scope;
1726 LocalContext env;
1727
1728 // Ensure that the test starts with an fresh heap to test whether the hash
1729 // code is based on the address.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001731 Local<v8::Object> obj = v8::Object::New();
1732 int hash = obj->GetIdentityHash();
1733 int hash1 = obj->GetIdentityHash();
1734 CHECK_EQ(hash, hash1);
1735 int hash2 = v8::Object::New()->GetIdentityHash();
1736 // Since the identity hash is essentially a random number two consecutive
1737 // objects should not be assigned the same hash code. If the test below fails
1738 // the random number generator should be evaluated.
1739 CHECK_NE(hash, hash2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001741 int hash3 = v8::Object::New()->GetIdentityHash();
1742 // Make sure that the identity hash is not based on the initial address of
1743 // the object alone. If the test below fails the random number generator
1744 // should be evaluated.
1745 CHECK_NE(hash, hash3);
1746 int hash4 = obj->GetIdentityHash();
1747 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001748
1749 // Check identity hashes behaviour in the presence of JS accessors.
1750 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1751 {
1752 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1753 Local<v8::Object> o1 = v8::Object::New();
1754 Local<v8::Object> o2 = v8::Object::New();
1755 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1756 }
1757 {
1758 CompileRun(
1759 "function cnst() { return 42; };\n"
1760 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1761 Local<v8::Object> o1 = v8::Object::New();
1762 Local<v8::Object> o2 = v8::Object::New();
1763 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1764 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001765}
1766
1767
1768THREADED_TEST(HiddenProperties) {
1769 v8::HandleScope scope;
1770 LocalContext env;
1771
1772 v8::Local<v8::Object> obj = v8::Object::New();
1773 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1774 v8::Local<v8::String> empty = v8_str("");
1775 v8::Local<v8::String> prop_name = v8_str("prop_name");
1776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001778
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001779 // Make sure delete of a non-existent hidden value works
1780 CHECK(obj->DeleteHiddenValue(key));
1781
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001782 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1783 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1784 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1785 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001788
1789 // Make sure we do not find the hidden property.
1790 CHECK(!obj->Has(empty));
1791 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1792 CHECK(obj->Get(empty)->IsUndefined());
1793 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1794 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1795 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1796 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001799
1800 // Add another property and delete it afterwards to force the object in
1801 // slow case.
1802 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1803 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1804 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1805 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1806 CHECK(obj->Delete(prop_name));
1807 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1808
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001810
1811 CHECK(obj->DeleteHiddenValue(key));
1812 CHECK(obj->GetHiddenValue(key).IsEmpty());
1813}
1814
1815
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001816static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001817static v8::Handle<Value> InterceptorForHiddenProperties(
1818 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001819 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001820 return v8::Handle<Value>();
1821}
1822
1823
1824THREADED_TEST(HiddenPropertiesWithInterceptors) {
1825 v8::HandleScope scope;
1826 LocalContext context;
1827
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001828 interceptor_for_hidden_properties_called = false;
1829
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001830 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1831
1832 // Associate an interceptor with an object and start setting hidden values.
1833 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1834 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1835 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1836 Local<v8::Function> function = fun_templ->GetFunction();
1837 Local<v8::Object> obj = function->NewInstance();
1838 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1839 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001840 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001841}
1842
1843
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001844THREADED_TEST(External) {
1845 v8::HandleScope scope;
1846 int x = 3;
1847 Local<v8::External> ext = v8::External::New(&x);
1848 LocalContext env;
1849 env->Global()->Set(v8_str("ext"), ext);
1850 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001851 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001852 int* ptr = static_cast<int*>(reext->Value());
1853 CHECK_EQ(x, 3);
1854 *ptr = 10;
1855 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001856
1857 // Make sure unaligned pointers are wrapped properly.
1858 char* data = i::StrDup("0123456789");
1859 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1860 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1861 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1862 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1863
1864 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1865 CHECK_EQ('0', *char_ptr);
1866 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1867 CHECK_EQ('1', *char_ptr);
1868 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1869 CHECK_EQ('2', *char_ptr);
1870 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1871 CHECK_EQ('3', *char_ptr);
1872 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001873}
1874
1875
1876THREADED_TEST(GlobalHandle) {
1877 v8::Persistent<String> global;
1878 {
1879 v8::HandleScope scope;
1880 Local<String> str = v8_str("str");
1881 global = v8::Persistent<String>::New(str);
1882 }
1883 CHECK_EQ(global->Length(), 3);
1884 global.Dispose();
1885}
1886
1887
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001888static int NumberOfWeakCalls = 0;
1889static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1890 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1891 NumberOfWeakCalls++;
1892 handle.Dispose();
1893}
1894
1895THREADED_TEST(ApiObjectGroups) {
1896 HandleScope scope;
1897 LocalContext env;
1898
1899 NumberOfWeakCalls = 0;
1900
1901 Persistent<Object> g1s1;
1902 Persistent<Object> g1s2;
1903 Persistent<Object> g1c1;
1904 Persistent<Object> g2s1;
1905 Persistent<Object> g2s2;
1906 Persistent<Object> g2c1;
1907
1908 {
1909 HandleScope scope;
1910 g1s1 = Persistent<Object>::New(Object::New());
1911 g1s2 = Persistent<Object>::New(Object::New());
1912 g1c1 = Persistent<Object>::New(Object::New());
1913 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1915 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1916
1917 g2s1 = Persistent<Object>::New(Object::New());
1918 g2s2 = Persistent<Object>::New(Object::New());
1919 g2c1 = Persistent<Object>::New(Object::New());
1920 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1921 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1922 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1923 }
1924
1925 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1926
1927 // Connect group 1 and 2, make a cycle.
1928 CHECK(g1s2->Set(0, g2s2));
1929 CHECK(g2s1->Set(0, g1s1));
1930
1931 {
1932 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1933 Persistent<Value> g1_children[] = { g1c1 };
1934 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1935 Persistent<Value> g2_children[] = { g2c1 };
1936 V8::AddObjectGroup(g1_objects, 2);
1937 V8::AddImplicitReferences(g1s1, g1_children, 1);
1938 V8::AddObjectGroup(g2_objects, 2);
1939 V8::AddImplicitReferences(g2s2, g2_children, 1);
1940 }
1941 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001943
1944 // All object should be alive.
1945 CHECK_EQ(0, NumberOfWeakCalls);
1946
1947 // Weaken the root.
1948 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1949 // But make children strong roots---all the objects (except for children)
1950 // should be collectable now.
1951 g1c1.ClearWeak();
1952 g2c1.ClearWeak();
1953
1954 // Groups are deleted, rebuild groups.
1955 {
1956 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1957 Persistent<Value> g1_children[] = { g1c1 };
1958 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1959 Persistent<Value> g2_children[] = { g2c1 };
1960 V8::AddObjectGroup(g1_objects, 2);
1961 V8::AddImplicitReferences(g1s1, g1_children, 1);
1962 V8::AddObjectGroup(g2_objects, 2);
1963 V8::AddImplicitReferences(g2s2, g2_children, 1);
1964 }
1965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001967
1968 // All objects should be gone. 5 global handles in total.
1969 CHECK_EQ(5, NumberOfWeakCalls);
1970
1971 // And now make children weak again and collect them.
1972 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1973 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001976 CHECK_EQ(7, NumberOfWeakCalls);
1977}
1978
1979
1980THREADED_TEST(ApiObjectGroupsCycle) {
1981 HandleScope scope;
1982 LocalContext env;
1983
1984 NumberOfWeakCalls = 0;
1985
1986 Persistent<Object> g1s1;
1987 Persistent<Object> g1s2;
1988 Persistent<Object> g2s1;
1989 Persistent<Object> g2s2;
1990 Persistent<Object> g3s1;
1991 Persistent<Object> g3s2;
1992
1993 {
1994 HandleScope scope;
1995 g1s1 = Persistent<Object>::New(Object::New());
1996 g1s2 = Persistent<Object>::New(Object::New());
1997 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1998 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1999
2000 g2s1 = Persistent<Object>::New(Object::New());
2001 g2s2 = Persistent<Object>::New(Object::New());
2002 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2003 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2004
2005 g3s1 = Persistent<Object>::New(Object::New());
2006 g3s2 = Persistent<Object>::New(Object::New());
2007 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2008 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2009 }
2010
2011 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2012
2013 // Connect groups. We're building the following cycle:
2014 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2015 // groups.
2016 {
2017 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2018 Persistent<Value> g1_children[] = { g2s1 };
2019 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2020 Persistent<Value> g2_children[] = { g3s1 };
2021 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2022 Persistent<Value> g3_children[] = { g1s1 };
2023 V8::AddObjectGroup(g1_objects, 2);
2024 V8::AddImplicitReferences(g1s1, g1_children, 1);
2025 V8::AddObjectGroup(g2_objects, 2);
2026 V8::AddImplicitReferences(g2s1, g2_children, 1);
2027 V8::AddObjectGroup(g3_objects, 2);
2028 V8::AddImplicitReferences(g3s1, g3_children, 1);
2029 }
2030 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002032
2033 // All object should be alive.
2034 CHECK_EQ(0, NumberOfWeakCalls);
2035
2036 // Weaken the root.
2037 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2038
2039 // Groups are deleted, rebuild groups.
2040 {
2041 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2042 Persistent<Value> g1_children[] = { g2s1 };
2043 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2044 Persistent<Value> g2_children[] = { g3s1 };
2045 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2046 Persistent<Value> g3_children[] = { g1s1 };
2047 V8::AddObjectGroup(g1_objects, 2);
2048 V8::AddImplicitReferences(g1s1, g1_children, 1);
2049 V8::AddObjectGroup(g2_objects, 2);
2050 V8::AddImplicitReferences(g2s1, g2_children, 1);
2051 V8::AddObjectGroup(g3_objects, 2);
2052 V8::AddImplicitReferences(g3s1, g3_children, 1);
2053 }
2054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002056
2057 // All objects should be gone. 7 global handles in total.
2058 CHECK_EQ(7, NumberOfWeakCalls);
2059}
2060
2061
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002062THREADED_TEST(ScriptException) {
2063 v8::HandleScope scope;
2064 LocalContext env;
2065 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2066 v8::TryCatch try_catch;
2067 Local<Value> result = script->Run();
2068 CHECK(result.IsEmpty());
2069 CHECK(try_catch.HasCaught());
2070 String::AsciiValue exception_value(try_catch.Exception());
2071 CHECK_EQ(*exception_value, "panama!");
2072}
2073
2074
2075bool message_received;
2076
2077
2078static void check_message(v8::Handle<v8::Message> message,
2079 v8::Handle<Value> data) {
2080 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002081 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002082 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002083 message_received = true;
2084}
2085
2086
2087THREADED_TEST(MessageHandlerData) {
2088 message_received = false;
2089 v8::HandleScope scope;
2090 CHECK(!message_received);
2091 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2092 LocalContext context;
2093 v8::ScriptOrigin origin =
2094 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002095 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2096 &origin);
2097 script->SetData(v8_str("7.56"));
2098 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002099 CHECK(message_received);
2100 // clear out the message listener
2101 v8::V8::RemoveMessageListeners(check_message);
2102}
2103
2104
2105THREADED_TEST(GetSetProperty) {
2106 v8::HandleScope scope;
2107 LocalContext context;
2108 context->Global()->Set(v8_str("foo"), v8_num(14));
2109 context->Global()->Set(v8_str("12"), v8_num(92));
2110 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2111 context->Global()->Set(v8_num(13), v8_num(56));
2112 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2113 CHECK_EQ(14, foo->Int32Value());
2114 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2115 CHECK_EQ(92, twelve->Int32Value());
2116 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2117 CHECK_EQ(32, sixteen->Int32Value());
2118 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2119 CHECK_EQ(56, thirteen->Int32Value());
2120 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2121 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2122 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2123 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2124 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2125 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2126 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2127 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2128 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2129}
2130
2131
2132THREADED_TEST(PropertyAttributes) {
2133 v8::HandleScope scope;
2134 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002135 // none
2136 Local<String> prop = v8_str("none");
2137 context->Global()->Set(prop, v8_num(7));
2138 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002139 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002140 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002141 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2142 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002143 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002144 Script::Compile(v8_str("read_only = 9"))->Run();
2145 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2146 context->Global()->Set(prop, v8_num(10));
2147 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2148 // dont-delete
2149 prop = v8_str("dont_delete");
2150 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2151 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2152 Script::Compile(v8_str("delete dont_delete"))->Run();
2153 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002154 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2155 // dont-enum
2156 prop = v8_str("dont_enum");
2157 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2158 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2159 // absent
2160 prop = v8_str("absent");
2161 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2162 Local<Value> fake_prop = v8_num(1);
2163 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2164 // exception
2165 TryCatch try_catch;
2166 Local<Value> exception =
2167 CompileRun("({ toString: function() { throw 'exception';} })");
2168 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2169 CHECK(try_catch.HasCaught());
2170 String::AsciiValue exception_value(try_catch.Exception());
2171 CHECK_EQ("exception", *exception_value);
2172 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173}
2174
2175
2176THREADED_TEST(Array) {
2177 v8::HandleScope scope;
2178 LocalContext context;
2179 Local<v8::Array> array = v8::Array::New();
2180 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002181 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002182 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002183 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002184 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002185 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002186 CHECK_EQ(3, array->Length());
2187 CHECK(!array->Has(0));
2188 CHECK(!array->Has(1));
2189 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002190 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002191 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002192 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002193 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002194 CHECK_EQ(1, arr->Get(0)->Int32Value());
2195 CHECK_EQ(2, arr->Get(1)->Int32Value());
2196 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002197 array = v8::Array::New(27);
2198 CHECK_EQ(27, array->Length());
2199 array = v8::Array::New(-27);
2200 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002201}
2202
2203
2204v8::Handle<Value> HandleF(const v8::Arguments& args) {
2205 v8::HandleScope scope;
2206 ApiTestFuzzer::Fuzz();
2207 Local<v8::Array> result = v8::Array::New(args.Length());
2208 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002209 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002210 return scope.Close(result);
2211}
2212
2213
2214THREADED_TEST(Vector) {
2215 v8::HandleScope scope;
2216 Local<ObjectTemplate> global = ObjectTemplate::New();
2217 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2218 LocalContext context(0, global);
2219
2220 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002221 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002222 CHECK_EQ(0, a0->Length());
2223
2224 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002225 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002226 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002227 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002228
2229 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002230 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002231 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002232 CHECK_EQ(12, a2->Get(0)->Int32Value());
2233 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002234
2235 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002236 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002237 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002238 CHECK_EQ(14, a3->Get(0)->Int32Value());
2239 CHECK_EQ(15, a3->Get(1)->Int32Value());
2240 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002241
2242 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002243 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002244 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002245 CHECK_EQ(17, a4->Get(0)->Int32Value());
2246 CHECK_EQ(18, a4->Get(1)->Int32Value());
2247 CHECK_EQ(19, a4->Get(2)->Int32Value());
2248 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002249}
2250
2251
2252THREADED_TEST(FunctionCall) {
2253 v8::HandleScope scope;
2254 LocalContext context;
2255 CompileRun(
2256 "function Foo() {"
2257 " var result = [];"
2258 " for (var i = 0; i < arguments.length; i++) {"
2259 " result.push(arguments[i]);"
2260 " }"
2261 " return result;"
2262 "}");
2263 Local<Function> Foo =
2264 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2265
2266 v8::Handle<Value>* args0 = NULL;
2267 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2268 CHECK_EQ(0, a0->Length());
2269
2270 v8::Handle<Value> args1[] = { v8_num(1.1) };
2271 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2272 CHECK_EQ(1, a1->Length());
2273 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2274
2275 v8::Handle<Value> args2[] = { v8_num(2.2),
2276 v8_num(3.3) };
2277 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2278 CHECK_EQ(2, a2->Length());
2279 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2280 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2281
2282 v8::Handle<Value> args3[] = { v8_num(4.4),
2283 v8_num(5.5),
2284 v8_num(6.6) };
2285 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2286 CHECK_EQ(3, a3->Length());
2287 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2288 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2289 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2290
2291 v8::Handle<Value> args4[] = { v8_num(7.7),
2292 v8_num(8.8),
2293 v8_num(9.9),
2294 v8_num(10.11) };
2295 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2296 CHECK_EQ(4, a4->Length());
2297 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2298 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2299 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2300 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2301}
2302
2303
2304static const char* js_code_causing_out_of_memory =
2305 "var a = new Array(); while(true) a.push(a);";
2306
2307
2308// These tests run for a long time and prevent us from running tests
2309// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002310TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002311 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002312 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002313 // Set heap limits.
2314 static const int K = 1024;
2315 v8::ResourceConstraints constraints;
2316 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002317 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318 v8::SetResourceConstraints(&constraints);
2319
2320 // Execute a script that causes out of memory.
2321 v8::HandleScope scope;
2322 LocalContext context;
2323 v8::V8::IgnoreOutOfMemoryException();
2324 Local<Script> script =
2325 Script::Compile(String::New(js_code_causing_out_of_memory));
2326 Local<Value> result = script->Run();
2327
2328 // Check for out of memory state.
2329 CHECK(result.IsEmpty());
2330 CHECK(context->HasOutOfMemoryException());
2331}
2332
2333
2334v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2335 ApiTestFuzzer::Fuzz();
2336
2337 v8::HandleScope scope;
2338 LocalContext context;
2339 Local<Script> script =
2340 Script::Compile(String::New(js_code_causing_out_of_memory));
2341 Local<Value> result = script->Run();
2342
2343 // Check for out of memory state.
2344 CHECK(result.IsEmpty());
2345 CHECK(context->HasOutOfMemoryException());
2346
2347 return result;
2348}
2349
2350
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002351TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002352 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002353 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002354 // Set heap limits.
2355 static const int K = 1024;
2356 v8::ResourceConstraints constraints;
2357 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002358 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002359 v8::SetResourceConstraints(&constraints);
2360
2361 v8::HandleScope scope;
2362 Local<ObjectTemplate> templ = ObjectTemplate::New();
2363 templ->Set(v8_str("ProvokeOutOfMemory"),
2364 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2365 LocalContext context(0, templ);
2366 v8::V8::IgnoreOutOfMemoryException();
2367 Local<Value> result = CompileRun(
2368 "var thrown = false;"
2369 "try {"
2370 " ProvokeOutOfMemory();"
2371 "} catch (e) {"
2372 " thrown = true;"
2373 "}");
2374 // Check for out of memory state.
2375 CHECK(result.IsEmpty());
2376 CHECK(context->HasOutOfMemoryException());
2377}
2378
2379
2380TEST(HugeConsStringOutOfMemory) {
2381 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002382 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002383 // Set heap limits.
2384 static const int K = 1024;
2385 v8::ResourceConstraints constraints;
2386 constraints.set_max_young_space_size(256 * K);
2387 constraints.set_max_old_space_size(2 * K * K);
2388 v8::SetResourceConstraints(&constraints);
2389
2390 // Execute a script that causes out of memory.
2391 v8::V8::IgnoreOutOfMemoryException();
2392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002393 v8::HandleScope scope;
2394 LocalContext context;
2395
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002396 // Build huge string. This should fail with out of memory exception.
2397 Local<Value> result = CompileRun(
2398 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002399 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002400
2401 // Check for out of memory state.
2402 CHECK(result.IsEmpty());
2403 CHECK(context->HasOutOfMemoryException());
2404}
2405
2406
2407THREADED_TEST(ConstructCall) {
2408 v8::HandleScope scope;
2409 LocalContext context;
2410 CompileRun(
2411 "function Foo() {"
2412 " var result = [];"
2413 " for (var i = 0; i < arguments.length; i++) {"
2414 " result.push(arguments[i]);"
2415 " }"
2416 " return result;"
2417 "}");
2418 Local<Function> Foo =
2419 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2420
2421 v8::Handle<Value>* args0 = NULL;
2422 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2423 CHECK_EQ(0, a0->Length());
2424
2425 v8::Handle<Value> args1[] = { v8_num(1.1) };
2426 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2427 CHECK_EQ(1, a1->Length());
2428 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2429
2430 v8::Handle<Value> args2[] = { v8_num(2.2),
2431 v8_num(3.3) };
2432 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2433 CHECK_EQ(2, a2->Length());
2434 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2435 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2436
2437 v8::Handle<Value> args3[] = { v8_num(4.4),
2438 v8_num(5.5),
2439 v8_num(6.6) };
2440 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2441 CHECK_EQ(3, a3->Length());
2442 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2443 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2444 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2445
2446 v8::Handle<Value> args4[] = { v8_num(7.7),
2447 v8_num(8.8),
2448 v8_num(9.9),
2449 v8_num(10.11) };
2450 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2451 CHECK_EQ(4, a4->Length());
2452 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2453 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2454 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2455 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2456}
2457
2458
2459static void CheckUncle(v8::TryCatch* try_catch) {
2460 CHECK(try_catch->HasCaught());
2461 String::AsciiValue str_value(try_catch->Exception());
2462 CHECK_EQ(*str_value, "uncle?");
2463 try_catch->Reset();
2464}
2465
2466
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002467THREADED_TEST(ConversionNumber) {
2468 v8::HandleScope scope;
2469 LocalContext env;
2470 // Very large number.
2471 CompileRun("var obj = Math.pow(2,32) * 1237;");
2472 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2473 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2474 CHECK_EQ(0, obj->ToInt32()->Value());
2475 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2476 // Large number.
2477 CompileRun("var obj = -1234567890123;");
2478 obj = env->Global()->Get(v8_str("obj"));
2479 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2480 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2481 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2482 // Small positive integer.
2483 CompileRun("var obj = 42;");
2484 obj = env->Global()->Get(v8_str("obj"));
2485 CHECK_EQ(42.0, obj->ToNumber()->Value());
2486 CHECK_EQ(42, obj->ToInt32()->Value());
2487 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2488 // Negative integer.
2489 CompileRun("var obj = -37;");
2490 obj = env->Global()->Get(v8_str("obj"));
2491 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2492 CHECK_EQ(-37, obj->ToInt32()->Value());
2493 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2494 // Positive non-int32 integer.
2495 CompileRun("var obj = 0x81234567;");
2496 obj = env->Global()->Get(v8_str("obj"));
2497 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2498 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2499 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2500 // Fraction.
2501 CompileRun("var obj = 42.3;");
2502 obj = env->Global()->Get(v8_str("obj"));
2503 CHECK_EQ(42.3, obj->ToNumber()->Value());
2504 CHECK_EQ(42, obj->ToInt32()->Value());
2505 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2506 // Large negative fraction.
2507 CompileRun("var obj = -5726623061.75;");
2508 obj = env->Global()->Get(v8_str("obj"));
2509 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2510 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2511 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2512}
2513
2514
2515THREADED_TEST(isNumberType) {
2516 v8::HandleScope scope;
2517 LocalContext env;
2518 // Very large number.
2519 CompileRun("var obj = Math.pow(2,32) * 1237;");
2520 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2521 CHECK(!obj->IsInt32());
2522 CHECK(!obj->IsUint32());
2523 // Large negative number.
2524 CompileRun("var obj = -1234567890123;");
2525 obj = env->Global()->Get(v8_str("obj"));
2526 CHECK(!obj->IsInt32());
2527 CHECK(!obj->IsUint32());
2528 // Small positive integer.
2529 CompileRun("var obj = 42;");
2530 obj = env->Global()->Get(v8_str("obj"));
2531 CHECK(obj->IsInt32());
2532 CHECK(obj->IsUint32());
2533 // Negative integer.
2534 CompileRun("var obj = -37;");
2535 obj = env->Global()->Get(v8_str("obj"));
2536 CHECK(obj->IsInt32());
2537 CHECK(!obj->IsUint32());
2538 // Positive non-int32 integer.
2539 CompileRun("var obj = 0x81234567;");
2540 obj = env->Global()->Get(v8_str("obj"));
2541 CHECK(!obj->IsInt32());
2542 CHECK(obj->IsUint32());
2543 // Fraction.
2544 CompileRun("var obj = 42.3;");
2545 obj = env->Global()->Get(v8_str("obj"));
2546 CHECK(!obj->IsInt32());
2547 CHECK(!obj->IsUint32());
2548 // Large negative fraction.
2549 CompileRun("var obj = -5726623061.75;");
2550 obj = env->Global()->Get(v8_str("obj"));
2551 CHECK(!obj->IsInt32());
2552 CHECK(!obj->IsUint32());
2553}
2554
2555
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002556THREADED_TEST(ConversionException) {
2557 v8::HandleScope scope;
2558 LocalContext env;
2559 CompileRun(
2560 "function TestClass() { };"
2561 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2562 "var obj = new TestClass();");
2563 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2564
2565 v8::TryCatch try_catch;
2566
2567 Local<Value> to_string_result = obj->ToString();
2568 CHECK(to_string_result.IsEmpty());
2569 CheckUncle(&try_catch);
2570
2571 Local<Value> to_number_result = obj->ToNumber();
2572 CHECK(to_number_result.IsEmpty());
2573 CheckUncle(&try_catch);
2574
2575 Local<Value> to_integer_result = obj->ToInteger();
2576 CHECK(to_integer_result.IsEmpty());
2577 CheckUncle(&try_catch);
2578
2579 Local<Value> to_uint32_result = obj->ToUint32();
2580 CHECK(to_uint32_result.IsEmpty());
2581 CheckUncle(&try_catch);
2582
2583 Local<Value> to_int32_result = obj->ToInt32();
2584 CHECK(to_int32_result.IsEmpty());
2585 CheckUncle(&try_catch);
2586
2587 Local<Value> to_object_result = v8::Undefined()->ToObject();
2588 CHECK(to_object_result.IsEmpty());
2589 CHECK(try_catch.HasCaught());
2590 try_catch.Reset();
2591
2592 int32_t int32_value = obj->Int32Value();
2593 CHECK_EQ(0, int32_value);
2594 CheckUncle(&try_catch);
2595
2596 uint32_t uint32_value = obj->Uint32Value();
2597 CHECK_EQ(0, uint32_value);
2598 CheckUncle(&try_catch);
2599
2600 double number_value = obj->NumberValue();
2601 CHECK_NE(0, IsNaN(number_value));
2602 CheckUncle(&try_catch);
2603
2604 int64_t integer_value = obj->IntegerValue();
2605 CHECK_EQ(0.0, static_cast<double>(integer_value));
2606 CheckUncle(&try_catch);
2607}
2608
2609
2610v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2611 ApiTestFuzzer::Fuzz();
2612 return v8::ThrowException(v8_str("konto"));
2613}
2614
2615
ager@chromium.org8bb60582008-12-11 12:02:20 +00002616v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2617 if (args.Length() < 1) return v8::Boolean::New(false);
2618 v8::HandleScope scope;
2619 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002620 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2621 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002622 return v8::Boolean::New(try_catch.HasCaught());
2623}
2624
2625
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002626THREADED_TEST(APICatch) {
2627 v8::HandleScope scope;
2628 Local<ObjectTemplate> templ = ObjectTemplate::New();
2629 templ->Set(v8_str("ThrowFromC"),
2630 v8::FunctionTemplate::New(ThrowFromC));
2631 LocalContext context(0, templ);
2632 CompileRun(
2633 "var thrown = false;"
2634 "try {"
2635 " ThrowFromC();"
2636 "} catch (e) {"
2637 " thrown = true;"
2638 "}");
2639 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2640 CHECK(thrown->BooleanValue());
2641}
2642
2643
ager@chromium.org8bb60582008-12-11 12:02:20 +00002644THREADED_TEST(APIThrowTryCatch) {
2645 v8::HandleScope scope;
2646 Local<ObjectTemplate> templ = ObjectTemplate::New();
2647 templ->Set(v8_str("ThrowFromC"),
2648 v8::FunctionTemplate::New(ThrowFromC));
2649 LocalContext context(0, templ);
2650 v8::TryCatch try_catch;
2651 CompileRun("ThrowFromC();");
2652 CHECK(try_catch.HasCaught());
2653}
2654
2655
2656// Test that a try-finally block doesn't shadow a try-catch block
2657// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002658//
2659// BUG(271): Some of the exception propagation does not work on the
2660// ARM simulator because the simulator separates the C++ stack and the
2661// JS stack. This test therefore fails on the simulator. The test is
2662// not threaded to allow the threading tests to run on the simulator.
2663TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002664 v8::HandleScope scope;
2665 Local<ObjectTemplate> templ = ObjectTemplate::New();
2666 templ->Set(v8_str("CCatcher"),
2667 v8::FunctionTemplate::New(CCatcher));
2668 LocalContext context(0, templ);
2669 Local<Value> result = CompileRun("try {"
2670 " try {"
2671 " CCatcher('throw 7;');"
2672 " } finally {"
2673 " }"
2674 "} catch (e) {"
2675 "}");
2676 CHECK(result->IsTrue());
2677}
2678
2679
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002680static void check_reference_error_message(
2681 v8::Handle<v8::Message> message,
2682 v8::Handle<v8::Value> data) {
2683 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2684 CHECK(message->Get()->Equals(v8_str(reference_error)));
2685}
2686
2687
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002688static v8::Handle<Value> Fail(const v8::Arguments& args) {
2689 ApiTestFuzzer::Fuzz();
2690 CHECK(false);
2691 return v8::Undefined();
2692}
2693
2694
2695// Test that overwritten methods are not invoked on uncaught exception
2696// formatting. However, they are invoked when performing normal error
2697// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002698TEST(APIThrowMessageOverwrittenToString) {
2699 v8::HandleScope scope;
2700 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002701 Local<ObjectTemplate> templ = ObjectTemplate::New();
2702 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2703 LocalContext context(NULL, templ);
2704 CompileRun("asdf;");
2705 CompileRun("var limit = {};"
2706 "limit.valueOf = fail;"
2707 "Error.stackTraceLimit = limit;");
2708 CompileRun("asdf");
2709 CompileRun("Array.prototype.pop = fail;");
2710 CompileRun("Object.prototype.hasOwnProperty = fail;");
2711 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002712 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2713 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002714 CompileRun("ReferenceError.prototype.toString ="
2715 " function() { return 'Whoops' }");
2716 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002717 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2718 CompileRun("asdf;");
2719 CompileRun("ReferenceError.prototype.constructor = void 0;");
2720 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002721 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2722 CompileRun("asdf;");
2723 CompileRun("ReferenceError.prototype = new Object();");
2724 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002725 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2726 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002727 CompileRun("ReferenceError.prototype.constructor = new Object();"
2728 "ReferenceError.prototype.constructor.name = 1;"
2729 "Number.prototype.toString = function() { return 'Whoops'; };"
2730 "ReferenceError.prototype.toString = Object.prototype.toString;");
2731 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002732 v8::V8::RemoveMessageListeners(check_message);
2733}
2734
2735
ager@chromium.org8bb60582008-12-11 12:02:20 +00002736static void receive_message(v8::Handle<v8::Message> message,
2737 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002738 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002739 message_received = true;
2740}
2741
2742
2743TEST(APIThrowMessage) {
2744 message_received = false;
2745 v8::HandleScope scope;
2746 v8::V8::AddMessageListener(receive_message);
2747 Local<ObjectTemplate> templ = ObjectTemplate::New();
2748 templ->Set(v8_str("ThrowFromC"),
2749 v8::FunctionTemplate::New(ThrowFromC));
2750 LocalContext context(0, templ);
2751 CompileRun("ThrowFromC();");
2752 CHECK(message_received);
2753 v8::V8::RemoveMessageListeners(check_message);
2754}
2755
2756
2757TEST(APIThrowMessageAndVerboseTryCatch) {
2758 message_received = false;
2759 v8::HandleScope scope;
2760 v8::V8::AddMessageListener(receive_message);
2761 Local<ObjectTemplate> templ = ObjectTemplate::New();
2762 templ->Set(v8_str("ThrowFromC"),
2763 v8::FunctionTemplate::New(ThrowFromC));
2764 LocalContext context(0, templ);
2765 v8::TryCatch try_catch;
2766 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002767 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002768 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002769 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002770 CHECK(message_received);
2771 v8::V8::RemoveMessageListeners(check_message);
2772}
2773
2774
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002775TEST(APIStackOverflowAndVerboseTryCatch) {
2776 message_received = false;
2777 v8::HandleScope scope;
2778 v8::V8::AddMessageListener(receive_message);
2779 LocalContext context;
2780 v8::TryCatch try_catch;
2781 try_catch.SetVerbose(true);
2782 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2783 CHECK(try_catch.HasCaught());
2784 CHECK(result.IsEmpty());
2785 CHECK(message_received);
2786 v8::V8::RemoveMessageListeners(receive_message);
2787}
2788
2789
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002790THREADED_TEST(ExternalScriptException) {
2791 v8::HandleScope scope;
2792 Local<ObjectTemplate> templ = ObjectTemplate::New();
2793 templ->Set(v8_str("ThrowFromC"),
2794 v8::FunctionTemplate::New(ThrowFromC));
2795 LocalContext context(0, templ);
2796
2797 v8::TryCatch try_catch;
2798 Local<Script> script
2799 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2800 Local<Value> result = script->Run();
2801 CHECK(result.IsEmpty());
2802 CHECK(try_catch.HasCaught());
2803 String::AsciiValue exception_value(try_catch.Exception());
2804 CHECK_EQ("konto", *exception_value);
2805}
2806
2807
2808
2809v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2810 ApiTestFuzzer::Fuzz();
2811 CHECK_EQ(4, args.Length());
2812 int count = args[0]->Int32Value();
2813 int cInterval = args[2]->Int32Value();
2814 if (count == 0) {
2815 return v8::ThrowException(v8_str("FromC"));
2816 } else {
2817 Local<v8::Object> global = Context::GetCurrent()->Global();
2818 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2819 v8::Handle<Value> argv[] = { v8_num(count - 1),
2820 args[1],
2821 args[2],
2822 args[3] };
2823 if (count % cInterval == 0) {
2824 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002825 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002826 int expected = args[3]->Int32Value();
2827 if (try_catch.HasCaught()) {
2828 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002829 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002830 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002831 } else {
2832 CHECK_NE(expected, count);
2833 }
2834 return result;
2835 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002836 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002837 }
2838 }
2839}
2840
2841
2842v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2843 ApiTestFuzzer::Fuzz();
2844 CHECK_EQ(3, args.Length());
2845 bool equality = args[0]->BooleanValue();
2846 int count = args[1]->Int32Value();
2847 int expected = args[2]->Int32Value();
2848 if (equality) {
2849 CHECK_EQ(count, expected);
2850 } else {
2851 CHECK_NE(count, expected);
2852 }
2853 return v8::Undefined();
2854}
2855
2856
ager@chromium.org8bb60582008-12-11 12:02:20 +00002857THREADED_TEST(EvalInTryFinally) {
2858 v8::HandleScope scope;
2859 LocalContext context;
2860 v8::TryCatch try_catch;
2861 CompileRun("(function() {"
2862 " try {"
2863 " eval('asldkf (*&^&*^');"
2864 " } finally {"
2865 " return;"
2866 " }"
2867 "})()");
2868 CHECK(!try_catch.HasCaught());
2869}
2870
2871
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002872// This test works by making a stack of alternating JavaScript and C
2873// activations. These activations set up exception handlers with regular
2874// intervals, one interval for C activations and another for JavaScript
2875// activations. When enough activations have been created an exception is
2876// thrown and we check that the right activation catches the exception and that
2877// no other activations do. The right activation is always the topmost one with
2878// a handler, regardless of whether it is in JavaScript or C.
2879//
2880// The notation used to describe a test case looks like this:
2881//
2882// *JS[4] *C[3] @JS[2] C[1] JS[0]
2883//
2884// Each entry is an activation, either JS or C. The index is the count at that
2885// level. Stars identify activations with exception handlers, the @ identifies
2886// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002887//
2888// BUG(271): Some of the exception propagation does not work on the
2889// ARM simulator because the simulator separates the C++ stack and the
2890// JS stack. This test therefore fails on the simulator. The test is
2891// not threaded to allow the threading tests to run on the simulator.
2892TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002893 v8::HandleScope scope;
2894 Local<ObjectTemplate> templ = ObjectTemplate::New();
2895 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2896 templ->Set(v8_str("CThrowCountDown"),
2897 v8::FunctionTemplate::New(CThrowCountDown));
2898 LocalContext context(0, templ);
2899 CompileRun(
2900 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2901 " if (count == 0) throw 'FromJS';"
2902 " if (count % jsInterval == 0) {"
2903 " try {"
2904 " var value = CThrowCountDown(count - 1,"
2905 " jsInterval,"
2906 " cInterval,"
2907 " expected);"
2908 " check(false, count, expected);"
2909 " return value;"
2910 " } catch (e) {"
2911 " check(true, count, expected);"
2912 " }"
2913 " } else {"
2914 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2915 " }"
2916 "}");
2917 Local<Function> fun =
2918 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2919
2920 const int argc = 4;
2921 // count jsInterval cInterval expected
2922
2923 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2924 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2925 fun->Call(fun, argc, a0);
2926
2927 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2928 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2929 fun->Call(fun, argc, a1);
2930
2931 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2932 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2933 fun->Call(fun, argc, a2);
2934
2935 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2936 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2937 fun->Call(fun, argc, a3);
2938
2939 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2940 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2941 fun->Call(fun, argc, a4);
2942
2943 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2944 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2945 fun->Call(fun, argc, a5);
2946}
2947
2948
2949v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2950 ApiTestFuzzer::Fuzz();
2951 CHECK_EQ(1, args.Length());
2952 return v8::ThrowException(args[0]);
2953}
2954
2955
2956THREADED_TEST(ThrowValues) {
2957 v8::HandleScope scope;
2958 Local<ObjectTemplate> templ = ObjectTemplate::New();
2959 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2960 LocalContext context(0, templ);
2961 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2962 "function Run(obj) {"
2963 " try {"
2964 " Throw(obj);"
2965 " } catch (e) {"
2966 " return e;"
2967 " }"
2968 " return 'no exception';"
2969 "}"
2970 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2971 CHECK_EQ(5, result->Length());
2972 CHECK(result->Get(v8::Integer::New(0))->IsString());
2973 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2974 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2975 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2976 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2977 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2978 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2979}
2980
2981
2982THREADED_TEST(CatchZero) {
2983 v8::HandleScope scope;
2984 LocalContext context;
2985 v8::TryCatch try_catch;
2986 CHECK(!try_catch.HasCaught());
2987 Script::Compile(v8_str("throw 10"))->Run();
2988 CHECK(try_catch.HasCaught());
2989 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2990 try_catch.Reset();
2991 CHECK(!try_catch.HasCaught());
2992 Script::Compile(v8_str("throw 0"))->Run();
2993 CHECK(try_catch.HasCaught());
2994 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2995}
2996
2997
2998THREADED_TEST(CatchExceptionFromWith) {
2999 v8::HandleScope scope;
3000 LocalContext context;
3001 v8::TryCatch try_catch;
3002 CHECK(!try_catch.HasCaught());
3003 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3004 CHECK(try_catch.HasCaught());
3005}
3006
3007
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003008THREADED_TEST(TryCatchAndFinallyHidingException) {
3009 v8::HandleScope scope;
3010 LocalContext context;
3011 v8::TryCatch try_catch;
3012 CHECK(!try_catch.HasCaught());
3013 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3014 CompileRun("f({toString: function() { throw 42; }});");
3015 CHECK(!try_catch.HasCaught());
3016}
3017
3018
3019v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3020 v8::TryCatch try_catch;
3021 return v8::Undefined();
3022}
3023
3024
3025THREADED_TEST(TryCatchAndFinally) {
3026 v8::HandleScope scope;
3027 LocalContext context;
3028 context->Global()->Set(
3029 v8_str("native_with_try_catch"),
3030 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3031 v8::TryCatch try_catch;
3032 CHECK(!try_catch.HasCaught());
3033 CompileRun(
3034 "try {\n"
3035 " throw new Error('a');\n"
3036 "} finally {\n"
3037 " native_with_try_catch();\n"
3038 "}\n");
3039 CHECK(try_catch.HasCaught());
3040}
3041
3042
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003043THREADED_TEST(Equality) {
3044 v8::HandleScope scope;
3045 LocalContext context;
3046 // Check that equality works at all before relying on CHECK_EQ
3047 CHECK(v8_str("a")->Equals(v8_str("a")));
3048 CHECK(!v8_str("a")->Equals(v8_str("b")));
3049
3050 CHECK_EQ(v8_str("a"), v8_str("a"));
3051 CHECK_NE(v8_str("a"), v8_str("b"));
3052 CHECK_EQ(v8_num(1), v8_num(1));
3053 CHECK_EQ(v8_num(1.00), v8_num(1));
3054 CHECK_NE(v8_num(1), v8_num(2));
3055
3056 // Assume String is not symbol.
3057 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3058 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3059 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3060 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3061 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3062 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3063 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3064 CHECK(!not_a_number->StrictEquals(not_a_number));
3065 CHECK(v8::False()->StrictEquals(v8::False()));
3066 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3067
3068 v8::Handle<v8::Object> obj = v8::Object::New();
3069 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3070 CHECK(alias->StrictEquals(obj));
3071 alias.Dispose();
3072}
3073
3074
3075THREADED_TEST(MultiRun) {
3076 v8::HandleScope scope;
3077 LocalContext context;
3078 Local<Script> script = Script::Compile(v8_str("x"));
3079 for (int i = 0; i < 10; i++)
3080 script->Run();
3081}
3082
3083
3084static v8::Handle<Value> GetXValue(Local<String> name,
3085 const AccessorInfo& info) {
3086 ApiTestFuzzer::Fuzz();
3087 CHECK_EQ(info.Data(), v8_str("donut"));
3088 CHECK_EQ(name, v8_str("x"));
3089 return name;
3090}
3091
3092
3093THREADED_TEST(SimplePropertyRead) {
3094 v8::HandleScope scope;
3095 Local<ObjectTemplate> templ = ObjectTemplate::New();
3096 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3097 LocalContext context;
3098 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3099 Local<Script> script = Script::Compile(v8_str("obj.x"));
3100 for (int i = 0; i < 10; i++) {
3101 Local<Value> result = script->Run();
3102 CHECK_EQ(result, v8_str("x"));
3103 }
3104}
3105
ager@chromium.org5c838252010-02-19 08:53:10 +00003106THREADED_TEST(DefinePropertyOnAPIAccessor) {
3107 v8::HandleScope scope;
3108 Local<ObjectTemplate> templ = ObjectTemplate::New();
3109 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3110 LocalContext context;
3111 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3112
3113 // Uses getOwnPropertyDescriptor to check the configurable status
3114 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003115 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003116 "obj, 'x');"
3117 "prop.configurable;"));
3118 Local<Value> result = script_desc->Run();
3119 CHECK_EQ(result->BooleanValue(), true);
3120
3121 // Redefine get - but still configurable
3122 Local<Script> script_define
3123 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3124 " configurable: true };"
3125 "Object.defineProperty(obj, 'x', desc);"
3126 "obj.x"));
3127 result = script_define->Run();
3128 CHECK_EQ(result, v8_num(42));
3129
3130 // Check that the accessor is still configurable
3131 result = script_desc->Run();
3132 CHECK_EQ(result->BooleanValue(), true);
3133
3134 // Redefine to a non-configurable
3135 script_define
3136 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3137 " configurable: false };"
3138 "Object.defineProperty(obj, 'x', desc);"
3139 "obj.x"));
3140 result = script_define->Run();
3141 CHECK_EQ(result, v8_num(43));
3142 result = script_desc->Run();
3143 CHECK_EQ(result->BooleanValue(), false);
3144
3145 // Make sure that it is not possible to redefine again
3146 v8::TryCatch try_catch;
3147 result = script_define->Run();
3148 CHECK(try_catch.HasCaught());
3149 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003150 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003151}
3152
3153THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3154 v8::HandleScope scope;
3155 Local<ObjectTemplate> templ = ObjectTemplate::New();
3156 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3157 LocalContext context;
3158 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3159
3160 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3161 "Object.getOwnPropertyDescriptor( "
3162 "obj, 'x');"
3163 "prop.configurable;"));
3164 Local<Value> result = script_desc->Run();
3165 CHECK_EQ(result->BooleanValue(), true);
3166
3167 Local<Script> script_define =
3168 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3169 " configurable: true };"
3170 "Object.defineProperty(obj, 'x', desc);"
3171 "obj.x"));
3172 result = script_define->Run();
3173 CHECK_EQ(result, v8_num(42));
3174
3175
3176 result = script_desc->Run();
3177 CHECK_EQ(result->BooleanValue(), true);
3178
3179
3180 script_define =
3181 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3182 " configurable: false };"
3183 "Object.defineProperty(obj, 'x', desc);"
3184 "obj.x"));
3185 result = script_define->Run();
3186 CHECK_EQ(result, v8_num(43));
3187 result = script_desc->Run();
3188
3189 CHECK_EQ(result->BooleanValue(), false);
3190
3191 v8::TryCatch try_catch;
3192 result = script_define->Run();
3193 CHECK(try_catch.HasCaught());
3194 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003195 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003196}
3197
3198
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003199static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3200 char const* name) {
3201 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3202}
ager@chromium.org5c838252010-02-19 08:53:10 +00003203
3204
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003205THREADED_TEST(DefineAPIAccessorOnObject) {
3206 v8::HandleScope scope;
3207 Local<ObjectTemplate> templ = ObjectTemplate::New();
3208 LocalContext context;
3209
3210 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3211 CompileRun("var obj2 = {};");
3212
3213 CHECK(CompileRun("obj1.x")->IsUndefined());
3214 CHECK(CompileRun("obj2.x")->IsUndefined());
3215
3216 CHECK(GetGlobalProperty(&context, "obj1")->
3217 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3218
3219 ExpectString("obj1.x", "x");
3220 CHECK(CompileRun("obj2.x")->IsUndefined());
3221
3222 CHECK(GetGlobalProperty(&context, "obj2")->
3223 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3224
3225 ExpectString("obj1.x", "x");
3226 ExpectString("obj2.x", "x");
3227
3228 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3229 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3230
3231 CompileRun("Object.defineProperty(obj1, 'x',"
3232 "{ get: function() { return 'y'; }, configurable: true })");
3233
3234 ExpectString("obj1.x", "y");
3235 ExpectString("obj2.x", "x");
3236
3237 CompileRun("Object.defineProperty(obj2, 'x',"
3238 "{ get: function() { return 'y'; }, configurable: true })");
3239
3240 ExpectString("obj1.x", "y");
3241 ExpectString("obj2.x", "y");
3242
3243 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3244 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3245
3246 CHECK(GetGlobalProperty(&context, "obj1")->
3247 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3248 CHECK(GetGlobalProperty(&context, "obj2")->
3249 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3250
3251 ExpectString("obj1.x", "x");
3252 ExpectString("obj2.x", "x");
3253
3254 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3255 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3256
3257 // Define getters/setters, but now make them not configurable.
3258 CompileRun("Object.defineProperty(obj1, 'x',"
3259 "{ get: function() { return 'z'; }, configurable: false })");
3260 CompileRun("Object.defineProperty(obj2, 'x',"
3261 "{ get: function() { return 'z'; }, configurable: false })");
3262
3263 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3264 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3265
3266 ExpectString("obj1.x", "z");
3267 ExpectString("obj2.x", "z");
3268
3269 CHECK(!GetGlobalProperty(&context, "obj1")->
3270 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3271 CHECK(!GetGlobalProperty(&context, "obj2")->
3272 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3273
3274 ExpectString("obj1.x", "z");
3275 ExpectString("obj2.x", "z");
3276}
3277
3278
3279THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3280 v8::HandleScope scope;
3281 Local<ObjectTemplate> templ = ObjectTemplate::New();
3282 LocalContext context;
3283
3284 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3285 CompileRun("var obj2 = {};");
3286
3287 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3288 v8_str("x"),
3289 GetXValue, NULL,
3290 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3291 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3292 v8_str("x"),
3293 GetXValue, NULL,
3294 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3295
3296 ExpectString("obj1.x", "x");
3297 ExpectString("obj2.x", "x");
3298
3299 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3300 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3301
3302 CHECK(!GetGlobalProperty(&context, "obj1")->
3303 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3304 CHECK(!GetGlobalProperty(&context, "obj2")->
3305 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3306
3307 {
3308 v8::TryCatch try_catch;
3309 CompileRun("Object.defineProperty(obj1, 'x',"
3310 "{get: function() { return 'func'; }})");
3311 CHECK(try_catch.HasCaught());
3312 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003313 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003314 }
3315 {
3316 v8::TryCatch try_catch;
3317 CompileRun("Object.defineProperty(obj2, 'x',"
3318 "{get: function() { return 'func'; }})");
3319 CHECK(try_catch.HasCaught());
3320 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003321 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003322 }
3323}
3324
3325
3326static v8::Handle<Value> Get239Value(Local<String> name,
3327 const AccessorInfo& info) {
3328 ApiTestFuzzer::Fuzz();
3329 CHECK_EQ(info.Data(), v8_str("donut"));
3330 CHECK_EQ(name, v8_str("239"));
3331 return name;
3332}
3333
3334
3335THREADED_TEST(ElementAPIAccessor) {
3336 v8::HandleScope scope;
3337 Local<ObjectTemplate> templ = ObjectTemplate::New();
3338 LocalContext context;
3339
3340 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3341 CompileRun("var obj2 = {};");
3342
3343 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3344 v8_str("239"),
3345 Get239Value, NULL,
3346 v8_str("donut")));
3347 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3348 v8_str("239"),
3349 Get239Value, NULL,
3350 v8_str("donut")));
3351
3352 ExpectString("obj1[239]", "239");
3353 ExpectString("obj2[239]", "239");
3354 ExpectString("obj1['239']", "239");
3355 ExpectString("obj2['239']", "239");
3356}
3357
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003358
3359v8::Persistent<Value> xValue;
3360
3361
3362static void SetXValue(Local<String> name,
3363 Local<Value> value,
3364 const AccessorInfo& info) {
3365 CHECK_EQ(value, v8_num(4));
3366 CHECK_EQ(info.Data(), v8_str("donut"));
3367 CHECK_EQ(name, v8_str("x"));
3368 CHECK(xValue.IsEmpty());
3369 xValue = v8::Persistent<Value>::New(value);
3370}
3371
3372
3373THREADED_TEST(SimplePropertyWrite) {
3374 v8::HandleScope scope;
3375 Local<ObjectTemplate> templ = ObjectTemplate::New();
3376 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3377 LocalContext context;
3378 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3379 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3380 for (int i = 0; i < 10; i++) {
3381 CHECK(xValue.IsEmpty());
3382 script->Run();
3383 CHECK_EQ(v8_num(4), xValue);
3384 xValue.Dispose();
3385 xValue = v8::Persistent<Value>();
3386 }
3387}
3388
3389
3390static v8::Handle<Value> XPropertyGetter(Local<String> property,
3391 const AccessorInfo& info) {
3392 ApiTestFuzzer::Fuzz();
3393 CHECK(info.Data()->IsUndefined());
3394 return property;
3395}
3396
3397
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003398THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003399 v8::HandleScope scope;
3400 Local<ObjectTemplate> templ = ObjectTemplate::New();
3401 templ->SetNamedPropertyHandler(XPropertyGetter);
3402 LocalContext context;
3403 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3404 Local<Script> script = Script::Compile(v8_str("obj.x"));
3405 for (int i = 0; i < 10; i++) {
3406 Local<Value> result = script->Run();
3407 CHECK_EQ(result, v8_str("x"));
3408 }
3409}
3410
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003411
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003412THREADED_TEST(NamedInterceptorDictionaryIC) {
3413 v8::HandleScope scope;
3414 Local<ObjectTemplate> templ = ObjectTemplate::New();
3415 templ->SetNamedPropertyHandler(XPropertyGetter);
3416 LocalContext context;
3417 // Create an object with a named interceptor.
3418 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3419 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3420 for (int i = 0; i < 10; i++) {
3421 Local<Value> result = script->Run();
3422 CHECK_EQ(result, v8_str("x"));
3423 }
3424 // Create a slow case object and a function accessing a property in
3425 // that slow case object (with dictionary probing in generated
3426 // code). Then force object with a named interceptor into slow-case,
3427 // pass it to the function, and check that the interceptor is called
3428 // instead of accessing the local property.
3429 Local<Value> result =
3430 CompileRun("function get_x(o) { return o.x; };"
3431 "var obj = { x : 42, y : 0 };"
3432 "delete obj.y;"
3433 "for (var i = 0; i < 10; i++) get_x(obj);"
3434 "interceptor_obj.x = 42;"
3435 "interceptor_obj.y = 10;"
3436 "delete interceptor_obj.y;"
3437 "get_x(interceptor_obj)");
3438 CHECK_EQ(result, v8_str("x"));
3439}
3440
3441
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003442THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3443 v8::HandleScope scope;
3444
3445 v8::Persistent<Context> context1 = Context::New();
3446
3447 context1->Enter();
3448 Local<ObjectTemplate> templ = ObjectTemplate::New();
3449 templ->SetNamedPropertyHandler(XPropertyGetter);
3450 // Create an object with a named interceptor.
3451 v8::Local<v8::Object> object = templ->NewInstance();
3452 context1->Global()->Set(v8_str("interceptor_obj"), object);
3453
3454 // Force the object into the slow case.
3455 CompileRun("interceptor_obj.y = 0;"
3456 "delete interceptor_obj.y;");
3457 context1->Exit();
3458
3459 {
3460 // Introduce the object into a different context.
3461 // Repeat named loads to exercise ICs.
3462 LocalContext context2;
3463 context2->Global()->Set(v8_str("interceptor_obj"), object);
3464 Local<Value> result =
3465 CompileRun("function get_x(o) { return o.x; }"
3466 "interceptor_obj.x = 42;"
3467 "for (var i=0; i != 10; i++) {"
3468 " get_x(interceptor_obj);"
3469 "}"
3470 "get_x(interceptor_obj)");
3471 // Check that the interceptor was actually invoked.
3472 CHECK_EQ(result, v8_str("x"));
3473 }
3474
3475 // Return to the original context and force some object to the slow case
3476 // to cause the NormalizedMapCache to verify.
3477 context1->Enter();
3478 CompileRun("var obj = { x : 0 }; delete obj.x;");
3479 context1->Exit();
3480
3481 context1.Dispose();
3482}
3483
3484
ager@chromium.org5c838252010-02-19 08:53:10 +00003485static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3486 const AccessorInfo& info) {
3487 // Set x on the prototype object and do not handle the get request.
3488 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003489 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003490 return v8::Handle<Value>();
3491}
3492
3493
3494// This is a regression test for http://crbug.com/20104. Map
3495// transitions should not interfere with post interceptor lookup.
3496THREADED_TEST(NamedInterceptorMapTransitionRead) {
3497 v8::HandleScope scope;
3498 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3499 Local<v8::ObjectTemplate> instance_template
3500 = function_template->InstanceTemplate();
3501 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3502 LocalContext context;
3503 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3504 // Create an instance of F and introduce a map transition for x.
3505 CompileRun("var o = new F(); o.x = 23;");
3506 // Create an instance of F and invoke the getter. The result should be 23.
3507 Local<Value> result = CompileRun("o = new F(); o.x");
3508 CHECK_EQ(result->Int32Value(), 23);
3509}
3510
3511
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003512static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3513 const AccessorInfo& info) {
3514 ApiTestFuzzer::Fuzz();
3515 if (index == 37) {
3516 return v8::Handle<Value>(v8_num(625));
3517 }
3518 return v8::Handle<Value>();
3519}
3520
3521
3522static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3523 Local<Value> value,
3524 const AccessorInfo& info) {
3525 ApiTestFuzzer::Fuzz();
3526 if (index == 39) {
3527 return value;
3528 }
3529 return v8::Handle<Value>();
3530}
3531
3532
3533THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3534 v8::HandleScope scope;
3535 Local<ObjectTemplate> templ = ObjectTemplate::New();
3536 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3537 IndexedPropertySetter);
3538 LocalContext context;
3539 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3540 Local<Script> getter_script = Script::Compile(v8_str(
3541 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3542 Local<Script> setter_script = Script::Compile(v8_str(
3543 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3544 "obj[17] = 23;"
3545 "obj.foo;"));
3546 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3547 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3548 "obj[39] = 47;"
3549 "obj.foo;")); // This setter should not run, due to the interceptor.
3550 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3551 "obj[37];"));
3552 Local<Value> result = getter_script->Run();
3553 CHECK_EQ(v8_num(5), result);
3554 result = setter_script->Run();
3555 CHECK_EQ(v8_num(23), result);
3556 result = interceptor_setter_script->Run();
3557 CHECK_EQ(v8_num(23), result);
3558 result = interceptor_getter_script->Run();
3559 CHECK_EQ(v8_num(625), result);
3560}
3561
3562
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003563static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3564 uint32_t index,
3565 const AccessorInfo& info) {
3566 ApiTestFuzzer::Fuzz();
3567 if (index < 25) {
3568 return v8::Handle<Value>(v8_num(index));
3569 }
3570 return v8::Handle<Value>();
3571}
3572
3573
3574static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3575 uint32_t index,
3576 Local<Value> value,
3577 const AccessorInfo& info) {
3578 ApiTestFuzzer::Fuzz();
3579 if (index < 25) {
3580 return v8::Handle<Value>(v8_num(index));
3581 }
3582 return v8::Handle<Value>();
3583}
3584
3585
3586Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3587 const AccessorInfo& info) {
3588 // Force the list of returned keys to be stored in a FastDoubleArray.
3589 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3590 "keys = new Array(); keys[125000] = 1;"
3591 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3592 "keys.length = 25; keys;"));
3593 Local<Value> result = indexed_property_names_script->Run();
3594 return Local<v8::Array>(::v8::Array::Cast(*result));
3595}
3596
3597
3598// Make sure that the the interceptor code in the runtime properly handles
3599// merging property name lists for double-array-backed arrays.
3600THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3601 v8::HandleScope scope;
3602 Local<ObjectTemplate> templ = ObjectTemplate::New();
3603 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3604 UnboxedDoubleIndexedPropertySetter,
3605 0,
3606 0,
3607 UnboxedDoubleIndexedPropertyEnumerator);
3608 LocalContext context;
3609 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3610 // When obj is created, force it to be Stored in a FastDoubleArray.
3611 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3612 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3613 "key_count = 0; "
3614 "for (x in obj) {key_count++;};"
3615 "obj;"));
3616 Local<Value> result = create_unboxed_double_script->Run();
3617 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3618 Local<Script> key_count_check = Script::Compile(v8_str(
3619 "key_count;"));
3620 result = key_count_check->Run();
3621 CHECK_EQ(v8_num(40013), result);
3622}
3623
3624
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003625static v8::Handle<Value> IdentityIndexedPropertyGetter(
3626 uint32_t index,
3627 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003628 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003629}
3630
3631
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003632THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3633 v8::HandleScope scope;
3634 Local<ObjectTemplate> templ = ObjectTemplate::New();
3635 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3636
3637 LocalContext context;
3638 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639
3640 // Check fast object case.
3641 const char* fast_case_code =
3642 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3643 ExpectString(fast_case_code, "0");
3644
3645 // Check slow case.
3646 const char* slow_case_code =
3647 "obj.x = 1; delete obj.x;"
3648 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3649 ExpectString(slow_case_code, "1");
3650}
3651
3652
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003653THREADED_TEST(IndexedInterceptorWithNoSetter) {
3654 v8::HandleScope scope;
3655 Local<ObjectTemplate> templ = ObjectTemplate::New();
3656 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3657
3658 LocalContext context;
3659 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3660
3661 const char* code =
3662 "try {"
3663 " obj[0] = 239;"
3664 " for (var i = 0; i < 100; i++) {"
3665 " var v = obj[0];"
3666 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3667 " }"
3668 " 'PASSED'"
3669 "} catch(e) {"
3670 " e"
3671 "}";
3672 ExpectString(code, "PASSED");
3673}
3674
3675
ager@chromium.org5c838252010-02-19 08:53:10 +00003676THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3677 v8::HandleScope scope;
3678 Local<ObjectTemplate> templ = ObjectTemplate::New();
3679 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3680
3681 LocalContext context;
3682 Local<v8::Object> obj = templ->NewInstance();
3683 obj->TurnOnAccessCheck();
3684 context->Global()->Set(v8_str("obj"), obj);
3685
3686 const char* code =
3687 "try {"
3688 " for (var i = 0; i < 100; i++) {"
3689 " var v = obj[0];"
3690 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3691 " }"
3692 " 'PASSED'"
3693 "} catch(e) {"
3694 " e"
3695 "}";
3696 ExpectString(code, "PASSED");
3697}
3698
3699
3700THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3701 i::FLAG_allow_natives_syntax = true;
3702 v8::HandleScope scope;
3703 Local<ObjectTemplate> templ = ObjectTemplate::New();
3704 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3705
3706 LocalContext context;
3707 Local<v8::Object> obj = templ->NewInstance();
3708 context->Global()->Set(v8_str("obj"), obj);
3709
3710 const char* code =
3711 "try {"
3712 " for (var i = 0; i < 100; i++) {"
3713 " var expected = i;"
3714 " if (i == 5) {"
3715 " %EnableAccessChecks(obj);"
3716 " expected = undefined;"
3717 " }"
3718 " var v = obj[i];"
3719 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3720 " if (i == 5) %DisableAccessChecks(obj);"
3721 " }"
3722 " 'PASSED'"
3723 "} catch(e) {"
3724 " e"
3725 "}";
3726 ExpectString(code, "PASSED");
3727}
3728
3729
3730THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3731 v8::HandleScope scope;
3732 Local<ObjectTemplate> templ = ObjectTemplate::New();
3733 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3734
3735 LocalContext context;
3736 Local<v8::Object> obj = templ->NewInstance();
3737 context->Global()->Set(v8_str("obj"), obj);
3738
3739 const char* code =
3740 "try {"
3741 " for (var i = 0; i < 100; i++) {"
3742 " var v = obj[i];"
3743 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3744 " }"
3745 " 'PASSED'"
3746 "} catch(e) {"
3747 " e"
3748 "}";
3749 ExpectString(code, "PASSED");
3750}
3751
3752
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003753THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3754 v8::HandleScope scope;
3755 Local<ObjectTemplate> templ = ObjectTemplate::New();
3756 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3757
3758 LocalContext context;
3759 Local<v8::Object> obj = templ->NewInstance();
3760 context->Global()->Set(v8_str("obj"), obj);
3761
3762 const char* code =
3763 "try {"
3764 " for (var i = 0; i < 100; i++) {"
3765 " var expected = i;"
3766 " var key = i;"
3767 " if (i == 25) {"
3768 " key = -1;"
3769 " expected = undefined;"
3770 " }"
3771 " if (i == 50) {"
3772 " /* probe minimal Smi number on 32-bit platforms */"
3773 " key = -(1 << 30);"
3774 " expected = undefined;"
3775 " }"
3776 " if (i == 75) {"
3777 " /* probe minimal Smi number on 64-bit platforms */"
3778 " key = 1 << 31;"
3779 " expected = undefined;"
3780 " }"
3781 " var v = obj[key];"
3782 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3783 " }"
3784 " 'PASSED'"
3785 "} catch(e) {"
3786 " e"
3787 "}";
3788 ExpectString(code, "PASSED");
3789}
3790
3791
ager@chromium.org5c838252010-02-19 08:53:10 +00003792THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3793 v8::HandleScope scope;
3794 Local<ObjectTemplate> templ = ObjectTemplate::New();
3795 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3796
3797 LocalContext context;
3798 Local<v8::Object> obj = templ->NewInstance();
3799 context->Global()->Set(v8_str("obj"), obj);
3800
3801 const char* code =
3802 "try {"
3803 " for (var i = 0; i < 100; i++) {"
3804 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003805 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003807 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 " expected = undefined;"
3809 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003810 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003811 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3812 " }"
3813 " 'PASSED'"
3814 "} catch(e) {"
3815 " e"
3816 "}";
3817 ExpectString(code, "PASSED");
3818}
3819
3820
3821THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3822 v8::HandleScope scope;
3823 Local<ObjectTemplate> templ = ObjectTemplate::New();
3824 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3825
3826 LocalContext context;
3827 Local<v8::Object> obj = templ->NewInstance();
3828 context->Global()->Set(v8_str("obj"), obj);
3829
3830 const char* code =
3831 "var original = obj;"
3832 "try {"
3833 " for (var i = 0; i < 100; i++) {"
3834 " var expected = i;"
3835 " if (i == 50) {"
3836 " obj = {50: 'foobar'};"
3837 " expected = 'foobar';"
3838 " }"
3839 " var v = obj[i];"
3840 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3841 " if (i == 50) obj = original;"
3842 " }"
3843 " 'PASSED'"
3844 "} catch(e) {"
3845 " e"
3846 "}";
3847 ExpectString(code, "PASSED");
3848}
3849
3850
3851THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3852 v8::HandleScope scope;
3853 Local<ObjectTemplate> templ = ObjectTemplate::New();
3854 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3855
3856 LocalContext context;
3857 Local<v8::Object> obj = templ->NewInstance();
3858 context->Global()->Set(v8_str("obj"), obj);
3859
3860 const char* code =
3861 "var original = obj;"
3862 "try {"
3863 " for (var i = 0; i < 100; i++) {"
3864 " var expected = i;"
3865 " if (i == 5) {"
3866 " obj = 239;"
3867 " expected = undefined;"
3868 " }"
3869 " var v = obj[i];"
3870 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3871 " if (i == 5) obj = original;"
3872 " }"
3873 " 'PASSED'"
3874 "} catch(e) {"
3875 " e"
3876 "}";
3877 ExpectString(code, "PASSED");
3878}
3879
3880
3881THREADED_TEST(IndexedInterceptorOnProto) {
3882 v8::HandleScope scope;
3883 Local<ObjectTemplate> templ = ObjectTemplate::New();
3884 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3885
3886 LocalContext context;
3887 Local<v8::Object> obj = templ->NewInstance();
3888 context->Global()->Set(v8_str("obj"), obj);
3889
3890 const char* code =
3891 "var o = {__proto__: obj};"
3892 "try {"
3893 " for (var i = 0; i < 100; i++) {"
3894 " var v = o[i];"
3895 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3896 " }"
3897 " 'PASSED'"
3898 "} catch(e) {"
3899 " e"
3900 "}";
3901 ExpectString(code, "PASSED");
3902}
3903
3904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003905THREADED_TEST(MultiContexts) {
3906 v8::HandleScope scope;
3907 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3908 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3909
3910 Local<String> password = v8_str("Password");
3911
3912 // Create an environment
3913 LocalContext context0(0, templ);
3914 context0->SetSecurityToken(password);
3915 v8::Handle<v8::Object> global0 = context0->Global();
3916 global0->Set(v8_str("custom"), v8_num(1234));
3917 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3918
3919 // Create an independent environment
3920 LocalContext context1(0, templ);
3921 context1->SetSecurityToken(password);
3922 v8::Handle<v8::Object> global1 = context1->Global();
3923 global1->Set(v8_str("custom"), v8_num(1234));
3924 CHECK_NE(global0, global1);
3925 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3926 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3927
3928 // Now create a new context with the old global
3929 LocalContext context2(0, templ, global1);
3930 context2->SetSecurityToken(password);
3931 v8::Handle<v8::Object> global2 = context2->Global();
3932 CHECK_EQ(global1, global2);
3933 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3934 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3935}
3936
3937
3938THREADED_TEST(FunctionPrototypeAcrossContexts) {
3939 // Make sure that functions created by cloning boilerplates cannot
3940 // communicate through their __proto__ field.
3941
3942 v8::HandleScope scope;
3943
3944 LocalContext env0;
3945 v8::Handle<v8::Object> global0 =
3946 env0->Global();
3947 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003948 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003949 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003950 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003951 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003952 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003953 proto0->Set(v8_str("custom"), v8_num(1234));
3954
3955 LocalContext env1;
3956 v8::Handle<v8::Object> global1 =
3957 env1->Global();
3958 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003959 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003961 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003962 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003963 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003964 CHECK(!proto1->Has(v8_str("custom")));
3965}
3966
3967
3968THREADED_TEST(Regress892105) {
3969 // Make sure that object and array literals created by cloning
3970 // boilerplates cannot communicate through their __proto__
3971 // field. This is rather difficult to check, but we try to add stuff
3972 // to Object.prototype and Array.prototype and create a new
3973 // environment. This should succeed.
3974
3975 v8::HandleScope scope;
3976
3977 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3978 "Array.prototype.arr = 4567;"
3979 "8901");
3980
3981 LocalContext env0;
3982 Local<Script> script0 = Script::Compile(source);
3983 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3984
3985 LocalContext env1;
3986 Local<Script> script1 = Script::Compile(source);
3987 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3988}
3989
3990
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003991THREADED_TEST(UndetectableObject) {
3992 v8::HandleScope scope;
3993 LocalContext env;
3994
3995 Local<v8::FunctionTemplate> desc =
3996 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3997 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3998
3999 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4000 env->Global()->Set(v8_str("undetectable"), obj);
4001
4002 ExpectString("undetectable.toString()", "[object Object]");
4003 ExpectString("typeof undetectable", "undefined");
4004 ExpectString("typeof(undetectable)", "undefined");
4005 ExpectBoolean("typeof undetectable == 'undefined'", true);
4006 ExpectBoolean("typeof undetectable == 'object'", false);
4007 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4008 ExpectBoolean("!undetectable", true);
4009
4010 ExpectObject("true&&undetectable", obj);
4011 ExpectBoolean("false&&undetectable", false);
4012 ExpectBoolean("true||undetectable", true);
4013 ExpectObject("false||undetectable", obj);
4014
4015 ExpectObject("undetectable&&true", obj);
4016 ExpectObject("undetectable&&false", obj);
4017 ExpectBoolean("undetectable||true", true);
4018 ExpectBoolean("undetectable||false", false);
4019
4020 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004021 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004022 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004023 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004024 ExpectBoolean("undetectable==undetectable", true);
4025
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004027 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004028 ExpectBoolean("null===undetectable", false);
4029 ExpectBoolean("undetectable===undefined", false);
4030 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 ExpectBoolean("undetectable===undetectable", true);
4032}
4033
4034
ager@chromium.org04921a82011-06-27 13:21:41 +00004035THREADED_TEST(VoidLiteral) {
4036 v8::HandleScope scope;
4037 LocalContext env;
4038
4039 Local<v8::FunctionTemplate> desc =
4040 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4041 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4042
4043 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4044 env->Global()->Set(v8_str("undetectable"), obj);
4045
4046 ExpectBoolean("undefined == void 0", true);
4047 ExpectBoolean("undetectable == void 0", true);
4048 ExpectBoolean("null == void 0", true);
4049 ExpectBoolean("undefined === void 0", true);
4050 ExpectBoolean("undetectable === void 0", false);
4051 ExpectBoolean("null === void 0", false);
4052
4053 ExpectBoolean("void 0 == undefined", true);
4054 ExpectBoolean("void 0 == undetectable", true);
4055 ExpectBoolean("void 0 == null", true);
4056 ExpectBoolean("void 0 === undefined", true);
4057 ExpectBoolean("void 0 === undetectable", false);
4058 ExpectBoolean("void 0 === null", false);
4059
4060 ExpectString("(function() {"
4061 " try {"
4062 " return x === void 0;"
4063 " } catch(e) {"
4064 " return e.toString();"
4065 " }"
4066 "})()",
4067 "ReferenceError: x is not defined");
4068 ExpectString("(function() {"
4069 " try {"
4070 " return void 0 === x;"
4071 " } catch(e) {"
4072 " return e.toString();"
4073 " }"
4074 "})()",
4075 "ReferenceError: x is not defined");
4076}
4077
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004078
4079THREADED_TEST(ExtensibleOnUndetectable) {
4080 v8::HandleScope scope;
4081 LocalContext env;
4082
4083 Local<v8::FunctionTemplate> desc =
4084 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4085 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4086
4087 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4088 env->Global()->Set(v8_str("undetectable"), obj);
4089
4090 Local<String> source = v8_str("undetectable.x = 42;"
4091 "undetectable.x");
4092
4093 Local<Script> script = Script::Compile(source);
4094
4095 CHECK_EQ(v8::Integer::New(42), script->Run());
4096
4097 ExpectBoolean("Object.isExtensible(undetectable)", true);
4098
4099 source = v8_str("Object.preventExtensions(undetectable);");
4100 script = Script::Compile(source);
4101 script->Run();
4102 ExpectBoolean("Object.isExtensible(undetectable)", false);
4103
4104 source = v8_str("undetectable.y = 2000;");
4105 script = Script::Compile(source);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004106 Local<Value> result = script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004107 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004108}
4109
4110
4111
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004112THREADED_TEST(UndetectableString) {
4113 v8::HandleScope scope;
4114 LocalContext env;
4115
4116 Local<String> obj = String::NewUndetectable("foo");
4117 env->Global()->Set(v8_str("undetectable"), obj);
4118
4119 ExpectString("undetectable", "foo");
4120 ExpectString("typeof undetectable", "undefined");
4121 ExpectString("typeof(undetectable)", "undefined");
4122 ExpectBoolean("typeof undetectable == 'undefined'", true);
4123 ExpectBoolean("typeof undetectable == 'string'", false);
4124 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4125 ExpectBoolean("!undetectable", true);
4126
4127 ExpectObject("true&&undetectable", obj);
4128 ExpectBoolean("false&&undetectable", false);
4129 ExpectBoolean("true||undetectable", true);
4130 ExpectObject("false||undetectable", obj);
4131
4132 ExpectObject("undetectable&&true", obj);
4133 ExpectObject("undetectable&&false", obj);
4134 ExpectBoolean("undetectable||true", true);
4135 ExpectBoolean("undetectable||false", false);
4136
4137 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004138 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004140 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004141 ExpectBoolean("undetectable==undetectable", true);
4142
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004143
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004145 ExpectBoolean("null===undetectable", false);
4146 ExpectBoolean("undetectable===undefined", false);
4147 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148 ExpectBoolean("undetectable===undetectable", true);
4149}
4150
4151
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004152TEST(UndetectableOptimized) {
4153 i::FLAG_allow_natives_syntax = true;
4154 v8::HandleScope scope;
4155 LocalContext env;
4156
4157 Local<String> obj = String::NewUndetectable("foo");
4158 env->Global()->Set(v8_str("undetectable"), obj);
4159 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4160
4161 ExpectString(
4162 "function testBranch() {"
4163 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4164 " if (%_IsUndetectableObject(detectable)) throw 2;"
4165 "}\n"
4166 "function testBool() {"
4167 " var b1 = !%_IsUndetectableObject(undetectable);"
4168 " var b2 = %_IsUndetectableObject(detectable);"
4169 " if (b1) throw 3;"
4170 " if (b2) throw 4;"
4171 " return b1 == b2;"
4172 "}\n"
4173 "%OptimizeFunctionOnNextCall(testBranch);"
4174 "%OptimizeFunctionOnNextCall(testBool);"
4175 "for (var i = 0; i < 10; i++) {"
4176 " testBranch();"
4177 " testBool();"
4178 "}\n"
4179 "\"PASS\"",
4180 "PASS");
4181}
4182
4183
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184template <typename T> static void USE(T) { }
4185
4186
4187// This test is not intended to be run, just type checked.
4188static void PersistentHandles() {
4189 USE(PersistentHandles);
4190 Local<String> str = v8_str("foo");
4191 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4192 USE(p_str);
4193 Local<Script> scr = Script::Compile(v8_str(""));
4194 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4195 USE(p_scr);
4196 Local<ObjectTemplate> templ = ObjectTemplate::New();
4197 v8::Persistent<ObjectTemplate> p_templ =
4198 v8::Persistent<ObjectTemplate>::New(templ);
4199 USE(p_templ);
4200}
4201
4202
4203static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4204 ApiTestFuzzer::Fuzz();
4205 return v8::Undefined();
4206}
4207
4208
4209THREADED_TEST(GlobalObjectTemplate) {
4210 v8::HandleScope handle_scope;
4211 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4212 global_template->Set(v8_str("JSNI_Log"),
4213 v8::FunctionTemplate::New(HandleLogDelegator));
4214 v8::Persistent<Context> context = Context::New(0, global_template);
4215 Context::Scope context_scope(context);
4216 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4217 context.Dispose();
4218}
4219
4220
4221static const char* kSimpleExtensionSource =
4222 "function Foo() {"
4223 " return 4;"
4224 "}";
4225
4226
4227THREADED_TEST(SimpleExtensions) {
4228 v8::HandleScope handle_scope;
4229 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4230 const char* extension_names[] = { "simpletest" };
4231 v8::ExtensionConfiguration extensions(1, extension_names);
4232 v8::Handle<Context> context = Context::New(&extensions);
4233 Context::Scope lock(context);
4234 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4235 CHECK_EQ(result, v8::Integer::New(4));
4236}
4237
4238
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004239static const char* kEvalExtensionSource1 =
4240 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004241 " var x = 42;"
4242 " return eval('x');"
4243 "}";
4244
4245
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004246static const char* kEvalExtensionSource2 =
4247 "(function() {"
4248 " var x = 42;"
4249 " function e() {"
4250 " return eval('x');"
4251 " }"
4252 " this.UseEval2 = e;"
4253 "})()";
4254
4255
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004256THREADED_TEST(UseEvalFromExtension) {
4257 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004258 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4259 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4260 const char* extension_names[] = { "evaltest1", "evaltest2" };
4261 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004262 v8::Handle<Context> context = Context::New(&extensions);
4263 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004264 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4265 CHECK_EQ(result, v8::Integer::New(42));
4266 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004267 CHECK_EQ(result, v8::Integer::New(42));
4268}
4269
4270
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004271static const char* kWithExtensionSource1 =
4272 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004273 " var x = 42;"
4274 " with({x:87}) { return x; }"
4275 "}";
4276
4277
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004278
4279static const char* kWithExtensionSource2 =
4280 "(function() {"
4281 " var x = 42;"
4282 " function e() {"
4283 " with ({x:87}) { return x; }"
4284 " }"
4285 " this.UseWith2 = e;"
4286 "})()";
4287
4288
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004289THREADED_TEST(UseWithFromExtension) {
4290 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004291 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4292 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4293 const char* extension_names[] = { "withtest1", "withtest2" };
4294 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004295 v8::Handle<Context> context = Context::New(&extensions);
4296 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004297 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4298 CHECK_EQ(result, v8::Integer::New(87));
4299 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004300 CHECK_EQ(result, v8::Integer::New(87));
4301}
4302
4303
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004304THREADED_TEST(AutoExtensions) {
4305 v8::HandleScope handle_scope;
4306 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4307 extension->set_auto_enable(true);
4308 v8::RegisterExtension(extension);
4309 v8::Handle<Context> context = Context::New();
4310 Context::Scope lock(context);
4311 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4312 CHECK_EQ(result, v8::Integer::New(4));
4313}
4314
4315
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004316static const char* kSyntaxErrorInExtensionSource =
4317 "[";
4318
4319
4320// Test that a syntax error in an extension does not cause a fatal
4321// error but results in an empty context.
4322THREADED_TEST(SyntaxErrorExtensions) {
4323 v8::HandleScope handle_scope;
4324 v8::RegisterExtension(new Extension("syntaxerror",
4325 kSyntaxErrorInExtensionSource));
4326 const char* extension_names[] = { "syntaxerror" };
4327 v8::ExtensionConfiguration extensions(1, extension_names);
4328 v8::Handle<Context> context = Context::New(&extensions);
4329 CHECK(context.IsEmpty());
4330}
4331
4332
4333static const char* kExceptionInExtensionSource =
4334 "throw 42";
4335
4336
4337// Test that an exception when installing an extension does not cause
4338// a fatal error but results in an empty context.
4339THREADED_TEST(ExceptionExtensions) {
4340 v8::HandleScope handle_scope;
4341 v8::RegisterExtension(new Extension("exception",
4342 kExceptionInExtensionSource));
4343 const char* extension_names[] = { "exception" };
4344 v8::ExtensionConfiguration extensions(1, extension_names);
4345 v8::Handle<Context> context = Context::New(&extensions);
4346 CHECK(context.IsEmpty());
4347}
4348
4349
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004350static const char* kNativeCallInExtensionSource =
4351 "function call_runtime_last_index_of(x) {"
4352 " return %StringLastIndexOf(x, 'bob', 10);"
4353 "}";
4354
4355
4356static const char* kNativeCallTest =
4357 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4358
4359// Test that a native runtime calls are supported in extensions.
4360THREADED_TEST(NativeCallInExtensions) {
4361 v8::HandleScope handle_scope;
4362 v8::RegisterExtension(new Extension("nativecall",
4363 kNativeCallInExtensionSource));
4364 const char* extension_names[] = { "nativecall" };
4365 v8::ExtensionConfiguration extensions(1, extension_names);
4366 v8::Handle<Context> context = Context::New(&extensions);
4367 Context::Scope lock(context);
4368 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4369 CHECK_EQ(result, v8::Integer::New(3));
4370}
4371
4372
whesse@chromium.org7b260152011-06-20 15:33:18 +00004373class NativeFunctionExtension : public Extension {
4374 public:
4375 NativeFunctionExtension(const char* name,
4376 const char* source,
4377 v8::InvocationCallback fun = &Echo)
4378 : Extension(name, source),
4379 function_(fun) { }
4380
4381 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4382 v8::Handle<v8::String> name) {
4383 return v8::FunctionTemplate::New(function_);
4384 }
4385
4386 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4387 if (args.Length() >= 1) return (args[0]);
4388 return v8::Undefined();
4389 }
4390 private:
4391 v8::InvocationCallback function_;
4392};
4393
4394
4395THREADED_TEST(NativeFunctionDeclaration) {
4396 v8::HandleScope handle_scope;
4397 const char* name = "nativedecl";
4398 v8::RegisterExtension(new NativeFunctionExtension(name,
4399 "native function foo();"));
4400 const char* extension_names[] = { name };
4401 v8::ExtensionConfiguration extensions(1, extension_names);
4402 v8::Handle<Context> context = Context::New(&extensions);
4403 Context::Scope lock(context);
4404 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4405 CHECK_EQ(result, v8::Integer::New(42));
4406}
4407
4408
4409THREADED_TEST(NativeFunctionDeclarationError) {
4410 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004411 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004412 // Syntax error in extension code.
4413 v8::RegisterExtension(new NativeFunctionExtension(name,
4414 "native\nfunction foo();"));
4415 const char* extension_names[] = { name };
4416 v8::ExtensionConfiguration extensions(1, extension_names);
4417 v8::Handle<Context> context = Context::New(&extensions);
4418 ASSERT(context.IsEmpty());
4419}
4420
4421THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4422 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004423 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004424 // Syntax error in extension code - escape code in "native" means that
4425 // it's not treated as a keyword.
4426 v8::RegisterExtension(new NativeFunctionExtension(
4427 name,
4428 "nativ\\u0065 function foo();"));
4429 const char* extension_names[] = { name };
4430 v8::ExtensionConfiguration extensions(1, extension_names);
4431 v8::Handle<Context> context = Context::New(&extensions);
4432 ASSERT(context.IsEmpty());
4433}
4434
4435
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004436static void CheckDependencies(const char* name, const char* expected) {
4437 v8::HandleScope handle_scope;
4438 v8::ExtensionConfiguration config(1, &name);
4439 LocalContext context(&config);
4440 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4441}
4442
4443
4444/*
4445 * Configuration:
4446 *
4447 * /-- B <--\
4448 * A <- -- D <-- E
4449 * \-- C <--/
4450 */
4451THREADED_TEST(ExtensionDependency) {
4452 static const char* kEDeps[] = { "D" };
4453 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4454 static const char* kDDeps[] = { "B", "C" };
4455 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4456 static const char* kBCDeps[] = { "A" };
4457 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4458 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4459 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4460 CheckDependencies("A", "undefinedA");
4461 CheckDependencies("B", "undefinedAB");
4462 CheckDependencies("C", "undefinedAC");
4463 CheckDependencies("D", "undefinedABCD");
4464 CheckDependencies("E", "undefinedABCDE");
4465 v8::HandleScope handle_scope;
4466 static const char* exts[2] = { "C", "E" };
4467 v8::ExtensionConfiguration config(2, exts);
4468 LocalContext context(&config);
4469 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4470}
4471
4472
4473static const char* kExtensionTestScript =
4474 "native function A();"
4475 "native function B();"
4476 "native function C();"
4477 "function Foo(i) {"
4478 " if (i == 0) return A();"
4479 " if (i == 1) return B();"
4480 " if (i == 2) return C();"
4481 "}";
4482
4483
4484static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4485 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004486 if (args.IsConstructCall()) {
4487 args.This()->Set(v8_str("data"), args.Data());
4488 return v8::Null();
4489 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004490 return args.Data();
4491}
4492
4493
4494class FunctionExtension : public Extension {
4495 public:
4496 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4497 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4498 v8::Handle<String> name);
4499};
4500
4501
4502static int lookup_count = 0;
4503v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4504 v8::Handle<String> name) {
4505 lookup_count++;
4506 if (name->Equals(v8_str("A"))) {
4507 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4508 } else if (name->Equals(v8_str("B"))) {
4509 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4510 } else if (name->Equals(v8_str("C"))) {
4511 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4512 } else {
4513 return v8::Handle<v8::FunctionTemplate>();
4514 }
4515}
4516
4517
4518THREADED_TEST(FunctionLookup) {
4519 v8::RegisterExtension(new FunctionExtension());
4520 v8::HandleScope handle_scope;
4521 static const char* exts[1] = { "functiontest" };
4522 v8::ExtensionConfiguration config(1, exts);
4523 LocalContext context(&config);
4524 CHECK_EQ(3, lookup_count);
4525 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4526 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4527 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4528}
4529
4530
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004531THREADED_TEST(NativeFunctionConstructCall) {
4532 v8::RegisterExtension(new FunctionExtension());
4533 v8::HandleScope handle_scope;
4534 static const char* exts[1] = { "functiontest" };
4535 v8::ExtensionConfiguration config(1, exts);
4536 LocalContext context(&config);
4537 for (int i = 0; i < 10; i++) {
4538 // Run a few times to ensure that allocation of objects doesn't
4539 // change behavior of a constructor function.
4540 CHECK_EQ(v8::Integer::New(8),
4541 Script::Compile(v8_str("(new A()).data"))->Run());
4542 CHECK_EQ(v8::Integer::New(7),
4543 Script::Compile(v8_str("(new B()).data"))->Run());
4544 CHECK_EQ(v8::Integer::New(6),
4545 Script::Compile(v8_str("(new C()).data"))->Run());
4546 }
4547}
4548
4549
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004550static const char* last_location;
4551static const char* last_message;
4552void StoringErrorCallback(const char* location, const char* message) {
4553 if (last_location == NULL) {
4554 last_location = location;
4555 last_message = message;
4556 }
4557}
4558
4559
4560// ErrorReporting creates a circular extensions configuration and
4561// tests that the fatal error handler gets called. This renders V8
4562// unusable and therefore this test cannot be run in parallel.
4563TEST(ErrorReporting) {
4564 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4565 static const char* aDeps[] = { "B" };
4566 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4567 static const char* bDeps[] = { "A" };
4568 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4569 last_location = NULL;
4570 v8::ExtensionConfiguration config(1, bDeps);
4571 v8::Handle<Context> context = Context::New(&config);
4572 CHECK(context.IsEmpty());
4573 CHECK_NE(last_location, NULL);
4574}
4575
4576
ager@chromium.org7c537e22008-10-16 08:43:32 +00004577static const char* js_code_causing_huge_string_flattening =
4578 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004579 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004580 " str = str + str;"
4581 "}"
4582 "str.match(/X/);";
4583
4584
4585void OOMCallback(const char* location, const char* message) {
4586 exit(0);
4587}
4588
4589
4590TEST(RegexpOutOfMemory) {
4591 // Execute a script that causes out of memory when flattening a string.
4592 v8::HandleScope scope;
4593 v8::V8::SetFatalErrorHandler(OOMCallback);
4594 LocalContext context;
4595 Local<Script> script =
4596 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4597 last_location = NULL;
4598 Local<Value> result = script->Run();
4599
4600 CHECK(false); // Should not return.
4601}
4602
4603
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004604static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4605 v8::Handle<Value> data) {
4606 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004607 CHECK(message->GetScriptResourceName()->IsUndefined());
4608 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004609 message->GetLineNumber();
4610 message->GetSourceLine();
4611}
4612
4613
4614THREADED_TEST(ErrorWithMissingScriptInfo) {
4615 v8::HandleScope scope;
4616 LocalContext context;
4617 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4618 Script::Compile(v8_str("throw Error()"))->Run();
4619 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4620}
4621
4622
4623int global_index = 0;
4624
4625class Snorkel {
4626 public:
4627 Snorkel() { index_ = global_index++; }
4628 int index_;
4629};
4630
4631class Whammy {
4632 public:
4633 Whammy() {
4634 cursor_ = 0;
4635 }
4636 ~Whammy() {
4637 script_.Dispose();
4638 }
4639 v8::Handle<Script> getScript() {
4640 if (script_.IsEmpty())
4641 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4642 return Local<Script>(*script_);
4643 }
4644
4645 public:
4646 static const int kObjectCount = 256;
4647 int cursor_;
4648 v8::Persistent<v8::Object> objects_[kObjectCount];
4649 v8::Persistent<Script> script_;
4650};
4651
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004652static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004653 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4654 delete snorkel;
4655 obj.ClearWeak();
4656}
4657
4658v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4659 const AccessorInfo& info) {
4660 Whammy* whammy =
4661 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4662
4663 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4664
4665 v8::Handle<v8::Object> obj = v8::Object::New();
4666 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4667 if (!prev.IsEmpty()) {
4668 prev->Set(v8_str("next"), obj);
4669 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4670 whammy->objects_[whammy->cursor_].Clear();
4671 }
4672 whammy->objects_[whammy->cursor_] = global;
4673 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4674 return whammy->getScript()->Run();
4675}
4676
4677THREADED_TEST(WeakReference) {
4678 v8::HandleScope handle_scope;
4679 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004680 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004681 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4682 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004683 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004684 const char* extension_list[] = { "v8/gc" };
4685 v8::ExtensionConfiguration extensions(1, extension_list);
4686 v8::Persistent<Context> context = Context::New(&extensions);
4687 Context::Scope context_scope(context);
4688
4689 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4690 context->Global()->Set(v8_str("whammy"), interceptor);
4691 const char* code =
4692 "var last;"
4693 "for (var i = 0; i < 10000; i++) {"
4694 " var obj = whammy.length;"
4695 " if (last) last.next = obj;"
4696 " last = obj;"
4697 "}"
4698 "gc();"
4699 "4";
4700 v8::Handle<Value> result = CompileRun(code);
4701 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004702 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004703 context.Dispose();
4704}
4705
4706
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004707static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004708 obj.Dispose();
4709 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004710 *(reinterpret_cast<bool*>(data)) = true;
4711}
4712
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004713
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004714THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004715 v8::Persistent<Context> context = Context::New();
4716 Context::Scope context_scope(context);
4717
4718 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004719
4720 {
4721 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004722 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4723 }
4724
4725 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004726 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4727 object_a.MarkIndependent();
4728 HEAP->PerformScavenge();
4729 CHECK(object_a_disposed);
4730}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004731
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004732
4733static void InvokeScavenge() {
4734 HEAP->PerformScavenge();
4735}
4736
4737
4738static void InvokeMarkSweep() {
4739 HEAP->CollectAllGarbage(false);
4740}
4741
4742
4743static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4744 obj.Dispose();
4745 obj.Clear();
4746 *(reinterpret_cast<bool*>(data)) = true;
4747 InvokeScavenge();
4748}
4749
4750
4751static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4752 obj.Dispose();
4753 obj.Clear();
4754 *(reinterpret_cast<bool*>(data)) = true;
4755 InvokeMarkSweep();
4756}
4757
4758
4759THREADED_TEST(GCFromWeakCallbacks) {
4760 v8::Persistent<Context> context = Context::New();
4761 Context::Scope context_scope(context);
4762
4763 static const int kNumberOfGCTypes = 2;
4764 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4765 {&ForceScavenge, &ForceMarkSweep};
4766
4767 typedef void (*GCInvoker)();
4768 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4769
4770 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4771 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4772 v8::Persistent<v8::Object> object;
4773 {
4774 v8::HandleScope handle_scope;
4775 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4776 }
4777 bool disposed = false;
4778 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4779 object.MarkIndependent();
4780 invoke_gc[outer_gc]();
4781 CHECK(disposed);
4782 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004783 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004784}
4785
4786
4787static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4788 obj.ClearWeak();
4789 *(reinterpret_cast<bool*>(data)) = true;
4790}
4791
4792
4793THREADED_TEST(IndependentHandleRevival) {
4794 v8::Persistent<Context> context = Context::New();
4795 Context::Scope context_scope(context);
4796
4797 v8::Persistent<v8::Object> object;
4798 {
4799 v8::HandleScope handle_scope;
4800 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4801 object->Set(v8_str("x"), v8::Integer::New(1));
4802 v8::Local<String> y_str = v8_str("y");
4803 object->Set(y_str, y_str);
4804 }
4805 bool revived = false;
4806 object.MakeWeak(&revived, &RevivingCallback);
4807 object.MarkIndependent();
4808 HEAP->PerformScavenge();
4809 CHECK(revived);
4810 HEAP->CollectAllGarbage(true);
4811 {
4812 v8::HandleScope handle_scope;
4813 v8::Local<String> y_str = v8_str("y");
4814 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4815 CHECK(object->Get(y_str)->Equals(y_str));
4816 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004817}
4818
4819
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004820v8::Handle<Function> args_fun;
4821
4822
4823static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4824 ApiTestFuzzer::Fuzz();
4825 CHECK_EQ(args_fun, args.Callee());
4826 CHECK_EQ(3, args.Length());
4827 CHECK_EQ(v8::Integer::New(1), args[0]);
4828 CHECK_EQ(v8::Integer::New(2), args[1]);
4829 CHECK_EQ(v8::Integer::New(3), args[2]);
4830 CHECK_EQ(v8::Undefined(), args[3]);
4831 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004833 return v8::Undefined();
4834}
4835
4836
4837THREADED_TEST(Arguments) {
4838 v8::HandleScope scope;
4839 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4840 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4841 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004842 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004843 v8_compile("f(1, 2, 3)")->Run();
4844}
4845
4846
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004847static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4848 const AccessorInfo&) {
4849 return v8::Handle<Value>();
4850}
4851
4852
4853static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4854 const AccessorInfo&) {
4855 return v8::Handle<Value>();
4856}
4857
4858
4859static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4860 const AccessorInfo&) {
4861 if (!name->Equals(v8_str("foo"))) {
4862 return v8::Handle<v8::Boolean>(); // not intercepted
4863 }
4864
4865 return v8::False(); // intercepted, and don't delete the property
4866}
4867
4868
4869static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4870 if (index != 2) {
4871 return v8::Handle<v8::Boolean>(); // not intercepted
4872 }
4873
4874 return v8::False(); // intercepted, and don't delete the property
4875}
4876
4877
4878THREADED_TEST(Deleter) {
4879 v8::HandleScope scope;
4880 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4881 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4882 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4883 LocalContext context;
4884 context->Global()->Set(v8_str("k"), obj->NewInstance());
4885 CompileRun(
4886 "k.foo = 'foo';"
4887 "k.bar = 'bar';"
4888 "k[2] = 2;"
4889 "k[4] = 4;");
4890 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4891 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4892
4893 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4894 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4895
4896 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4897 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4898
4899 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4900 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4901}
4902
4903
4904static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4905 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004906 if (name->Equals(v8_str("foo")) ||
4907 name->Equals(v8_str("bar")) ||
4908 name->Equals(v8_str("baz"))) {
4909 return v8::Undefined();
4910 }
4911 return v8::Handle<Value>();
4912}
4913
4914
4915static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4916 ApiTestFuzzer::Fuzz();
4917 if (index == 0 || index == 1) return v8::Undefined();
4918 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004919}
4920
4921
4922static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4923 ApiTestFuzzer::Fuzz();
4924 v8::Handle<v8::Array> result = v8::Array::New(3);
4925 result->Set(v8::Integer::New(0), v8_str("foo"));
4926 result->Set(v8::Integer::New(1), v8_str("bar"));
4927 result->Set(v8::Integer::New(2), v8_str("baz"));
4928 return result;
4929}
4930
4931
4932static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4933 ApiTestFuzzer::Fuzz();
4934 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004935 result->Set(v8::Integer::New(0), v8_str("0"));
4936 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004937 return result;
4938}
4939
4940
4941THREADED_TEST(Enumerators) {
4942 v8::HandleScope scope;
4943 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4944 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004945 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004946 LocalContext context;
4947 context->Global()->Set(v8_str("k"), obj->NewInstance());
4948 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004949 "k[10] = 0;"
4950 "k.a = 0;"
4951 "k[5] = 0;"
4952 "k.b = 0;"
4953 "k[4294967295] = 0;"
4954 "k.c = 0;"
4955 "k[4294967296] = 0;"
4956 "k.d = 0;"
4957 "k[140000] = 0;"
4958 "k.e = 0;"
4959 "k[30000000000] = 0;"
4960 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004961 "var result = [];"
4962 "for (var prop in k) {"
4963 " result.push(prop);"
4964 "}"
4965 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004966 // Check that we get all the property names returned including the
4967 // ones from the enumerators in the right order: indexed properties
4968 // in numerical order, indexed interceptor properties, named
4969 // properties in insertion order, named interceptor properties.
4970 // This order is not mandated by the spec, so this test is just
4971 // documenting our behavior.
4972 CHECK_EQ(17, result->Length());
4973 // Indexed properties in numerical order.
4974 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4975 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4976 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4977 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4978 // Indexed interceptor properties in the order they are returned
4979 // from the enumerator interceptor.
4980 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4981 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4982 // Named properties in insertion order.
4983 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4984 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4985 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4986 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4987 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4988 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4989 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4990 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4991 // Named interceptor properties.
4992 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4993 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4994 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004995}
4996
4997
4998int p_getter_count;
4999int p_getter_count2;
5000
5001
5002static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5003 ApiTestFuzzer::Fuzz();
5004 p_getter_count++;
5005 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5006 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5007 if (name->Equals(v8_str("p1"))) {
5008 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5009 } else if (name->Equals(v8_str("p2"))) {
5010 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5011 } else if (name->Equals(v8_str("p3"))) {
5012 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5013 } else if (name->Equals(v8_str("p4"))) {
5014 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5015 }
5016 return v8::Undefined();
5017}
5018
5019
5020static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5021 ApiTestFuzzer::Fuzz();
5022 LocalContext context;
5023 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5024 CompileRun(
5025 "o1.__proto__ = { };"
5026 "var o2 = { __proto__: o1 };"
5027 "var o3 = { __proto__: o2 };"
5028 "var o4 = { __proto__: o3 };"
5029 "for (var i = 0; i < 10; i++) o4.p4;"
5030 "for (var i = 0; i < 10; i++) o3.p3;"
5031 "for (var i = 0; i < 10; i++) o2.p2;"
5032 "for (var i = 0; i < 10; i++) o1.p1;");
5033}
5034
5035
5036static v8::Handle<Value> PGetter2(Local<String> name,
5037 const AccessorInfo& info) {
5038 ApiTestFuzzer::Fuzz();
5039 p_getter_count2++;
5040 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5041 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5042 if (name->Equals(v8_str("p1"))) {
5043 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5044 } else if (name->Equals(v8_str("p2"))) {
5045 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5046 } else if (name->Equals(v8_str("p3"))) {
5047 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5048 } else if (name->Equals(v8_str("p4"))) {
5049 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5050 }
5051 return v8::Undefined();
5052}
5053
5054
5055THREADED_TEST(GetterHolders) {
5056 v8::HandleScope scope;
5057 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5058 obj->SetAccessor(v8_str("p1"), PGetter);
5059 obj->SetAccessor(v8_str("p2"), PGetter);
5060 obj->SetAccessor(v8_str("p3"), PGetter);
5061 obj->SetAccessor(v8_str("p4"), PGetter);
5062 p_getter_count = 0;
5063 RunHolderTest(obj);
5064 CHECK_EQ(40, p_getter_count);
5065}
5066
5067
5068THREADED_TEST(PreInterceptorHolders) {
5069 v8::HandleScope scope;
5070 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5071 obj->SetNamedPropertyHandler(PGetter2);
5072 p_getter_count2 = 0;
5073 RunHolderTest(obj);
5074 CHECK_EQ(40, p_getter_count2);
5075}
5076
5077
5078THREADED_TEST(ObjectInstantiation) {
5079 v8::HandleScope scope;
5080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5081 templ->SetAccessor(v8_str("t"), PGetter2);
5082 LocalContext context;
5083 context->Global()->Set(v8_str("o"), templ->NewInstance());
5084 for (int i = 0; i < 100; i++) {
5085 v8::HandleScope inner_scope;
5086 v8::Handle<v8::Object> obj = templ->NewInstance();
5087 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5088 context->Global()->Set(v8_str("o2"), obj);
5089 v8::Handle<Value> value =
5090 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5091 CHECK_EQ(v8::True(), value);
5092 context->Global()->Set(v8_str("o"), obj);
5093 }
5094}
5095
5096
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005097static int StrCmp16(uint16_t* a, uint16_t* b) {
5098 while (true) {
5099 if (*a == 0 && *b == 0) return 0;
5100 if (*a != *b) return 0 + *a - *b;
5101 a++;
5102 b++;
5103 }
5104}
5105
5106
5107static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5108 while (true) {
5109 if (n-- == 0) return 0;
5110 if (*a == 0 && *b == 0) return 0;
5111 if (*a != *b) return 0 + *a - *b;
5112 a++;
5113 b++;
5114 }
5115}
5116
5117
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005118THREADED_TEST(StringWrite) {
5119 v8::HandleScope scope;
5120 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121 // abc<Icelandic eth><Unicode snowman>.
5122 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5123
5124 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005125
5126 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005127 char utf8buf[100];
5128 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005129 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005130 int charlen;
5131
5132 memset(utf8buf, 0x1, sizeof(utf8buf));
5133 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005134 CHECK_EQ(9, len);
5135 CHECK_EQ(5, charlen);
5136 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005137
5138 memset(utf8buf, 0x1, sizeof(utf8buf));
5139 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005140 CHECK_EQ(8, len);
5141 CHECK_EQ(5, charlen);
5142 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005143
5144 memset(utf8buf, 0x1, sizeof(utf8buf));
5145 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005146 CHECK_EQ(5, len);
5147 CHECK_EQ(4, charlen);
5148 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005149
5150 memset(utf8buf, 0x1, sizeof(utf8buf));
5151 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005152 CHECK_EQ(5, len);
5153 CHECK_EQ(4, charlen);
5154 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155
5156 memset(utf8buf, 0x1, sizeof(utf8buf));
5157 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005158 CHECK_EQ(5, len);
5159 CHECK_EQ(4, charlen);
5160 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005161
5162 memset(utf8buf, 0x1, sizeof(utf8buf));
5163 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005164 CHECK_EQ(3, len);
5165 CHECK_EQ(3, charlen);
5166 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005167
5168 memset(utf8buf, 0x1, sizeof(utf8buf));
5169 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005170 CHECK_EQ(3, len);
5171 CHECK_EQ(3, charlen);
5172 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005173
5174 memset(utf8buf, 0x1, sizeof(utf8buf));
5175 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005176 CHECK_EQ(2, len);
5177 CHECK_EQ(2, charlen);
5178 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005179
5180 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005181 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005182 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005183 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005184 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005185 CHECK_EQ(5, len);
5186 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005187 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005188 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005189
5190 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005191 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005192 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005193 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005195 CHECK_EQ(4, len);
5196 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005197 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005198 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005199
5200 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005201 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005202 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005203 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005204 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005205 CHECK_EQ(5, len);
5206 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005207 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005208 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005209
5210 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005211 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005212 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005213 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005214 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005215 CHECK_EQ(5, len);
5216 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005217 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005218 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005219
5220 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005222 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005223 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005225 CHECK_EQ(1, len);
5226 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005227 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005228 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005229
5230 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005231 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005232 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005233 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005234 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005235 CHECK_EQ(1, len);
5236 CHECK_EQ(0, strcmp("e", buf));
5237 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005238
5239 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005240 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005241 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005242 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005243 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005244 CHECK_EQ(1, len);
5245 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005246 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005247 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005248
5249 memset(buf, 0x1, sizeof(buf));
5250 memset(wbuf, 0x1, sizeof(wbuf));
5251 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005252 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005253 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005254 CHECK_EQ(1, len);
5255 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005256 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005257 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005258}
5259
5260
5261THREADED_TEST(ToArrayIndex) {
5262 v8::HandleScope scope;
5263 LocalContext context;
5264
5265 v8::Handle<String> str = v8_str("42");
5266 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5267 CHECK(!index.IsEmpty());
5268 CHECK_EQ(42.0, index->Uint32Value());
5269 str = v8_str("42asdf");
5270 index = str->ToArrayIndex();
5271 CHECK(index.IsEmpty());
5272 str = v8_str("-42");
5273 index = str->ToArrayIndex();
5274 CHECK(index.IsEmpty());
5275 str = v8_str("4294967295");
5276 index = str->ToArrayIndex();
5277 CHECK(!index.IsEmpty());
5278 CHECK_EQ(4294967295.0, index->Uint32Value());
5279 v8::Handle<v8::Number> num = v8::Number::New(1);
5280 index = num->ToArrayIndex();
5281 CHECK(!index.IsEmpty());
5282 CHECK_EQ(1.0, index->Uint32Value());
5283 num = v8::Number::New(-1);
5284 index = num->ToArrayIndex();
5285 CHECK(index.IsEmpty());
5286 v8::Handle<v8::Object> obj = v8::Object::New();
5287 index = obj->ToArrayIndex();
5288 CHECK(index.IsEmpty());
5289}
5290
5291
5292THREADED_TEST(ErrorConstruction) {
5293 v8::HandleScope scope;
5294 LocalContext context;
5295
5296 v8::Handle<String> foo = v8_str("foo");
5297 v8::Handle<String> message = v8_str("message");
5298 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5299 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005300 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5301 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005302 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5303 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005304 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005305 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5306 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005307 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005308 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5309 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005310 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005311 v8::Handle<Value> error = v8::Exception::Error(foo);
5312 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005313 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005314}
5315
5316
5317static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5318 ApiTestFuzzer::Fuzz();
5319 return v8_num(10);
5320}
5321
5322
5323static void YSetter(Local<String> name,
5324 Local<Value> value,
5325 const AccessorInfo& info) {
5326 if (info.This()->Has(name)) {
5327 info.This()->Delete(name);
5328 }
5329 info.This()->Set(name, value);
5330}
5331
5332
5333THREADED_TEST(DeleteAccessor) {
5334 v8::HandleScope scope;
5335 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5336 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5337 LocalContext context;
5338 v8::Handle<v8::Object> holder = obj->NewInstance();
5339 context->Global()->Set(v8_str("holder"), holder);
5340 v8::Handle<Value> result = CompileRun(
5341 "holder.y = 11; holder.y = 12; holder.y");
5342 CHECK_EQ(12, result->Uint32Value());
5343}
5344
5345
5346THREADED_TEST(TypeSwitch) {
5347 v8::HandleScope scope;
5348 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5349 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5350 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5351 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5352 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5353 LocalContext context;
5354 v8::Handle<v8::Object> obj0 = v8::Object::New();
5355 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5356 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5357 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5358 for (int i = 0; i < 10; i++) {
5359 CHECK_EQ(0, type_switch->match(obj0));
5360 CHECK_EQ(1, type_switch->match(obj1));
5361 CHECK_EQ(2, type_switch->match(obj2));
5362 CHECK_EQ(3, type_switch->match(obj3));
5363 CHECK_EQ(3, type_switch->match(obj3));
5364 CHECK_EQ(2, type_switch->match(obj2));
5365 CHECK_EQ(1, type_switch->match(obj1));
5366 CHECK_EQ(0, type_switch->match(obj0));
5367 }
5368}
5369
5370
5371// For use within the TestSecurityHandler() test.
5372static bool g_security_callback_result = false;
5373static bool NamedSecurityTestCallback(Local<v8::Object> global,
5374 Local<Value> name,
5375 v8::AccessType type,
5376 Local<Value> data) {
5377 // Always allow read access.
5378 if (type == v8::ACCESS_GET)
5379 return true;
5380
5381 // Sometimes allow other access.
5382 return g_security_callback_result;
5383}
5384
5385
5386static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5387 uint32_t key,
5388 v8::AccessType type,
5389 Local<Value> data) {
5390 // Always allow read access.
5391 if (type == v8::ACCESS_GET)
5392 return true;
5393
5394 // Sometimes allow other access.
5395 return g_security_callback_result;
5396}
5397
5398
5399static int trouble_nesting = 0;
5400static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5401 ApiTestFuzzer::Fuzz();
5402 trouble_nesting++;
5403
5404 // Call a JS function that throws an uncaught exception.
5405 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5406 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5407 arg_this->Get(v8_str("trouble_callee")) :
5408 arg_this->Get(v8_str("trouble_caller"));
5409 CHECK(trouble_callee->IsFunction());
5410 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5411}
5412
5413
5414static int report_count = 0;
5415static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5416 v8::Handle<Value>) {
5417 report_count++;
5418}
5419
5420
5421// Counts uncaught exceptions, but other tests running in parallel
5422// also have uncaught exceptions.
5423TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005424 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005425 v8::HandleScope scope;
5426 LocalContext env;
5427 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5428
5429 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5430 v8::Local<v8::Object> global = env->Global();
5431 global->Set(v8_str("trouble"), fun->GetFunction());
5432
5433 Script::Compile(v8_str("function trouble_callee() {"
5434 " var x = null;"
5435 " return x.foo;"
5436 "};"
5437 "function trouble_caller() {"
5438 " trouble();"
5439 "};"))->Run();
5440 Local<Value> trouble = global->Get(v8_str("trouble"));
5441 CHECK(trouble->IsFunction());
5442 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5443 CHECK(trouble_callee->IsFunction());
5444 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5445 CHECK(trouble_caller->IsFunction());
5446 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5447 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005448 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5449}
5450
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005451static const char* script_resource_name = "ExceptionInNativeScript.js";
5452static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5453 v8::Handle<Value>) {
5454 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5455 CHECK(!name_val.IsEmpty() && name_val->IsString());
5456 v8::String::AsciiValue name(message->GetScriptResourceName());
5457 CHECK_EQ(script_resource_name, *name);
5458 CHECK_EQ(3, message->GetLineNumber());
5459 v8::String::AsciiValue source_line(message->GetSourceLine());
5460 CHECK_EQ(" new o.foo();", *source_line);
5461}
5462
5463TEST(ExceptionInNativeScript) {
5464 v8::HandleScope scope;
5465 LocalContext env;
5466 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5467
5468 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5469 v8::Local<v8::Object> global = env->Global();
5470 global->Set(v8_str("trouble"), fun->GetFunction());
5471
5472 Script::Compile(v8_str("function trouble() {\n"
5473 " var o = {};\n"
5474 " new o.foo();\n"
5475 "};"), v8::String::New(script_resource_name))->Run();
5476 Local<Value> trouble = global->Get(v8_str("trouble"));
5477 CHECK(trouble->IsFunction());
5478 Function::Cast(*trouble)->Call(global, 0, NULL);
5479 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5480}
5481
ager@chromium.org8bb60582008-12-11 12:02:20 +00005482
5483TEST(CompilationErrorUsingTryCatchHandler) {
5484 v8::HandleScope scope;
5485 LocalContext env;
5486 v8::TryCatch try_catch;
5487 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5488 CHECK_NE(NULL, *try_catch.Exception());
5489 CHECK(try_catch.HasCaught());
5490}
5491
5492
5493TEST(TryCatchFinallyUsingTryCatchHandler) {
5494 v8::HandleScope scope;
5495 LocalContext env;
5496 v8::TryCatch try_catch;
5497 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5498 CHECK(!try_catch.HasCaught());
5499 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5500 CHECK(try_catch.HasCaught());
5501 try_catch.Reset();
5502 Script::Compile(v8_str("(function() {"
5503 "try { throw ''; } finally { return; }"
5504 "})()"))->Run();
5505 CHECK(!try_catch.HasCaught());
5506 Script::Compile(v8_str("(function()"
5507 " { try { throw ''; } finally { throw 0; }"
5508 "})()"))->Run();
5509 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005510}
5511
5512
5513// SecurityHandler can't be run twice
5514TEST(SecurityHandler) {
5515 v8::HandleScope scope0;
5516 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5517 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5518 IndexedSecurityTestCallback);
5519 // Create an environment
5520 v8::Persistent<Context> context0 =
5521 Context::New(NULL, global_template);
5522 context0->Enter();
5523
5524 v8::Handle<v8::Object> global0 = context0->Global();
5525 v8::Handle<Script> script0 = v8_compile("foo = 111");
5526 script0->Run();
5527 global0->Set(v8_str("0"), v8_num(999));
5528 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5529 CHECK_EQ(111, foo0->Int32Value());
5530 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5531 CHECK_EQ(999, z0->Int32Value());
5532
5533 // Create another environment, should fail security checks.
5534 v8::HandleScope scope1;
5535
5536 v8::Persistent<Context> context1 =
5537 Context::New(NULL, global_template);
5538 context1->Enter();
5539
5540 v8::Handle<v8::Object> global1 = context1->Global();
5541 global1->Set(v8_str("othercontext"), global0);
5542 // This set will fail the security check.
5543 v8::Handle<Script> script1 =
5544 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5545 script1->Run();
5546 // This read will pass the security check.
5547 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5548 CHECK_EQ(111, foo1->Int32Value());
5549 // This read will pass the security check.
5550 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5551 CHECK_EQ(999, z1->Int32Value());
5552
5553 // Create another environment, should pass security checks.
5554 { g_security_callback_result = true; // allow security handler to pass.
5555 v8::HandleScope scope2;
5556 LocalContext context2;
5557 v8::Handle<v8::Object> global2 = context2->Global();
5558 global2->Set(v8_str("othercontext"), global0);
5559 v8::Handle<Script> script2 =
5560 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5561 script2->Run();
5562 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5563 CHECK_EQ(333, foo2->Int32Value());
5564 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5565 CHECK_EQ(888, z2->Int32Value());
5566 }
5567
5568 context1->Exit();
5569 context1.Dispose();
5570
5571 context0->Exit();
5572 context0.Dispose();
5573}
5574
5575
5576THREADED_TEST(SecurityChecks) {
5577 v8::HandleScope handle_scope;
5578 LocalContext env1;
5579 v8::Persistent<Context> env2 = Context::New();
5580
5581 Local<Value> foo = v8_str("foo");
5582 Local<Value> bar = v8_str("bar");
5583
5584 // Set to the same domain.
5585 env1->SetSecurityToken(foo);
5586
5587 // Create a function in env1.
5588 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5589 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5590 CHECK(spy->IsFunction());
5591
5592 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005593 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005594 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5595 CHECK(spy2->IsFunction());
5596
5597 // Switch to env2 in the same domain and invoke spy on env2.
5598 {
5599 env2->SetSecurityToken(foo);
5600 // Enter env2
5601 Context::Scope scope_env2(env2);
5602 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5603 CHECK(result->IsFunction());
5604 }
5605
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005606 {
5607 env2->SetSecurityToken(bar);
5608 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005609
5610 // Call cross_domain_call, it should throw an exception
5611 v8::TryCatch try_catch;
5612 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5613 CHECK(try_catch.HasCaught());
5614 }
5615
5616 env2.Dispose();
5617}
5618
5619
5620// Regression test case for issue 1183439.
5621THREADED_TEST(SecurityChecksForPrototypeChain) {
5622 v8::HandleScope scope;
5623 LocalContext current;
5624 v8::Persistent<Context> other = Context::New();
5625
5626 // Change context to be able to get to the Object function in the
5627 // other context without hitting the security checks.
5628 v8::Local<Value> other_object;
5629 { Context::Scope scope(other);
5630 other_object = other->Global()->Get(v8_str("Object"));
5631 other->Global()->Set(v8_num(42), v8_num(87));
5632 }
5633
5634 current->Global()->Set(v8_str("other"), other->Global());
5635 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5636
5637 // Make sure the security check fails here and we get an undefined
5638 // result instead of getting the Object function. Repeat in a loop
5639 // to make sure to exercise the IC code.
5640 v8::Local<Script> access_other0 = v8_compile("other.Object");
5641 v8::Local<Script> access_other1 = v8_compile("other[42]");
5642 for (int i = 0; i < 5; i++) {
5643 CHECK(!access_other0->Run()->Equals(other_object));
5644 CHECK(access_other0->Run()->IsUndefined());
5645 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5646 CHECK(access_other1->Run()->IsUndefined());
5647 }
5648
5649 // Create an object that has 'other' in its prototype chain and make
5650 // sure we cannot access the Object function indirectly through
5651 // that. Repeat in a loop to make sure to exercise the IC code.
5652 v8_compile("function F() { };"
5653 "F.prototype = other;"
5654 "var f = new F();")->Run();
5655 v8::Local<Script> access_f0 = v8_compile("f.Object");
5656 v8::Local<Script> access_f1 = v8_compile("f[42]");
5657 for (int j = 0; j < 5; j++) {
5658 CHECK(!access_f0->Run()->Equals(other_object));
5659 CHECK(access_f0->Run()->IsUndefined());
5660 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5661 CHECK(access_f1->Run()->IsUndefined());
5662 }
5663
5664 // Now it gets hairy: Set the prototype for the other global object
5665 // to be the current global object. The prototype chain for 'f' now
5666 // goes through 'other' but ends up in the current global object.
5667 { Context::Scope scope(other);
5668 other->Global()->Set(v8_str("__proto__"), current->Global());
5669 }
5670 // Set a named and an index property on the current global
5671 // object. To force the lookup to go through the other global object,
5672 // the properties must not exist in the other global object.
5673 current->Global()->Set(v8_str("foo"), v8_num(100));
5674 current->Global()->Set(v8_num(99), v8_num(101));
5675 // Try to read the properties from f and make sure that the access
5676 // gets stopped by the security checks on the other global object.
5677 Local<Script> access_f2 = v8_compile("f.foo");
5678 Local<Script> access_f3 = v8_compile("f[99]");
5679 for (int k = 0; k < 5; k++) {
5680 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5681 CHECK(access_f2->Run()->IsUndefined());
5682 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5683 CHECK(access_f3->Run()->IsUndefined());
5684 }
5685 other.Dispose();
5686}
5687
5688
5689THREADED_TEST(CrossDomainDelete) {
5690 v8::HandleScope handle_scope;
5691 LocalContext env1;
5692 v8::Persistent<Context> env2 = Context::New();
5693
5694 Local<Value> foo = v8_str("foo");
5695 Local<Value> bar = v8_str("bar");
5696
5697 // Set to the same domain.
5698 env1->SetSecurityToken(foo);
5699 env2->SetSecurityToken(foo);
5700
5701 env1->Global()->Set(v8_str("prop"), v8_num(3));
5702 env2->Global()->Set(v8_str("env1"), env1->Global());
5703
5704 // Change env2 to a different domain and delete env1.prop.
5705 env2->SetSecurityToken(bar);
5706 {
5707 Context::Scope scope_env2(env2);
5708 Local<Value> result =
5709 Script::Compile(v8_str("delete env1.prop"))->Run();
5710 CHECK(result->IsFalse());
5711 }
5712
5713 // Check that env1.prop still exists.
5714 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5715 CHECK(v->IsNumber());
5716 CHECK_EQ(3, v->Int32Value());
5717
5718 env2.Dispose();
5719}
5720
5721
ager@chromium.org870a0b62008-11-04 11:43:05 +00005722THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5723 v8::HandleScope handle_scope;
5724 LocalContext env1;
5725 v8::Persistent<Context> env2 = Context::New();
5726
5727 Local<Value> foo = v8_str("foo");
5728 Local<Value> bar = v8_str("bar");
5729
5730 // Set to the same domain.
5731 env1->SetSecurityToken(foo);
5732 env2->SetSecurityToken(foo);
5733
5734 env1->Global()->Set(v8_str("prop"), v8_num(3));
5735 env2->Global()->Set(v8_str("env1"), env1->Global());
5736
5737 // env1.prop is enumerable in env2.
5738 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5739 {
5740 Context::Scope scope_env2(env2);
5741 Local<Value> result = Script::Compile(test)->Run();
5742 CHECK(result->IsTrue());
5743 }
5744
5745 // Change env2 to a different domain and test again.
5746 env2->SetSecurityToken(bar);
5747 {
5748 Context::Scope scope_env2(env2);
5749 Local<Value> result = Script::Compile(test)->Run();
5750 CHECK(result->IsFalse());
5751 }
5752
5753 env2.Dispose();
5754}
5755
5756
ager@chromium.org236ad962008-09-25 09:45:57 +00005757THREADED_TEST(CrossDomainForIn) {
5758 v8::HandleScope handle_scope;
5759 LocalContext env1;
5760 v8::Persistent<Context> env2 = Context::New();
5761
5762 Local<Value> foo = v8_str("foo");
5763 Local<Value> bar = v8_str("bar");
5764
5765 // Set to the same domain.
5766 env1->SetSecurityToken(foo);
5767 env2->SetSecurityToken(foo);
5768
5769 env1->Global()->Set(v8_str("prop"), v8_num(3));
5770 env2->Global()->Set(v8_str("env1"), env1->Global());
5771
5772 // Change env2 to a different domain and set env1's global object
5773 // as the __proto__ of an object in env2 and enumerate properties
5774 // in for-in. It shouldn't enumerate properties on env1's global
5775 // object.
5776 env2->SetSecurityToken(bar);
5777 {
5778 Context::Scope scope_env2(env2);
5779 Local<Value> result =
5780 CompileRun("(function(){var obj = {'__proto__':env1};"
5781 "for (var p in obj)"
5782 " if (p == 'prop') return false;"
5783 "return true;})()");
5784 CHECK(result->IsTrue());
5785 }
5786 env2.Dispose();
5787}
5788
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005789
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005790TEST(ContextDetachGlobal) {
5791 v8::HandleScope handle_scope;
5792 LocalContext env1;
5793 v8::Persistent<Context> env2 = Context::New();
5794
5795 Local<v8::Object> global1 = env1->Global();
5796
5797 Local<Value> foo = v8_str("foo");
5798
5799 // Set to the same domain.
5800 env1->SetSecurityToken(foo);
5801 env2->SetSecurityToken(foo);
5802
5803 // Enter env2
5804 env2->Enter();
5805
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005806 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005807 Local<v8::Object> global2 = env2->Global();
5808 global2->Set(v8_str("prop"), v8::Integer::New(1));
5809 CompileRun("function getProp() {return prop;}");
5810
5811 env1->Global()->Set(v8_str("getProp"),
5812 global2->Get(v8_str("getProp")));
5813
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005814 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005815 env2->Exit();
5816 env2->DetachGlobal();
5817 // env2 has a new global object.
5818 CHECK(!env2->Global()->Equals(global2));
5819
5820 v8::Persistent<Context> env3 =
5821 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5822 env3->SetSecurityToken(v8_str("bar"));
5823 env3->Enter();
5824
5825 Local<v8::Object> global3 = env3->Global();
5826 CHECK_EQ(global2, global3);
5827 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5828 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5829 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5830 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5831 env3->Exit();
5832
5833 // Call getProp in env1, and it should return the value 1
5834 {
5835 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5836 CHECK(get_prop->IsFunction());
5837 v8::TryCatch try_catch;
5838 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5839 CHECK(!try_catch.HasCaught());
5840 CHECK_EQ(1, r->Int32Value());
5841 }
5842
5843 // Check that env3 is not accessible from env1
5844 {
5845 Local<Value> r = global3->Get(v8_str("prop2"));
5846 CHECK(r->IsUndefined());
5847 }
5848
5849 env2.Dispose();
5850 env3.Dispose();
5851}
5852
5853
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005854TEST(DetachAndReattachGlobal) {
5855 v8::HandleScope scope;
5856 LocalContext env1;
5857
5858 // Create second environment.
5859 v8::Persistent<Context> env2 = Context::New();
5860
5861 Local<Value> foo = v8_str("foo");
5862
5863 // Set same security token for env1 and env2.
5864 env1->SetSecurityToken(foo);
5865 env2->SetSecurityToken(foo);
5866
5867 // Create a property on the global object in env2.
5868 {
5869 v8::Context::Scope scope(env2);
5870 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5871 }
5872
5873 // Create a reference to env2 global from env1 global.
5874 env1->Global()->Set(v8_str("other"), env2->Global());
5875
5876 // Check that we have access to other.p in env2 from env1.
5877 Local<Value> result = CompileRun("other.p");
5878 CHECK(result->IsInt32());
5879 CHECK_EQ(42, result->Int32Value());
5880
5881 // Hold on to global from env2 and detach global from env2.
5882 Local<v8::Object> global2 = env2->Global();
5883 env2->DetachGlobal();
5884
5885 // Check that the global has been detached. No other.p property can
5886 // be found.
5887 result = CompileRun("other.p");
5888 CHECK(result->IsUndefined());
5889
5890 // Reuse global2 for env3.
5891 v8::Persistent<Context> env3 =
5892 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5893 CHECK_EQ(global2, env3->Global());
5894
5895 // Start by using the same security token for env3 as for env1 and env2.
5896 env3->SetSecurityToken(foo);
5897
5898 // Create a property on the global object in env3.
5899 {
5900 v8::Context::Scope scope(env3);
5901 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5902 }
5903
5904 // Check that other.p is now the property in env3 and that we have access.
5905 result = CompileRun("other.p");
5906 CHECK(result->IsInt32());
5907 CHECK_EQ(24, result->Int32Value());
5908
5909 // Change security token for env3 to something different from env1 and env2.
5910 env3->SetSecurityToken(v8_str("bar"));
5911
5912 // Check that we do not have access to other.p in env1. |other| is now
5913 // the global object for env3 which has a different security token,
5914 // so access should be blocked.
5915 result = CompileRun("other.p");
5916 CHECK(result->IsUndefined());
5917
5918 // Detach the global for env3 and reattach it to env2.
5919 env3->DetachGlobal();
5920 env2->ReattachGlobal(global2);
5921
5922 // Check that we have access to other.p again in env1. |other| is now
5923 // the global object for env2 which has the same security token as env1.
5924 result = CompileRun("other.p");
5925 CHECK(result->IsInt32());
5926 CHECK_EQ(42, result->Int32Value());
5927
5928 env2.Dispose();
5929 env3.Dispose();
5930}
5931
5932
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005933static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005934static bool NamedAccessBlocker(Local<v8::Object> global,
5935 Local<Value> name,
5936 v8::AccessType type,
5937 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005938 return Context::GetCurrent()->Global()->Equals(global) ||
5939 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005940}
5941
5942
5943static bool IndexedAccessBlocker(Local<v8::Object> global,
5944 uint32_t key,
5945 v8::AccessType type,
5946 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005947 return Context::GetCurrent()->Global()->Equals(global) ||
5948 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005949}
5950
5951
5952static int g_echo_value = -1;
5953static v8::Handle<Value> EchoGetter(Local<String> name,
5954 const AccessorInfo& info) {
5955 return v8_num(g_echo_value);
5956}
5957
5958
5959static void EchoSetter(Local<String> name,
5960 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005961 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005962 if (value->IsNumber())
5963 g_echo_value = value->Int32Value();
5964}
5965
5966
5967static v8::Handle<Value> UnreachableGetter(Local<String> name,
5968 const AccessorInfo& info) {
5969 CHECK(false); // This function should not be called..
5970 return v8::Undefined();
5971}
5972
5973
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005974static void UnreachableSetter(Local<String>, Local<Value>,
5975 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005976 CHECK(false); // This function should nto be called.
5977}
5978
5979
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005980TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005981 v8::HandleScope handle_scope;
5982 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5983
5984 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5985 IndexedAccessBlocker);
5986
5987 // Add an accessor accessible by cross-domain JS code.
5988 global_template->SetAccessor(
5989 v8_str("accessible_prop"),
5990 EchoGetter, EchoSetter,
5991 v8::Handle<Value>(),
5992 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5993
5994 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005995 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005996 UnreachableGetter, UnreachableSetter,
5997 v8::Handle<Value>(),
5998 v8::DEFAULT);
5999
6000 // Create an environment
6001 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6002 context0->Enter();
6003
6004 v8::Handle<v8::Object> global0 = context0->Global();
6005
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006006 // Define a property with JS getter and setter.
6007 CompileRun(
6008 "function getter() { return 'getter'; };\n"
6009 "function setter() { return 'setter'; }\n"
6010 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6011
6012 Local<Value> getter = global0->Get(v8_str("getter"));
6013 Local<Value> setter = global0->Get(v8_str("setter"));
6014
6015 // And define normal element.
6016 global0->Set(239, v8_str("239"));
6017
6018 // Define an element with JS getter and setter.
6019 CompileRun(
6020 "function el_getter() { return 'el_getter'; };\n"
6021 "function el_setter() { return 'el_setter'; };\n"
6022 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6023
6024 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6025 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006027 v8::HandleScope scope1;
6028
6029 v8::Persistent<Context> context1 = Context::New();
6030 context1->Enter();
6031
6032 v8::Handle<v8::Object> global1 = context1->Global();
6033 global1->Set(v8_str("other"), global0);
6034
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006035 // Access blocked property.
6036 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006037
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006038 ExpectUndefined("other.blocked_prop");
6039 ExpectUndefined(
6040 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6041 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006042
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006043 // Enable ACCESS_HAS
6044 allowed_access_type[v8::ACCESS_HAS] = true;
6045 ExpectUndefined("other.blocked_prop");
6046 // ... and now we can get the descriptor...
6047 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006048 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006049 // ... and enumerate the property.
6050 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6051 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006052
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006053 // Access blocked element.
6054 CompileRun("other[239] = 1");
6055
6056 ExpectUndefined("other[239]");
6057 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6058 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6059
6060 // Enable ACCESS_HAS
6061 allowed_access_type[v8::ACCESS_HAS] = true;
6062 ExpectUndefined("other[239]");
6063 // ... and now we can get the descriptor...
6064 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6065 // ... and enumerate the property.
6066 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6067 allowed_access_type[v8::ACCESS_HAS] = false;
6068
6069 // Access a property with JS accessor.
6070 CompileRun("other.js_accessor_p = 2");
6071
6072 ExpectUndefined("other.js_accessor_p");
6073 ExpectUndefined(
6074 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6075
6076 // Enable ACCESS_HAS.
6077 allowed_access_type[v8::ACCESS_HAS] = true;
6078 ExpectUndefined("other.js_accessor_p");
6079 ExpectUndefined(
6080 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6081 ExpectUndefined(
6082 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6083 ExpectUndefined(
6084 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6085 allowed_access_type[v8::ACCESS_HAS] = false;
6086
6087 // Enable both ACCESS_HAS and ACCESS_GET.
6088 allowed_access_type[v8::ACCESS_HAS] = true;
6089 allowed_access_type[v8::ACCESS_GET] = true;
6090
6091 ExpectString("other.js_accessor_p", "getter");
6092 ExpectObject(
6093 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6094 ExpectUndefined(
6095 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6096 ExpectUndefined(
6097 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6098
6099 allowed_access_type[v8::ACCESS_GET] = false;
6100 allowed_access_type[v8::ACCESS_HAS] = false;
6101
6102 // Enable both ACCESS_HAS and ACCESS_SET.
6103 allowed_access_type[v8::ACCESS_HAS] = true;
6104 allowed_access_type[v8::ACCESS_SET] = true;
6105
6106 ExpectUndefined("other.js_accessor_p");
6107 ExpectUndefined(
6108 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6109 ExpectObject(
6110 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6111 ExpectUndefined(
6112 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6113
6114 allowed_access_type[v8::ACCESS_SET] = false;
6115 allowed_access_type[v8::ACCESS_HAS] = false;
6116
6117 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6118 allowed_access_type[v8::ACCESS_HAS] = true;
6119 allowed_access_type[v8::ACCESS_GET] = true;
6120 allowed_access_type[v8::ACCESS_SET] = true;
6121
6122 ExpectString("other.js_accessor_p", "getter");
6123 ExpectObject(
6124 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6125 ExpectObject(
6126 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6127 ExpectUndefined(
6128 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6129
6130 allowed_access_type[v8::ACCESS_SET] = false;
6131 allowed_access_type[v8::ACCESS_GET] = false;
6132 allowed_access_type[v8::ACCESS_HAS] = false;
6133
6134 // Access an element with JS accessor.
6135 CompileRun("other[42] = 2");
6136
6137 ExpectUndefined("other[42]");
6138 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6139
6140 // Enable ACCESS_HAS.
6141 allowed_access_type[v8::ACCESS_HAS] = true;
6142 ExpectUndefined("other[42]");
6143 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6144 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6145 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6146 allowed_access_type[v8::ACCESS_HAS] = false;
6147
6148 // Enable both ACCESS_HAS and ACCESS_GET.
6149 allowed_access_type[v8::ACCESS_HAS] = true;
6150 allowed_access_type[v8::ACCESS_GET] = true;
6151
6152 ExpectString("other[42]", "el_getter");
6153 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6154 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6155 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6156
6157 allowed_access_type[v8::ACCESS_GET] = false;
6158 allowed_access_type[v8::ACCESS_HAS] = false;
6159
6160 // Enable both ACCESS_HAS and ACCESS_SET.
6161 allowed_access_type[v8::ACCESS_HAS] = true;
6162 allowed_access_type[v8::ACCESS_SET] = true;
6163
6164 ExpectUndefined("other[42]");
6165 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6166 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6167 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6168
6169 allowed_access_type[v8::ACCESS_SET] = false;
6170 allowed_access_type[v8::ACCESS_HAS] = false;
6171
6172 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6173 allowed_access_type[v8::ACCESS_HAS] = true;
6174 allowed_access_type[v8::ACCESS_GET] = true;
6175 allowed_access_type[v8::ACCESS_SET] = true;
6176
6177 ExpectString("other[42]", "el_getter");
6178 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6179 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6180 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6181
6182 allowed_access_type[v8::ACCESS_SET] = false;
6183 allowed_access_type[v8::ACCESS_GET] = false;
6184 allowed_access_type[v8::ACCESS_HAS] = false;
6185
6186 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006188 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006189 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006190 CHECK(value->IsNumber());
6191 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006192 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006193
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006194 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006195 CHECK(value->IsNumber());
6196 CHECK_EQ(3, value->Int32Value());
6197
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006198 value = CompileRun(
6199 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6200 CHECK(value->IsNumber());
6201 CHECK_EQ(3, value->Int32Value());
6202
6203 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00006204 CHECK(value->IsTrue());
6205
6206 // Enumeration doesn't enumerate accessors from inaccessible objects in
6207 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006208 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00006209 CompileRun("(function(){var obj = {'__proto__':other};"
6210 "for (var p in obj)"
6211 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6212 " return false;"
6213 " }"
6214 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006215 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006216
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006217 context1->Exit();
6218 context0->Exit();
6219 context1.Dispose();
6220 context0.Dispose();
6221}
6222
6223
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006224TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00006225 v8::HandleScope handle_scope;
6226 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6227
6228 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6229 IndexedAccessBlocker);
6230
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006231 // Add accessible accessor.
6232 global_template->SetAccessor(
6233 v8_str("accessible_prop"),
6234 EchoGetter, EchoSetter,
6235 v8::Handle<Value>(),
6236 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6237
6238
ricow@chromium.org65001782011-02-15 13:36:41 +00006239 // Add an accessor that is not accessible by cross-domain JS code.
6240 global_template->SetAccessor(v8_str("blocked_prop"),
6241 UnreachableGetter, UnreachableSetter,
6242 v8::Handle<Value>(),
6243 v8::DEFAULT);
6244
6245 // Create an environment
6246 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6247 context0->Enter();
6248
6249 v8::Handle<v8::Object> global0 = context0->Global();
6250
6251 v8::Persistent<Context> context1 = Context::New();
6252 context1->Enter();
6253 v8::Handle<v8::Object> global1 = context1->Global();
6254 global1->Set(v8_str("other"), global0);
6255
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006256 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00006257 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006258
6259 ExpectUndefined("other.blocked_prop");
6260
6261 // Regression test for issue 1027.
6262 CompileRun("Object.defineProperty(\n"
6263 " other, 'blocked_prop', {configurable: false})");
6264 ExpectUndefined("other.blocked_prop");
6265 ExpectUndefined(
6266 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6267
6268 // Regression test for issue 1171.
6269 ExpectTrue("Object.isExtensible(other)");
6270 CompileRun("Object.preventExtensions(other)");
6271 ExpectTrue("Object.isExtensible(other)");
6272
6273 // Object.seal and Object.freeze.
6274 CompileRun("Object.freeze(other)");
6275 ExpectTrue("Object.isExtensible(other)");
6276
6277 CompileRun("Object.seal(other)");
6278 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006279
6280 // Regression test for issue 1250.
6281 // Make sure that we can set the accessible accessors value using normal
6282 // assignment.
6283 CompileRun("other.accessible_prop = 42");
6284 CHECK_EQ(42, g_echo_value);
6285
6286 v8::Handle<Value> value;
6287 // We follow Safari in ignoring assignments to host object accessors.
6288 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6289 value = CompileRun("other.accessible_prop == 42");
6290 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006291}
6292
6293
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006294static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6295 Local<Value> name,
6296 v8::AccessType type,
6297 Local<Value> data) {
6298 return false;
6299}
6300
6301
6302static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6303 uint32_t key,
6304 v8::AccessType type,
6305 Local<Value> data) {
6306 return false;
6307}
6308
6309
6310THREADED_TEST(AccessControlGetOwnPropertyNames) {
6311 v8::HandleScope handle_scope;
6312 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6313
6314 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6315 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6316 GetOwnPropertyNamesIndexedBlocker);
6317
6318 // Create an environment
6319 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6320 context0->Enter();
6321
6322 v8::Handle<v8::Object> global0 = context0->Global();
6323
6324 v8::HandleScope scope1;
6325
6326 v8::Persistent<Context> context1 = Context::New();
6327 context1->Enter();
6328
6329 v8::Handle<v8::Object> global1 = context1->Global();
6330 global1->Set(v8_str("other"), global0);
6331 global1->Set(v8_str("object"), obj_template->NewInstance());
6332
6333 v8::Handle<Value> value;
6334
6335 // Attempt to get the property names of the other global object and
6336 // of an object that requires access checks. Accessing the other
6337 // global object should be blocked by access checks on the global
6338 // proxy object. Accessing the object that requires access checks
6339 // is blocked by the access checks on the object itself.
6340 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6341 CHECK(value->IsTrue());
6342
6343 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6344 CHECK(value->IsTrue());
6345
6346 context1->Exit();
6347 context0->Exit();
6348 context1.Dispose();
6349 context0.Dispose();
6350}
6351
6352
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006353static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6354 v8::Handle<v8::Array> result = v8::Array::New(1);
6355 result->Set(0, v8_str("x"));
6356 return result;
6357}
6358
6359
6360THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6361 v8::HandleScope handle_scope;
6362 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6363
6364 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6365 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6366 NamedPropertyEnumerator);
6367
6368 LocalContext context;
6369 v8::Handle<v8::Object> global = context->Global();
6370 global->Set(v8_str("object"), obj_template->NewInstance());
6371
6372 v8::Handle<Value> value =
6373 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6374 CHECK_EQ(v8_str("x"), value);
6375}
6376
6377
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006378static v8::Handle<Value> ConstTenGetter(Local<String> name,
6379 const AccessorInfo& info) {
6380 return v8_num(10);
6381}
6382
6383
6384THREADED_TEST(CrossDomainAccessors) {
6385 v8::HandleScope handle_scope;
6386
6387 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6388
6389 v8::Handle<v8::ObjectTemplate> global_template =
6390 func_template->InstanceTemplate();
6391
6392 v8::Handle<v8::ObjectTemplate> proto_template =
6393 func_template->PrototypeTemplate();
6394
6395 // Add an accessor to proto that's accessible by cross-domain JS code.
6396 proto_template->SetAccessor(v8_str("accessible"),
6397 ConstTenGetter, 0,
6398 v8::Handle<Value>(),
6399 v8::ALL_CAN_READ);
6400
6401 // Add an accessor that is not accessible by cross-domain JS code.
6402 global_template->SetAccessor(v8_str("unreachable"),
6403 UnreachableGetter, 0,
6404 v8::Handle<Value>(),
6405 v8::DEFAULT);
6406
6407 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6408 context0->Enter();
6409
6410 Local<v8::Object> global = context0->Global();
6411 // Add a normal property that shadows 'accessible'
6412 global->Set(v8_str("accessible"), v8_num(11));
6413
6414 // Enter a new context.
6415 v8::HandleScope scope1;
6416 v8::Persistent<Context> context1 = Context::New();
6417 context1->Enter();
6418
6419 v8::Handle<v8::Object> global1 = context1->Global();
6420 global1->Set(v8_str("other"), global);
6421
6422 // Should return 10, instead of 11
6423 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6424 CHECK(value->IsNumber());
6425 CHECK_EQ(10, value->Int32Value());
6426
6427 value = v8_compile("other.unreachable")->Run();
6428 CHECK(value->IsUndefined());
6429
6430 context1->Exit();
6431 context0->Exit();
6432 context1.Dispose();
6433 context0.Dispose();
6434}
6435
6436
6437static int named_access_count = 0;
6438static int indexed_access_count = 0;
6439
6440static bool NamedAccessCounter(Local<v8::Object> global,
6441 Local<Value> name,
6442 v8::AccessType type,
6443 Local<Value> data) {
6444 named_access_count++;
6445 return true;
6446}
6447
6448
6449static bool IndexedAccessCounter(Local<v8::Object> global,
6450 uint32_t key,
6451 v8::AccessType type,
6452 Local<Value> data) {
6453 indexed_access_count++;
6454 return true;
6455}
6456
6457
6458// This one is too easily disturbed by other tests.
6459TEST(AccessControlIC) {
6460 named_access_count = 0;
6461 indexed_access_count = 0;
6462
6463 v8::HandleScope handle_scope;
6464
6465 // Create an environment.
6466 v8::Persistent<Context> context0 = Context::New();
6467 context0->Enter();
6468
6469 // Create an object that requires access-check functions to be
6470 // called for cross-domain access.
6471 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6472 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6473 IndexedAccessCounter);
6474 Local<v8::Object> object = object_template->NewInstance();
6475
6476 v8::HandleScope scope1;
6477
6478 // Create another environment.
6479 v8::Persistent<Context> context1 = Context::New();
6480 context1->Enter();
6481
6482 // Make easy access to the object from the other environment.
6483 v8::Handle<v8::Object> global1 = context1->Global();
6484 global1->Set(v8_str("obj"), object);
6485
6486 v8::Handle<Value> value;
6487
6488 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006489 CompileRun("function testProp(obj) {"
6490 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6491 " for (var j = 0; j < 10; j++) obj.prop;"
6492 " return obj.prop"
6493 "}");
6494 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006495 CHECK(value->IsNumber());
6496 CHECK_EQ(1, value->Int32Value());
6497 CHECK_EQ(21, named_access_count);
6498
6499 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006500 CompileRun("var p = 'prop';"
6501 "function testKeyed(obj) {"
6502 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6503 " for (var j = 0; j < 10; j++) obj[p];"
6504 " return obj[p];"
6505 "}");
6506 // Use obj which requires access checks. No inline caching is used
6507 // in that case.
6508 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006509 CHECK(value->IsNumber());
6510 CHECK_EQ(1, value->Int32Value());
6511 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006512 // Force the inline caches into generic state and try again.
6513 CompileRun("testKeyed({ a: 0 })");
6514 CompileRun("testKeyed({ b: 0 })");
6515 value = CompileRun("testKeyed(obj)");
6516 CHECK(value->IsNumber());
6517 CHECK_EQ(1, value->Int32Value());
6518 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006519
6520 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006521 CompileRun("function testIndexed(obj) {"
6522 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6523 " for (var j = 0; j < 10; j++) obj[0];"
6524 " return obj[0]"
6525 "}");
6526 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006527 CHECK(value->IsNumber());
6528 CHECK_EQ(1, value->Int32Value());
6529 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006530 // Force the inline caches into generic state.
6531 CompileRun("testIndexed(new Array(1))");
6532 // Test that the indexed access check is called.
6533 value = CompileRun("testIndexed(obj)");
6534 CHECK(value->IsNumber());
6535 CHECK_EQ(1, value->Int32Value());
6536 CHECK_EQ(42, indexed_access_count);
6537
6538 // Check that the named access check is called when invoking
6539 // functions on an object that requires access checks.
6540 CompileRun("obj.f = function() {}");
6541 CompileRun("function testCallNormal(obj) {"
6542 " for (var i = 0; i < 10; i++) obj.f();"
6543 "}");
6544 CompileRun("testCallNormal(obj)");
6545 CHECK_EQ(74, named_access_count);
6546
6547 // Force obj into slow case.
6548 value = CompileRun("delete obj.prop");
6549 CHECK(value->BooleanValue());
6550 // Force inline caches into dictionary probing mode.
6551 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6552 // Test that the named access check is called.
6553 value = CompileRun("testProp(obj);");
6554 CHECK(value->IsNumber());
6555 CHECK_EQ(1, value->Int32Value());
6556 CHECK_EQ(96, named_access_count);
6557
6558 // Force the call inline cache into dictionary probing mode.
6559 CompileRun("o.f = function() {}; testCallNormal(o)");
6560 // Test that the named access check is still called for each
6561 // invocation of the function.
6562 value = CompileRun("testCallNormal(obj)");
6563 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006564
6565 context1->Exit();
6566 context0->Exit();
6567 context1.Dispose();
6568 context0.Dispose();
6569}
6570
6571
6572static bool NamedAccessFlatten(Local<v8::Object> global,
6573 Local<Value> name,
6574 v8::AccessType type,
6575 Local<Value> data) {
6576 char buf[100];
6577 int len;
6578
6579 CHECK(name->IsString());
6580
6581 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006582 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006583 CHECK_EQ(4, len);
6584
6585 uint16_t buf2[100];
6586
6587 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006588 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006589 CHECK_EQ(4, len);
6590
6591 return true;
6592}
6593
6594
6595static bool IndexedAccessFlatten(Local<v8::Object> global,
6596 uint32_t key,
6597 v8::AccessType type,
6598 Local<Value> data) {
6599 return true;
6600}
6601
6602
6603// Regression test. In access checks, operations that may cause
6604// garbage collection are not allowed. It used to be the case that
6605// using the Write operation on a string could cause a garbage
6606// collection due to flattening of the string. This is no longer the
6607// case.
6608THREADED_TEST(AccessControlFlatten) {
6609 named_access_count = 0;
6610 indexed_access_count = 0;
6611
6612 v8::HandleScope handle_scope;
6613
6614 // Create an environment.
6615 v8::Persistent<Context> context0 = Context::New();
6616 context0->Enter();
6617
6618 // Create an object that requires access-check functions to be
6619 // called for cross-domain access.
6620 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6621 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6622 IndexedAccessFlatten);
6623 Local<v8::Object> object = object_template->NewInstance();
6624
6625 v8::HandleScope scope1;
6626
6627 // Create another environment.
6628 v8::Persistent<Context> context1 = Context::New();
6629 context1->Enter();
6630
6631 // Make easy access to the object from the other environment.
6632 v8::Handle<v8::Object> global1 = context1->Global();
6633 global1->Set(v8_str("obj"), object);
6634
6635 v8::Handle<Value> value;
6636
6637 value = v8_compile("var p = 'as' + 'df';")->Run();
6638 value = v8_compile("obj[p];")->Run();
6639
6640 context1->Exit();
6641 context0->Exit();
6642 context1.Dispose();
6643 context0.Dispose();
6644}
6645
6646
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647static v8::Handle<Value> AccessControlNamedGetter(
6648 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006649 return v8::Integer::New(42);
6650}
6651
6652
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006653static v8::Handle<Value> AccessControlNamedSetter(
6654 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006655 return value;
6656}
6657
6658
6659static v8::Handle<Value> AccessControlIndexedGetter(
6660 uint32_t index,
6661 const AccessorInfo& info) {
6662 return v8_num(42);
6663}
6664
6665
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006666static v8::Handle<Value> AccessControlIndexedSetter(
6667 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006668 return value;
6669}
6670
6671
6672THREADED_TEST(AccessControlInterceptorIC) {
6673 named_access_count = 0;
6674 indexed_access_count = 0;
6675
6676 v8::HandleScope handle_scope;
6677
6678 // Create an environment.
6679 v8::Persistent<Context> context0 = Context::New();
6680 context0->Enter();
6681
6682 // Create an object that requires access-check functions to be
6683 // called for cross-domain access. The object also has interceptors
6684 // interceptor.
6685 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6686 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6687 IndexedAccessCounter);
6688 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6689 AccessControlNamedSetter);
6690 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6691 AccessControlIndexedSetter);
6692 Local<v8::Object> object = object_template->NewInstance();
6693
6694 v8::HandleScope scope1;
6695
6696 // Create another environment.
6697 v8::Persistent<Context> context1 = Context::New();
6698 context1->Enter();
6699
6700 // Make easy access to the object from the other environment.
6701 v8::Handle<v8::Object> global1 = context1->Global();
6702 global1->Set(v8_str("obj"), object);
6703
6704 v8::Handle<Value> value;
6705
6706 // Check that the named access-control function is called every time
6707 // eventhough there is an interceptor on the object.
6708 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6709 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6710 "obj.x")->Run();
6711 CHECK(value->IsNumber());
6712 CHECK_EQ(42, value->Int32Value());
6713 CHECK_EQ(21, named_access_count);
6714
6715 value = v8_compile("var p = 'x';")->Run();
6716 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6717 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6718 "obj[p]")->Run();
6719 CHECK(value->IsNumber());
6720 CHECK_EQ(42, value->Int32Value());
6721 CHECK_EQ(42, named_access_count);
6722
6723 // Check that the indexed access-control function is called every
6724 // time eventhough there is an interceptor on the object.
6725 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6726 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6727 "obj[0]")->Run();
6728 CHECK(value->IsNumber());
6729 CHECK_EQ(42, value->Int32Value());
6730 CHECK_EQ(21, indexed_access_count);
6731
6732 context1->Exit();
6733 context0->Exit();
6734 context1.Dispose();
6735 context0.Dispose();
6736}
6737
6738
6739THREADED_TEST(Version) {
6740 v8::V8::GetVersion();
6741}
6742
6743
6744static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6745 ApiTestFuzzer::Fuzz();
6746 return v8_num(12);
6747}
6748
6749
6750THREADED_TEST(InstanceProperties) {
6751 v8::HandleScope handle_scope;
6752 LocalContext context;
6753
6754 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6755 Local<ObjectTemplate> instance = t->InstanceTemplate();
6756
6757 instance->Set(v8_str("x"), v8_num(42));
6758 instance->Set(v8_str("f"),
6759 v8::FunctionTemplate::New(InstanceFunctionCallback));
6760
6761 Local<Value> o = t->GetFunction()->NewInstance();
6762
6763 context->Global()->Set(v8_str("i"), o);
6764 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6765 CHECK_EQ(42, value->Int32Value());
6766
6767 value = Script::Compile(v8_str("i.f()"))->Run();
6768 CHECK_EQ(12, value->Int32Value());
6769}
6770
6771
6772static v8::Handle<Value>
6773GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6774 ApiTestFuzzer::Fuzz();
6775 return v8::Handle<Value>();
6776}
6777
6778
6779THREADED_TEST(GlobalObjectInstanceProperties) {
6780 v8::HandleScope handle_scope;
6781
6782 Local<Value> global_object;
6783
6784 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6785 t->InstanceTemplate()->SetNamedPropertyHandler(
6786 GlobalObjectInstancePropertiesGet);
6787 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6788 instance_template->Set(v8_str("x"), v8_num(42));
6789 instance_template->Set(v8_str("f"),
6790 v8::FunctionTemplate::New(InstanceFunctionCallback));
6791
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006792 // The script to check how Crankshaft compiles missing global function
6793 // invocations. function g is not defined and should throw on call.
6794 const char* script =
6795 "function wrapper(call) {"
6796 " var x = 0, y = 1;"
6797 " for (var i = 0; i < 1000; i++) {"
6798 " x += i * 100;"
6799 " y += i * 100;"
6800 " }"
6801 " if (call) g();"
6802 "}"
6803 "for (var i = 0; i < 17; i++) wrapper(false);"
6804 "var thrown = 0;"
6805 "try { wrapper(true); } catch (e) { thrown = 1; };"
6806 "thrown";
6807
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006808 {
6809 LocalContext env(NULL, instance_template);
6810 // Hold on to the global object so it can be used again in another
6811 // environment initialization.
6812 global_object = env->Global();
6813
6814 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6815 CHECK_EQ(42, value->Int32Value());
6816 value = Script::Compile(v8_str("f()"))->Run();
6817 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006818 value = Script::Compile(v8_str(script))->Run();
6819 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006820 }
6821
6822 {
6823 // Create new environment reusing the global object.
6824 LocalContext env(NULL, instance_template, global_object);
6825 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6826 CHECK_EQ(42, value->Int32Value());
6827 value = Script::Compile(v8_str("f()"))->Run();
6828 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006829 value = Script::Compile(v8_str(script))->Run();
6830 CHECK_EQ(1, value->Int32Value());
6831 }
6832}
6833
6834
6835THREADED_TEST(CallKnownGlobalReceiver) {
6836 v8::HandleScope handle_scope;
6837
6838 Local<Value> global_object;
6839
6840 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6841 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6842
6843 // The script to check that we leave global object not
6844 // global object proxy on stack when we deoptimize from inside
6845 // arguments evaluation.
6846 // To provoke error we need to both force deoptimization
6847 // from arguments evaluation and to force CallIC to take
6848 // CallIC_Miss code path that can't cope with global proxy.
6849 const char* script =
6850 "function bar(x, y) { try { } finally { } }"
6851 "function baz(x) { try { } finally { } }"
6852 "function bom(x) { try { } finally { } }"
6853 "function foo(x) { bar([x], bom(2)); }"
6854 "for (var i = 0; i < 10000; i++) foo(1);"
6855 "foo";
6856
6857 Local<Value> foo;
6858 {
6859 LocalContext env(NULL, instance_template);
6860 // Hold on to the global object so it can be used again in another
6861 // environment initialization.
6862 global_object = env->Global();
6863 foo = Script::Compile(v8_str(script))->Run();
6864 }
6865
6866 {
6867 // Create new environment reusing the global object.
6868 LocalContext env(NULL, instance_template, global_object);
6869 env->Global()->Set(v8_str("foo"), foo);
6870 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006871 }
6872}
6873
6874
6875static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6876 ApiTestFuzzer::Fuzz();
6877 return v8_num(42);
6878}
6879
6880
6881static int shadow_y;
6882static int shadow_y_setter_call_count;
6883static int shadow_y_getter_call_count;
6884
6885
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006886static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006887 shadow_y_setter_call_count++;
6888 shadow_y = 42;
6889}
6890
6891
6892static v8::Handle<Value> ShadowYGetter(Local<String> name,
6893 const AccessorInfo& info) {
6894 ApiTestFuzzer::Fuzz();
6895 shadow_y_getter_call_count++;
6896 return v8_num(shadow_y);
6897}
6898
6899
6900static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6901 const AccessorInfo& info) {
6902 return v8::Handle<Value>();
6903}
6904
6905
6906static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6907 const AccessorInfo&) {
6908 return v8::Handle<Value>();
6909}
6910
6911
6912THREADED_TEST(ShadowObject) {
6913 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6914 v8::HandleScope handle_scope;
6915
6916 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6917 LocalContext context(NULL, global_template);
6918
6919 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6920 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6921 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6922 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6923 Local<ObjectTemplate> instance = t->InstanceTemplate();
6924
6925 // Only allow calls of f on instances of t.
6926 Local<v8::Signature> signature = v8::Signature::New(t);
6927 proto->Set(v8_str("f"),
6928 v8::FunctionTemplate::New(ShadowFunctionCallback,
6929 Local<Value>(),
6930 signature));
6931 proto->Set(v8_str("x"), v8_num(12));
6932
6933 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6934
6935 Local<Value> o = t->GetFunction()->NewInstance();
6936 context->Global()->Set(v8_str("__proto__"), o);
6937
6938 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006939 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006940 CHECK(value->IsBoolean());
6941 CHECK(!value->BooleanValue());
6942
6943 value = Script::Compile(v8_str("x"))->Run();
6944 CHECK_EQ(12, value->Int32Value());
6945
6946 value = Script::Compile(v8_str("f()"))->Run();
6947 CHECK_EQ(42, value->Int32Value());
6948
6949 Script::Compile(v8_str("y = 42"))->Run();
6950 CHECK_EQ(1, shadow_y_setter_call_count);
6951 value = Script::Compile(v8_str("y"))->Run();
6952 CHECK_EQ(1, shadow_y_getter_call_count);
6953 CHECK_EQ(42, value->Int32Value());
6954}
6955
6956
6957THREADED_TEST(HiddenPrototype) {
6958 v8::HandleScope handle_scope;
6959 LocalContext context;
6960
6961 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6962 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6963 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6964 t1->SetHiddenPrototype(true);
6965 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6966 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6967 t2->SetHiddenPrototype(true);
6968 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6969 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6970 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6971
6972 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6973 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6974 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6975 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6976
6977 // Setting the prototype on an object skips hidden prototypes.
6978 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6979 o0->Set(v8_str("__proto__"), o1);
6980 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6981 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6982 o0->Set(v8_str("__proto__"), o2);
6983 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6984 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6985 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6986 o0->Set(v8_str("__proto__"), o3);
6987 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6988 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6989 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6990 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6991
6992 // Getting the prototype of o0 should get the first visible one
6993 // which is o3. Therefore, z should not be defined on the prototype
6994 // object.
6995 Local<Value> proto = o0->Get(v8_str("__proto__"));
6996 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006997 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006998}
6999
7000
ager@chromium.org5c838252010-02-19 08:53:10 +00007001THREADED_TEST(SetPrototype) {
7002 v8::HandleScope handle_scope;
7003 LocalContext context;
7004
7005 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7006 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7007 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7008 t1->SetHiddenPrototype(true);
7009 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7010 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7011 t2->SetHiddenPrototype(true);
7012 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7013 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7014 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7015
7016 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7017 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7018 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7019 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7020
7021 // Setting the prototype on an object does not skip hidden prototypes.
7022 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7023 CHECK(o0->SetPrototype(o1));
7024 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7025 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7026 CHECK(o1->SetPrototype(o2));
7027 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7028 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7029 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7030 CHECK(o2->SetPrototype(o3));
7031 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7032 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7033 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7034 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7035
7036 // Getting the prototype of o0 should get the first visible one
7037 // which is o3. Therefore, z should not be defined on the prototype
7038 // object.
7039 Local<Value> proto = o0->Get(v8_str("__proto__"));
7040 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007041 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007042
7043 // However, Object::GetPrototype ignores hidden prototype.
7044 Local<Value> proto0 = o0->GetPrototype();
7045 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007046 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00007047
7048 Local<Value> proto1 = o1->GetPrototype();
7049 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007050 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00007051
7052 Local<Value> proto2 = o2->GetPrototype();
7053 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007054 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007055}
7056
7057
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007058THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00007059 v8::HandleScope handle_scope;
7060 LocalContext context;
7061
7062 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007063 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7064 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00007065 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007066 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007067 CHECK(CompileRun(
7068 "(function() {"
7069 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007070 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007071 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007072 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7073 CHECK_EQ(42,
7074 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007075
7076 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007077 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00007078 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007079 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007080 CHECK(CompileRun(
7081 "(function() {"
7082 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007083 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007084 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007085 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007086}
7087
7088
ager@chromium.org5c838252010-02-19 08:53:10 +00007089THREADED_TEST(SetPrototypeThrows) {
7090 v8::HandleScope handle_scope;
7091 LocalContext context;
7092
7093 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7094
7095 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7096 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7097
7098 CHECK(o0->SetPrototype(o1));
7099 // If setting the prototype leads to the cycle, SetPrototype should
7100 // return false and keep VM in sane state.
7101 v8::TryCatch try_catch;
7102 CHECK(!o1->SetPrototype(o0));
7103 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007104 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007105
7106 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7107}
7108
7109
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007110THREADED_TEST(GetterSetterExceptions) {
7111 v8::HandleScope handle_scope;
7112 LocalContext context;
7113 CompileRun(
7114 "function Foo() { };"
7115 "function Throw() { throw 5; };"
7116 "var x = { };"
7117 "x.__defineSetter__('set', Throw);"
7118 "x.__defineGetter__('get', Throw);");
7119 Local<v8::Object> x =
7120 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7121 v8::TryCatch try_catch;
7122 x->Set(v8_str("set"), v8::Integer::New(8));
7123 x->Get(v8_str("get"));
7124 x->Set(v8_str("set"), v8::Integer::New(8));
7125 x->Get(v8_str("get"));
7126 x->Set(v8_str("set"), v8::Integer::New(8));
7127 x->Get(v8_str("get"));
7128 x->Set(v8_str("set"), v8::Integer::New(8));
7129 x->Get(v8_str("get"));
7130}
7131
7132
7133THREADED_TEST(Constructor) {
7134 v8::HandleScope handle_scope;
7135 LocalContext context;
7136 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7137 templ->SetClassName(v8_str("Fun"));
7138 Local<Function> cons = templ->GetFunction();
7139 context->Global()->Set(v8_str("Fun"), cons);
7140 Local<v8::Object> inst = cons->NewInstance();
7141 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7142 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7143 CHECK(value->BooleanValue());
7144}
7145
lrn@chromium.org1c092762011-05-09 09:42:16 +00007146
7147static Handle<Value> ConstructorCallback(const Arguments& args) {
7148 ApiTestFuzzer::Fuzz();
7149 Local<Object> This;
7150
7151 if (args.IsConstructCall()) {
7152 Local<Object> Holder = args.Holder();
7153 This = Object::New();
7154 Local<Value> proto = Holder->GetPrototype();
7155 if (proto->IsObject()) {
7156 This->SetPrototype(proto);
7157 }
7158 } else {
7159 This = args.This();
7160 }
7161
7162 This->Set(v8_str("a"), args[0]);
7163 return This;
7164}
7165
7166
7167static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7168 ApiTestFuzzer::Fuzz();
7169 return args[0];
7170}
7171
7172
7173THREADED_TEST(ConstructorForObject) {
7174 v8::HandleScope handle_scope;
7175 LocalContext context;
7176
7177 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7178 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7179 Local<Object> instance = instance_template->NewInstance();
7180 context->Global()->Set(v8_str("obj"), instance);
7181 v8::TryCatch try_catch;
7182 Local<Value> value;
7183 CHECK(!try_catch.HasCaught());
7184
7185 // Call the Object's constructor with a 32-bit signed integer.
7186 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7187 CHECK(!try_catch.HasCaught());
7188 CHECK(value->IsInt32());
7189 CHECK_EQ(28, value->Int32Value());
7190
7191 Local<Value> args1[] = { v8_num(28) };
7192 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7193 CHECK(value_obj1->IsObject());
7194 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7195 value = object1->Get(v8_str("a"));
7196 CHECK(value->IsInt32());
7197 CHECK(!try_catch.HasCaught());
7198 CHECK_EQ(28, value->Int32Value());
7199
7200 // Call the Object's constructor with a String.
7201 value = CompileRun(
7202 "(function() { var o = new obj('tipli'); return o.a; })()");
7203 CHECK(!try_catch.HasCaught());
7204 CHECK(value->IsString());
7205 String::AsciiValue string_value1(value->ToString());
7206 CHECK_EQ("tipli", *string_value1);
7207
7208 Local<Value> args2[] = { v8_str("tipli") };
7209 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7210 CHECK(value_obj2->IsObject());
7211 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7212 value = object2->Get(v8_str("a"));
7213 CHECK(!try_catch.HasCaught());
7214 CHECK(value->IsString());
7215 String::AsciiValue string_value2(value->ToString());
7216 CHECK_EQ("tipli", *string_value2);
7217
7218 // Call the Object's constructor with a Boolean.
7219 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7220 CHECK(!try_catch.HasCaught());
7221 CHECK(value->IsBoolean());
7222 CHECK_EQ(true, value->BooleanValue());
7223
7224 Handle<Value> args3[] = { v8::Boolean::New(true) };
7225 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7226 CHECK(value_obj3->IsObject());
7227 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7228 value = object3->Get(v8_str("a"));
7229 CHECK(!try_catch.HasCaught());
7230 CHECK(value->IsBoolean());
7231 CHECK_EQ(true, value->BooleanValue());
7232
7233 // Call the Object's constructor with undefined.
7234 Handle<Value> args4[] = { v8::Undefined() };
7235 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7236 CHECK(value_obj4->IsObject());
7237 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7238 value = object4->Get(v8_str("a"));
7239 CHECK(!try_catch.HasCaught());
7240 CHECK(value->IsUndefined());
7241
7242 // Call the Object's constructor with null.
7243 Handle<Value> args5[] = { v8::Null() };
7244 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7245 CHECK(value_obj5->IsObject());
7246 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7247 value = object5->Get(v8_str("a"));
7248 CHECK(!try_catch.HasCaught());
7249 CHECK(value->IsNull());
7250 }
7251
7252 // Check exception handling when there is no constructor set for the Object.
7253 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7254 Local<Object> instance = instance_template->NewInstance();
7255 context->Global()->Set(v8_str("obj2"), instance);
7256 v8::TryCatch try_catch;
7257 Local<Value> value;
7258 CHECK(!try_catch.HasCaught());
7259
7260 value = CompileRun("new obj2(28)");
7261 CHECK(try_catch.HasCaught());
7262 String::AsciiValue exception_value1(try_catch.Exception());
7263 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7264 try_catch.Reset();
7265
7266 Local<Value> args[] = { v8_num(29) };
7267 value = instance->CallAsConstructor(1, args);
7268 CHECK(try_catch.HasCaught());
7269 String::AsciiValue exception_value2(try_catch.Exception());
7270 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7271 try_catch.Reset();
7272 }
7273
7274 // Check the case when constructor throws exception.
7275 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7276 instance_template->SetCallAsFunctionHandler(ThrowValue);
7277 Local<Object> instance = instance_template->NewInstance();
7278 context->Global()->Set(v8_str("obj3"), instance);
7279 v8::TryCatch try_catch;
7280 Local<Value> value;
7281 CHECK(!try_catch.HasCaught());
7282
7283 value = CompileRun("new obj3(22)");
7284 CHECK(try_catch.HasCaught());
7285 String::AsciiValue exception_value1(try_catch.Exception());
7286 CHECK_EQ("22", *exception_value1);
7287 try_catch.Reset();
7288
7289 Local<Value> args[] = { v8_num(23) };
7290 value = instance->CallAsConstructor(1, args);
7291 CHECK(try_catch.HasCaught());
7292 String::AsciiValue exception_value2(try_catch.Exception());
7293 CHECK_EQ("23", *exception_value2);
7294 try_catch.Reset();
7295 }
7296
7297 // Check whether constructor returns with an object or non-object.
7298 { Local<FunctionTemplate> function_template =
7299 FunctionTemplate::New(FakeConstructorCallback);
7300 Local<Function> function = function_template->GetFunction();
7301 Local<Object> instance1 = function;
7302 context->Global()->Set(v8_str("obj4"), instance1);
7303 v8::TryCatch try_catch;
7304 Local<Value> value;
7305 CHECK(!try_catch.HasCaught());
7306
7307 CHECK(instance1->IsObject());
7308 CHECK(instance1->IsFunction());
7309
7310 value = CompileRun("new obj4(28)");
7311 CHECK(!try_catch.HasCaught());
7312 CHECK(value->IsObject());
7313
7314 Local<Value> args1[] = { v8_num(28) };
7315 value = instance1->CallAsConstructor(1, args1);
7316 CHECK(!try_catch.HasCaught());
7317 CHECK(value->IsObject());
7318
7319 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7320 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7321 Local<Object> instance2 = instance_template->NewInstance();
7322 context->Global()->Set(v8_str("obj5"), instance2);
7323 CHECK(!try_catch.HasCaught());
7324
7325 CHECK(instance2->IsObject());
7326 CHECK(!instance2->IsFunction());
7327
7328 value = CompileRun("new obj5(28)");
7329 CHECK(!try_catch.HasCaught());
7330 CHECK(!value->IsObject());
7331
7332 Local<Value> args2[] = { v8_num(28) };
7333 value = instance2->CallAsConstructor(1, args2);
7334 CHECK(!try_catch.HasCaught());
7335 CHECK(!value->IsObject());
7336 }
7337}
7338
7339
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007340THREADED_TEST(FunctionDescriptorException) {
7341 v8::HandleScope handle_scope;
7342 LocalContext context;
7343 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7344 templ->SetClassName(v8_str("Fun"));
7345 Local<Function> cons = templ->GetFunction();
7346 context->Global()->Set(v8_str("Fun"), cons);
7347 Local<Value> value = CompileRun(
7348 "function test() {"
7349 " try {"
7350 " (new Fun()).blah()"
7351 " } catch (e) {"
7352 " var str = String(e);"
7353 " if (str.indexOf('TypeError') == -1) return 1;"
7354 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007355 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007356 " return 0;"
7357 " }"
7358 " return 4;"
7359 "}"
7360 "test();");
7361 CHECK_EQ(0, value->Int32Value());
7362}
7363
7364
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007365THREADED_TEST(EvalAliasedDynamic) {
7366 v8::HandleScope scope;
7367 LocalContext current;
7368
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007369 // Tests where aliased eval can only be resolved dynamically.
7370 Local<Script> script =
7371 Script::Compile(v8_str("function f(x) { "
7372 " var foo = 2;"
7373 " with (x) { return eval('foo'); }"
7374 "}"
7375 "foo = 0;"
7376 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007377 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007378 "var x = new Object();"
7379 "x.eval = function(x) { return 1; };"
7380 "result3 = f(x);"));
7381 script->Run();
7382 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7383 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7384 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7385
7386 v8::TryCatch try_catch;
7387 script =
7388 Script::Compile(v8_str("function f(x) { "
7389 " var bar = 2;"
7390 " with (x) { return eval('bar'); }"
7391 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007392 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007393 script->Run();
7394 CHECK(try_catch.HasCaught());
7395 try_catch.Reset();
7396}
7397
7398
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007399THREADED_TEST(CrossEval) {
7400 v8::HandleScope scope;
7401 LocalContext other;
7402 LocalContext current;
7403
7404 Local<String> token = v8_str("<security token>");
7405 other->SetSecurityToken(token);
7406 current->SetSecurityToken(token);
7407
7408 // Setup reference from current to other.
7409 current->Global()->Set(v8_str("other"), other->Global());
7410
7411 // Check that new variables are introduced in other context.
7412 Local<Script> script =
7413 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7414 script->Run();
7415 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7416 CHECK_EQ(1234, foo->Int32Value());
7417 CHECK(!current->Global()->Has(v8_str("foo")));
7418
7419 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007420 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007421 script =
7422 Script::Compile(v8_str("other.eval('na = 1234')"));
7423 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007424 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7425 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007426
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007427 // Check that global variables in current context are not visible in other
7428 // context.
7429 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007430 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007431 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007432 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007433 CHECK(try_catch.HasCaught());
7434 try_catch.Reset();
7435
7436 // Check that local variables in current context are not visible in other
7437 // context.
7438 script =
7439 Script::Compile(v8_str("(function() { "
7440 " var baz = 87;"
7441 " return other.eval('baz');"
7442 "})();"));
7443 result = script->Run();
7444 CHECK(try_catch.HasCaught());
7445 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007446
7447 // Check that global variables in the other environment are visible
7448 // when evaluting code.
7449 other->Global()->Set(v8_str("bis"), v8_num(1234));
7450 script = Script::Compile(v8_str("other.eval('bis')"));
7451 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007452 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007453
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007454 // Check that the 'this' pointer points to the global object evaluating
7455 // code.
7456 other->Global()->Set(v8_str("t"), other->Global());
7457 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007458 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007459 CHECK(result->IsTrue());
7460 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007461
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007462 // Check that variables introduced in with-statement are not visible in
7463 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007464 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007465 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007466 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007467 CHECK(try_catch.HasCaught());
7468 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007469
7470 // Check that you cannot use 'eval.call' with another object than the
7471 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007472 script =
7473 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7474 result = script->Run();
7475 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007476}
7477
7478
ager@chromium.orge2902be2009-06-08 12:21:35 +00007479// Test that calling eval in a context which has been detached from
7480// its global throws an exception. This behavior is consistent with
7481// other JavaScript implementations.
7482THREADED_TEST(EvalInDetachedGlobal) {
7483 v8::HandleScope scope;
7484
7485 v8::Persistent<Context> context0 = Context::New();
7486 v8::Persistent<Context> context1 = Context::New();
7487
7488 // Setup function in context0 that uses eval from context0.
7489 context0->Enter();
7490 v8::Handle<v8::Value> fun =
7491 CompileRun("var x = 42;"
7492 "(function() {"
7493 " var e = eval;"
7494 " return function(s) { return e(s); }"
7495 "})()");
7496 context0->Exit();
7497
7498 // Put the function into context1 and call it before and after
7499 // detaching the global. Before detaching, the call succeeds and
7500 // after detaching and exception is thrown.
7501 context1->Enter();
7502 context1->Global()->Set(v8_str("fun"), fun);
7503 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7504 CHECK_EQ(42, x_value->Int32Value());
7505 context0->DetachGlobal();
7506 v8::TryCatch catcher;
7507 x_value = CompileRun("fun('x')");
7508 CHECK(x_value.IsEmpty());
7509 CHECK(catcher.HasCaught());
7510 context1->Exit();
7511
7512 context1.Dispose();
7513 context0.Dispose();
7514}
7515
7516
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007517THREADED_TEST(CrossLazyLoad) {
7518 v8::HandleScope scope;
7519 LocalContext other;
7520 LocalContext current;
7521
7522 Local<String> token = v8_str("<security token>");
7523 other->SetSecurityToken(token);
7524 current->SetSecurityToken(token);
7525
7526 // Setup reference from current to other.
7527 current->Global()->Set(v8_str("other"), other->Global());
7528
7529 // Trigger lazy loading in other context.
7530 Local<Script> script =
7531 Script::Compile(v8_str("other.eval('new Date(42)')"));
7532 Local<Value> value = script->Run();
7533 CHECK_EQ(42.0, value->NumberValue());
7534}
7535
7536
7537static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7538 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007539 if (args.IsConstructCall()) {
7540 if (args[0]->IsInt32()) {
7541 return v8_num(-args[0]->Int32Value());
7542 }
7543 }
7544
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007545 return args[0];
7546}
7547
7548
7549// Test that a call handler can be set for objects which will allow
7550// non-function objects created through the API to be called as
7551// functions.
7552THREADED_TEST(CallAsFunction) {
7553 v8::HandleScope scope;
7554 LocalContext context;
7555
lrn@chromium.org1c092762011-05-09 09:42:16 +00007556 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7557 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7558 instance_template->SetCallAsFunctionHandler(call_as_function);
7559 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7560 context->Global()->Set(v8_str("obj"), instance);
7561 v8::TryCatch try_catch;
7562 Local<Value> value;
7563 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007564
lrn@chromium.org1c092762011-05-09 09:42:16 +00007565 value = CompileRun("obj(42)");
7566 CHECK(!try_catch.HasCaught());
7567 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007568
lrn@chromium.org1c092762011-05-09 09:42:16 +00007569 value = CompileRun("(function(o){return o(49)})(obj)");
7570 CHECK(!try_catch.HasCaught());
7571 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007572
lrn@chromium.org1c092762011-05-09 09:42:16 +00007573 // test special case of call as function
7574 value = CompileRun("[obj]['0'](45)");
7575 CHECK(!try_catch.HasCaught());
7576 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007577
lrn@chromium.org1c092762011-05-09 09:42:16 +00007578 value = CompileRun("obj.call = Function.prototype.call;"
7579 "obj.call(null, 87)");
7580 CHECK(!try_catch.HasCaught());
7581 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007582
lrn@chromium.org1c092762011-05-09 09:42:16 +00007583 // Regression tests for bug #1116356: Calling call through call/apply
7584 // must work for non-function receivers.
7585 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7586 value = CompileRun(apply_99);
7587 CHECK(!try_catch.HasCaught());
7588 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007589
lrn@chromium.org1c092762011-05-09 09:42:16 +00007590 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7591 value = CompileRun(call_17);
7592 CHECK(!try_catch.HasCaught());
7593 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007594
lrn@chromium.org1c092762011-05-09 09:42:16 +00007595 // Check that the call-as-function handler can be called through
7596 // new.
7597 value = CompileRun("new obj(43)");
7598 CHECK(!try_catch.HasCaught());
7599 CHECK_EQ(-43, value->Int32Value());
7600
7601 // Check that the call-as-function handler can be called through
7602 // the API.
7603 v8::Handle<Value> args[] = { v8_num(28) };
7604 value = instance->CallAsFunction(instance, 1, args);
7605 CHECK(!try_catch.HasCaught());
7606 CHECK_EQ(28, value->Int32Value());
7607 }
7608
7609 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7610 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7611 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7612 context->Global()->Set(v8_str("obj2"), instance);
7613 v8::TryCatch try_catch;
7614 Local<Value> value;
7615 CHECK(!try_catch.HasCaught());
7616
7617 // Call an object without call-as-function handler through the JS
7618 value = CompileRun("obj2(28)");
7619 CHECK(value.IsEmpty());
7620 CHECK(try_catch.HasCaught());
7621 String::AsciiValue exception_value1(try_catch.Exception());
7622 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7623 *exception_value1);
7624 try_catch.Reset();
7625
7626 // Call an object without call-as-function handler through the API
7627 value = CompileRun("obj2(28)");
7628 v8::Handle<Value> args[] = { v8_num(28) };
7629 value = instance->CallAsFunction(instance, 1, args);
7630 CHECK(value.IsEmpty());
7631 CHECK(try_catch.HasCaught());
7632 String::AsciiValue exception_value2(try_catch.Exception());
7633 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7634 try_catch.Reset();
7635 }
7636
7637 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7638 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7639 instance_template->SetCallAsFunctionHandler(ThrowValue);
7640 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7641 context->Global()->Set(v8_str("obj3"), instance);
7642 v8::TryCatch try_catch;
7643 Local<Value> value;
7644 CHECK(!try_catch.HasCaught());
7645
7646 // Catch the exception which is thrown by call-as-function handler
7647 value = CompileRun("obj3(22)");
7648 CHECK(try_catch.HasCaught());
7649 String::AsciiValue exception_value1(try_catch.Exception());
7650 CHECK_EQ("22", *exception_value1);
7651 try_catch.Reset();
7652
7653 v8::Handle<Value> args[] = { v8_num(23) };
7654 value = instance->CallAsFunction(instance, 1, args);
7655 CHECK(try_catch.HasCaught());
7656 String::AsciiValue exception_value2(try_catch.Exception());
7657 CHECK_EQ("23", *exception_value2);
7658 try_catch.Reset();
7659 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007660}
7661
7662
karlklose@chromium.org83a47282011-05-11 11:54:09 +00007663// Check whether a non-function object is callable.
7664THREADED_TEST(CallableObject) {
7665 v8::HandleScope scope;
7666 LocalContext context;
7667
7668 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7669 instance_template->SetCallAsFunctionHandler(call_as_function);
7670 Local<Object> instance = instance_template->NewInstance();
7671 v8::TryCatch try_catch;
7672
7673 CHECK(instance->IsCallable());
7674 CHECK(!try_catch.HasCaught());
7675 }
7676
7677 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7678 Local<Object> instance = instance_template->NewInstance();
7679 v8::TryCatch try_catch;
7680
7681 CHECK(!instance->IsCallable());
7682 CHECK(!try_catch.HasCaught());
7683 }
7684
7685 { Local<FunctionTemplate> function_template =
7686 FunctionTemplate::New(call_as_function);
7687 Local<Function> function = function_template->GetFunction();
7688 Local<Object> instance = function;
7689 v8::TryCatch try_catch;
7690
7691 CHECK(instance->IsCallable());
7692 CHECK(!try_catch.HasCaught());
7693 }
7694
7695 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7696 Local<Function> function = function_template->GetFunction();
7697 Local<Object> instance = function;
7698 v8::TryCatch try_catch;
7699
7700 CHECK(instance->IsCallable());
7701 CHECK(!try_catch.HasCaught());
7702 }
7703}
7704
7705
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007706static int CountHandles() {
7707 return v8::HandleScope::NumberOfHandles();
7708}
7709
7710
7711static int Recurse(int depth, int iterations) {
7712 v8::HandleScope scope;
7713 if (depth == 0) return CountHandles();
7714 for (int i = 0; i < iterations; i++) {
7715 Local<v8::Number> n = v8::Integer::New(42);
7716 }
7717 return Recurse(depth - 1, iterations);
7718}
7719
7720
7721THREADED_TEST(HandleIteration) {
7722 static const int kIterations = 500;
7723 static const int kNesting = 200;
7724 CHECK_EQ(0, CountHandles());
7725 {
7726 v8::HandleScope scope1;
7727 CHECK_EQ(0, CountHandles());
7728 for (int i = 0; i < kIterations; i++) {
7729 Local<v8::Number> n = v8::Integer::New(42);
7730 CHECK_EQ(i + 1, CountHandles());
7731 }
7732
7733 CHECK_EQ(kIterations, CountHandles());
7734 {
7735 v8::HandleScope scope2;
7736 for (int j = 0; j < kIterations; j++) {
7737 Local<v8::Number> n = v8::Integer::New(42);
7738 CHECK_EQ(j + 1 + kIterations, CountHandles());
7739 }
7740 }
7741 CHECK_EQ(kIterations, CountHandles());
7742 }
7743 CHECK_EQ(0, CountHandles());
7744 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7745}
7746
7747
7748static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7749 Local<String> name,
7750 const AccessorInfo& info) {
7751 ApiTestFuzzer::Fuzz();
7752 return v8::Handle<Value>();
7753}
7754
7755
7756THREADED_TEST(InterceptorHasOwnProperty) {
7757 v8::HandleScope scope;
7758 LocalContext context;
7759 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7760 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7761 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7762 Local<Function> function = fun_templ->GetFunction();
7763 context->Global()->Set(v8_str("constructor"), function);
7764 v8::Handle<Value> value = CompileRun(
7765 "var o = new constructor();"
7766 "o.hasOwnProperty('ostehaps');");
7767 CHECK_EQ(false, value->BooleanValue());
7768 value = CompileRun(
7769 "o.ostehaps = 42;"
7770 "o.hasOwnProperty('ostehaps');");
7771 CHECK_EQ(true, value->BooleanValue());
7772 value = CompileRun(
7773 "var p = new constructor();"
7774 "p.hasOwnProperty('ostehaps');");
7775 CHECK_EQ(false, value->BooleanValue());
7776}
7777
7778
ager@chromium.org9085a012009-05-11 19:22:57 +00007779static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7780 Local<String> name,
7781 const AccessorInfo& info) {
7782 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007784 return v8::Handle<Value>();
7785}
7786
7787
7788THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7789 v8::HandleScope scope;
7790 LocalContext context;
7791 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7792 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7793 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7794 Local<Function> function = fun_templ->GetFunction();
7795 context->Global()->Set(v8_str("constructor"), function);
7796 // Let's first make some stuff so we can be sure to get a good GC.
7797 CompileRun(
7798 "function makestr(size) {"
7799 " switch (size) {"
7800 " case 1: return 'f';"
7801 " case 2: return 'fo';"
7802 " case 3: return 'foo';"
7803 " }"
7804 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7805 "}"
7806 "var x = makestr(12345);"
7807 "x = makestr(31415);"
7808 "x = makestr(23456);");
7809 v8::Handle<Value> value = CompileRun(
7810 "var o = new constructor();"
7811 "o.__proto__ = new String(x);"
7812 "o.hasOwnProperty('ostehaps');");
7813 CHECK_EQ(false, value->BooleanValue());
7814}
7815
7816
ager@chromium.orge2902be2009-06-08 12:21:35 +00007817typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7818 const AccessorInfo& info);
7819
7820
7821static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7822 const char* source,
7823 int expected) {
7824 v8::HandleScope scope;
7825 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007826 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007827 LocalContext context;
7828 context->Global()->Set(v8_str("o"), templ->NewInstance());
7829 v8::Handle<Value> value = CompileRun(source);
7830 CHECK_EQ(expected, value->Int32Value());
7831}
7832
7833
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007834static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7835 const AccessorInfo& info) {
7836 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007837 CHECK_EQ(v8_str("data"), info.Data());
7838 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007839 return v8::Integer::New(42);
7840}
7841
7842
7843// This test should hit the load IC for the interceptor case.
7844THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007845 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007846 "var result = 0;"
7847 "for (var i = 0; i < 1000; i++) {"
7848 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007849 "}",
7850 42);
7851}
7852
7853
7854// Below go several tests which verify that JITing for various
7855// configurations of interceptor and explicit fields works fine
7856// (those cases are special cased to get better performance).
7857
7858static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7859 const AccessorInfo& info) {
7860 ApiTestFuzzer::Fuzz();
7861 return v8_str("x")->Equals(name)
7862 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7863}
7864
7865
7866THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7867 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7868 "var result = 0;"
7869 "o.y = 239;"
7870 "for (var i = 0; i < 1000; i++) {"
7871 " result = o.y;"
7872 "}",
7873 239);
7874}
7875
7876
7877THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7878 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7879 "var result = 0;"
7880 "o.__proto__ = { 'y': 239 };"
7881 "for (var i = 0; i < 1000; i++) {"
7882 " result = o.y + o.x;"
7883 "}",
7884 239 + 42);
7885}
7886
7887
7888THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7889 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7890 "var result = 0;"
7891 "o.__proto__.y = 239;"
7892 "for (var i = 0; i < 1000; i++) {"
7893 " result = o.y + o.x;"
7894 "}",
7895 239 + 42);
7896}
7897
7898
7899THREADED_TEST(InterceptorLoadICUndefined) {
7900 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7901 "var result = 0;"
7902 "for (var i = 0; i < 1000; i++) {"
7903 " result = (o.y == undefined) ? 239 : 42;"
7904 "}",
7905 239);
7906}
7907
7908
7909THREADED_TEST(InterceptorLoadICWithOverride) {
7910 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7911 "fst = new Object(); fst.__proto__ = o;"
7912 "snd = new Object(); snd.__proto__ = fst;"
7913 "var result1 = 0;"
7914 "for (var i = 0; i < 1000; i++) {"
7915 " result1 = snd.x;"
7916 "}"
7917 "fst.x = 239;"
7918 "var result = 0;"
7919 "for (var i = 0; i < 1000; i++) {"
7920 " result = snd.x;"
7921 "}"
7922 "result + result1",
7923 239 + 42);
7924}
7925
7926
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007927// Test the case when we stored field into
7928// a stub, but interceptor produced value on its own.
7929THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7930 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7931 "proto = new Object();"
7932 "o.__proto__ = proto;"
7933 "proto.x = 239;"
7934 "for (var i = 0; i < 1000; i++) {"
7935 " o.x;"
7936 // Now it should be ICed and keep a reference to x defined on proto
7937 "}"
7938 "var result = 0;"
7939 "for (var i = 0; i < 1000; i++) {"
7940 " result += o.x;"
7941 "}"
7942 "result;",
7943 42 * 1000);
7944}
7945
7946
7947// Test the case when we stored field into
7948// a stub, but it got invalidated later on.
7949THREADED_TEST(InterceptorLoadICInvalidatedField) {
7950 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7951 "proto1 = new Object();"
7952 "proto2 = new Object();"
7953 "o.__proto__ = proto1;"
7954 "proto1.__proto__ = proto2;"
7955 "proto2.y = 239;"
7956 "for (var i = 0; i < 1000; i++) {"
7957 " o.y;"
7958 // Now it should be ICed and keep a reference to y defined on proto2
7959 "}"
7960 "proto1.y = 42;"
7961 "var result = 0;"
7962 "for (var i = 0; i < 1000; i++) {"
7963 " result += o.y;"
7964 "}"
7965 "result;",
7966 42 * 1000);
7967}
7968
7969
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007970static int interceptor_load_not_handled_calls = 0;
7971static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7972 const AccessorInfo& info) {
7973 ++interceptor_load_not_handled_calls;
7974 return v8::Handle<v8::Value>();
7975}
7976
7977
7978// Test how post-interceptor lookups are done in the non-cacheable
7979// case: the interceptor should not be invoked during this lookup.
7980THREADED_TEST(InterceptorLoadICPostInterceptor) {
7981 interceptor_load_not_handled_calls = 0;
7982 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7983 "receiver = new Object();"
7984 "receiver.__proto__ = o;"
7985 "proto = new Object();"
7986 "/* Make proto a slow-case object. */"
7987 "for (var i = 0; i < 1000; i++) {"
7988 " proto[\"xxxxxxxx\" + i] = [];"
7989 "}"
7990 "proto.x = 17;"
7991 "o.__proto__ = proto;"
7992 "var result = 0;"
7993 "for (var i = 0; i < 1000; i++) {"
7994 " result += receiver.x;"
7995 "}"
7996 "result;",
7997 17 * 1000);
7998 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7999}
8000
8001
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008002// Test the case when we stored field into
8003// a stub, but it got invalidated later on due to override on
8004// global object which is between interceptor and fields' holders.
8005THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8006 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8007 "o.__proto__ = this;" // set a global to be a proto of o.
8008 "this.__proto__.y = 239;"
8009 "for (var i = 0; i < 10; i++) {"
8010 " if (o.y != 239) throw 'oops: ' + o.y;"
8011 // Now it should be ICed and keep a reference to y defined on field_holder.
8012 "}"
8013 "this.y = 42;" // Assign on a global.
8014 "var result = 0;"
8015 "for (var i = 0; i < 10; i++) {"
8016 " result += o.y;"
8017 "}"
8018 "result;",
8019 42 * 10);
8020}
8021
8022
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008023static void SetOnThis(Local<String> name,
8024 Local<Value> value,
8025 const AccessorInfo& info) {
8026 info.This()->ForceSet(name, value);
8027}
8028
8029
8030THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8031 v8::HandleScope scope;
8032 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8033 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8034 templ->SetAccessor(v8_str("y"), Return239);
8035 LocalContext context;
8036 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008037
8038 // Check the case when receiver and interceptor's holder
8039 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008040 v8::Handle<Value> value = CompileRun(
8041 "var result = 0;"
8042 "for (var i = 0; i < 7; i++) {"
8043 " result = o.y;"
8044 "}");
8045 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008046
8047 // Check the case when interceptor's holder is in proto chain
8048 // of receiver.
8049 value = CompileRun(
8050 "r = { __proto__: o };"
8051 "var result = 0;"
8052 "for (var i = 0; i < 7; i++) {"
8053 " result = r.y;"
8054 "}");
8055 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008056}
8057
8058
8059THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8060 v8::HandleScope scope;
8061 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8062 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8063 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8064 templ_p->SetAccessor(v8_str("y"), Return239);
8065
8066 LocalContext context;
8067 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8068 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8069
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008070 // Check the case when receiver and interceptor's holder
8071 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008072 v8::Handle<Value> value = CompileRun(
8073 "o.__proto__ = p;"
8074 "var result = 0;"
8075 "for (var i = 0; i < 7; i++) {"
8076 " result = o.x + o.y;"
8077 "}");
8078 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008079
8080 // Check the case when interceptor's holder is in proto chain
8081 // of receiver.
8082 value = CompileRun(
8083 "r = { __proto__: o };"
8084 "var result = 0;"
8085 "for (var i = 0; i < 7; i++) {"
8086 " result = r.x + r.y;"
8087 "}");
8088 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008089}
8090
8091
8092THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8093 v8::HandleScope scope;
8094 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8095 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8096 templ->SetAccessor(v8_str("y"), Return239);
8097
8098 LocalContext context;
8099 context->Global()->Set(v8_str("o"), templ->NewInstance());
8100
8101 v8::Handle<Value> value = CompileRun(
8102 "fst = new Object(); fst.__proto__ = o;"
8103 "snd = new Object(); snd.__proto__ = fst;"
8104 "var result1 = 0;"
8105 "for (var i = 0; i < 7; i++) {"
8106 " result1 = snd.x;"
8107 "}"
8108 "fst.x = 239;"
8109 "var result = 0;"
8110 "for (var i = 0; i < 7; i++) {"
8111 " result = snd.x;"
8112 "}"
8113 "result + result1");
8114 CHECK_EQ(239 + 42, value->Int32Value());
8115}
8116
8117
8118// Test the case when we stored callback into
8119// a stub, but interceptor produced value on its own.
8120THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8121 v8::HandleScope scope;
8122 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8123 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8124 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8125 templ_p->SetAccessor(v8_str("y"), Return239);
8126
8127 LocalContext context;
8128 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8129 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8130
8131 v8::Handle<Value> value = CompileRun(
8132 "o.__proto__ = p;"
8133 "for (var i = 0; i < 7; i++) {"
8134 " o.x;"
8135 // Now it should be ICed and keep a reference to x defined on p
8136 "}"
8137 "var result = 0;"
8138 "for (var i = 0; i < 7; i++) {"
8139 " result += o.x;"
8140 "}"
8141 "result");
8142 CHECK_EQ(42 * 7, value->Int32Value());
8143}
8144
8145
8146// Test the case when we stored callback into
8147// a stub, but it got invalidated later on.
8148THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8149 v8::HandleScope scope;
8150 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8151 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8152 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8153 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8154
8155 LocalContext context;
8156 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8157 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8158
8159 v8::Handle<Value> value = CompileRun(
8160 "inbetween = new Object();"
8161 "o.__proto__ = inbetween;"
8162 "inbetween.__proto__ = p;"
8163 "for (var i = 0; i < 10; i++) {"
8164 " o.y;"
8165 // Now it should be ICed and keep a reference to y defined on p
8166 "}"
8167 "inbetween.y = 42;"
8168 "var result = 0;"
8169 "for (var i = 0; i < 10; i++) {"
8170 " result += o.y;"
8171 "}"
8172 "result");
8173 CHECK_EQ(42 * 10, value->Int32Value());
8174}
8175
8176
8177// Test the case when we stored callback into
8178// a stub, but it got invalidated later on due to override on
8179// global object which is between interceptor and callbacks' holders.
8180THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8181 v8::HandleScope scope;
8182 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8183 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8184 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8185 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8186
8187 LocalContext context;
8188 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8189 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8190
8191 v8::Handle<Value> value = CompileRun(
8192 "o.__proto__ = this;"
8193 "this.__proto__ = p;"
8194 "for (var i = 0; i < 10; i++) {"
8195 " if (o.y != 239) throw 'oops: ' + o.y;"
8196 // Now it should be ICed and keep a reference to y defined on p
8197 "}"
8198 "this.y = 42;"
8199 "var result = 0;"
8200 "for (var i = 0; i < 10; i++) {"
8201 " result += o.y;"
8202 "}"
8203 "result");
8204 CHECK_EQ(42 * 10, value->Int32Value());
8205}
8206
8207
ager@chromium.orge2902be2009-06-08 12:21:35 +00008208static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8209 const AccessorInfo& info) {
8210 ApiTestFuzzer::Fuzz();
8211 CHECK(v8_str("x")->Equals(name));
8212 return v8::Integer::New(0);
8213}
8214
8215
8216THREADED_TEST(InterceptorReturningZero) {
8217 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8218 "o.x == undefined ? 1 : 0",
8219 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008220}
8221
8222
8223static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008224 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008225 CHECK(v8_str("x")->Equals(key));
8226 CHECK_EQ(42, value->Int32Value());
8227 return value;
8228}
8229
8230
8231// This test should hit the store IC for the interceptor case.
8232THREADED_TEST(InterceptorStoreIC) {
8233 v8::HandleScope scope;
8234 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8235 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008236 InterceptorStoreICSetter,
8237 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008238 LocalContext context;
8239 context->Global()->Set(v8_str("o"), templ->NewInstance());
8240 v8::Handle<Value> value = CompileRun(
8241 "for (var i = 0; i < 1000; i++) {"
8242 " o.x = 42;"
8243 "}");
8244}
8245
8246
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008247THREADED_TEST(InterceptorStoreICWithNoSetter) {
8248 v8::HandleScope scope;
8249 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8250 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8251 LocalContext context;
8252 context->Global()->Set(v8_str("o"), templ->NewInstance());
8253 v8::Handle<Value> value = CompileRun(
8254 "for (var i = 0; i < 1000; i++) {"
8255 " o.y = 239;"
8256 "}"
8257 "42 + o.y");
8258 CHECK_EQ(239 + 42, value->Int32Value());
8259}
8260
8261
8262
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008263
8264v8::Handle<Value> call_ic_function;
8265v8::Handle<Value> call_ic_function2;
8266v8::Handle<Value> call_ic_function3;
8267
8268static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8269 const AccessorInfo& info) {
8270 ApiTestFuzzer::Fuzz();
8271 CHECK(v8_str("x")->Equals(name));
8272 return call_ic_function;
8273}
8274
8275
8276// This test should hit the call IC for the interceptor case.
8277THREADED_TEST(InterceptorCallIC) {
8278 v8::HandleScope scope;
8279 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8280 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8281 LocalContext context;
8282 context->Global()->Set(v8_str("o"), templ->NewInstance());
8283 call_ic_function =
8284 v8_compile("function f(x) { return x + 1; }; f")->Run();
8285 v8::Handle<Value> value = CompileRun(
8286 "var result = 0;"
8287 "for (var i = 0; i < 1000; i++) {"
8288 " result = o.x(41);"
8289 "}");
8290 CHECK_EQ(42, value->Int32Value());
8291}
8292
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008293
8294// This test checks that if interceptor doesn't provide
8295// a value, we can fetch regular value.
8296THREADED_TEST(InterceptorCallICSeesOthers) {
8297 v8::HandleScope scope;
8298 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8299 templ->SetNamedPropertyHandler(NoBlockGetterX);
8300 LocalContext context;
8301 context->Global()->Set(v8_str("o"), templ->NewInstance());
8302 v8::Handle<Value> value = CompileRun(
8303 "o.x = function f(x) { return x + 1; };"
8304 "var result = 0;"
8305 "for (var i = 0; i < 7; i++) {"
8306 " result = o.x(41);"
8307 "}");
8308 CHECK_EQ(42, value->Int32Value());
8309}
8310
8311
8312static v8::Handle<Value> call_ic_function4;
8313static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8314 const AccessorInfo& info) {
8315 ApiTestFuzzer::Fuzz();
8316 CHECK(v8_str("x")->Equals(name));
8317 return call_ic_function4;
8318}
8319
8320
8321// This test checks that if interceptor provides a function,
8322// even if we cached shadowed variant, interceptor's function
8323// is invoked
8324THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8325 v8::HandleScope scope;
8326 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8327 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8328 LocalContext context;
8329 context->Global()->Set(v8_str("o"), templ->NewInstance());
8330 call_ic_function4 =
8331 v8_compile("function f(x) { return x - 1; }; f")->Run();
8332 v8::Handle<Value> value = CompileRun(
8333 "o.__proto__.x = function(x) { return x + 1; };"
8334 "var result = 0;"
8335 "for (var i = 0; i < 1000; i++) {"
8336 " result = o.x(42);"
8337 "}");
8338 CHECK_EQ(41, value->Int32Value());
8339}
8340
8341
8342// Test the case when we stored cacheable lookup into
8343// a stub, but it got invalidated later on
8344THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8345 v8::HandleScope scope;
8346 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8347 templ->SetNamedPropertyHandler(NoBlockGetterX);
8348 LocalContext context;
8349 context->Global()->Set(v8_str("o"), templ->NewInstance());
8350 v8::Handle<Value> value = CompileRun(
8351 "proto1 = new Object();"
8352 "proto2 = new Object();"
8353 "o.__proto__ = proto1;"
8354 "proto1.__proto__ = proto2;"
8355 "proto2.y = function(x) { return x + 1; };"
8356 // Invoke it many times to compile a stub
8357 "for (var i = 0; i < 7; i++) {"
8358 " o.y(42);"
8359 "}"
8360 "proto1.y = function(x) { return x - 1; };"
8361 "var result = 0;"
8362 "for (var i = 0; i < 7; i++) {"
8363 " result += o.y(42);"
8364 "}");
8365 CHECK_EQ(41 * 7, value->Int32Value());
8366}
8367
8368
8369static v8::Handle<Value> call_ic_function5;
8370static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8371 const AccessorInfo& info) {
8372 ApiTestFuzzer::Fuzz();
8373 if (v8_str("x")->Equals(name))
8374 return call_ic_function5;
8375 else
8376 return Local<Value>();
8377}
8378
8379
8380// This test checks that if interceptor doesn't provide a function,
8381// cached constant function is used
8382THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8383 v8::HandleScope scope;
8384 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8385 templ->SetNamedPropertyHandler(NoBlockGetterX);
8386 LocalContext context;
8387 context->Global()->Set(v8_str("o"), templ->NewInstance());
8388 v8::Handle<Value> value = CompileRun(
8389 "function inc(x) { return x + 1; };"
8390 "inc(1);"
8391 "o.x = inc;"
8392 "var result = 0;"
8393 "for (var i = 0; i < 1000; i++) {"
8394 " result = o.x(42);"
8395 "}");
8396 CHECK_EQ(43, value->Int32Value());
8397}
8398
8399
8400// This test checks that if interceptor provides a function,
8401// even if we cached constant function, interceptor's function
8402// is invoked
8403THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8404 v8::HandleScope scope;
8405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8406 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8407 LocalContext context;
8408 context->Global()->Set(v8_str("o"), templ->NewInstance());
8409 call_ic_function5 =
8410 v8_compile("function f(x) { return x - 1; }; f")->Run();
8411 v8::Handle<Value> value = CompileRun(
8412 "function inc(x) { return x + 1; };"
8413 "inc(1);"
8414 "o.x = inc;"
8415 "var result = 0;"
8416 "for (var i = 0; i < 1000; i++) {"
8417 " result = o.x(42);"
8418 "}");
8419 CHECK_EQ(41, value->Int32Value());
8420}
8421
8422
8423// Test the case when we stored constant function into
8424// a stub, but it got invalidated later on
8425THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8426 v8::HandleScope scope;
8427 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8428 templ->SetNamedPropertyHandler(NoBlockGetterX);
8429 LocalContext context;
8430 context->Global()->Set(v8_str("o"), templ->NewInstance());
8431 v8::Handle<Value> value = CompileRun(
8432 "function inc(x) { return x + 1; };"
8433 "inc(1);"
8434 "proto1 = new Object();"
8435 "proto2 = new Object();"
8436 "o.__proto__ = proto1;"
8437 "proto1.__proto__ = proto2;"
8438 "proto2.y = inc;"
8439 // Invoke it many times to compile a stub
8440 "for (var i = 0; i < 7; i++) {"
8441 " o.y(42);"
8442 "}"
8443 "proto1.y = function(x) { return x - 1; };"
8444 "var result = 0;"
8445 "for (var i = 0; i < 7; i++) {"
8446 " result += o.y(42);"
8447 "}");
8448 CHECK_EQ(41 * 7, value->Int32Value());
8449}
8450
8451
8452// Test the case when we stored constant function into
8453// a stub, but it got invalidated later on due to override on
8454// global object which is between interceptor and constant function' holders.
8455THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8456 v8::HandleScope scope;
8457 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8458 templ->SetNamedPropertyHandler(NoBlockGetterX);
8459 LocalContext context;
8460 context->Global()->Set(v8_str("o"), templ->NewInstance());
8461 v8::Handle<Value> value = CompileRun(
8462 "function inc(x) { return x + 1; };"
8463 "inc(1);"
8464 "o.__proto__ = this;"
8465 "this.__proto__.y = inc;"
8466 // Invoke it many times to compile a stub
8467 "for (var i = 0; i < 7; i++) {"
8468 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8469 "}"
8470 "this.y = function(x) { return x - 1; };"
8471 "var result = 0;"
8472 "for (var i = 0; i < 7; i++) {"
8473 " result += o.y(42);"
8474 "}");
8475 CHECK_EQ(41 * 7, value->Int32Value());
8476}
8477
8478
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008479// Test the case when actual function to call sits on global object.
8480THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8481 v8::HandleScope scope;
8482 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8483 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8484
8485 LocalContext context;
8486 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8487
8488 v8::Handle<Value> value = CompileRun(
8489 "try {"
8490 " o.__proto__ = this;"
8491 " for (var i = 0; i < 10; i++) {"
8492 " var v = o.parseFloat('239');"
8493 " if (v != 239) throw v;"
8494 // Now it should be ICed and keep a reference to parseFloat.
8495 " }"
8496 " var result = 0;"
8497 " for (var i = 0; i < 10; i++) {"
8498 " result += o.parseFloat('239');"
8499 " }"
8500 " result"
8501 "} catch(e) {"
8502 " e"
8503 "};");
8504 CHECK_EQ(239 * 10, value->Int32Value());
8505}
8506
ager@chromium.org5c838252010-02-19 08:53:10 +00008507static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8508 const AccessorInfo& info) {
8509 ApiTestFuzzer::Fuzz();
8510 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8511 ++(*call_count);
8512 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00008514 }
8515 return v8::Handle<Value>();
8516}
8517
8518static v8::Handle<Value> FastApiCallback_TrivialSignature(
8519 const v8::Arguments& args) {
8520 ApiTestFuzzer::Fuzz();
8521 CHECK_EQ(args.This(), args.Holder());
8522 CHECK(args.Data()->Equals(v8_str("method_data")));
8523 return v8::Integer::New(args[0]->Int32Value() + 1);
8524}
8525
8526static v8::Handle<Value> FastApiCallback_SimpleSignature(
8527 const v8::Arguments& args) {
8528 ApiTestFuzzer::Fuzz();
8529 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8530 CHECK(args.Data()->Equals(v8_str("method_data")));
8531 // Note, we're using HasRealNamedProperty instead of Has to avoid
8532 // invoking the interceptor again.
8533 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8534 return v8::Integer::New(args[0]->Int32Value() + 1);
8535}
8536
8537// Helper to maximize the odds of object moving.
8538static void GenerateSomeGarbage() {
8539 CompileRun(
8540 "var garbage;"
8541 "for (var i = 0; i < 1000; i++) {"
8542 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8543 "}"
8544 "garbage = undefined;");
8545}
8546
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008547
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008548v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8549 static int count = 0;
8550 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008551 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008552 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8553 }
8554 return v8::Handle<v8::Value>();
8555}
8556
8557
8558THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8559 v8::HandleScope scope;
8560 LocalContext context;
8561 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8562 nativeobject_templ->Set("callback",
8563 v8::FunctionTemplate::New(DirectApiCallback));
8564 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8565 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8566 // call the api function multiple times to ensure direct call stub creation.
8567 CompileRun(
8568 "function f() {"
8569 " for (var i = 1; i <= 30; i++) {"
8570 " nativeobject.callback();"
8571 " }"
8572 "}"
8573 "f();");
8574}
8575
8576
8577v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8578 return v8::ThrowException(v8_str("g"));
8579}
8580
8581
8582THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8583 v8::HandleScope scope;
8584 LocalContext context;
8585 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8586 nativeobject_templ->Set("callback",
8587 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8588 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8589 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8590 // call the api function multiple times to ensure direct call stub creation.
8591 v8::Handle<Value> result = CompileRun(
8592 "var result = '';"
8593 "function f() {"
8594 " for (var i = 1; i <= 5; i++) {"
8595 " try { nativeobject.callback(); } catch (e) { result += e; }"
8596 " }"
8597 "}"
8598 "f(); result;");
8599 CHECK_EQ(v8_str("ggggg"), result);
8600}
8601
8602
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008603v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8604 const v8::AccessorInfo& info) {
8605 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008607 GenerateSomeGarbage();
8608 }
8609 return v8::Handle<v8::Value>();
8610}
8611
8612
8613THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8614 v8::HandleScope scope;
8615 LocalContext context;
8616 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8617 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8618 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8619 p_getter_count = 0;
8620 CompileRun(
8621 "function f() {"
8622 " for (var i = 0; i < 30; i++) o1.p1;"
8623 "}"
8624 "f();");
8625 CHECK_EQ(30, p_getter_count);
8626}
8627
8628
8629v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8630 Local<String> name, const v8::AccessorInfo& info) {
8631 return v8::ThrowException(v8_str("g"));
8632}
8633
8634
8635THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8636 v8::HandleScope scope;
8637 LocalContext context;
8638 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8639 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8640 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8641 v8::Handle<Value> result = CompileRun(
8642 "var result = '';"
8643 "for (var i = 0; i < 5; i++) {"
8644 " try { o1.p1; } catch (e) { result += e; }"
8645 "}"
8646 "result;");
8647 CHECK_EQ(v8_str("ggggg"), result);
8648}
8649
8650
ager@chromium.org5c838252010-02-19 08:53:10 +00008651THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8652 int interceptor_call_count = 0;
8653 v8::HandleScope scope;
8654 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8655 v8::Handle<v8::FunctionTemplate> method_templ =
8656 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8657 v8_str("method_data"),
8658 v8::Handle<v8::Signature>());
8659 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8660 proto_templ->Set(v8_str("method"), method_templ);
8661 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8662 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8663 NULL, NULL, NULL, NULL,
8664 v8::External::Wrap(&interceptor_call_count));
8665 LocalContext context;
8666 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8667 GenerateSomeGarbage();
8668 context->Global()->Set(v8_str("o"), fun->NewInstance());
8669 v8::Handle<Value> value = CompileRun(
8670 "var result = 0;"
8671 "for (var i = 0; i < 100; i++) {"
8672 " result = o.method(41);"
8673 "}");
8674 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8675 CHECK_EQ(100, interceptor_call_count);
8676}
8677
8678THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8679 int interceptor_call_count = 0;
8680 v8::HandleScope scope;
8681 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8682 v8::Handle<v8::FunctionTemplate> method_templ =
8683 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8684 v8_str("method_data"),
8685 v8::Signature::New(fun_templ));
8686 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8687 proto_templ->Set(v8_str("method"), method_templ);
8688 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8689 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8690 NULL, NULL, NULL, NULL,
8691 v8::External::Wrap(&interceptor_call_count));
8692 LocalContext context;
8693 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8694 GenerateSomeGarbage();
8695 context->Global()->Set(v8_str("o"), fun->NewInstance());
8696 v8::Handle<Value> value = CompileRun(
8697 "o.foo = 17;"
8698 "var receiver = {};"
8699 "receiver.__proto__ = o;"
8700 "var result = 0;"
8701 "for (var i = 0; i < 100; i++) {"
8702 " result = receiver.method(41);"
8703 "}");
8704 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8705 CHECK_EQ(100, interceptor_call_count);
8706}
8707
8708THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8709 int interceptor_call_count = 0;
8710 v8::HandleScope scope;
8711 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8712 v8::Handle<v8::FunctionTemplate> method_templ =
8713 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8714 v8_str("method_data"),
8715 v8::Signature::New(fun_templ));
8716 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8717 proto_templ->Set(v8_str("method"), method_templ);
8718 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8719 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8720 NULL, NULL, NULL, NULL,
8721 v8::External::Wrap(&interceptor_call_count));
8722 LocalContext context;
8723 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8724 GenerateSomeGarbage();
8725 context->Global()->Set(v8_str("o"), fun->NewInstance());
8726 v8::Handle<Value> value = CompileRun(
8727 "o.foo = 17;"
8728 "var receiver = {};"
8729 "receiver.__proto__ = o;"
8730 "var result = 0;"
8731 "var saved_result = 0;"
8732 "for (var i = 0; i < 100; i++) {"
8733 " result = receiver.method(41);"
8734 " if (i == 50) {"
8735 " saved_result = result;"
8736 " receiver = {method: function(x) { return x - 1 }};"
8737 " }"
8738 "}");
8739 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8740 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8741 CHECK_GE(interceptor_call_count, 50);
8742}
8743
8744THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8745 int interceptor_call_count = 0;
8746 v8::HandleScope scope;
8747 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8748 v8::Handle<v8::FunctionTemplate> method_templ =
8749 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8750 v8_str("method_data"),
8751 v8::Signature::New(fun_templ));
8752 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8753 proto_templ->Set(v8_str("method"), method_templ);
8754 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8755 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8756 NULL, NULL, NULL, NULL,
8757 v8::External::Wrap(&interceptor_call_count));
8758 LocalContext context;
8759 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8760 GenerateSomeGarbage();
8761 context->Global()->Set(v8_str("o"), fun->NewInstance());
8762 v8::Handle<Value> value = CompileRun(
8763 "o.foo = 17;"
8764 "var receiver = {};"
8765 "receiver.__proto__ = o;"
8766 "var result = 0;"
8767 "var saved_result = 0;"
8768 "for (var i = 0; i < 100; i++) {"
8769 " result = receiver.method(41);"
8770 " if (i == 50) {"
8771 " saved_result = result;"
8772 " o.method = function(x) { return x - 1 };"
8773 " }"
8774 "}");
8775 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8776 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8777 CHECK_GE(interceptor_call_count, 50);
8778}
8779
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008780THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8781 int interceptor_call_count = 0;
8782 v8::HandleScope scope;
8783 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8784 v8::Handle<v8::FunctionTemplate> method_templ =
8785 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8786 v8_str("method_data"),
8787 v8::Signature::New(fun_templ));
8788 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8789 proto_templ->Set(v8_str("method"), method_templ);
8790 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8791 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8792 NULL, NULL, NULL, NULL,
8793 v8::External::Wrap(&interceptor_call_count));
8794 LocalContext context;
8795 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8796 GenerateSomeGarbage();
8797 context->Global()->Set(v8_str("o"), fun->NewInstance());
8798 v8::TryCatch try_catch;
8799 v8::Handle<Value> value = CompileRun(
8800 "o.foo = 17;"
8801 "var receiver = {};"
8802 "receiver.__proto__ = o;"
8803 "var result = 0;"
8804 "var saved_result = 0;"
8805 "for (var i = 0; i < 100; i++) {"
8806 " result = receiver.method(41);"
8807 " if (i == 50) {"
8808 " saved_result = result;"
8809 " receiver = 333;"
8810 " }"
8811 "}");
8812 CHECK(try_catch.HasCaught());
8813 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8814 try_catch.Exception()->ToString());
8815 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8816 CHECK_GE(interceptor_call_count, 50);
8817}
8818
ager@chromium.org5c838252010-02-19 08:53:10 +00008819THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8820 int interceptor_call_count = 0;
8821 v8::HandleScope scope;
8822 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8823 v8::Handle<v8::FunctionTemplate> method_templ =
8824 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8825 v8_str("method_data"),
8826 v8::Signature::New(fun_templ));
8827 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8828 proto_templ->Set(v8_str("method"), method_templ);
8829 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8830 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8831 NULL, NULL, NULL, NULL,
8832 v8::External::Wrap(&interceptor_call_count));
8833 LocalContext context;
8834 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8835 GenerateSomeGarbage();
8836 context->Global()->Set(v8_str("o"), fun->NewInstance());
8837 v8::TryCatch try_catch;
8838 v8::Handle<Value> value = CompileRun(
8839 "o.foo = 17;"
8840 "var receiver = {};"
8841 "receiver.__proto__ = o;"
8842 "var result = 0;"
8843 "var saved_result = 0;"
8844 "for (var i = 0; i < 100; i++) {"
8845 " result = receiver.method(41);"
8846 " if (i == 50) {"
8847 " saved_result = result;"
8848 " receiver = {method: receiver.method};"
8849 " }"
8850 "}");
8851 CHECK(try_catch.HasCaught());
8852 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8853 try_catch.Exception()->ToString());
8854 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8855 CHECK_GE(interceptor_call_count, 50);
8856}
8857
8858THREADED_TEST(CallICFastApi_TrivialSignature) {
8859 v8::HandleScope scope;
8860 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8861 v8::Handle<v8::FunctionTemplate> method_templ =
8862 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8863 v8_str("method_data"),
8864 v8::Handle<v8::Signature>());
8865 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8866 proto_templ->Set(v8_str("method"), method_templ);
8867 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8868 LocalContext context;
8869 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8870 GenerateSomeGarbage();
8871 context->Global()->Set(v8_str("o"), fun->NewInstance());
8872 v8::Handle<Value> value = CompileRun(
8873 "var result = 0;"
8874 "for (var i = 0; i < 100; i++) {"
8875 " result = o.method(41);"
8876 "}");
8877
8878 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8879}
8880
8881THREADED_TEST(CallICFastApi_SimpleSignature) {
8882 v8::HandleScope scope;
8883 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8884 v8::Handle<v8::FunctionTemplate> method_templ =
8885 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8886 v8_str("method_data"),
8887 v8::Signature::New(fun_templ));
8888 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8889 proto_templ->Set(v8_str("method"), method_templ);
8890 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8891 LocalContext context;
8892 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8893 GenerateSomeGarbage();
8894 context->Global()->Set(v8_str("o"), fun->NewInstance());
8895 v8::Handle<Value> value = CompileRun(
8896 "o.foo = 17;"
8897 "var receiver = {};"
8898 "receiver.__proto__ = o;"
8899 "var result = 0;"
8900 "for (var i = 0; i < 100; i++) {"
8901 " result = receiver.method(41);"
8902 "}");
8903
8904 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8905}
8906
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008907THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008908 v8::HandleScope scope;
8909 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8910 v8::Handle<v8::FunctionTemplate> method_templ =
8911 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8912 v8_str("method_data"),
8913 v8::Signature::New(fun_templ));
8914 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8915 proto_templ->Set(v8_str("method"), method_templ);
8916 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8917 LocalContext context;
8918 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8919 GenerateSomeGarbage();
8920 context->Global()->Set(v8_str("o"), fun->NewInstance());
8921 v8::Handle<Value> value = CompileRun(
8922 "o.foo = 17;"
8923 "var receiver = {};"
8924 "receiver.__proto__ = o;"
8925 "var result = 0;"
8926 "var saved_result = 0;"
8927 "for (var i = 0; i < 100; i++) {"
8928 " result = receiver.method(41);"
8929 " if (i == 50) {"
8930 " saved_result = result;"
8931 " receiver = {method: function(x) { return x - 1 }};"
8932 " }"
8933 "}");
8934 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8935 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8936}
8937
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008938THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8939 v8::HandleScope scope;
8940 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8941 v8::Handle<v8::FunctionTemplate> method_templ =
8942 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8943 v8_str("method_data"),
8944 v8::Signature::New(fun_templ));
8945 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8946 proto_templ->Set(v8_str("method"), method_templ);
8947 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8948 LocalContext context;
8949 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8950 GenerateSomeGarbage();
8951 context->Global()->Set(v8_str("o"), fun->NewInstance());
8952 v8::TryCatch try_catch;
8953 v8::Handle<Value> value = CompileRun(
8954 "o.foo = 17;"
8955 "var receiver = {};"
8956 "receiver.__proto__ = o;"
8957 "var result = 0;"
8958 "var saved_result = 0;"
8959 "for (var i = 0; i < 100; i++) {"
8960 " result = receiver.method(41);"
8961 " if (i == 50) {"
8962 " saved_result = result;"
8963 " receiver = 333;"
8964 " }"
8965 "}");
8966 CHECK(try_catch.HasCaught());
8967 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8968 try_catch.Exception()->ToString());
8969 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8970}
8971
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008972
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008973v8::Handle<Value> keyed_call_ic_function;
8974
8975static v8::Handle<Value> InterceptorKeyedCallICGetter(
8976 Local<String> name, const AccessorInfo& info) {
8977 ApiTestFuzzer::Fuzz();
8978 if (v8_str("x")->Equals(name)) {
8979 return keyed_call_ic_function;
8980 }
8981 return v8::Handle<Value>();
8982}
8983
8984
8985// Test the case when we stored cacheable lookup into
8986// a stub, but the function name changed (to another cacheable function).
8987THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8988 v8::HandleScope scope;
8989 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8990 templ->SetNamedPropertyHandler(NoBlockGetterX);
8991 LocalContext context;
8992 context->Global()->Set(v8_str("o"), templ->NewInstance());
8993 v8::Handle<Value> value = CompileRun(
8994 "proto = new Object();"
8995 "proto.y = function(x) { return x + 1; };"
8996 "proto.z = function(x) { return x - 1; };"
8997 "o.__proto__ = proto;"
8998 "var result = 0;"
8999 "var method = 'y';"
9000 "for (var i = 0; i < 10; i++) {"
9001 " if (i == 5) { method = 'z'; };"
9002 " result += o[method](41);"
9003 "}");
9004 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9005}
9006
9007
9008// Test the case when we stored cacheable lookup into
9009// a stub, but the function name changed (and the new function is present
9010// both before and after the interceptor in the prototype chain).
9011THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9012 v8::HandleScope scope;
9013 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9014 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9015 LocalContext context;
9016 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9017 keyed_call_ic_function =
9018 v8_compile("function f(x) { return x - 1; }; f")->Run();
9019 v8::Handle<Value> value = CompileRun(
9020 "o = new Object();"
9021 "proto2 = new Object();"
9022 "o.y = function(x) { return x + 1; };"
9023 "proto2.y = function(x) { return x + 2; };"
9024 "o.__proto__ = proto1;"
9025 "proto1.__proto__ = proto2;"
9026 "var result = 0;"
9027 "var method = 'x';"
9028 "for (var i = 0; i < 10; i++) {"
9029 " if (i == 5) { method = 'y'; };"
9030 " result += o[method](41);"
9031 "}");
9032 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9033}
9034
9035
9036// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9037// on the global object.
9038THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9039 v8::HandleScope scope;
9040 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9041 templ->SetNamedPropertyHandler(NoBlockGetterX);
9042 LocalContext context;
9043 context->Global()->Set(v8_str("o"), templ->NewInstance());
9044 v8::Handle<Value> value = CompileRun(
9045 "function inc(x) { return x + 1; };"
9046 "inc(1);"
9047 "function dec(x) { return x - 1; };"
9048 "dec(1);"
9049 "o.__proto__ = this;"
9050 "this.__proto__.x = inc;"
9051 "this.__proto__.y = dec;"
9052 "var result = 0;"
9053 "var method = 'x';"
9054 "for (var i = 0; i < 10; i++) {"
9055 " if (i == 5) { method = 'y'; };"
9056 " result += o[method](41);"
9057 "}");
9058 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9059}
9060
9061
9062// Test the case when actual function to call sits on global object.
9063THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9064 v8::HandleScope scope;
9065 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9066 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9067 LocalContext context;
9068 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9069
9070 v8::Handle<Value> value = CompileRun(
9071 "function len(x) { return x.length; };"
9072 "o.__proto__ = this;"
9073 "var m = 'parseFloat';"
9074 "var result = 0;"
9075 "for (var i = 0; i < 10; i++) {"
9076 " if (i == 5) {"
9077 " m = 'len';"
9078 " saved_result = result;"
9079 " };"
9080 " result = o[m]('239');"
9081 "}");
9082 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9083 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9084}
9085
9086// Test the map transition before the interceptor.
9087THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9088 v8::HandleScope scope;
9089 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9090 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9091 LocalContext context;
9092 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9093
9094 v8::Handle<Value> value = CompileRun(
9095 "var o = new Object();"
9096 "o.__proto__ = proto;"
9097 "o.method = function(x) { return x + 1; };"
9098 "var m = 'method';"
9099 "var result = 0;"
9100 "for (var i = 0; i < 10; i++) {"
9101 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9102 " result += o[m](41);"
9103 "}");
9104 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9105}
9106
9107
9108// Test the map transition after the interceptor.
9109THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9110 v8::HandleScope scope;
9111 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9112 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9113 LocalContext context;
9114 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9115
9116 v8::Handle<Value> value = CompileRun(
9117 "var proto = new Object();"
9118 "o.__proto__ = proto;"
9119 "proto.method = function(x) { return x + 1; };"
9120 "var m = 'method';"
9121 "var result = 0;"
9122 "for (var i = 0; i < 10; i++) {"
9123 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9124 " result += o[m](41);"
9125 "}");
9126 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9127}
9128
9129
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009130static int interceptor_call_count = 0;
9131
9132static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9133 const AccessorInfo& info) {
9134 ApiTestFuzzer::Fuzz();
9135 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9136 return call_ic_function2;
9137 }
9138 return v8::Handle<Value>();
9139}
9140
9141
9142// This test should hit load and call ICs for the interceptor case.
9143// Once in a while, the interceptor will reply that a property was not
9144// found in which case we should get a reference error.
9145THREADED_TEST(InterceptorICReferenceErrors) {
9146 v8::HandleScope scope;
9147 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9148 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9149 LocalContext context(0, templ, v8::Handle<Value>());
9150 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9151 v8::Handle<Value> value = CompileRun(
9152 "function f() {"
9153 " for (var i = 0; i < 1000; i++) {"
9154 " try { x; } catch(e) { return true; }"
9155 " }"
9156 " return false;"
9157 "};"
9158 "f();");
9159 CHECK_EQ(true, value->BooleanValue());
9160 interceptor_call_count = 0;
9161 value = CompileRun(
9162 "function g() {"
9163 " for (var i = 0; i < 1000; i++) {"
9164 " try { x(42); } catch(e) { return true; }"
9165 " }"
9166 " return false;"
9167 "};"
9168 "g();");
9169 CHECK_EQ(true, value->BooleanValue());
9170}
9171
9172
9173static int interceptor_ic_exception_get_count = 0;
9174
9175static v8::Handle<Value> InterceptorICExceptionGetter(
9176 Local<String> name,
9177 const AccessorInfo& info) {
9178 ApiTestFuzzer::Fuzz();
9179 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9180 return call_ic_function3;
9181 }
9182 if (interceptor_ic_exception_get_count == 20) {
9183 return v8::ThrowException(v8_num(42));
9184 }
9185 // Do not handle get for properties other than x.
9186 return v8::Handle<Value>();
9187}
9188
9189// Test interceptor load/call IC where the interceptor throws an
9190// exception once in a while.
9191THREADED_TEST(InterceptorICGetterExceptions) {
9192 interceptor_ic_exception_get_count = 0;
9193 v8::HandleScope scope;
9194 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9195 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9196 LocalContext context(0, templ, v8::Handle<Value>());
9197 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9198 v8::Handle<Value> value = CompileRun(
9199 "function f() {"
9200 " for (var i = 0; i < 100; i++) {"
9201 " try { x; } catch(e) { return true; }"
9202 " }"
9203 " return false;"
9204 "};"
9205 "f();");
9206 CHECK_EQ(true, value->BooleanValue());
9207 interceptor_ic_exception_get_count = 0;
9208 value = CompileRun(
9209 "function f() {"
9210 " for (var i = 0; i < 100; i++) {"
9211 " try { x(42); } catch(e) { return true; }"
9212 " }"
9213 " return false;"
9214 "};"
9215 "f();");
9216 CHECK_EQ(true, value->BooleanValue());
9217}
9218
9219
9220static int interceptor_ic_exception_set_count = 0;
9221
9222static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009223 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009224 ApiTestFuzzer::Fuzz();
9225 if (++interceptor_ic_exception_set_count > 20) {
9226 return v8::ThrowException(v8_num(42));
9227 }
9228 // Do not actually handle setting.
9229 return v8::Handle<Value>();
9230}
9231
9232// Test interceptor store IC where the interceptor throws an exception
9233// once in a while.
9234THREADED_TEST(InterceptorICSetterExceptions) {
9235 interceptor_ic_exception_set_count = 0;
9236 v8::HandleScope scope;
9237 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9238 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9239 LocalContext context(0, templ, v8::Handle<Value>());
9240 v8::Handle<Value> value = CompileRun(
9241 "function f() {"
9242 " for (var i = 0; i < 100; i++) {"
9243 " try { x = 42; } catch(e) { return true; }"
9244 " }"
9245 " return false;"
9246 "};"
9247 "f();");
9248 CHECK_EQ(true, value->BooleanValue());
9249}
9250
9251
9252// Test that we ignore null interceptors.
9253THREADED_TEST(NullNamedInterceptor) {
9254 v8::HandleScope scope;
9255 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9256 templ->SetNamedPropertyHandler(0);
9257 LocalContext context;
9258 templ->Set("x", v8_num(42));
9259 v8::Handle<v8::Object> obj = templ->NewInstance();
9260 context->Global()->Set(v8_str("obj"), obj);
9261 v8::Handle<Value> value = CompileRun("obj.x");
9262 CHECK(value->IsInt32());
9263 CHECK_EQ(42, value->Int32Value());
9264}
9265
9266
9267// Test that we ignore null interceptors.
9268THREADED_TEST(NullIndexedInterceptor) {
9269 v8::HandleScope scope;
9270 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9271 templ->SetIndexedPropertyHandler(0);
9272 LocalContext context;
9273 templ->Set("42", v8_num(42));
9274 v8::Handle<v8::Object> obj = templ->NewInstance();
9275 context->Global()->Set(v8_str("obj"), obj);
9276 v8::Handle<Value> value = CompileRun("obj[42]");
9277 CHECK(value->IsInt32());
9278 CHECK_EQ(42, value->Int32Value());
9279}
9280
9281
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009282THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9283 v8::HandleScope scope;
9284 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9285 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9286 LocalContext env;
9287 env->Global()->Set(v8_str("obj"),
9288 templ->GetFunction()->NewInstance());
9289 ExpectTrue("obj.x === 42");
9290 ExpectTrue("!obj.propertyIsEnumerable('x')");
9291}
9292
9293
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009294static Handle<Value> ThrowingGetter(Local<String> name,
9295 const AccessorInfo& info) {
9296 ApiTestFuzzer::Fuzz();
9297 ThrowException(Handle<Value>());
9298 return Undefined();
9299}
9300
9301
9302THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9303 HandleScope scope;
9304 LocalContext context;
9305
9306 Local<FunctionTemplate> templ = FunctionTemplate::New();
9307 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9308 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9309
9310 Local<Object> instance = templ->GetFunction()->NewInstance();
9311
9312 Local<Object> another = Object::New();
9313 another->SetPrototype(instance);
9314
9315 Local<Object> with_js_getter = CompileRun(
9316 "o = {};\n"
9317 "o.__defineGetter__('f', function() { throw undefined; });\n"
9318 "o\n").As<Object>();
9319 CHECK(!with_js_getter.IsEmpty());
9320
9321 TryCatch try_catch;
9322
9323 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9324 CHECK(try_catch.HasCaught());
9325 try_catch.Reset();
9326 CHECK(result.IsEmpty());
9327
9328 result = another->GetRealNamedProperty(v8_str("f"));
9329 CHECK(try_catch.HasCaught());
9330 try_catch.Reset();
9331 CHECK(result.IsEmpty());
9332
9333 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9334 CHECK(try_catch.HasCaught());
9335 try_catch.Reset();
9336 CHECK(result.IsEmpty());
9337
9338 result = another->Get(v8_str("f"));
9339 CHECK(try_catch.HasCaught());
9340 try_catch.Reset();
9341 CHECK(result.IsEmpty());
9342
9343 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9344 CHECK(try_catch.HasCaught());
9345 try_catch.Reset();
9346 CHECK(result.IsEmpty());
9347
9348 result = with_js_getter->Get(v8_str("f"));
9349 CHECK(try_catch.HasCaught());
9350 try_catch.Reset();
9351 CHECK(result.IsEmpty());
9352}
9353
9354
9355static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9356 TryCatch try_catch;
9357 // Verboseness is important: it triggers message delivery which can call into
9358 // external code.
9359 try_catch.SetVerbose(true);
9360 CompileRun("throw 'from JS';");
9361 CHECK(try_catch.HasCaught());
9362 CHECK(!i::Isolate::Current()->has_pending_exception());
9363 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9364 return Undefined();
9365}
9366
9367
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009368static int call_depth;
9369
9370
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009371static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9372 TryCatch try_catch;
9373}
9374
9375
9376static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009377 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009378}
9379
9380
9381static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009382 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009383}
9384
9385
9386static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9387 Handle<String> errorMessageString = message->Get();
9388 CHECK(!errorMessageString.IsEmpty());
9389 message->GetStackTrace();
9390 message->GetScriptResourceName();
9391}
9392
9393THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9394 HandleScope scope;
9395 LocalContext context;
9396
9397 Local<Function> func =
9398 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9399 context->Global()->Set(v8_str("func"), func);
9400
9401 MessageCallback callbacks[] =
9402 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9403 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9404 MessageCallback callback = callbacks[i];
9405 if (callback != NULL) {
9406 V8::AddMessageListener(callback);
9407 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009408 // Some small number to control number of times message handler should
9409 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009410 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009411 ExpectFalse(
9412 "var thrown = false;\n"
9413 "try { func(); } catch(e) { thrown = true; }\n"
9414 "thrown\n");
9415 if (callback != NULL) {
9416 V8::RemoveMessageListeners(callback);
9417 }
9418 }
9419}
9420
9421
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009422static v8::Handle<Value> ParentGetter(Local<String> name,
9423 const AccessorInfo& info) {
9424 ApiTestFuzzer::Fuzz();
9425 return v8_num(1);
9426}
9427
9428
9429static v8::Handle<Value> ChildGetter(Local<String> name,
9430 const AccessorInfo& info) {
9431 ApiTestFuzzer::Fuzz();
9432 return v8_num(42);
9433}
9434
9435
9436THREADED_TEST(Overriding) {
9437 v8::HandleScope scope;
9438 LocalContext context;
9439
9440 // Parent template.
9441 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9442 Local<ObjectTemplate> parent_instance_templ =
9443 parent_templ->InstanceTemplate();
9444 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9445
9446 // Template that inherits from the parent template.
9447 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9448 Local<ObjectTemplate> child_instance_templ =
9449 child_templ->InstanceTemplate();
9450 child_templ->Inherit(parent_templ);
9451 // Override 'f'. The child version of 'f' should get called for child
9452 // instances.
9453 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9454 // Add 'g' twice. The 'g' added last should get called for instances.
9455 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9456 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9457
9458 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9459 // so 'h' can be shadowed on the instance object.
9460 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9461 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9462 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9463
9464 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9465 // but the attribute does not have effect because it is duplicated with
9466 // NULL setter.
9467 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9468 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9469
9470
9471
9472 // Instantiate the child template.
9473 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9474
9475 // Check that the child function overrides the parent one.
9476 context->Global()->Set(v8_str("o"), instance);
9477 Local<Value> value = v8_compile("o.f")->Run();
9478 // Check that the 'g' that was added last is hit.
9479 CHECK_EQ(42, value->Int32Value());
9480 value = v8_compile("o.g")->Run();
9481 CHECK_EQ(42, value->Int32Value());
9482
9483 // Check 'h' can be shadowed.
9484 value = v8_compile("o.h = 3; o.h")->Run();
9485 CHECK_EQ(3, value->Int32Value());
9486
9487 // Check 'i' is cannot be shadowed or changed.
9488 value = v8_compile("o.i = 3; o.i")->Run();
9489 CHECK_EQ(42, value->Int32Value());
9490}
9491
9492
9493static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9494 ApiTestFuzzer::Fuzz();
9495 if (args.IsConstructCall()) {
9496 return v8::Boolean::New(true);
9497 }
9498 return v8::Boolean::New(false);
9499}
9500
9501
9502THREADED_TEST(IsConstructCall) {
9503 v8::HandleScope scope;
9504
9505 // Function template with call handler.
9506 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9507 templ->SetCallHandler(IsConstructHandler);
9508
9509 LocalContext context;
9510
9511 context->Global()->Set(v8_str("f"), templ->GetFunction());
9512 Local<Value> value = v8_compile("f()")->Run();
9513 CHECK(!value->BooleanValue());
9514 value = v8_compile("new f()")->Run();
9515 CHECK(value->BooleanValue());
9516}
9517
9518
9519THREADED_TEST(ObjectProtoToString) {
9520 v8::HandleScope scope;
9521 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9522 templ->SetClassName(v8_str("MyClass"));
9523
9524 LocalContext context;
9525
9526 Local<String> customized_tostring = v8_str("customized toString");
9527
9528 // Replace Object.prototype.toString
9529 v8_compile("Object.prototype.toString = function() {"
9530 " return 'customized toString';"
9531 "}")->Run();
9532
9533 // Normal ToString call should call replaced Object.prototype.toString
9534 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9535 Local<String> value = instance->ToString();
9536 CHECK(value->IsString() && value->Equals(customized_tostring));
9537
9538 // ObjectProtoToString should not call replace toString function.
9539 value = instance->ObjectProtoToString();
9540 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9541
9542 // Check global
9543 value = context->Global()->ObjectProtoToString();
9544 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9545
9546 // Check ordinary object
9547 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009548 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009549 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9550}
9551
9552
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009553THREADED_TEST(ObjectGetConstructorName) {
9554 v8::HandleScope scope;
9555 LocalContext context;
9556 v8_compile("function Parent() {};"
9557 "function Child() {};"
9558 "Child.prototype = new Parent();"
9559 "var outer = { inner: function() { } };"
9560 "var p = new Parent();"
9561 "var c = new Child();"
9562 "var x = new outer.inner();")->Run();
9563
9564 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9565 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9566 v8_str("Parent")));
9567
9568 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9569 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9570 v8_str("Child")));
9571
9572 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9573 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9574 v8_str("outer.inner")));
9575}
9576
9577
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009578bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009579i::Semaphore* ApiTestFuzzer::all_tests_done_=
9580 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009581int ApiTestFuzzer::active_tests_;
9582int ApiTestFuzzer::tests_being_run_;
9583int ApiTestFuzzer::current_;
9584
9585
9586// We are in a callback and want to switch to another thread (if we
9587// are currently running the thread fuzzing test).
9588void ApiTestFuzzer::Fuzz() {
9589 if (!fuzzing_) return;
9590 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9591 test->ContextSwitch();
9592}
9593
9594
9595// Let the next thread go. Since it is also waiting on the V8 lock it may
9596// not start immediately.
9597bool ApiTestFuzzer::NextThread() {
9598 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009599 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009600 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009601 if (kLogThreading)
9602 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009603 return false;
9604 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009605 if (kLogThreading) {
9606 printf("Switch from %s to %s\n",
9607 test_name,
9608 RegisterThreadedTest::nth(test_position)->name());
9609 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009610 current_ = test_position;
9611 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9612 return true;
9613}
9614
9615
9616void ApiTestFuzzer::Run() {
9617 // When it is our turn...
9618 gate_->Wait();
9619 {
9620 // ... get the V8 lock and start running the test.
9621 v8::Locker locker;
9622 CallTest();
9623 }
9624 // This test finished.
9625 active_ = false;
9626 active_tests_--;
9627 // If it was the last then signal that fact.
9628 if (active_tests_ == 0) {
9629 all_tests_done_->Signal();
9630 } else {
9631 // Otherwise select a new test and start that.
9632 NextThread();
9633 }
9634}
9635
9636
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009637static unsigned linear_congruential_generator;
9638
9639
9640void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009641 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009642 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +00009643 int count = RegisterThreadedTest::count();
9644 int start = count * part / (LAST_PART + 1);
9645 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9646 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009647 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009648 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009649 }
9650 for (int i = 0; i < active_tests_; i++) {
9651 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9652 }
9653}
9654
9655
9656static void CallTestNumber(int test_number) {
9657 (RegisterThreadedTest::nth(test_number)->callback())();
9658}
9659
9660
9661void ApiTestFuzzer::RunAllTests() {
9662 // Set off the first test.
9663 current_ = -1;
9664 NextThread();
9665 // Wait till they are all done.
9666 all_tests_done_->Wait();
9667}
9668
9669
9670int ApiTestFuzzer::GetNextTestNumber() {
9671 int next_test;
9672 do {
9673 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9674 linear_congruential_generator *= 1664525u;
9675 linear_congruential_generator += 1013904223u;
9676 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9677 return next_test;
9678}
9679
9680
9681void ApiTestFuzzer::ContextSwitch() {
9682 // If the new thread is the same as the current thread there is nothing to do.
9683 if (NextThread()) {
9684 // Now it can start.
9685 v8::Unlocker unlocker;
9686 // Wait till someone starts us again.
9687 gate_->Wait();
9688 // And we're off.
9689 }
9690}
9691
9692
9693void ApiTestFuzzer::TearDown() {
9694 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009695 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9696 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9697 if (fuzzer != NULL) fuzzer->Join();
9698 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009699}
9700
9701
9702// Lets not be needlessly self-referential.
9703TEST(Threading) {
9704 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9705 ApiTestFuzzer::RunAllTests();
9706 ApiTestFuzzer::TearDown();
9707}
9708
9709TEST(Threading2) {
9710 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9711 ApiTestFuzzer::RunAllTests();
9712 ApiTestFuzzer::TearDown();
9713}
9714
lrn@chromium.org1c092762011-05-09 09:42:16 +00009715TEST(Threading3) {
9716 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9717 ApiTestFuzzer::RunAllTests();
9718 ApiTestFuzzer::TearDown();
9719}
9720
9721TEST(Threading4) {
9722 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9723 ApiTestFuzzer::RunAllTests();
9724 ApiTestFuzzer::TearDown();
9725}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009726
9727void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009728 if (kLogThreading)
9729 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009730 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009731 if (kLogThreading)
9732 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009733}
9734
9735
9736static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009737 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009738 ApiTestFuzzer::Fuzz();
9739 v8::Unlocker unlocker;
9740 const char* code = "throw 7;";
9741 {
9742 v8::Locker nested_locker;
9743 v8::HandleScope scope;
9744 v8::Handle<Value> exception;
9745 { v8::TryCatch try_catch;
9746 v8::Handle<Value> value = CompileRun(code);
9747 CHECK(value.IsEmpty());
9748 CHECK(try_catch.HasCaught());
9749 // Make sure to wrap the exception in a new handle because
9750 // the handle returned from the TryCatch is destroyed
9751 // when the TryCatch is destroyed.
9752 exception = Local<Value>::New(try_catch.Exception());
9753 }
9754 return v8::ThrowException(exception);
9755 }
9756}
9757
9758
9759static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009760 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009761 ApiTestFuzzer::Fuzz();
9762 v8::Unlocker unlocker;
9763 const char* code = "throw 7;";
9764 {
9765 v8::Locker nested_locker;
9766 v8::HandleScope scope;
9767 v8::Handle<Value> value = CompileRun(code);
9768 CHECK(value.IsEmpty());
9769 return v8_str("foo");
9770 }
9771}
9772
9773
9774// These are locking tests that don't need to be run again
9775// as part of the locking aggregation tests.
9776TEST(NestedLockers) {
9777 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009778 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009779 v8::HandleScope scope;
9780 LocalContext env;
9781 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9782 Local<Function> fun = fun_templ->GetFunction();
9783 env->Global()->Set(v8_str("throw_in_js"), fun);
9784 Local<Script> script = v8_compile("(function () {"
9785 " try {"
9786 " throw_in_js();"
9787 " return 42;"
9788 " } catch (e) {"
9789 " return e * 13;"
9790 " }"
9791 "})();");
9792 CHECK_EQ(91, script->Run()->Int32Value());
9793}
9794
9795
9796// These are locking tests that don't need to be run again
9797// as part of the locking aggregation tests.
9798TEST(NestedLockersNoTryCatch) {
9799 v8::Locker locker;
9800 v8::HandleScope scope;
9801 LocalContext env;
9802 Local<v8::FunctionTemplate> fun_templ =
9803 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9804 Local<Function> fun = fun_templ->GetFunction();
9805 env->Global()->Set(v8_str("throw_in_js"), fun);
9806 Local<Script> script = v8_compile("(function () {"
9807 " try {"
9808 " throw_in_js();"
9809 " return 42;"
9810 " } catch (e) {"
9811 " return e * 13;"
9812 " }"
9813 "})();");
9814 CHECK_EQ(91, script->Run()->Int32Value());
9815}
9816
9817
9818THREADED_TEST(RecursiveLocking) {
9819 v8::Locker locker;
9820 {
9821 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009822 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009823 }
9824}
9825
9826
9827static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9828 ApiTestFuzzer::Fuzz();
9829 v8::Unlocker unlocker;
9830 return v8::Undefined();
9831}
9832
9833
9834THREADED_TEST(LockUnlockLock) {
9835 {
9836 v8::Locker locker;
9837 v8::HandleScope scope;
9838 LocalContext env;
9839 Local<v8::FunctionTemplate> fun_templ =
9840 v8::FunctionTemplate::New(UnlockForAMoment);
9841 Local<Function> fun = fun_templ->GetFunction();
9842 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9843 Local<Script> script = v8_compile("(function () {"
9844 " unlock_for_a_moment();"
9845 " return 42;"
9846 "})();");
9847 CHECK_EQ(42, script->Run()->Int32Value());
9848 }
9849 {
9850 v8::Locker locker;
9851 v8::HandleScope scope;
9852 LocalContext env;
9853 Local<v8::FunctionTemplate> fun_templ =
9854 v8::FunctionTemplate::New(UnlockForAMoment);
9855 Local<Function> fun = fun_templ->GetFunction();
9856 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9857 Local<Script> script = v8_compile("(function () {"
9858 " unlock_for_a_moment();"
9859 " return 42;"
9860 "})();");
9861 CHECK_EQ(42, script->Run()->Int32Value());
9862 }
9863}
9864
9865
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009866static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009867 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009868 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009869 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9870 if (object->IsJSGlobalObject()) count++;
9871 return count;
9872}
9873
9874
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009875static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009876 // We need to collect all garbage twice to be sure that everything
9877 // has been collected. This is because inline caches are cleared in
9878 // the first garbage collection but some of the maps have already
9879 // been marked at that point. Therefore some of the maps are not
9880 // collected until the second garbage collection.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009881 HEAP->global_context_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 HEAP->CollectAllGarbage(false);
9883 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009884 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009885#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009886 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009887#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009888 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009889}
9890
9891
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009892TEST(DontLeakGlobalObjects) {
9893 // Regression test for issues 1139850 and 1174891.
9894
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009895 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009896
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009897 for (int i = 0; i < 5; i++) {
9898 { v8::HandleScope scope;
9899 LocalContext context;
9900 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009901 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009902
9903 { v8::HandleScope scope;
9904 LocalContext context;
9905 v8_compile("Date")->Run();
9906 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009907 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009908
9909 { v8::HandleScope scope;
9910 LocalContext context;
9911 v8_compile("/aaa/")->Run();
9912 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009913 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009914
9915 { v8::HandleScope scope;
9916 const char* extension_list[] = { "v8/gc" };
9917 v8::ExtensionConfiguration extensions(1, extension_list);
9918 LocalContext context(&extensions);
9919 v8_compile("gc();")->Run();
9920 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009921 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009922 }
9923}
9924
9925
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009926v8::Persistent<v8::Object> some_object;
9927v8::Persistent<v8::Object> bad_handle;
9928
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009929void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009930 v8::HandleScope scope;
9931 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009932 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009933}
9934
9935
9936THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9937 LocalContext context;
9938
9939 v8::Persistent<v8::Object> handle1, handle2;
9940 {
9941 v8::HandleScope scope;
9942 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9943 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9944 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9945 }
9946 // Note: order is implementation dependent alas: currently
9947 // global handle nodes are processed by PostGarbageCollectionProcessing
9948 // in reverse allocation order, so if second allocated handle is deleted,
9949 // weak callback of the first handle would be able to 'reallocate' it.
9950 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9951 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009953}
9954
9955
9956v8::Persistent<v8::Object> to_be_disposed;
9957
9958void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9959 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009961 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009962}
9963
9964
9965THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9966 LocalContext context;
9967
9968 v8::Persistent<v8::Object> handle1, handle2;
9969 {
9970 v8::HandleScope scope;
9971 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9972 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9973 }
9974 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9975 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009977}
9978
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009979void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9980 handle.Dispose();
9981}
9982
9983void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9984 v8::HandleScope scope;
9985 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009986 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009987}
9988
9989
9990THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9991 LocalContext context;
9992
9993 v8::Persistent<v8::Object> handle1, handle2, handle3;
9994 {
9995 v8::HandleScope scope;
9996 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9997 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9998 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9999 }
10000 handle2.MakeWeak(NULL, DisposingCallback);
10001 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010003}
10004
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010005
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010006THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010007 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010008
10009 const int nof = 2;
10010 const char* sources[nof] = {
10011 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10012 "Object()"
10013 };
10014
10015 for (int i = 0; i < nof; i++) {
10016 const char* source = sources[i];
10017 { v8::HandleScope scope;
10018 LocalContext context;
10019 CompileRun(source);
10020 }
10021 { v8::HandleScope scope;
10022 LocalContext context;
10023 CompileRun(source);
10024 }
10025 }
10026}
10027
10028
10029static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10030 v8::HandleScope inner;
10031 env->Enter();
10032 v8::Handle<Value> three = v8_num(3);
10033 v8::Handle<Value> value = inner.Close(three);
10034 env->Exit();
10035 return value;
10036}
10037
10038
10039THREADED_TEST(NestedHandleScopeAndContexts) {
10040 v8::HandleScope outer;
10041 v8::Persistent<Context> env = Context::New();
10042 env->Enter();
10043 v8::Handle<Value> value = NestedScope(env);
10044 v8::Handle<String> str = value->ToString();
10045 env->Exit();
10046 env.Dispose();
10047}
10048
10049
10050THREADED_TEST(ExternalAllocatedMemory) {
10051 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010052 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010053 const int kSize = 1024*1024;
10054 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10055 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10056}
10057
10058
10059THREADED_TEST(DisposeEnteredContext) {
10060 v8::HandleScope scope;
10061 LocalContext outer;
10062 { v8::Persistent<v8::Context> inner = v8::Context::New();
10063 inner->Enter();
10064 inner.Dispose();
10065 inner.Clear();
10066 inner->Exit();
10067 }
10068}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010069
10070
10071// Regression test for issue 54, object templates with internal fields
10072// but no accessors or interceptors did not get their internal field
10073// count set on instances.
10074THREADED_TEST(Regress54) {
10075 v8::HandleScope outer;
10076 LocalContext context;
10077 static v8::Persistent<v8::ObjectTemplate> templ;
10078 if (templ.IsEmpty()) {
10079 v8::HandleScope inner;
10080 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10081 local->SetInternalFieldCount(1);
10082 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10083 }
10084 v8::Handle<v8::Object> result = templ->NewInstance();
10085 CHECK_EQ(1, result->InternalFieldCount());
10086}
10087
10088
10089// If part of the threaded tests, this test makes ThreadingTest fail
10090// on mac.
10091TEST(CatchStackOverflow) {
10092 v8::HandleScope scope;
10093 LocalContext context;
10094 v8::TryCatch try_catch;
10095 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10096 "function f() {"
10097 " return f();"
10098 "}"
10099 ""
10100 "f();"));
10101 v8::Handle<v8::Value> result = script->Run();
10102 CHECK(result.IsEmpty());
10103}
10104
10105
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010106static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10107 const char* resource_name,
10108 int line_offset) {
10109 v8::HandleScope scope;
10110 v8::TryCatch try_catch;
10111 v8::Handle<v8::Value> result = script->Run();
10112 CHECK(result.IsEmpty());
10113 CHECK(try_catch.HasCaught());
10114 v8::Handle<v8::Message> message = try_catch.Message();
10115 CHECK(!message.IsEmpty());
10116 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10117 CHECK_EQ(91, message->GetStartPosition());
10118 CHECK_EQ(92, message->GetEndPosition());
10119 CHECK_EQ(2, message->GetStartColumn());
10120 CHECK_EQ(3, message->GetEndColumn());
10121 v8::String::AsciiValue line(message->GetSourceLine());
10122 CHECK_EQ(" throw 'nirk';", *line);
10123 v8::String::AsciiValue name(message->GetScriptResourceName());
10124 CHECK_EQ(resource_name, *name);
10125}
10126
10127
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010128THREADED_TEST(TryCatchSourceInfo) {
10129 v8::HandleScope scope;
10130 LocalContext context;
10131 v8::Handle<v8::String> source = v8::String::New(
10132 "function Foo() {\n"
10133 " return Bar();\n"
10134 "}\n"
10135 "\n"
10136 "function Bar() {\n"
10137 " return Baz();\n"
10138 "}\n"
10139 "\n"
10140 "function Baz() {\n"
10141 " throw 'nirk';\n"
10142 "}\n"
10143 "\n"
10144 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010145
10146 const char* resource_name;
10147 v8::Handle<v8::Script> script;
10148 resource_name = "test.js";
10149 script = v8::Script::Compile(source, v8::String::New(resource_name));
10150 CheckTryCatchSourceInfo(script, resource_name, 0);
10151
10152 resource_name = "test1.js";
10153 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10154 script = v8::Script::Compile(source, &origin1);
10155 CheckTryCatchSourceInfo(script, resource_name, 0);
10156
10157 resource_name = "test2.js";
10158 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10159 script = v8::Script::Compile(source, &origin2);
10160 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010161}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010162
10163
10164THREADED_TEST(CompilationCache) {
10165 v8::HandleScope scope;
10166 LocalContext context;
10167 v8::Handle<v8::String> source0 = v8::String::New("1234");
10168 v8::Handle<v8::String> source1 = v8::String::New("1234");
10169 v8::Handle<v8::Script> script0 =
10170 v8::Script::Compile(source0, v8::String::New("test.js"));
10171 v8::Handle<v8::Script> script1 =
10172 v8::Script::Compile(source1, v8::String::New("test.js"));
10173 v8::Handle<v8::Script> script2 =
10174 v8::Script::Compile(source0); // different origin
10175 CHECK_EQ(1234, script0->Run()->Int32Value());
10176 CHECK_EQ(1234, script1->Run()->Int32Value());
10177 CHECK_EQ(1234, script2->Run()->Int32Value());
10178}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010179
10180
10181static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10182 ApiTestFuzzer::Fuzz();
10183 return v8_num(42);
10184}
10185
10186
10187THREADED_TEST(CallbackFunctionName) {
10188 v8::HandleScope scope;
10189 LocalContext context;
10190 Local<ObjectTemplate> t = ObjectTemplate::New();
10191 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10192 context->Global()->Set(v8_str("obj"), t->NewInstance());
10193 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10194 CHECK(value->IsString());
10195 v8::String::AsciiValue name(value);
10196 CHECK_EQ("asdf", *name);
10197}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010198
10199
10200THREADED_TEST(DateAccess) {
10201 v8::HandleScope scope;
10202 LocalContext context;
10203 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10204 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010205 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010206}
10207
10208
10209void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010210 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010211 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10212 CHECK_EQ(elmc, props->Length());
10213 for (int i = 0; i < elmc; i++) {
10214 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10215 CHECK_EQ(elmv[i], *elm);
10216 }
10217}
10218
10219
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010220void CheckOwnProperties(v8::Handle<v8::Value> val,
10221 int elmc,
10222 const char* elmv[]) {
10223 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10224 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10225 CHECK_EQ(elmc, props->Length());
10226 for (int i = 0; i < elmc; i++) {
10227 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10228 CHECK_EQ(elmv[i], *elm);
10229 }
10230}
10231
10232
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010233THREADED_TEST(PropertyEnumeration) {
10234 v8::HandleScope scope;
10235 LocalContext context;
10236 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10237 "var result = [];"
10238 "result[0] = {};"
10239 "result[1] = {a: 1, b: 2};"
10240 "result[2] = [1, 2, 3];"
10241 "var proto = {x: 1, y: 2, z: 3};"
10242 "var x = { __proto__: proto, w: 0, z: 1 };"
10243 "result[3] = x;"
10244 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010245 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010246 CHECK_EQ(4, elms->Length());
10247 int elmc0 = 0;
10248 const char** elmv0 = NULL;
10249 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010250 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010251 int elmc1 = 2;
10252 const char* elmv1[] = {"a", "b"};
10253 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010254 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010255 int elmc2 = 3;
10256 const char* elmv2[] = {"0", "1", "2"};
10257 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010258 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010259 int elmc3 = 4;
10260 const char* elmv3[] = {"w", "z", "x", "y"};
10261 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010262 int elmc4 = 2;
10263 const char* elmv4[] = {"w", "z"};
10264 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010265}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010267THREADED_TEST(PropertyEnumeration2) {
10268 v8::HandleScope scope;
10269 LocalContext context;
10270 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10271 "var result = [];"
10272 "result[0] = {};"
10273 "result[1] = {a: 1, b: 2};"
10274 "result[2] = [1, 2, 3];"
10275 "var proto = {x: 1, y: 2, z: 3};"
10276 "var x = { __proto__: proto, w: 0, z: 1 };"
10277 "result[3] = x;"
10278 "result;"))->Run();
10279 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10280 CHECK_EQ(4, elms->Length());
10281 int elmc0 = 0;
10282 const char** elmv0 = NULL;
10283 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10284
10285 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10286 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10287 CHECK_EQ(0, props->Length());
10288 for (uint32_t i = 0; i < props->Length(); i++) {
10289 printf("p[%d]\n", i);
10290 }
10291}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010292
ager@chromium.org870a0b62008-11-04 11:43:05 +000010293static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10294 Local<Value> name,
10295 v8::AccessType type,
10296 Local<Value> data) {
10297 return type != v8::ACCESS_SET;
10298}
10299
10300
10301static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10302 uint32_t key,
10303 v8::AccessType type,
10304 Local<Value> data) {
10305 return type != v8::ACCESS_SET;
10306}
10307
10308
10309THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10310 v8::HandleScope scope;
10311 LocalContext context;
10312 Local<ObjectTemplate> templ = ObjectTemplate::New();
10313 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10314 IndexedSetAccessBlocker);
10315 templ->Set(v8_str("x"), v8::True());
10316 Local<v8::Object> instance = templ->NewInstance();
10317 context->Global()->Set(v8_str("obj"), instance);
10318 Local<Value> value = CompileRun("obj.x");
10319 CHECK(value->BooleanValue());
10320}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010321
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010322
ager@chromium.org32912102009-01-16 10:38:43 +000010323static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10324 Local<Value> name,
10325 v8::AccessType type,
10326 Local<Value> data) {
10327 return false;
10328}
10329
10330
10331static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10332 uint32_t key,
10333 v8::AccessType type,
10334 Local<Value> data) {
10335 return false;
10336}
10337
10338
10339
10340THREADED_TEST(AccessChecksReenabledCorrectly) {
10341 v8::HandleScope scope;
10342 LocalContext context;
10343 Local<ObjectTemplate> templ = ObjectTemplate::New();
10344 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10345 IndexedGetAccessBlocker);
10346 templ->Set(v8_str("a"), v8_str("a"));
10347 // Add more than 8 (see kMaxFastProperties) properties
10348 // so that the constructor will force copying map.
10349 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010350 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010351 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010352 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010353 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010354 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010355 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010356 buf[2] = k;
10357 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010358 templ->Set(v8_str(buf), v8::Number::New(k));
10359 }
10360 }
10361 }
10362
10363 Local<v8::Object> instance_1 = templ->NewInstance();
10364 context->Global()->Set(v8_str("obj_1"), instance_1);
10365
10366 Local<Value> value_1 = CompileRun("obj_1.a");
10367 CHECK(value_1->IsUndefined());
10368
10369 Local<v8::Object> instance_2 = templ->NewInstance();
10370 context->Global()->Set(v8_str("obj_2"), instance_2);
10371
10372 Local<Value> value_2 = CompileRun("obj_2.a");
10373 CHECK(value_2->IsUndefined());
10374}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010375
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010376
ager@chromium.org8bb60582008-12-11 12:02:20 +000010377// This tests that access check information remains on the global
10378// object template when creating contexts.
10379THREADED_TEST(AccessControlRepeatedContextCreation) {
10380 v8::HandleScope handle_scope;
10381 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10382 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10383 IndexedSetAccessBlocker);
10384 i::Handle<i::ObjectTemplateInfo> internal_template =
10385 v8::Utils::OpenHandle(*global_template);
10386 CHECK(!internal_template->constructor()->IsUndefined());
10387 i::Handle<i::FunctionTemplateInfo> constructor(
10388 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10389 CHECK(!constructor->access_check_info()->IsUndefined());
10390 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10391 CHECK(!constructor->access_check_info()->IsUndefined());
10392}
10393
10394
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010395THREADED_TEST(TurnOnAccessCheck) {
10396 v8::HandleScope handle_scope;
10397
10398 // Create an environment with access check to the global object disabled by
10399 // default.
10400 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10401 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10402 IndexedGetAccessBlocker,
10403 v8::Handle<v8::Value>(),
10404 false);
10405 v8::Persistent<Context> context = Context::New(NULL, global_template);
10406 Context::Scope context_scope(context);
10407
10408 // Set up a property and a number of functions.
10409 context->Global()->Set(v8_str("a"), v8_num(1));
10410 CompileRun("function f1() {return a;}"
10411 "function f2() {return a;}"
10412 "function g1() {return h();}"
10413 "function g2() {return h();}"
10414 "function h() {return 1;}");
10415 Local<Function> f1 =
10416 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10417 Local<Function> f2 =
10418 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10419 Local<Function> g1 =
10420 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10421 Local<Function> g2 =
10422 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10423 Local<Function> h =
10424 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10425
10426 // Get the global object.
10427 v8::Handle<v8::Object> global = context->Global();
10428
10429 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10430 // uses the runtime system to retreive property a whereas f2 uses global load
10431 // inline cache.
10432 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10433 for (int i = 0; i < 4; i++) {
10434 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10435 }
10436
10437 // Same for g1 and g2.
10438 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10439 for (int i = 0; i < 4; i++) {
10440 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10441 }
10442
10443 // Detach the global and turn on access check.
10444 context->DetachGlobal();
10445 context->Global()->TurnOnAccessCheck();
10446
10447 // Failing access check to property get results in undefined.
10448 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10449 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10450
10451 // Failing access check to function call results in exception.
10452 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10453 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10454
10455 // No failing access check when just returning a constant.
10456 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10457}
10458
10459
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010460v8::Handle<v8::String> a;
10461v8::Handle<v8::String> h;
10462
10463static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10464 Local<Value> name,
10465 v8::AccessType type,
10466 Local<Value> data) {
10467 return !(name->Equals(a) || name->Equals(h));
10468}
10469
10470
10471THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10472 v8::HandleScope handle_scope;
10473
10474 // Create an environment with access check to the global object disabled by
10475 // default. When the registered access checker will block access to properties
10476 // a and h
10477 a = v8_str("a");
10478 h = v8_str("h");
10479 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10480 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10481 IndexedGetAccessBlocker,
10482 v8::Handle<v8::Value>(),
10483 false);
10484 v8::Persistent<Context> context = Context::New(NULL, global_template);
10485 Context::Scope context_scope(context);
10486
10487 // Set up a property and a number of functions.
10488 context->Global()->Set(v8_str("a"), v8_num(1));
10489 static const char* source = "function f1() {return a;}"
10490 "function f2() {return a;}"
10491 "function g1() {return h();}"
10492 "function g2() {return h();}"
10493 "function h() {return 1;}";
10494
10495 CompileRun(source);
10496 Local<Function> f1;
10497 Local<Function> f2;
10498 Local<Function> g1;
10499 Local<Function> g2;
10500 Local<Function> h;
10501 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10502 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10503 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10504 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10505 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10506
10507 // Get the global object.
10508 v8::Handle<v8::Object> global = context->Global();
10509
10510 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10511 // uses the runtime system to retreive property a whereas f2 uses global load
10512 // inline cache.
10513 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10514 for (int i = 0; i < 4; i++) {
10515 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10516 }
10517
10518 // Same for g1 and g2.
10519 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10520 for (int i = 0; i < 4; i++) {
10521 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10522 }
10523
10524 // Detach the global and turn on access check now blocking access to property
10525 // a and function h.
10526 context->DetachGlobal();
10527 context->Global()->TurnOnAccessCheck();
10528
10529 // Failing access check to property get results in undefined.
10530 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10531 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10532
10533 // Failing access check to function call results in exception.
10534 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10535 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10536
10537 // No failing access check when just returning a constant.
10538 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10539
10540 // Now compile the source again. And get the newly compiled functions, except
10541 // for h for which access is blocked.
10542 CompileRun(source);
10543 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10544 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10545 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10546 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10547 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10548
10549 // Failing access check to property get results in undefined.
10550 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10551 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10552
10553 // Failing access check to function call results in exception.
10554 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10555 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10556}
10557
10558
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010559// This test verifies that pre-compilation (aka preparsing) can be called
10560// without initializing the whole VM. Thus we cannot run this test in a
10561// multi-threaded setup.
10562TEST(PreCompile) {
10563 // TODO(155): This test would break without the initialization of V8. This is
10564 // a workaround for now to make this test not fail.
10565 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010566 const char* script = "function foo(a) { return a+1; }";
10567 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010568 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010569 CHECK_NE(sd->Length(), 0);
10570 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010571 CHECK(!sd->HasError());
10572 delete sd;
10573}
10574
10575
10576TEST(PreCompileWithError) {
10577 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010578 const char* script = "function foo(a) { return 1 * * 2; }";
10579 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010580 v8::ScriptData::PreCompile(script, i::StrLength(script));
10581 CHECK(sd->HasError());
10582 delete sd;
10583}
10584
10585
10586TEST(Regress31661) {
10587 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010588 const char* script = " The Definintive Guide";
10589 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010590 v8::ScriptData::PreCompile(script, i::StrLength(script));
10591 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010592 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010593}
10594
10595
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010596// Tests that ScriptData can be serialized and deserialized.
10597TEST(PreCompileSerialization) {
10598 v8::V8::Initialize();
10599 const char* script = "function foo(a) { return a+1; }";
10600 v8::ScriptData* sd =
10601 v8::ScriptData::PreCompile(script, i::StrLength(script));
10602
10603 // Serialize.
10604 int serialized_data_length = sd->Length();
10605 char* serialized_data = i::NewArray<char>(serialized_data_length);
10606 memcpy(serialized_data, sd->Data(), serialized_data_length);
10607
10608 // Deserialize.
10609 v8::ScriptData* deserialized_sd =
10610 v8::ScriptData::New(serialized_data, serialized_data_length);
10611
10612 // Verify that the original is the same as the deserialized.
10613 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10614 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10615 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10616
10617 delete sd;
10618 delete deserialized_sd;
10619}
10620
10621
10622// Attempts to deserialize bad data.
10623TEST(PreCompileDeserializationError) {
10624 v8::V8::Initialize();
10625 const char* data = "DONT CARE";
10626 int invalid_size = 3;
10627 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10628
10629 CHECK_EQ(0, sd->Length());
10630
10631 delete sd;
10632}
10633
10634
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010635// Attempts to deserialize bad data.
10636TEST(PreCompileInvalidPreparseDataError) {
10637 v8::V8::Initialize();
10638 v8::HandleScope scope;
10639 LocalContext context;
10640
10641 const char* script = "function foo(){ return 5;}\n"
10642 "function bar(){ return 6 + 7;} foo();";
10643 v8::ScriptData* sd =
10644 v8::ScriptData::PreCompile(script, i::StrLength(script));
10645 CHECK(!sd->HasError());
10646 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010647 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000010648 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010649 const int kFunctionEntryStartOffset = 0;
10650 const int kFunctionEntryEndOffset = 1;
10651 unsigned* sd_data =
10652 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010653
10654 // Overwrite function bar's end position with 0.
10655 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10656 v8::TryCatch try_catch;
10657
10658 Local<String> source = String::New(script);
10659 Local<Script> compiled_script = Script::New(source, NULL, sd);
10660 CHECK(try_catch.HasCaught());
10661 String::AsciiValue exception_value(try_catch.Message()->Get());
10662 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10663 *exception_value);
10664
10665 try_catch.Reset();
10666 // Overwrite function bar's start position with 200. The function entry
10667 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000010668 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10669 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010670 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10671 200;
10672 compiled_script = Script::New(source, NULL, sd);
10673 CHECK(try_catch.HasCaught());
10674 String::AsciiValue second_exception_value(try_catch.Message()->Get());
10675 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10676 *second_exception_value);
10677
10678 delete sd;
10679}
10680
10681
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010682// Verifies that the Handle<String> and const char* versions of the API produce
10683// the same results (at least for one trivial case).
10684TEST(PreCompileAPIVariationsAreSame) {
10685 v8::V8::Initialize();
10686 v8::HandleScope scope;
10687
10688 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010689
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010690 v8::ScriptData* sd_from_cstring =
10691 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10692
10693 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010694 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010695 v8::String::NewExternal(resource));
10696
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010697 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10698 v8::String::New(cstring));
10699
10700 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010701 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010702 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010703 sd_from_cstring->Length()));
10704
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010705 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10706 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10707 sd_from_string->Data(),
10708 sd_from_cstring->Length()));
10709
10710
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010711 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010712 delete sd_from_external_string;
10713 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010714}
10715
10716
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010717// This tests that we do not allow dictionary load/call inline caches
10718// to use functions that have not yet been compiled. The potential
10719// problem of loading a function that has not yet been compiled can
10720// arise because we share code between contexts via the compilation
10721// cache.
10722THREADED_TEST(DictionaryICLoadedFunction) {
10723 v8::HandleScope scope;
10724 // Test LoadIC.
10725 for (int i = 0; i < 2; i++) {
10726 LocalContext context;
10727 context->Global()->Set(v8_str("tmp"), v8::True());
10728 context->Global()->Delete(v8_str("tmp"));
10729 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10730 }
10731 // Test CallIC.
10732 for (int i = 0; i < 2; i++) {
10733 LocalContext context;
10734 context->Global()->Set(v8_str("tmp"), v8::True());
10735 context->Global()->Delete(v8_str("tmp"));
10736 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10737 }
10738}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010739
10740
10741// Test that cross-context new calls use the context of the callee to
10742// create the new JavaScript object.
10743THREADED_TEST(CrossContextNew) {
10744 v8::HandleScope scope;
10745 v8::Persistent<Context> context0 = Context::New();
10746 v8::Persistent<Context> context1 = Context::New();
10747
10748 // Allow cross-domain access.
10749 Local<String> token = v8_str("<security token>");
10750 context0->SetSecurityToken(token);
10751 context1->SetSecurityToken(token);
10752
10753 // Set an 'x' property on the Object prototype and define a
10754 // constructor function in context0.
10755 context0->Enter();
10756 CompileRun("Object.prototype.x = 42; function C() {};");
10757 context0->Exit();
10758
10759 // Call the constructor function from context0 and check that the
10760 // result has the 'x' property.
10761 context1->Enter();
10762 context1->Global()->Set(v8_str("other"), context0->Global());
10763 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10764 CHECK(value->IsInt32());
10765 CHECK_EQ(42, value->Int32Value());
10766 context1->Exit();
10767
10768 // Dispose the contexts to allow them to be garbage collected.
10769 context0.Dispose();
10770 context1.Dispose();
10771}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010772
10773
10774class RegExpInterruptTest {
10775 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010776 RegExpInterruptTest() : block_(NULL) {}
10777 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010778 void RunTest() {
10779 block_ = i::OS::CreateSemaphore(0);
10780 gc_count_ = 0;
10781 gc_during_regexp_ = 0;
10782 regexp_success_ = false;
10783 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010784 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010785 gc_thread.Start();
10786 v8::Locker::StartPreemption(1);
10787
10788 LongRunningRegExp();
10789 {
10790 v8::Unlocker unlock;
10791 gc_thread.Join();
10792 }
10793 v8::Locker::StopPreemption();
10794 CHECK(regexp_success_);
10795 CHECK(gc_success_);
10796 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010797
ager@chromium.org381abbb2009-02-25 13:23:22 +000010798 private:
10799 // Number of garbage collections required.
10800 static const int kRequiredGCs = 5;
10801
10802 class GCThread : public i::Thread {
10803 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010804 explicit GCThread(RegExpInterruptTest* test)
10805 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010806 virtual void Run() {
10807 test_->CollectGarbage();
10808 }
10809 private:
10810 RegExpInterruptTest* test_;
10811 };
10812
10813 void CollectGarbage() {
10814 block_->Wait();
10815 while (gc_during_regexp_ < kRequiredGCs) {
10816 {
10817 v8::Locker lock;
10818 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010820 gc_count_++;
10821 }
10822 i::OS::Sleep(1);
10823 }
10824 gc_success_ = true;
10825 }
10826
10827 void LongRunningRegExp() {
10828 block_->Signal(); // Enable garbage collection thread on next preemption.
10829 int rounds = 0;
10830 while (gc_during_regexp_ < kRequiredGCs) {
10831 int gc_before = gc_count_;
10832 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010833 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010834 const char* c_source =
10835 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10836 ".exec('aaaaaaaaaaaaaaab') === null";
10837 Local<String> source = String::New(c_source);
10838 Local<Script> script = Script::Compile(source);
10839 Local<Value> result = script->Run();
10840 if (!result->BooleanValue()) {
10841 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10842 return;
10843 }
10844 }
10845 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010846 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010847 const char* c_source =
10848 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10849 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10850 Local<String> source = String::New(c_source);
10851 Local<Script> script = Script::Compile(source);
10852 Local<Value> result = script->Run();
10853 if (!result->BooleanValue()) {
10854 gc_during_regexp_ = kRequiredGCs;
10855 return;
10856 }
10857 }
10858 int gc_after = gc_count_;
10859 gc_during_regexp_ += gc_after - gc_before;
10860 rounds++;
10861 i::OS::Sleep(1);
10862 }
10863 regexp_success_ = true;
10864 }
10865
10866 i::Semaphore* block_;
10867 int gc_count_;
10868 int gc_during_regexp_;
10869 bool regexp_success_;
10870 bool gc_success_;
10871};
10872
10873
10874// Test that a regular expression execution can be interrupted and
10875// survive a garbage collection.
10876TEST(RegExpInterruption) {
10877 v8::Locker lock;
10878 v8::V8::Initialize();
10879 v8::HandleScope scope;
10880 Local<Context> local_env;
10881 {
10882 LocalContext env;
10883 local_env = env.local();
10884 }
10885
10886 // Local context should still be live.
10887 CHECK(!local_env.IsEmpty());
10888 local_env->Enter();
10889
10890 // Should complete without problems.
10891 RegExpInterruptTest().RunTest();
10892
10893 local_env->Exit();
10894}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010895
10896
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010897class ApplyInterruptTest {
10898 public:
10899 ApplyInterruptTest() : block_(NULL) {}
10900 ~ApplyInterruptTest() { delete block_; }
10901 void RunTest() {
10902 block_ = i::OS::CreateSemaphore(0);
10903 gc_count_ = 0;
10904 gc_during_apply_ = 0;
10905 apply_success_ = false;
10906 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010907 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010908 gc_thread.Start();
10909 v8::Locker::StartPreemption(1);
10910
10911 LongRunningApply();
10912 {
10913 v8::Unlocker unlock;
10914 gc_thread.Join();
10915 }
10916 v8::Locker::StopPreemption();
10917 CHECK(apply_success_);
10918 CHECK(gc_success_);
10919 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010920
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010921 private:
10922 // Number of garbage collections required.
10923 static const int kRequiredGCs = 2;
10924
10925 class GCThread : public i::Thread {
10926 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010927 explicit GCThread(ApplyInterruptTest* test)
10928 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010929 virtual void Run() {
10930 test_->CollectGarbage();
10931 }
10932 private:
10933 ApplyInterruptTest* test_;
10934 };
10935
10936 void CollectGarbage() {
10937 block_->Wait();
10938 while (gc_during_apply_ < kRequiredGCs) {
10939 {
10940 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010941 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010942 gc_count_++;
10943 }
10944 i::OS::Sleep(1);
10945 }
10946 gc_success_ = true;
10947 }
10948
10949 void LongRunningApply() {
10950 block_->Signal();
10951 int rounds = 0;
10952 while (gc_during_apply_ < kRequiredGCs) {
10953 int gc_before = gc_count_;
10954 {
10955 const char* c_source =
10956 "function do_very_little(bar) {"
10957 " this.foo = bar;"
10958 "}"
10959 "for (var i = 0; i < 100000; i++) {"
10960 " do_very_little.apply(this, ['bar']);"
10961 "}";
10962 Local<String> source = String::New(c_source);
10963 Local<Script> script = Script::Compile(source);
10964 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010965 // Check that no exception was thrown.
10966 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010967 }
10968 int gc_after = gc_count_;
10969 gc_during_apply_ += gc_after - gc_before;
10970 rounds++;
10971 }
10972 apply_success_ = true;
10973 }
10974
10975 i::Semaphore* block_;
10976 int gc_count_;
10977 int gc_during_apply_;
10978 bool apply_success_;
10979 bool gc_success_;
10980};
10981
10982
10983// Test that nothing bad happens if we get a preemption just when we were
10984// about to do an apply().
10985TEST(ApplyInterruption) {
10986 v8::Locker lock;
10987 v8::V8::Initialize();
10988 v8::HandleScope scope;
10989 Local<Context> local_env;
10990 {
10991 LocalContext env;
10992 local_env = env.local();
10993 }
10994
10995 // Local context should still be live.
10996 CHECK(!local_env.IsEmpty());
10997 local_env->Enter();
10998
10999 // Should complete without problems.
11000 ApplyInterruptTest().RunTest();
11001
11002 local_env->Exit();
11003}
11004
11005
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011006// Verify that we can clone an object
11007TEST(ObjectClone) {
11008 v8::HandleScope scope;
11009 LocalContext env;
11010
11011 const char* sample =
11012 "var rv = {};" \
11013 "rv.alpha = 'hello';" \
11014 "rv.beta = 123;" \
11015 "rv;";
11016
11017 // Create an object, verify basics.
11018 Local<Value> val = CompileRun(sample);
11019 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011020 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011021 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11022
11023 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11024 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11025 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11026
11027 // Clone it.
11028 Local<v8::Object> clone = obj->Clone();
11029 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11030 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11031 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11032
11033 // Set a property on the clone, verify each object.
11034 clone->Set(v8_str("beta"), v8::Integer::New(456));
11035 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11036 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11037}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011038
11039
ager@chromium.org5ec48922009-05-05 07:25:34 +000011040class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11041 public:
11042 explicit AsciiVectorResource(i::Vector<const char> vector)
11043 : data_(vector) {}
11044 virtual ~AsciiVectorResource() {}
11045 virtual size_t length() const { return data_.length(); }
11046 virtual const char* data() const { return data_.start(); }
11047 private:
11048 i::Vector<const char> data_;
11049};
11050
11051
11052class UC16VectorResource : public v8::String::ExternalStringResource {
11053 public:
11054 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11055 : data_(vector) {}
11056 virtual ~UC16VectorResource() {}
11057 virtual size_t length() const { return data_.length(); }
11058 virtual const i::uc16* data() const { return data_.start(); }
11059 private:
11060 i::Vector<const i::uc16> data_;
11061};
11062
11063
11064static void MorphAString(i::String* string,
11065 AsciiVectorResource* ascii_resource,
11066 UC16VectorResource* uc16_resource) {
11067 CHECK(i::StringShape(string).IsExternal());
11068 if (string->IsAsciiRepresentation()) {
11069 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011071 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011073 i::ExternalTwoByteString* morphed =
11074 i::ExternalTwoByteString::cast(string);
11075 morphed->set_resource(uc16_resource);
11076 } else {
11077 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011078 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011079 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011081 i::ExternalAsciiString* morphed =
11082 i::ExternalAsciiString::cast(string);
11083 morphed->set_resource(ascii_resource);
11084 }
11085}
11086
11087
11088// Test that we can still flatten a string if the components it is built up
11089// from have been turned into 16 bit strings in the mean time.
11090THREADED_TEST(MorphCompositeStringTest) {
11091 const char* c_string = "Now is the time for all good men"
11092 " to come to the aid of the party";
11093 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11094 {
11095 v8::HandleScope scope;
11096 LocalContext env;
11097 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011098 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011099 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011100 i::Vector<const uint16_t>(two_byte_string,
11101 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011102
11103 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011105 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011107
11108 env->Global()->Set(v8_str("lhs"), lhs);
11109 env->Global()->Set(v8_str("rhs"), rhs);
11110
11111 CompileRun(
11112 "var cons = lhs + rhs;"
11113 "var slice = lhs.substring(1, lhs.length - 1);"
11114 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11115
11116 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11117 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11118
11119 // Now do some stuff to make sure the strings are flattened, etc.
11120 CompileRun(
11121 "/[^a-z]/.test(cons);"
11122 "/[^a-z]/.test(slice);"
11123 "/[^a-z]/.test(slice_on_cons);");
11124 const char* expected_cons =
11125 "Now is the time for all good men to come to the aid of the party"
11126 "Now is the time for all good men to come to the aid of the party";
11127 const char* expected_slice =
11128 "ow is the time for all good men to come to the aid of the part";
11129 const char* expected_slice_on_cons =
11130 "ow is the time for all good men to come to the aid of the party"
11131 "Now is the time for all good men to come to the aid of the part";
11132 CHECK_EQ(String::New(expected_cons),
11133 env->Global()->Get(v8_str("cons")));
11134 CHECK_EQ(String::New(expected_slice),
11135 env->Global()->Get(v8_str("slice")));
11136 CHECK_EQ(String::New(expected_slice_on_cons),
11137 env->Global()->Get(v8_str("slice_on_cons")));
11138 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011139 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011140}
11141
11142
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011143TEST(CompileExternalTwoByteSource) {
11144 v8::HandleScope scope;
11145 LocalContext context;
11146
11147 // This is a very short list of sources, which currently is to check for a
11148 // regression caused by r2703.
11149 const char* ascii_sources[] = {
11150 "0.5",
11151 "-0.5", // This mainly testes PushBack in the Scanner.
11152 "--0.5", // This mainly testes PushBack in the Scanner.
11153 NULL
11154 };
11155
11156 // Compile the sources as external two byte strings.
11157 for (int i = 0; ascii_sources[i] != NULL; i++) {
11158 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11159 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011160 i::Vector<const uint16_t>(two_byte_string,
11161 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011162 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11163 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011164 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011165 }
11166}
11167
11168
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011169class RegExpStringModificationTest {
11170 public:
11171 RegExpStringModificationTest()
11172 : block_(i::OS::CreateSemaphore(0)),
11173 morphs_(0),
11174 morphs_during_regexp_(0),
11175 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11176 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11177 ~RegExpStringModificationTest() { delete block_; }
11178 void RunTest() {
11179 regexp_success_ = false;
11180 morph_success_ = false;
11181
11182 // Initialize the contents of two_byte_content_ to be a uc16 representation
11183 // of "aaaaaaaaaaaaaab".
11184 for (int i = 0; i < 14; i++) {
11185 two_byte_content_[i] = 'a';
11186 }
11187 two_byte_content_[14] = 'b';
11188
11189 // Create the input string for the regexp - the one we are going to change
11190 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011191 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011192
11193 // Inject the input as a global variable.
11194 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011195 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11196 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011197 *input_name,
11198 *input_,
11199 NONE,
11200 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011201
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011202 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011203 morph_thread.Start();
11204 v8::Locker::StartPreemption(1);
11205 LongRunningRegExp();
11206 {
11207 v8::Unlocker unlock;
11208 morph_thread.Join();
11209 }
11210 v8::Locker::StopPreemption();
11211 CHECK(regexp_success_);
11212 CHECK(morph_success_);
11213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011214
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011215 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011216 // Number of string modifications required.
11217 static const int kRequiredModifications = 5;
11218 static const int kMaxModifications = 100;
11219
11220 class MorphThread : public i::Thread {
11221 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011222 explicit MorphThread(RegExpStringModificationTest* test)
11223 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011224 virtual void Run() {
11225 test_->MorphString();
11226 }
11227 private:
11228 RegExpStringModificationTest* test_;
11229 };
11230
11231 void MorphString() {
11232 block_->Wait();
11233 while (morphs_during_regexp_ < kRequiredModifications &&
11234 morphs_ < kMaxModifications) {
11235 {
11236 v8::Locker lock;
11237 // Swap string between ascii and two-byte representation.
11238 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011239 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011240 morphs_++;
11241 }
11242 i::OS::Sleep(1);
11243 }
11244 morph_success_ = true;
11245 }
11246
11247 void LongRunningRegExp() {
11248 block_->Signal(); // Enable morphing thread on next preemption.
11249 while (morphs_during_regexp_ < kRequiredModifications &&
11250 morphs_ < kMaxModifications) {
11251 int morphs_before = morphs_;
11252 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011253 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011254 // Match 15-30 "a"'s against 14 and a "b".
11255 const char* c_source =
11256 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11257 ".exec(input) === null";
11258 Local<String> source = String::New(c_source);
11259 Local<Script> script = Script::Compile(source);
11260 Local<Value> result = script->Run();
11261 CHECK(result->IsTrue());
11262 }
11263 int morphs_after = morphs_;
11264 morphs_during_regexp_ += morphs_after - morphs_before;
11265 }
11266 regexp_success_ = true;
11267 }
11268
11269 i::uc16 two_byte_content_[15];
11270 i::Semaphore* block_;
11271 int morphs_;
11272 int morphs_during_regexp_;
11273 bool regexp_success_;
11274 bool morph_success_;
11275 i::Handle<i::String> input_;
11276 AsciiVectorResource ascii_resource_;
11277 UC16VectorResource uc16_resource_;
11278};
11279
11280
11281// Test that a regular expression execution can be interrupted and
11282// the string changed without failing.
11283TEST(RegExpStringModification) {
11284 v8::Locker lock;
11285 v8::V8::Initialize();
11286 v8::HandleScope scope;
11287 Local<Context> local_env;
11288 {
11289 LocalContext env;
11290 local_env = env.local();
11291 }
11292
11293 // Local context should still be live.
11294 CHECK(!local_env.IsEmpty());
11295 local_env->Enter();
11296
11297 // Should complete without problems.
11298 RegExpStringModificationTest().RunTest();
11299
11300 local_env->Exit();
11301}
11302
11303
11304// Test that we can set a property on the global object even if there
11305// is a read-only property in the prototype chain.
11306TEST(ReadOnlyPropertyInGlobalProto) {
11307 v8::HandleScope scope;
11308 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11309 LocalContext context(0, templ);
11310 v8::Handle<v8::Object> global = context->Global();
11311 v8::Handle<v8::Object> global_proto =
11312 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11313 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11314 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11315 // Check without 'eval' or 'with'.
11316 v8::Handle<v8::Value> res =
11317 CompileRun("function f() { x = 42; return x; }; f()");
11318 // Check with 'eval'.
11319 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11320 CHECK_EQ(v8::Integer::New(42), res);
11321 // Check with 'with'.
11322 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11323 CHECK_EQ(v8::Integer::New(42), res);
11324}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011325
11326static int force_set_set_count = 0;
11327static int force_set_get_count = 0;
11328bool pass_on_get = false;
11329
11330static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11331 const v8::AccessorInfo& info) {
11332 force_set_get_count++;
11333 if (pass_on_get) {
11334 return v8::Handle<v8::Value>();
11335 } else {
11336 return v8::Int32::New(3);
11337 }
11338}
11339
11340static void ForceSetSetter(v8::Local<v8::String> name,
11341 v8::Local<v8::Value> value,
11342 const v8::AccessorInfo& info) {
11343 force_set_set_count++;
11344}
11345
11346static v8::Handle<v8::Value> ForceSetInterceptSetter(
11347 v8::Local<v8::String> name,
11348 v8::Local<v8::Value> value,
11349 const v8::AccessorInfo& info) {
11350 force_set_set_count++;
11351 return v8::Undefined();
11352}
11353
11354TEST(ForceSet) {
11355 force_set_get_count = 0;
11356 force_set_set_count = 0;
11357 pass_on_get = false;
11358
11359 v8::HandleScope scope;
11360 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11361 v8::Handle<v8::String> access_property = v8::String::New("a");
11362 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11363 LocalContext context(NULL, templ);
11364 v8::Handle<v8::Object> global = context->Global();
11365
11366 // Ordinary properties
11367 v8::Handle<v8::String> simple_property = v8::String::New("p");
11368 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11369 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11370 // This should fail because the property is read-only
11371 global->Set(simple_property, v8::Int32::New(5));
11372 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11373 // This should succeed even though the property is read-only
11374 global->ForceSet(simple_property, v8::Int32::New(6));
11375 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11376
11377 // Accessors
11378 CHECK_EQ(0, force_set_set_count);
11379 CHECK_EQ(0, force_set_get_count);
11380 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11381 // CHECK_EQ the property shouldn't override it, just call the setter
11382 // which in this case does nothing.
11383 global->Set(access_property, v8::Int32::New(7));
11384 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11385 CHECK_EQ(1, force_set_set_count);
11386 CHECK_EQ(2, force_set_get_count);
11387 // Forcing the property to be set should override the accessor without
11388 // calling it
11389 global->ForceSet(access_property, v8::Int32::New(8));
11390 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11391 CHECK_EQ(1, force_set_set_count);
11392 CHECK_EQ(2, force_set_get_count);
11393}
11394
11395TEST(ForceSetWithInterceptor) {
11396 force_set_get_count = 0;
11397 force_set_set_count = 0;
11398 pass_on_get = false;
11399
11400 v8::HandleScope scope;
11401 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11402 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11403 LocalContext context(NULL, templ);
11404 v8::Handle<v8::Object> global = context->Global();
11405
11406 v8::Handle<v8::String> some_property = v8::String::New("a");
11407 CHECK_EQ(0, force_set_set_count);
11408 CHECK_EQ(0, force_set_get_count);
11409 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11410 // Setting the property shouldn't override it, just call the setter
11411 // which in this case does nothing.
11412 global->Set(some_property, v8::Int32::New(7));
11413 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11414 CHECK_EQ(1, force_set_set_count);
11415 CHECK_EQ(2, force_set_get_count);
11416 // Getting the property when the interceptor returns an empty handle
11417 // should yield undefined, since the property isn't present on the
11418 // object itself yet.
11419 pass_on_get = true;
11420 CHECK(global->Get(some_property)->IsUndefined());
11421 CHECK_EQ(1, force_set_set_count);
11422 CHECK_EQ(3, force_set_get_count);
11423 // Forcing the property to be set should cause the value to be
11424 // set locally without calling the interceptor.
11425 global->ForceSet(some_property, v8::Int32::New(8));
11426 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11427 CHECK_EQ(1, force_set_set_count);
11428 CHECK_EQ(4, force_set_get_count);
11429 // Reenabling the interceptor should cause it to take precedence over
11430 // the property
11431 pass_on_get = false;
11432 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11433 CHECK_EQ(1, force_set_set_count);
11434 CHECK_EQ(5, force_set_get_count);
11435 // The interceptor should also work for other properties
11436 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11437 CHECK_EQ(1, force_set_set_count);
11438 CHECK_EQ(6, force_set_get_count);
11439}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011440
11441
ager@chromium.orge2902be2009-06-08 12:21:35 +000011442THREADED_TEST(ForceDelete) {
11443 v8::HandleScope scope;
11444 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11445 LocalContext context(NULL, templ);
11446 v8::Handle<v8::Object> global = context->Global();
11447
11448 // Ordinary properties
11449 v8::Handle<v8::String> simple_property = v8::String::New("p");
11450 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11451 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11452 // This should fail because the property is dont-delete.
11453 CHECK(!global->Delete(simple_property));
11454 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11455 // This should succeed even though the property is dont-delete.
11456 CHECK(global->ForceDelete(simple_property));
11457 CHECK(global->Get(simple_property)->IsUndefined());
11458}
11459
11460
11461static int force_delete_interceptor_count = 0;
11462static bool pass_on_delete = false;
11463
11464
11465static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11466 v8::Local<v8::String> name,
11467 const v8::AccessorInfo& info) {
11468 force_delete_interceptor_count++;
11469 if (pass_on_delete) {
11470 return v8::Handle<v8::Boolean>();
11471 } else {
11472 return v8::True();
11473 }
11474}
11475
11476
11477THREADED_TEST(ForceDeleteWithInterceptor) {
11478 force_delete_interceptor_count = 0;
11479 pass_on_delete = false;
11480
11481 v8::HandleScope scope;
11482 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11483 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11484 LocalContext context(NULL, templ);
11485 v8::Handle<v8::Object> global = context->Global();
11486
11487 v8::Handle<v8::String> some_property = v8::String::New("a");
11488 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11489
11490 // Deleting a property should get intercepted and nothing should
11491 // happen.
11492 CHECK_EQ(0, force_delete_interceptor_count);
11493 CHECK(global->Delete(some_property));
11494 CHECK_EQ(1, force_delete_interceptor_count);
11495 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11496 // Deleting the property when the interceptor returns an empty
11497 // handle should not delete the property since it is DontDelete.
11498 pass_on_delete = true;
11499 CHECK(!global->Delete(some_property));
11500 CHECK_EQ(2, force_delete_interceptor_count);
11501 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11502 // Forcing the property to be deleted should delete the value
11503 // without calling the interceptor.
11504 CHECK(global->ForceDelete(some_property));
11505 CHECK(global->Get(some_property)->IsUndefined());
11506 CHECK_EQ(2, force_delete_interceptor_count);
11507}
11508
11509
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011510// Make sure that forcing a delete invalidates any IC stubs, so we
11511// don't read the hole value.
11512THREADED_TEST(ForceDeleteIC) {
11513 v8::HandleScope scope;
11514 LocalContext context;
11515 // Create a DontDelete variable on the global object.
11516 CompileRun("this.__proto__ = { foo: 'horse' };"
11517 "var foo = 'fish';"
11518 "function f() { return foo.length; }");
11519 // Initialize the IC for foo in f.
11520 CompileRun("for (var i = 0; i < 4; i++) f();");
11521 // Make sure the value of foo is correct before the deletion.
11522 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11523 // Force the deletion of foo.
11524 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11525 // Make sure the value for foo is read from the prototype, and that
11526 // we don't get in trouble with reading the deleted cell value
11527 // sentinel.
11528 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11529}
11530
11531
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011532v8::Persistent<Context> calling_context0;
11533v8::Persistent<Context> calling_context1;
11534v8::Persistent<Context> calling_context2;
11535
11536
11537// Check that the call to the callback is initiated in
11538// calling_context2, the directly calling context is calling_context1
11539// and the callback itself is in calling_context0.
11540static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11541 ApiTestFuzzer::Fuzz();
11542 CHECK(Context::GetCurrent() == calling_context0);
11543 CHECK(Context::GetCalling() == calling_context1);
11544 CHECK(Context::GetEntered() == calling_context2);
11545 return v8::Integer::New(42);
11546}
11547
11548
11549THREADED_TEST(GetCallingContext) {
11550 v8::HandleScope scope;
11551
11552 calling_context0 = Context::New();
11553 calling_context1 = Context::New();
11554 calling_context2 = Context::New();
11555
11556 // Allow cross-domain access.
11557 Local<String> token = v8_str("<security token>");
11558 calling_context0->SetSecurityToken(token);
11559 calling_context1->SetSecurityToken(token);
11560 calling_context2->SetSecurityToken(token);
11561
11562 // Create an object with a C++ callback in context0.
11563 calling_context0->Enter();
11564 Local<v8::FunctionTemplate> callback_templ =
11565 v8::FunctionTemplate::New(GetCallingContextCallback);
11566 calling_context0->Global()->Set(v8_str("callback"),
11567 callback_templ->GetFunction());
11568 calling_context0->Exit();
11569
11570 // Expose context0 in context1 and setup a function that calls the
11571 // callback function.
11572 calling_context1->Enter();
11573 calling_context1->Global()->Set(v8_str("context0"),
11574 calling_context0->Global());
11575 CompileRun("function f() { context0.callback() }");
11576 calling_context1->Exit();
11577
11578 // Expose context1 in context2 and call the callback function in
11579 // context0 indirectly through f in context1.
11580 calling_context2->Enter();
11581 calling_context2->Global()->Set(v8_str("context1"),
11582 calling_context1->Global());
11583 CompileRun("context1.f()");
11584 calling_context2->Exit();
11585
11586 // Dispose the contexts to allow them to be garbage collected.
11587 calling_context0.Dispose();
11588 calling_context1.Dispose();
11589 calling_context2.Dispose();
11590 calling_context0.Clear();
11591 calling_context1.Clear();
11592 calling_context2.Clear();
11593}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011594
11595
11596// Check that a variable declaration with no explicit initialization
11597// value does not shadow an existing property in the prototype chain.
11598//
11599// This is consistent with Firefox and Safari.
11600//
11601// See http://crbug.com/12548.
11602THREADED_TEST(InitGlobalVarInProtoChain) {
11603 v8::HandleScope scope;
11604 LocalContext context;
11605 // Introduce a variable in the prototype chain.
11606 CompileRun("__proto__.x = 42");
11607 v8::Handle<v8::Value> result = CompileRun("var x; x");
11608 CHECK(!result->IsUndefined());
11609 CHECK_EQ(42, result->Int32Value());
11610}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011611
11612
11613// Regression test for issue 398.
11614// If a function is added to an object, creating a constant function
11615// field, and the result is cloned, replacing the constant function on the
11616// original should not affect the clone.
11617// See http://code.google.com/p/v8/issues/detail?id=398
11618THREADED_TEST(ReplaceConstantFunction) {
11619 v8::HandleScope scope;
11620 LocalContext context;
11621 v8::Handle<v8::Object> obj = v8::Object::New();
11622 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11623 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11624 obj->Set(foo_string, func_templ->GetFunction());
11625 v8::Handle<v8::Object> obj_clone = obj->Clone();
11626 obj_clone->Set(foo_string, v8::String::New("Hello"));
11627 CHECK(!obj->Get(foo_string)->IsUndefined());
11628}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000011629
11630
11631// Regression test for http://crbug.com/16276.
11632THREADED_TEST(Regress16276) {
11633 v8::HandleScope scope;
11634 LocalContext context;
11635 // Force the IC in f to be a dictionary load IC.
11636 CompileRun("function f(obj) { return obj.x; }\n"
11637 "var obj = { x: { foo: 42 }, y: 87 };\n"
11638 "var x = obj.x;\n"
11639 "delete obj.y;\n"
11640 "for (var i = 0; i < 5; i++) f(obj);");
11641 // Detach the global object to make 'this' refer directly to the
11642 // global object (not the proxy), and make sure that the dictionary
11643 // load IC doesn't mess up loading directly from the global object.
11644 context->DetachGlobal();
11645 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11646}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011647
11648
11649THREADED_TEST(PixelArray) {
11650 v8::HandleScope scope;
11651 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011652 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011653 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011654 i::Handle<i::ExternalPixelArray> pixels =
11655 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011657 v8::kExternalPixelArray,
11658 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011660 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011661 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011662 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011664 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011665 CHECK_EQ(i % 256, pixels->get(i));
11666 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011667 }
11668
11669 v8::Handle<v8::Object> obj = v8::Object::New();
11670 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11671 // Set the elements to be the pixels.
11672 // jsobj->set_elements(*pixels);
11673 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011674 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011675 obj->Set(v8_str("field"), v8::Int32::New(1503));
11676 context->Global()->Set(v8_str("pixels"), obj);
11677 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11678 CHECK_EQ(1503, result->Int32Value());
11679 result = CompileRun("pixels[1]");
11680 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011681
11682 result = CompileRun("var sum = 0;"
11683 "for (var i = 0; i < 8; i++) {"
11684 " sum += pixels[i] = pixels[i] = -i;"
11685 "}"
11686 "sum;");
11687 CHECK_EQ(-28, result->Int32Value());
11688
11689 result = CompileRun("var sum = 0;"
11690 "for (var i = 0; i < 8; i++) {"
11691 " sum += pixels[i] = pixels[i] = 0;"
11692 "}"
11693 "sum;");
11694 CHECK_EQ(0, result->Int32Value());
11695
11696 result = CompileRun("var sum = 0;"
11697 "for (var i = 0; i < 8; i++) {"
11698 " sum += pixels[i] = pixels[i] = 255;"
11699 "}"
11700 "sum;");
11701 CHECK_EQ(8 * 255, result->Int32Value());
11702
11703 result = CompileRun("var sum = 0;"
11704 "for (var i = 0; i < 8; i++) {"
11705 " sum += pixels[i] = pixels[i] = 256 + i;"
11706 "}"
11707 "sum;");
11708 CHECK_EQ(2076, result->Int32Value());
11709
11710 result = CompileRun("var sum = 0;"
11711 "for (var i = 0; i < 8; i++) {"
11712 " sum += pixels[i] = pixels[i] = i;"
11713 "}"
11714 "sum;");
11715 CHECK_EQ(28, result->Int32Value());
11716
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011717 result = CompileRun("var sum = 0;"
11718 "for (var i = 0; i < 8; i++) {"
11719 " sum += pixels[i];"
11720 "}"
11721 "sum;");
11722 CHECK_EQ(28, result->Int32Value());
11723
11724 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011725 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011726 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011727 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011728 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011729 CHECK_EQ(255,
11730 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011731 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011732 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011733 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011734
11735 result = CompileRun("for (var i = 0; i < 8; i++) {"
11736 " pixels[i] = (i * 65) - 109;"
11737 "}"
11738 "pixels[1] + pixels[6];");
11739 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011740 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11741 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11742 CHECK_EQ(21,
11743 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11744 CHECK_EQ(86,
11745 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11746 CHECK_EQ(151,
11747 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11748 CHECK_EQ(216,
11749 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11750 CHECK_EQ(255,
11751 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11752 CHECK_EQ(255,
11753 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011754 result = CompileRun("var sum = 0;"
11755 "for (var i = 0; i < 8; i++) {"
11756 " sum += pixels[i];"
11757 "}"
11758 "sum;");
11759 CHECK_EQ(984, result->Int32Value());
11760
11761 result = CompileRun("for (var i = 0; i < 8; i++) {"
11762 " pixels[i] = (i * 1.1);"
11763 "}"
11764 "pixels[1] + pixels[6];");
11765 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011766 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11767 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11768 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11769 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11770 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11771 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11772 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11773 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011774
11775 result = CompileRun("for (var i = 0; i < 8; i++) {"
11776 " pixels[7] = undefined;"
11777 "}"
11778 "pixels[7];");
11779 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011780 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011781
11782 result = CompileRun("for (var i = 0; i < 8; i++) {"
11783 " pixels[6] = '2.3';"
11784 "}"
11785 "pixels[6];");
11786 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011787 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011788
11789 result = CompileRun("for (var i = 0; i < 8; i++) {"
11790 " pixels[5] = NaN;"
11791 "}"
11792 "pixels[5];");
11793 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011794 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011795
11796 result = CompileRun("for (var i = 0; i < 8; i++) {"
11797 " pixels[8] = Infinity;"
11798 "}"
11799 "pixels[8];");
11800 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011801 CHECK_EQ(255,
11802 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011803
11804 result = CompileRun("for (var i = 0; i < 8; i++) {"
11805 " pixels[9] = -Infinity;"
11806 "}"
11807 "pixels[9];");
11808 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011809 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011810
11811 result = CompileRun("pixels[3] = 33;"
11812 "delete pixels[3];"
11813 "pixels[3];");
11814 CHECK_EQ(33, result->Int32Value());
11815
11816 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11817 "pixels[2] = 12; pixels[3] = 13;"
11818 "pixels.__defineGetter__('2',"
11819 "function() { return 120; });"
11820 "pixels[2];");
11821 CHECK_EQ(12, result->Int32Value());
11822
11823 result = CompileRun("var js_array = new Array(40);"
11824 "js_array[0] = 77;"
11825 "js_array;");
11826 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11827
11828 result = CompileRun("pixels[1] = 23;"
11829 "pixels.__proto__ = [];"
11830 "js_array.__proto__ = pixels;"
11831 "js_array.concat(pixels);");
11832 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11833 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11834
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011835 result = CompileRun("pixels[1] = 23;");
11836 CHECK_EQ(23, result->Int32Value());
11837
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011838 // Test for index greater than 255. Regression test for:
11839 // http://code.google.com/p/chromium/issues/detail?id=26337.
11840 result = CompileRun("pixels[256] = 255;");
11841 CHECK_EQ(255, result->Int32Value());
11842 result = CompileRun("var i = 0;"
11843 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11844 "i");
11845 CHECK_EQ(255, result->Int32Value());
11846
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011847 // Make sure that pixel array ICs recognize when a non-pixel array
11848 // is passed to it.
11849 result = CompileRun("function pa_load(p) {"
11850 " var sum = 0;"
11851 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11852 " return sum;"
11853 "}"
11854 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11855 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11856 "just_ints = new Object();"
11857 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11858 "for (var i = 0; i < 10; ++i) {"
11859 " result = pa_load(just_ints);"
11860 "}"
11861 "result");
11862 CHECK_EQ(32640, result->Int32Value());
11863
11864 // Make sure that pixel array ICs recognize out-of-bound accesses.
11865 result = CompileRun("function pa_load(p, start) {"
11866 " var sum = 0;"
11867 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11868 " return sum;"
11869 "}"
11870 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11871 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11872 "for (var i = 0; i < 10; ++i) {"
11873 " result = pa_load(pixels,-10);"
11874 "}"
11875 "result");
11876 CHECK_EQ(0, result->Int32Value());
11877
11878 // Make sure that generic ICs properly handles a pixel array.
11879 result = CompileRun("function pa_load(p) {"
11880 " var sum = 0;"
11881 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11882 " return sum;"
11883 "}"
11884 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11885 "just_ints = new Object();"
11886 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11887 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11888 "for (var i = 0; i < 10; ++i) {"
11889 " result = pa_load(pixels);"
11890 "}"
11891 "result");
11892 CHECK_EQ(32640, result->Int32Value());
11893
11894 // Make sure that generic load ICs recognize out-of-bound accesses in
11895 // pixel arrays.
11896 result = CompileRun("function pa_load(p, start) {"
11897 " var sum = 0;"
11898 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11899 " return sum;"
11900 "}"
11901 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11902 "just_ints = new Object();"
11903 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11904 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11905 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11906 "for (var i = 0; i < 10; ++i) {"
11907 " result = pa_load(pixels,-10);"
11908 "}"
11909 "result");
11910 CHECK_EQ(0, result->Int32Value());
11911
11912 // Make sure that generic ICs properly handles other types than pixel
11913 // arrays (that the inlined fast pixel array test leaves the right information
11914 // in the right registers).
11915 result = CompileRun("function pa_load(p) {"
11916 " var sum = 0;"
11917 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11918 " return sum;"
11919 "}"
11920 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11921 "just_ints = new Object();"
11922 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11923 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11924 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11925 "sparse_array = new Object();"
11926 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11927 "sparse_array[1000000] = 3;"
11928 "for (var i = 0; i < 10; ++i) {"
11929 " result = pa_load(sparse_array);"
11930 "}"
11931 "result");
11932 CHECK_EQ(32640, result->Int32Value());
11933
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011934 // Make sure that pixel array store ICs clamp values correctly.
11935 result = CompileRun("function pa_store(p) {"
11936 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11937 "}"
11938 "pa_store(pixels);"
11939 "var sum = 0;"
11940 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11941 "sum");
11942 CHECK_EQ(48896, result->Int32Value());
11943
11944 // Make sure that pixel array stores correctly handle accesses outside
11945 // of the pixel array..
11946 result = CompileRun("function pa_store(p,start) {"
11947 " for (var j = 0; j < 256; j++) {"
11948 " p[j+start] = j * 2;"
11949 " }"
11950 "}"
11951 "pa_store(pixels,0);"
11952 "pa_store(pixels,-128);"
11953 "var sum = 0;"
11954 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11955 "sum");
11956 CHECK_EQ(65280, result->Int32Value());
11957
11958 // Make sure that the generic store stub correctly handle accesses outside
11959 // of the pixel array..
11960 result = CompileRun("function pa_store(p,start) {"
11961 " for (var j = 0; j < 256; j++) {"
11962 " p[j+start] = j * 2;"
11963 " }"
11964 "}"
11965 "pa_store(pixels,0);"
11966 "just_ints = new Object();"
11967 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11968 "pa_store(just_ints, 0);"
11969 "pa_store(pixels,-128);"
11970 "var sum = 0;"
11971 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11972 "sum");
11973 CHECK_EQ(65280, result->Int32Value());
11974
11975 // Make sure that the generic keyed store stub clamps pixel array values
11976 // correctly.
11977 result = CompileRun("function pa_store(p) {"
11978 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11979 "}"
11980 "pa_store(pixels);"
11981 "just_ints = new Object();"
11982 "pa_store(just_ints);"
11983 "pa_store(pixels);"
11984 "var sum = 0;"
11985 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11986 "sum");
11987 CHECK_EQ(48896, result->Int32Value());
11988
11989 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011990 result = CompileRun("function pa_load(p) {"
11991 " var sum = 0;"
11992 " for (var i=0; i<256; ++i) {"
11993 " sum += p[i];"
11994 " }"
11995 " return sum; "
11996 "}"
11997 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011998 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011999 " result = pa_load(pixels);"
12000 "}"
12001 "result");
12002 CHECK_EQ(32640, result->Int32Value());
12003
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012004 // Make sure that pixel array stores are optimized by crankshaft.
12005 result = CompileRun("function pa_init(p) {"
12006 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12007 "}"
12008 "function pa_load(p) {"
12009 " var sum = 0;"
12010 " for (var i=0; i<256; ++i) {"
12011 " sum += p[i];"
12012 " }"
12013 " return sum; "
12014 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012015 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012016 " pa_init(pixels);"
12017 "}"
12018 "result = pa_load(pixels);"
12019 "result");
12020 CHECK_EQ(32640, result->Int32Value());
12021
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012022 free(pixel_data);
12023}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012024
ager@chromium.org96c75b52009-08-26 09:13:16 +000012025
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012026THREADED_TEST(PixelArrayInfo) {
12027 v8::HandleScope scope;
12028 LocalContext context;
12029 for (int size = 0; size < 100; size += 10) {
12030 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12031 v8::Handle<v8::Object> obj = v8::Object::New();
12032 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12033 CHECK(obj->HasIndexedPropertiesInPixelData());
12034 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12035 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12036 free(pixel_data);
12037 }
12038}
12039
12040
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012041static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12042 uint32_t index,
12043 const AccessorInfo& info) {
12044 ApiTestFuzzer::Fuzz();
12045 return v8::Handle<Value>();
12046}
12047
12048
12049static v8::Handle<Value> NotHandledIndexedPropertySetter(
12050 uint32_t index,
12051 Local<Value> value,
12052 const AccessorInfo& info) {
12053 ApiTestFuzzer::Fuzz();
12054 return v8::Handle<Value>();
12055}
12056
12057
12058THREADED_TEST(PixelArrayWithInterceptor) {
12059 v8::HandleScope scope;
12060 LocalContext context;
12061 const int kElementCount = 260;
12062 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012063 i::Handle<i::ExternalPixelArray> pixels =
12064 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012065 FACTORY->NewExternalArray(kElementCount,
12066 v8::kExternalPixelArray,
12067 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012068 for (int i = 0; i < kElementCount; i++) {
12069 pixels->set(i, i % 256);
12070 }
12071 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12072 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12073 NotHandledIndexedPropertySetter);
12074 v8::Handle<v8::Object> obj = templ->NewInstance();
12075 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12076 context->Global()->Set(v8_str("pixels"), obj);
12077 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12078 CHECK_EQ(1, result->Int32Value());
12079 result = CompileRun("var sum = 0;"
12080 "for (var i = 0; i < 8; i++) {"
12081 " sum += pixels[i] = pixels[i] = -i;"
12082 "}"
12083 "sum;");
12084 CHECK_EQ(-28, result->Int32Value());
12085 result = CompileRun("pixels.hasOwnProperty('1')");
12086 CHECK(result->BooleanValue());
12087 free(pixel_data);
12088}
12089
12090
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012091static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12092 switch (array_type) {
12093 case v8::kExternalByteArray:
12094 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012095 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012096 return 1;
12097 break;
12098 case v8::kExternalShortArray:
12099 case v8::kExternalUnsignedShortArray:
12100 return 2;
12101 break;
12102 case v8::kExternalIntArray:
12103 case v8::kExternalUnsignedIntArray:
12104 case v8::kExternalFloatArray:
12105 return 4;
12106 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012107 case v8::kExternalDoubleArray:
12108 return 8;
12109 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012110 default:
12111 UNREACHABLE();
12112 return -1;
12113 }
12114 UNREACHABLE();
12115 return -1;
12116}
12117
12118
ager@chromium.org3811b432009-10-28 14:53:37 +000012119template <class ExternalArrayClass, class ElementType>
12120static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12121 int64_t low,
12122 int64_t high) {
12123 v8::HandleScope scope;
12124 LocalContext context;
12125 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012126 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012127 ElementType* array_data =
12128 static_cast<ElementType*>(malloc(kElementCount * element_size));
12129 i::Handle<ExternalArrayClass> array =
12130 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12132 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012133 for (int i = 0; i < kElementCount; i++) {
12134 array->set(i, static_cast<ElementType>(i));
12135 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012136 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012137 for (int i = 0; i < kElementCount; i++) {
12138 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
12139 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12140 }
12141
12142 v8::Handle<v8::Object> obj = v8::Object::New();
12143 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12144 // Set the elements to be the external array.
12145 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12146 array_type,
12147 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012148 CHECK_EQ(
12149 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012150 obj->Set(v8_str("field"), v8::Int32::New(1503));
12151 context->Global()->Set(v8_str("ext_array"), obj);
12152 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12153 CHECK_EQ(1503, result->Int32Value());
12154 result = CompileRun("ext_array[1]");
12155 CHECK_EQ(1, result->Int32Value());
12156
12157 // Check pass through of assigned smis
12158 result = CompileRun("var sum = 0;"
12159 "for (var i = 0; i < 8; i++) {"
12160 " sum += ext_array[i] = ext_array[i] = -i;"
12161 "}"
12162 "sum;");
12163 CHECK_EQ(-28, result->Int32Value());
12164
12165 // Check assigned smis
12166 result = CompileRun("for (var i = 0; i < 8; i++) {"
12167 " ext_array[i] = i;"
12168 "}"
12169 "var sum = 0;"
12170 "for (var i = 0; i < 8; i++) {"
12171 " sum += ext_array[i];"
12172 "}"
12173 "sum;");
12174 CHECK_EQ(28, result->Int32Value());
12175
12176 // Check assigned smis in reverse order
12177 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12178 " ext_array[i] = i;"
12179 "}"
12180 "var sum = 0;"
12181 "for (var i = 0; i < 8; i++) {"
12182 " sum += ext_array[i];"
12183 "}"
12184 "sum;");
12185 CHECK_EQ(28, result->Int32Value());
12186
12187 // Check pass through of assigned HeapNumbers
12188 result = CompileRun("var sum = 0;"
12189 "for (var i = 0; i < 16; i+=2) {"
12190 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12191 "}"
12192 "sum;");
12193 CHECK_EQ(-28, result->Int32Value());
12194
12195 // Check assigned HeapNumbers
12196 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12197 " ext_array[i] = (i * 0.5);"
12198 "}"
12199 "var sum = 0;"
12200 "for (var i = 0; i < 16; i+=2) {"
12201 " sum += ext_array[i];"
12202 "}"
12203 "sum;");
12204 CHECK_EQ(28, result->Int32Value());
12205
12206 // Check assigned HeapNumbers in reverse order
12207 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12208 " ext_array[i] = (i * 0.5);"
12209 "}"
12210 "var sum = 0;"
12211 "for (var i = 0; i < 16; i+=2) {"
12212 " sum += ext_array[i];"
12213 "}"
12214 "sum;");
12215 CHECK_EQ(28, result->Int32Value());
12216
12217 i::ScopedVector<char> test_buf(1024);
12218
12219 // Check legal boundary conditions.
12220 // The repeated loads and stores ensure the ICs are exercised.
12221 const char* boundary_program =
12222 "var res = 0;"
12223 "for (var i = 0; i < 16; i++) {"
12224 " ext_array[i] = %lld;"
12225 " if (i > 8) {"
12226 " res = ext_array[i];"
12227 " }"
12228 "}"
12229 "res;";
12230 i::OS::SNPrintF(test_buf,
12231 boundary_program,
12232 low);
12233 result = CompileRun(test_buf.start());
12234 CHECK_EQ(low, result->IntegerValue());
12235
12236 i::OS::SNPrintF(test_buf,
12237 boundary_program,
12238 high);
12239 result = CompileRun(test_buf.start());
12240 CHECK_EQ(high, result->IntegerValue());
12241
12242 // Check misprediction of type in IC.
12243 result = CompileRun("var tmp_array = ext_array;"
12244 "var sum = 0;"
12245 "for (var i = 0; i < 8; i++) {"
12246 " tmp_array[i] = i;"
12247 " sum += tmp_array[i];"
12248 " if (i == 4) {"
12249 " tmp_array = {};"
12250 " }"
12251 "}"
12252 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012254 CHECK_EQ(28, result->Int32Value());
12255
12256 // Make sure out-of-range loads do not throw.
12257 i::OS::SNPrintF(test_buf,
12258 "var caught_exception = false;"
12259 "try {"
12260 " ext_array[%d];"
12261 "} catch (e) {"
12262 " caught_exception = true;"
12263 "}"
12264 "caught_exception;",
12265 kElementCount);
12266 result = CompileRun(test_buf.start());
12267 CHECK_EQ(false, result->BooleanValue());
12268
12269 // Make sure out-of-range stores do not throw.
12270 i::OS::SNPrintF(test_buf,
12271 "var caught_exception = false;"
12272 "try {"
12273 " ext_array[%d] = 1;"
12274 "} catch (e) {"
12275 " caught_exception = true;"
12276 "}"
12277 "caught_exception;",
12278 kElementCount);
12279 result = CompileRun(test_buf.start());
12280 CHECK_EQ(false, result->BooleanValue());
12281
12282 // Check other boundary conditions, values and operations.
12283 result = CompileRun("for (var i = 0; i < 8; i++) {"
12284 " ext_array[7] = undefined;"
12285 "}"
12286 "ext_array[7];");
12287 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012288 CHECK_EQ(
12289 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012290
12291 result = CompileRun("for (var i = 0; i < 8; i++) {"
12292 " ext_array[6] = '2.3';"
12293 "}"
12294 "ext_array[6];");
12295 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012296 CHECK_EQ(
12297 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012298
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012299 if (array_type != v8::kExternalFloatArray &&
12300 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012301 // Though the specification doesn't state it, be explicit about
12302 // converting NaNs and +/-Infinity to zero.
12303 result = CompileRun("for (var i = 0; i < 8; i++) {"
12304 " ext_array[i] = 5;"
12305 "}"
12306 "for (var i = 0; i < 8; i++) {"
12307 " ext_array[i] = NaN;"
12308 "}"
12309 "ext_array[5];");
12310 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012311 CHECK_EQ(0,
12312 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012313
12314 result = CompileRun("for (var i = 0; i < 8; i++) {"
12315 " ext_array[i] = 5;"
12316 "}"
12317 "for (var i = 0; i < 8; i++) {"
12318 " ext_array[i] = Infinity;"
12319 "}"
12320 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012321 int expected_value =
12322 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12323 CHECK_EQ(expected_value, result->Int32Value());
12324 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012325 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012326
12327 result = CompileRun("for (var i = 0; i < 8; i++) {"
12328 " ext_array[i] = 5;"
12329 "}"
12330 "for (var i = 0; i < 8; i++) {"
12331 " ext_array[i] = -Infinity;"
12332 "}"
12333 "ext_array[5];");
12334 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012335 CHECK_EQ(0,
12336 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012337
12338 // Check truncation behavior of integral arrays.
12339 const char* unsigned_data =
12340 "var source_data = [0.6, 10.6];"
12341 "var expected_results = [0, 10];";
12342 const char* signed_data =
12343 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12344 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012345 const char* pixel_data =
12346 "var source_data = [0.6, 10.6];"
12347 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012348 bool is_unsigned =
12349 (array_type == v8::kExternalUnsignedByteArray ||
12350 array_type == v8::kExternalUnsignedShortArray ||
12351 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012352 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012353
12354 i::OS::SNPrintF(test_buf,
12355 "%s"
12356 "var all_passed = true;"
12357 "for (var i = 0; i < source_data.length; i++) {"
12358 " for (var j = 0; j < 8; j++) {"
12359 " ext_array[j] = source_data[i];"
12360 " }"
12361 " all_passed = all_passed &&"
12362 " (ext_array[5] == expected_results[i]);"
12363 "}"
12364 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012365 (is_unsigned ?
12366 unsigned_data :
12367 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012368 result = CompileRun(test_buf.start());
12369 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012370 }
12371
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012372 for (int i = 0; i < kElementCount; i++) {
12373 array->set(i, static_cast<ElementType>(i));
12374 }
12375 // Test complex assignments
12376 result = CompileRun("function ee_op_test_complex_func(sum) {"
12377 " for (var i = 0; i < 40; ++i) {"
12378 " sum += (ext_array[i] += 1);"
12379 " sum += (ext_array[i] -= 1);"
12380 " } "
12381 " return sum;"
12382 "}"
12383 "sum=0;"
12384 "for (var i=0;i<10000;++i) {"
12385 " sum=ee_op_test_complex_func(sum);"
12386 "}"
12387 "sum;");
12388 CHECK_EQ(16000000, result->Int32Value());
12389
12390 // Test count operations
12391 result = CompileRun("function ee_op_test_count_func(sum) {"
12392 " for (var i = 0; i < 40; ++i) {"
12393 " sum += (++ext_array[i]);"
12394 " sum += (--ext_array[i]);"
12395 " } "
12396 " return sum;"
12397 "}"
12398 "sum=0;"
12399 "for (var i=0;i<10000;++i) {"
12400 " sum=ee_op_test_count_func(sum);"
12401 "}"
12402 "sum;");
12403 CHECK_EQ(16000000, result->Int32Value());
12404
ager@chromium.org3811b432009-10-28 14:53:37 +000012405 result = CompileRun("ext_array[3] = 33;"
12406 "delete ext_array[3];"
12407 "ext_array[3];");
12408 CHECK_EQ(33, result->Int32Value());
12409
12410 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12411 "ext_array[2] = 12; ext_array[3] = 13;"
12412 "ext_array.__defineGetter__('2',"
12413 "function() { return 120; });"
12414 "ext_array[2];");
12415 CHECK_EQ(12, result->Int32Value());
12416
12417 result = CompileRun("var js_array = new Array(40);"
12418 "js_array[0] = 77;"
12419 "js_array;");
12420 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12421
12422 result = CompileRun("ext_array[1] = 23;"
12423 "ext_array.__proto__ = [];"
12424 "js_array.__proto__ = ext_array;"
12425 "js_array.concat(ext_array);");
12426 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12427 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12428
12429 result = CompileRun("ext_array[1] = 23;");
12430 CHECK_EQ(23, result->Int32Value());
12431
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012432 // Test more complex manipulations which cause eax to contain values
12433 // that won't be completely overwritten by loads from the arrays.
12434 // This catches bugs in the instructions used for the KeyedLoadIC
12435 // for byte and word types.
12436 {
12437 const int kXSize = 300;
12438 const int kYSize = 300;
12439 const int kLargeElementCount = kXSize * kYSize * 4;
12440 ElementType* large_array_data =
12441 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12442 i::Handle<ExternalArrayClass> large_array =
12443 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012445 array_type,
12446 array_data));
12447 v8::Handle<v8::Object> large_obj = v8::Object::New();
12448 // Set the elements to be the external array.
12449 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12450 array_type,
12451 kLargeElementCount);
12452 context->Global()->Set(v8_str("large_array"), large_obj);
12453 // Initialize contents of a few rows.
12454 for (int x = 0; x < 300; x++) {
12455 int row = 0;
12456 int offset = row * 300 * 4;
12457 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12458 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12459 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12460 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12461 row = 150;
12462 offset = row * 300 * 4;
12463 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12464 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12465 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12466 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12467 row = 298;
12468 offset = row * 300 * 4;
12469 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12470 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12471 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12472 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12473 }
12474 // The goal of the code below is to make "offset" large enough
12475 // that the computation of the index (which goes into eax) has
12476 // high bits set which will not be overwritten by a byte or short
12477 // load.
12478 result = CompileRun("var failed = false;"
12479 "var offset = 0;"
12480 "for (var i = 0; i < 300; i++) {"
12481 " if (large_array[4 * i] != 127 ||"
12482 " large_array[4 * i + 1] != 0 ||"
12483 " large_array[4 * i + 2] != 0 ||"
12484 " large_array[4 * i + 3] != 127) {"
12485 " failed = true;"
12486 " }"
12487 "}"
12488 "offset = 150 * 300 * 4;"
12489 "for (var i = 0; i < 300; i++) {"
12490 " if (large_array[offset + 4 * i] != 127 ||"
12491 " large_array[offset + 4 * i + 1] != 0 ||"
12492 " large_array[offset + 4 * i + 2] != 0 ||"
12493 " large_array[offset + 4 * i + 3] != 127) {"
12494 " failed = true;"
12495 " }"
12496 "}"
12497 "offset = 298 * 300 * 4;"
12498 "for (var i = 0; i < 300; i++) {"
12499 " if (large_array[offset + 4 * i] != 127 ||"
12500 " large_array[offset + 4 * i + 1] != 0 ||"
12501 " large_array[offset + 4 * i + 2] != 0 ||"
12502 " large_array[offset + 4 * i + 3] != 127) {"
12503 " failed = true;"
12504 " }"
12505 "}"
12506 "!failed;");
12507 CHECK_EQ(true, result->BooleanValue());
12508 free(large_array_data);
12509 }
12510
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012511 // The "" property descriptor is overloaded to store information about
12512 // the external array. Ensure that setting and accessing the "" property
12513 // works (it should overwrite the information cached about the external
12514 // array in the DescriptorArray) in various situations.
12515 result = CompileRun("ext_array[''] = 23; ext_array['']");
12516 CHECK_EQ(23, result->Int32Value());
12517
12518 // Property "" set after the external array is associated with the object.
12519 {
12520 v8::Handle<v8::Object> obj2 = v8::Object::New();
12521 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12522 obj2->Set(v8_str(""), v8::Int32::New(1503));
12523 // Set the elements to be the external array.
12524 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12525 array_type,
12526 kElementCount);
12527 context->Global()->Set(v8_str("ext_array"), obj2);
12528 result = CompileRun("ext_array['']");
12529 CHECK_EQ(1503, result->Int32Value());
12530 }
12531
12532 // Property "" set after the external array is associated with the object.
12533 {
12534 v8::Handle<v8::Object> obj2 = v8::Object::New();
12535 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12536 // Set the elements to be the external array.
12537 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12538 array_type,
12539 kElementCount);
12540 obj2->Set(v8_str(""), v8::Int32::New(1503));
12541 context->Global()->Set(v8_str("ext_array"), obj2);
12542 result = CompileRun("ext_array['']");
12543 CHECK_EQ(1503, result->Int32Value());
12544 }
12545
12546 // Should reuse the map from previous test.
12547 {
12548 v8::Handle<v8::Object> obj2 = v8::Object::New();
12549 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12550 // Set the elements to be the external array. Should re-use the map
12551 // from previous test.
12552 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12553 array_type,
12554 kElementCount);
12555 context->Global()->Set(v8_str("ext_array"), obj2);
12556 result = CompileRun("ext_array['']");
12557 }
12558
12559 // Property "" is a constant function that shouldn't not be interfered with
12560 // when an external array is set.
12561 {
12562 v8::Handle<v8::Object> obj2 = v8::Object::New();
12563 // Start
12564 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12565
12566 // Add a constant function to an object.
12567 context->Global()->Set(v8_str("ext_array"), obj2);
12568 result = CompileRun("ext_array[''] = function() {return 1503;};"
12569 "ext_array['']();");
12570
12571 // Add an external array transition to the same map that
12572 // has the constant transition.
12573 v8::Handle<v8::Object> obj3 = v8::Object::New();
12574 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12575 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12576 array_type,
12577 kElementCount);
12578 context->Global()->Set(v8_str("ext_array"), obj3);
12579 }
12580
12581 // If a external array transition is in the map, it should get clobbered
12582 // by a constant function.
12583 {
12584 // Add an external array transition.
12585 v8::Handle<v8::Object> obj3 = v8::Object::New();
12586 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12587 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12588 array_type,
12589 kElementCount);
12590
12591 // Add a constant function to the same map that just got an external array
12592 // transition.
12593 v8::Handle<v8::Object> obj2 = v8::Object::New();
12594 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12595 context->Global()->Set(v8_str("ext_array"), obj2);
12596 result = CompileRun("ext_array[''] = function() {return 1503;};"
12597 "ext_array['']();");
12598 }
12599
ager@chromium.org3811b432009-10-28 14:53:37 +000012600 free(array_data);
12601}
12602
12603
12604THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012605 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012606 v8::kExternalByteArray,
12607 -128,
12608 127);
12609}
12610
12611
12612THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012613 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012614 v8::kExternalUnsignedByteArray,
12615 0,
12616 255);
12617}
12618
12619
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012620THREADED_TEST(ExternalPixelArray) {
12621 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12622 v8::kExternalPixelArray,
12623 0,
12624 255);
12625}
12626
12627
ager@chromium.org3811b432009-10-28 14:53:37 +000012628THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012629 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012630 v8::kExternalShortArray,
12631 -32768,
12632 32767);
12633}
12634
12635
12636THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012637 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012638 v8::kExternalUnsignedShortArray,
12639 0,
12640 65535);
12641}
12642
12643
12644THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012645 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012646 v8::kExternalIntArray,
12647 INT_MIN, // -2147483648
12648 INT_MAX); // 2147483647
12649}
12650
12651
12652THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012653 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012654 v8::kExternalUnsignedIntArray,
12655 0,
12656 UINT_MAX); // 4294967295
12657}
12658
12659
12660THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012661 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012662 v8::kExternalFloatArray,
12663 -500,
12664 500);
12665}
12666
12667
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012668THREADED_TEST(ExternalDoubleArray) {
12669 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12670 v8::kExternalDoubleArray,
12671 -500,
12672 500);
12673}
12674
12675
ager@chromium.org3811b432009-10-28 14:53:37 +000012676THREADED_TEST(ExternalArrays) {
12677 TestExternalByteArray();
12678 TestExternalUnsignedByteArray();
12679 TestExternalShortArray();
12680 TestExternalUnsignedShortArray();
12681 TestExternalIntArray();
12682 TestExternalUnsignedIntArray();
12683 TestExternalFloatArray();
12684}
12685
12686
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012687void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12688 v8::HandleScope scope;
12689 LocalContext context;
12690 for (int size = 0; size < 100; size += 10) {
12691 int element_size = ExternalArrayElementSize(array_type);
12692 void* external_data = malloc(size * element_size);
12693 v8::Handle<v8::Object> obj = v8::Object::New();
12694 obj->SetIndexedPropertiesToExternalArrayData(
12695 external_data, array_type, size);
12696 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12697 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12698 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12699 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12700 free(external_data);
12701 }
12702}
12703
12704
12705THREADED_TEST(ExternalArrayInfo) {
12706 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12707 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12708 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12709 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12710 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12711 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12712 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012713 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012714 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012715}
12716
12717
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012718THREADED_TEST(ScriptContextDependence) {
12719 v8::HandleScope scope;
12720 LocalContext c1;
12721 const char *source = "foo";
12722 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12723 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12724 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12725 CHECK_EQ(dep->Run()->Int32Value(), 100);
12726 CHECK_EQ(indep->Run()->Int32Value(), 100);
12727 LocalContext c2;
12728 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12729 CHECK_EQ(dep->Run()->Int32Value(), 100);
12730 CHECK_EQ(indep->Run()->Int32Value(), 101);
12731}
12732
ager@chromium.org96c75b52009-08-26 09:13:16 +000012733
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012734THREADED_TEST(StackTrace) {
12735 v8::HandleScope scope;
12736 LocalContext context;
12737 v8::TryCatch try_catch;
12738 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12739 v8::Handle<v8::String> src = v8::String::New(source);
12740 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12741 v8::Script::New(src, origin)->Run();
12742 CHECK(try_catch.HasCaught());
12743 v8::String::Utf8Value stack(try_catch.StackTrace());
12744 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12745}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012746
12747
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012748// Checks that a StackFrame has certain expected values.
12749void checkStackFrame(const char* expected_script_name,
12750 const char* expected_func_name, int expected_line_number,
12751 int expected_column, bool is_eval, bool is_constructor,
12752 v8::Handle<v8::StackFrame> frame) {
12753 v8::HandleScope scope;
12754 v8::String::Utf8Value func_name(frame->GetFunctionName());
12755 v8::String::Utf8Value script_name(frame->GetScriptName());
12756 if (*script_name == NULL) {
12757 // The situation where there is no associated script, like for evals.
12758 CHECK(expected_script_name == NULL);
12759 } else {
12760 CHECK(strstr(*script_name, expected_script_name) != NULL);
12761 }
12762 CHECK(strstr(*func_name, expected_func_name) != NULL);
12763 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12764 CHECK_EQ(expected_column, frame->GetColumn());
12765 CHECK_EQ(is_eval, frame->IsEval());
12766 CHECK_EQ(is_constructor, frame->IsConstructor());
12767}
12768
12769
12770v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12771 v8::HandleScope scope;
12772 const char* origin = "capture-stack-trace-test";
12773 const int kOverviewTest = 1;
12774 const int kDetailedTest = 2;
12775
12776 ASSERT(args.Length() == 1);
12777
12778 int testGroup = args[0]->Int32Value();
12779 if (testGroup == kOverviewTest) {
12780 v8::Handle<v8::StackTrace> stackTrace =
12781 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12782 CHECK_EQ(4, stackTrace->GetFrameCount());
12783 checkStackFrame(origin, "bar", 2, 10, false, false,
12784 stackTrace->GetFrame(0));
12785 checkStackFrame(origin, "foo", 6, 3, false, false,
12786 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012787 // This is the source string inside the eval which has the call to foo.
12788 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012789 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012790 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012791 checkStackFrame(origin, "", 8, 7, false, false,
12792 stackTrace->GetFrame(3));
12793
12794 CHECK(stackTrace->AsArray()->IsArray());
12795 } else if (testGroup == kDetailedTest) {
12796 v8::Handle<v8::StackTrace> stackTrace =
12797 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12798 CHECK_EQ(4, stackTrace->GetFrameCount());
12799 checkStackFrame(origin, "bat", 4, 22, false, false,
12800 stackTrace->GetFrame(0));
12801 checkStackFrame(origin, "baz", 8, 3, false, true,
12802 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012803#ifdef ENABLE_DEBUGGER_SUPPORT
12804 bool is_eval = true;
12805#else // ENABLE_DEBUGGER_SUPPORT
12806 bool is_eval = false;
12807#endif // ENABLE_DEBUGGER_SUPPORT
12808
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012809 // This is the source string inside the eval which has the call to baz.
12810 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012811 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012812 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012813 checkStackFrame(origin, "", 10, 1, false, false,
12814 stackTrace->GetFrame(3));
12815
12816 CHECK(stackTrace->AsArray()->IsArray());
12817 }
12818 return v8::Undefined();
12819}
12820
12821
12822// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012823// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12824// THREADED_TEST(CaptureStackTrace) {
12825TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012826 v8::HandleScope scope;
12827 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12828 Local<ObjectTemplate> templ = ObjectTemplate::New();
12829 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12830 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12831 LocalContext context(0, templ);
12832
12833 // Test getting OVERVIEW information. Should ignore information that is not
12834 // script name, function name, line number, and column offset.
12835 const char *overview_source =
12836 "function bar() {\n"
12837 " var y; AnalyzeStackInNativeCode(1);\n"
12838 "}\n"
12839 "function foo() {\n"
12840 "\n"
12841 " bar();\n"
12842 "}\n"
12843 "var x;eval('new foo();');";
12844 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12845 v8::Handle<Value> overview_result =
12846 v8::Script::New(overview_src, origin)->Run();
12847 ASSERT(!overview_result.IsEmpty());
12848 ASSERT(overview_result->IsObject());
12849
12850 // Test getting DETAILED information.
12851 const char *detailed_source =
12852 "function bat() {AnalyzeStackInNativeCode(2);\n"
12853 "}\n"
12854 "\n"
12855 "function baz() {\n"
12856 " bat();\n"
12857 "}\n"
12858 "eval('new baz();');";
12859 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12860 // Make the script using a non-zero line and column offset.
12861 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12862 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12863 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12864 v8::Handle<v8::Script> detailed_script(
12865 v8::Script::New(detailed_src, &detailed_origin));
12866 v8::Handle<Value> detailed_result = detailed_script->Run();
12867 ASSERT(!detailed_result.IsEmpty());
12868 ASSERT(detailed_result->IsObject());
12869}
12870
12871
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012872static void StackTraceForUncaughtExceptionListener(
12873 v8::Handle<v8::Message> message,
12874 v8::Handle<Value>) {
12875 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12876 CHECK_EQ(2, stack_trace->GetFrameCount());
12877 checkStackFrame("origin", "foo", 2, 3, false, false,
12878 stack_trace->GetFrame(0));
12879 checkStackFrame("origin", "bar", 5, 3, false, false,
12880 stack_trace->GetFrame(1));
12881}
12882
12883TEST(CaptureStackTraceForUncaughtException) {
12884 report_count = 0;
12885 v8::HandleScope scope;
12886 LocalContext env;
12887 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12888 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12889
12890 Script::Compile(v8_str("function foo() {\n"
12891 " throw 1;\n"
12892 "};\n"
12893 "function bar() {\n"
12894 " foo();\n"
12895 "};"),
12896 v8_str("origin"))->Run();
12897 v8::Local<v8::Object> global = env->Global();
12898 Local<Value> trouble = global->Get(v8_str("bar"));
12899 CHECK(trouble->IsFunction());
12900 Function::Cast(*trouble)->Call(global, 0, NULL);
12901 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12902 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12903}
12904
12905
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012906TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12907 v8::HandleScope scope;
12908 LocalContext env;
12909 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12910 1024,
12911 v8::StackTrace::kDetailed);
12912
12913 CompileRun(
12914 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12915 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12916 " 'isConstructor'];\n"
12917 "for (var i = 0; i < setters.length; i++) {\n"
12918 " var prop = setters[i];\n"
12919 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12920 "}\n");
12921 CompileRun("throw 'exception';");
12922 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12923}
12924
12925
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012926v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12927 v8::HandleScope scope;
12928 v8::Handle<v8::StackTrace> stackTrace =
12929 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12930 CHECK_EQ(5, stackTrace->GetFrameCount());
12931 v8::Handle<v8::String> url = v8_str("eval_url");
12932 for (int i = 0; i < 3; i++) {
12933 v8::Handle<v8::String> name =
12934 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12935 CHECK(!name.IsEmpty());
12936 CHECK_EQ(url, name);
12937 }
12938 return v8::Undefined();
12939}
12940
12941
12942TEST(SourceURLInStackTrace) {
12943 v8::HandleScope scope;
12944 Local<ObjectTemplate> templ = ObjectTemplate::New();
12945 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12946 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12947 LocalContext context(0, templ);
12948
12949 const char *source =
12950 "function outer() {\n"
12951 "function bar() {\n"
12952 " AnalyzeStackOfEvalWithSourceURL();\n"
12953 "}\n"
12954 "function foo() {\n"
12955 "\n"
12956 " bar();\n"
12957 "}\n"
12958 "foo();\n"
12959 "}\n"
12960 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12961 CHECK(CompileRun(source)->IsUndefined());
12962}
12963
12964
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012965// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012966THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012967 bool rv = false;
12968 for (int i = 0; i < 100; i++) {
12969 rv = v8::V8::IdleNotification();
12970 if (rv)
12971 break;
12972 }
12973 CHECK(rv == true);
12974}
12975
12976
12977static uint32_t* stack_limit;
12978
12979static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012980 stack_limit = reinterpret_cast<uint32_t*>(
12981 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012982 return v8::Undefined();
12983}
12984
12985
12986// Uses the address of a local variable to determine the stack top now.
12987// Given a size, returns an address that is that far from the current
12988// top of stack.
12989static uint32_t* ComputeStackLimit(uint32_t size) {
12990 uint32_t* answer = &size - (size / sizeof(size));
12991 // If the size is very large and the stack is very near the bottom of
12992 // memory then the calculation above may wrap around and give an address
12993 // that is above the (downwards-growing) stack. In that case we return
12994 // a very low address.
12995 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12996 return answer;
12997}
12998
12999
13000TEST(SetResourceConstraints) {
13001 static const int K = 1024;
13002 uint32_t* set_limit = ComputeStackLimit(128 * K);
13003
13004 // Set stack limit.
13005 v8::ResourceConstraints constraints;
13006 constraints.set_stack_limit(set_limit);
13007 CHECK(v8::SetResourceConstraints(&constraints));
13008
13009 // Execute a script.
13010 v8::HandleScope scope;
13011 LocalContext env;
13012 Local<v8::FunctionTemplate> fun_templ =
13013 v8::FunctionTemplate::New(GetStackLimitCallback);
13014 Local<Function> fun = fun_templ->GetFunction();
13015 env->Global()->Set(v8_str("get_stack_limit"), fun);
13016 CompileRun("get_stack_limit();");
13017
13018 CHECK(stack_limit == set_limit);
13019}
13020
13021
13022TEST(SetResourceConstraintsInThread) {
13023 uint32_t* set_limit;
13024 {
13025 v8::Locker locker;
13026 static const int K = 1024;
13027 set_limit = ComputeStackLimit(128 * K);
13028
13029 // Set stack limit.
13030 v8::ResourceConstraints constraints;
13031 constraints.set_stack_limit(set_limit);
13032 CHECK(v8::SetResourceConstraints(&constraints));
13033
13034 // Execute a script.
13035 v8::HandleScope scope;
13036 LocalContext env;
13037 Local<v8::FunctionTemplate> fun_templ =
13038 v8::FunctionTemplate::New(GetStackLimitCallback);
13039 Local<Function> fun = fun_templ->GetFunction();
13040 env->Global()->Set(v8_str("get_stack_limit"), fun);
13041 CompileRun("get_stack_limit();");
13042
13043 CHECK(stack_limit == set_limit);
13044 }
13045 {
13046 v8::Locker locker;
13047 CHECK(stack_limit == set_limit);
13048 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013049}
ager@chromium.org3811b432009-10-28 14:53:37 +000013050
13051
13052THREADED_TEST(GetHeapStatistics) {
13053 v8::HandleScope scope;
13054 LocalContext c1;
13055 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013056 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13057 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013058 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013059 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13060 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013061}
13062
13063
13064static double DoubleFromBits(uint64_t value) {
13065 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013066 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013067 return target;
13068}
13069
13070
13071static uint64_t DoubleToBits(double value) {
13072 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013073 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013074 return target;
13075}
13076
13077
13078static double DoubleToDateTime(double input) {
13079 double date_limit = 864e13;
13080 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13081 return i::OS::nan_value();
13082 }
13083 return (input < 0) ? -(floor(-input)) : floor(input);
13084}
13085
13086// We don't have a consistent way to write 64-bit constants syntactically, so we
13087// split them into two 32-bit constants and combine them programmatically.
13088static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13089 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13090}
13091
13092
13093THREADED_TEST(QuietSignalingNaNs) {
13094 v8::HandleScope scope;
13095 LocalContext context;
13096 v8::TryCatch try_catch;
13097
13098 // Special double values.
13099 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13100 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13101 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13102 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13103 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13104 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13105 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13106
13107 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13108 // on either side of the epoch.
13109 double date_limit = 864e13;
13110
13111 double test_values[] = {
13112 snan,
13113 qnan,
13114 infinity,
13115 max_normal,
13116 date_limit + 1,
13117 date_limit,
13118 min_normal,
13119 max_denormal,
13120 min_denormal,
13121 0,
13122 -0,
13123 -min_denormal,
13124 -max_denormal,
13125 -min_normal,
13126 -date_limit,
13127 -date_limit - 1,
13128 -max_normal,
13129 -infinity,
13130 -qnan,
13131 -snan
13132 };
13133 int num_test_values = 20;
13134
13135 for (int i = 0; i < num_test_values; i++) {
13136 double test_value = test_values[i];
13137
13138 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13139 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13140 double stored_number = number->NumberValue();
13141 if (!IsNaN(test_value)) {
13142 CHECK_EQ(test_value, stored_number);
13143 } else {
13144 uint64_t stored_bits = DoubleToBits(stored_number);
13145 // Check if quiet nan (bits 51..62 all set).
13146 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13147 }
13148
13149 // Check that Date::New preserves non-NaNs in the date range and
13150 // quiets SNaNs.
13151 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13152 double expected_stored_date = DoubleToDateTime(test_value);
13153 double stored_date = date->NumberValue();
13154 if (!IsNaN(expected_stored_date)) {
13155 CHECK_EQ(expected_stored_date, stored_date);
13156 } else {
13157 uint64_t stored_bits = DoubleToBits(stored_date);
13158 // Check if quiet nan (bits 51..62 all set).
13159 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13160 }
13161 }
13162}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013163
13164
13165static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13166 v8::HandleScope scope;
13167 v8::TryCatch tc;
13168 v8::Handle<v8::String> str = args[0]->ToString();
13169 if (tc.HasCaught())
13170 return tc.ReThrow();
13171 return v8::Undefined();
13172}
13173
13174
13175// Test that an exception can be propagated down through a spaghetti
13176// stack using ReThrow.
13177THREADED_TEST(SpaghettiStackReThrow) {
13178 v8::HandleScope scope;
13179 LocalContext context;
13180 context->Global()->Set(
13181 v8::String::New("s"),
13182 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13183 v8::TryCatch try_catch;
13184 CompileRun(
13185 "var i = 0;"
13186 "var o = {"
13187 " toString: function () {"
13188 " if (i == 10) {"
13189 " throw 'Hey!';"
13190 " } else {"
13191 " i++;"
13192 " return s(o);"
13193 " }"
13194 " }"
13195 "};"
13196 "s(o);");
13197 CHECK(try_catch.HasCaught());
13198 v8::String::Utf8Value value(try_catch.Exception());
13199 CHECK_EQ(0, strcmp(*value, "Hey!"));
13200}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013201
13202
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013203TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013204 v8::V8::Initialize();
13205
13206 v8::HandleScope scope;
13207 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013208 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013209 int gc_count;
13210
ager@chromium.org60121232009-12-03 11:25:37 +000013211 // Create a context used to keep the code from aging in the compilation
13212 // cache.
13213 other_context = Context::New();
13214
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013215 // Context-dependent context data creates reference from the compilation
13216 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013217 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013218 context = Context::New();
13219 {
13220 v8::HandleScope scope;
13221
13222 context->Enter();
13223 Local<v8::String> obj = v8::String::New("");
13224 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013225 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013226 context->Exit();
13227 }
13228 context.Dispose();
13229 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013230 other_context->Enter();
13231 CompileRun(source_simple);
13232 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013233 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013234 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013235 }
ager@chromium.org60121232009-12-03 11:25:37 +000013236 CHECK_GE(2, gc_count);
13237 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013238
13239 // Eval in a function creates reference from the compilation cache to the
13240 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013241 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013242 context = Context::New();
13243 {
13244 v8::HandleScope scope;
13245
13246 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013247 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013248 context->Exit();
13249 }
13250 context.Dispose();
13251 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013252 other_context->Enter();
13253 CompileRun(source_eval);
13254 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013255 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013256 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013257 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013258 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013259 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013260
13261 // Looking up the line number for an exception creates reference from the
13262 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013263 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013264 context = Context::New();
13265 {
13266 v8::HandleScope scope;
13267
13268 context->Enter();
13269 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013270 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013271 CHECK(try_catch.HasCaught());
13272 v8::Handle<v8::Message> message = try_catch.Message();
13273 CHECK(!message.IsEmpty());
13274 CHECK_EQ(1, message->GetLineNumber());
13275 context->Exit();
13276 }
13277 context.Dispose();
13278 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013279 other_context->Enter();
13280 CompileRun(source_exception);
13281 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013282 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013283 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013284 }
ager@chromium.org60121232009-12-03 11:25:37 +000013285 CHECK_GE(2, gc_count);
13286 CHECK_EQ(1, GetGlobalObjectsCount());
13287
13288 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013289}
ager@chromium.org5c838252010-02-19 08:53:10 +000013290
13291
13292THREADED_TEST(ScriptOrigin) {
13293 v8::HandleScope scope;
13294 LocalContext env;
13295 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13296 v8::Handle<v8::String> script = v8::String::New(
13297 "function f() {}\n\nfunction g() {}");
13298 v8::Script::Compile(script, &origin)->Run();
13299 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13300 env->Global()->Get(v8::String::New("f")));
13301 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13302 env->Global()->Get(v8::String::New("g")));
13303
13304 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13305 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13306 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13307
13308 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13309 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13310 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13311}
13312
13313
13314THREADED_TEST(ScriptLineNumber) {
13315 v8::HandleScope scope;
13316 LocalContext env;
13317 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13318 v8::Handle<v8::String> script = v8::String::New(
13319 "function f() {}\n\nfunction g() {}");
13320 v8::Script::Compile(script, &origin)->Run();
13321 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13322 env->Global()->Get(v8::String::New("f")));
13323 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13324 env->Global()->Get(v8::String::New("g")));
13325 CHECK_EQ(0, f->GetScriptLineNumber());
13326 CHECK_EQ(2, g->GetScriptLineNumber());
13327}
13328
13329
13330static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13331 const AccessorInfo& info) {
13332 return v8_num(42);
13333}
13334
13335
13336static void SetterWhichSetsYOnThisTo23(Local<String> name,
13337 Local<Value> value,
13338 const AccessorInfo& info) {
13339 info.This()->Set(v8_str("y"), v8_num(23));
13340}
13341
13342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013343TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013344 v8::HandleScope scope;
13345 Local<ObjectTemplate> templ = ObjectTemplate::New();
13346 templ->SetAccessor(v8_str("x"),
13347 GetterWhichReturns42,
13348 SetterWhichSetsYOnThisTo23);
13349 LocalContext context;
13350 context->Global()->Set(v8_str("P"), templ->NewInstance());
13351 CompileRun("function C1() {"
13352 " this.x = 23;"
13353 "};"
13354 "C1.prototype = P;"
13355 "function C2() {"
13356 " this.x = 23"
13357 "};"
13358 "C2.prototype = { };"
13359 "C2.prototype.__proto__ = P;");
13360
13361 v8::Local<v8::Script> script;
13362 script = v8::Script::Compile(v8_str("new C1();"));
13363 for (int i = 0; i < 10; i++) {
13364 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13365 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13366 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13367 }
13368
13369 script = v8::Script::Compile(v8_str("new C2();"));
13370 for (int i = 0; i < 10; i++) {
13371 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13372 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13373 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13374 }
13375}
13376
13377
13378static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13379 Local<String> name, const AccessorInfo& info) {
13380 return v8_num(42);
13381}
13382
13383
13384static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13385 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13386 if (name->Equals(v8_str("x"))) {
13387 info.This()->Set(v8_str("y"), v8_num(23));
13388 }
13389 return v8::Handle<Value>();
13390}
13391
13392
13393THREADED_TEST(InterceptorOnConstructorPrototype) {
13394 v8::HandleScope scope;
13395 Local<ObjectTemplate> templ = ObjectTemplate::New();
13396 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13397 NamedPropertySetterWhichSetsYOnThisTo23);
13398 LocalContext context;
13399 context->Global()->Set(v8_str("P"), templ->NewInstance());
13400 CompileRun("function C1() {"
13401 " this.x = 23;"
13402 "};"
13403 "C1.prototype = P;"
13404 "function C2() {"
13405 " this.x = 23"
13406 "};"
13407 "C2.prototype = { };"
13408 "C2.prototype.__proto__ = P;");
13409
13410 v8::Local<v8::Script> script;
13411 script = v8::Script::Compile(v8_str("new C1();"));
13412 for (int i = 0; i < 10; i++) {
13413 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13414 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13415 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13416 }
13417
13418 script = v8::Script::Compile(v8_str("new C2();"));
13419 for (int i = 0; i < 10; i++) {
13420 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13421 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13422 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13423 }
13424}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013425
13426
13427TEST(Bug618) {
13428 const char* source = "function C1() {"
13429 " this.x = 23;"
13430 "};"
13431 "C1.prototype = P;";
13432
13433 v8::HandleScope scope;
13434 LocalContext context;
13435 v8::Local<v8::Script> script;
13436
13437 // Use a simple object as prototype.
13438 v8::Local<v8::Object> prototype = v8::Object::New();
13439 prototype->Set(v8_str("y"), v8_num(42));
13440 context->Global()->Set(v8_str("P"), prototype);
13441
13442 // This compile will add the code to the compilation cache.
13443 CompileRun(source);
13444
13445 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000013446 // Allow enough iterations for the inobject slack tracking logic
13447 // to finalize instance size and install the fast construct stub.
13448 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013449 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13450 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13451 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13452 }
13453
13454 // Use an API object with accessors as prototype.
13455 Local<ObjectTemplate> templ = ObjectTemplate::New();
13456 templ->SetAccessor(v8_str("x"),
13457 GetterWhichReturns42,
13458 SetterWhichSetsYOnThisTo23);
13459 context->Global()->Set(v8_str("P"), templ->NewInstance());
13460
13461 // This compile will get the code from the compilation cache.
13462 CompileRun(source);
13463
13464 script = v8::Script::Compile(v8_str("new C1();"));
13465 for (int i = 0; i < 10; i++) {
13466 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13467 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13468 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13469 }
13470}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013471
13472int prologue_call_count = 0;
13473int epilogue_call_count = 0;
13474int prologue_call_count_second = 0;
13475int epilogue_call_count_second = 0;
13476
13477void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13478 ++prologue_call_count;
13479}
13480
13481void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13482 ++epilogue_call_count;
13483}
13484
13485void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13486 ++prologue_call_count_second;
13487}
13488
13489void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13490 ++epilogue_call_count_second;
13491}
13492
13493TEST(GCCallbacks) {
13494 LocalContext context;
13495
13496 v8::V8::AddGCPrologueCallback(PrologueCallback);
13497 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13498 CHECK_EQ(0, prologue_call_count);
13499 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013500 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013501 CHECK_EQ(1, prologue_call_count);
13502 CHECK_EQ(1, epilogue_call_count);
13503 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13504 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013505 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013506 CHECK_EQ(2, prologue_call_count);
13507 CHECK_EQ(2, epilogue_call_count);
13508 CHECK_EQ(1, prologue_call_count_second);
13509 CHECK_EQ(1, epilogue_call_count_second);
13510 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13511 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013512 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013513 CHECK_EQ(2, prologue_call_count);
13514 CHECK_EQ(2, epilogue_call_count);
13515 CHECK_EQ(2, prologue_call_count_second);
13516 CHECK_EQ(2, epilogue_call_count_second);
13517 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13518 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013519 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013520 CHECK_EQ(2, prologue_call_count);
13521 CHECK_EQ(2, epilogue_call_count);
13522 CHECK_EQ(2, prologue_call_count_second);
13523 CHECK_EQ(2, epilogue_call_count_second);
13524}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013525
13526
13527THREADED_TEST(AddToJSFunctionResultCache) {
13528 i::FLAG_allow_natives_syntax = true;
13529 v8::HandleScope scope;
13530
13531 LocalContext context;
13532
13533 const char* code =
13534 "(function() {"
13535 " var key0 = 'a';"
13536 " var key1 = 'b';"
13537 " var r0 = %_GetFromCache(0, key0);"
13538 " var r1 = %_GetFromCache(0, key1);"
13539 " var r0_ = %_GetFromCache(0, key0);"
13540 " if (r0 !== r0_)"
13541 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13542 " var r1_ = %_GetFromCache(0, key1);"
13543 " if (r1 !== r1_)"
13544 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13545 " return 'PASSED';"
13546 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013547 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013548 ExpectString(code, "PASSED");
13549}
13550
13551
13552static const int k0CacheSize = 16;
13553
13554THREADED_TEST(FillJSFunctionResultCache) {
13555 i::FLAG_allow_natives_syntax = true;
13556 v8::HandleScope scope;
13557
13558 LocalContext context;
13559
13560 const char* code =
13561 "(function() {"
13562 " var k = 'a';"
13563 " var r = %_GetFromCache(0, k);"
13564 " for (var i = 0; i < 16; i++) {"
13565 " %_GetFromCache(0, 'a' + i);"
13566 " };"
13567 " if (r === %_GetFromCache(0, k))"
13568 " return 'FAILED: k0CacheSize is too small';"
13569 " return 'PASSED';"
13570 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013571 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013572 ExpectString(code, "PASSED");
13573}
13574
13575
13576THREADED_TEST(RoundRobinGetFromCache) {
13577 i::FLAG_allow_natives_syntax = true;
13578 v8::HandleScope scope;
13579
13580 LocalContext context;
13581
13582 const char* code =
13583 "(function() {"
13584 " var keys = [];"
13585 " for (var i = 0; i < 16; i++) keys.push(i);"
13586 " var values = [];"
13587 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13588 " for (var i = 0; i < 16; i++) {"
13589 " var v = %_GetFromCache(0, keys[i]);"
13590 " if (v !== values[i])"
13591 " return 'Wrong value for ' + "
13592 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13593 " };"
13594 " return 'PASSED';"
13595 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013596 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013597 ExpectString(code, "PASSED");
13598}
13599
13600
13601THREADED_TEST(ReverseGetFromCache) {
13602 i::FLAG_allow_natives_syntax = true;
13603 v8::HandleScope scope;
13604
13605 LocalContext context;
13606
13607 const char* code =
13608 "(function() {"
13609 " var keys = [];"
13610 " for (var i = 0; i < 16; i++) keys.push(i);"
13611 " var values = [];"
13612 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13613 " for (var i = 15; i >= 16; i--) {"
13614 " var v = %_GetFromCache(0, keys[i]);"
13615 " if (v !== values[i])"
13616 " return 'Wrong value for ' + "
13617 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13618 " };"
13619 " return 'PASSED';"
13620 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013621 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013622 ExpectString(code, "PASSED");
13623}
13624
13625
13626THREADED_TEST(TestEviction) {
13627 i::FLAG_allow_natives_syntax = true;
13628 v8::HandleScope scope;
13629
13630 LocalContext context;
13631
13632 const char* code =
13633 "(function() {"
13634 " for (var i = 0; i < 2*16; i++) {"
13635 " %_GetFromCache(0, 'a' + i);"
13636 " };"
13637 " return 'PASSED';"
13638 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013639 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013640 ExpectString(code, "PASSED");
13641}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013642
13643
13644THREADED_TEST(TwoByteStringInAsciiCons) {
13645 // See Chromium issue 47824.
13646 v8::HandleScope scope;
13647
13648 LocalContext context;
13649 const char* init_code =
13650 "var str1 = 'abelspendabel';"
13651 "var str2 = str1 + str1 + str1;"
13652 "str2;";
13653 Local<Value> result = CompileRun(init_code);
13654
13655 CHECK(result->IsString());
13656 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13657 int length = string->length();
13658 CHECK(string->IsAsciiRepresentation());
13659
13660 FlattenString(string);
13661 i::Handle<i::String> flat_string = FlattenGetString(string);
13662
13663 CHECK(string->IsAsciiRepresentation());
13664 CHECK(flat_string->IsAsciiRepresentation());
13665
13666 // Create external resource.
13667 uint16_t* uc16_buffer = new uint16_t[length + 1];
13668
13669 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13670 uc16_buffer[length] = 0;
13671
13672 TestResource resource(uc16_buffer);
13673
13674 flat_string->MakeExternal(&resource);
13675
13676 CHECK(flat_string->IsTwoByteRepresentation());
13677
13678 // At this point, we should have a Cons string which is flat and ASCII,
13679 // with a first half that is a two-byte string (although it only contains
13680 // ASCII characters). This is a valid sequence of steps, and it can happen
13681 // in real pages.
13682
13683 CHECK(string->IsAsciiRepresentation());
13684 i::ConsString* cons = i::ConsString::cast(*string);
13685 CHECK_EQ(0, cons->second()->length());
13686 CHECK(cons->first()->IsTwoByteRepresentation());
13687
13688 // Check that some string operations work.
13689
13690 // Atom RegExp.
13691 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13692 CHECK_EQ(6, reresult->Int32Value());
13693
13694 // Nonatom RegExp.
13695 reresult = CompileRun("str2.match(/abe./g).length;");
13696 CHECK_EQ(6, reresult->Int32Value());
13697
13698 reresult = CompileRun("str2.search(/bel/g);");
13699 CHECK_EQ(1, reresult->Int32Value());
13700
13701 reresult = CompileRun("str2.search(/be./g);");
13702 CHECK_EQ(1, reresult->Int32Value());
13703
13704 ExpectTrue("/bel/g.test(str2);");
13705
13706 ExpectTrue("/be./g.test(str2);");
13707
13708 reresult = CompileRun("/bel/g.exec(str2);");
13709 CHECK(!reresult->IsNull());
13710
13711 reresult = CompileRun("/be./g.exec(str2);");
13712 CHECK(!reresult->IsNull());
13713
13714 ExpectString("str2.substring(2, 10);", "elspenda");
13715
13716 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13717
13718 ExpectString("str2.charAt(2);", "e");
13719
13720 reresult = CompileRun("str2.charCodeAt(2);");
13721 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13722}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013723
13724
13725// Failed access check callback that performs a GC on each invocation.
13726void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13727 v8::AccessType type,
13728 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013729 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013730}
13731
13732
13733TEST(GCInFailedAccessCheckCallback) {
13734 // Install a failed access check callback that performs a GC on each
13735 // invocation. Then force the callback to be called from va
13736
13737 v8::V8::Initialize();
13738 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13739
13740 v8::HandleScope scope;
13741
13742 // Create an ObjectTemplate for global objects and install access
13743 // check callbacks that will block access.
13744 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13745 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13746 IndexedGetAccessBlocker,
13747 v8::Handle<v8::Value>(),
13748 false);
13749
13750 // Create a context and set an x property on it's global object.
13751 LocalContext context0(NULL, global_template);
13752 context0->Global()->Set(v8_str("x"), v8_num(42));
13753 v8::Handle<v8::Object> global0 = context0->Global();
13754
13755 // Create a context with a different security token so that the
13756 // failed access check callback will be called on each access.
13757 LocalContext context1(NULL, global_template);
13758 context1->Global()->Set(v8_str("other"), global0);
13759
13760 // Get property with failed access check.
13761 ExpectUndefined("other.x");
13762
13763 // Get element with failed access check.
13764 ExpectUndefined("other[0]");
13765
13766 // Set property with failed access check.
13767 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13768 CHECK(result->IsObject());
13769
13770 // Set element with failed access check.
13771 result = CompileRun("other[0] = new Object()");
13772 CHECK(result->IsObject());
13773
13774 // Get property attribute with failed access check.
13775 ExpectFalse("\'x\' in other");
13776
13777 // Get property attribute for element with failed access check.
13778 ExpectFalse("0 in other");
13779
13780 // Delete property.
13781 ExpectFalse("delete other.x");
13782
13783 // Delete element.
13784 CHECK_EQ(false, global0->Delete(0));
13785
13786 // DefineAccessor.
13787 CHECK_EQ(false,
13788 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13789
13790 // Define JavaScript accessor.
13791 ExpectUndefined("Object.prototype.__defineGetter__.call("
13792 " other, \'x\', function() { return 42; })");
13793
13794 // LookupAccessor.
13795 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13796 " other, \'x\')");
13797
13798 // HasLocalElement.
13799 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13800
13801 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13802 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13803 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13804
13805 // Reset the failed access check callback so it does not influence
13806 // the other tests.
13807 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13808}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013810TEST(DefaultIsolateGetCurrent) {
13811 CHECK(v8::Isolate::GetCurrent() != NULL);
13812 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13813 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13814 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13815}
13816
13817TEST(IsolateNewDispose) {
13818 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13819 v8::Isolate* isolate = v8::Isolate::New();
13820 CHECK(isolate != NULL);
13821 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13822 CHECK(current_isolate != isolate);
13823 CHECK(current_isolate == v8::Isolate::GetCurrent());
13824
13825 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13826 last_location = last_message = NULL;
13827 isolate->Dispose();
13828 CHECK_EQ(last_location, NULL);
13829 CHECK_EQ(last_message, NULL);
13830}
13831
13832TEST(IsolateEnterExitDefault) {
13833 v8::HandleScope scope;
13834 LocalContext context;
13835 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13836 CHECK(current_isolate != NULL); // Default isolate.
13837 ExpectString("'hello'", "hello");
13838 current_isolate->Enter();
13839 ExpectString("'still working'", "still working");
13840 current_isolate->Exit();
13841 ExpectString("'still working 2'", "still working 2");
13842 current_isolate->Exit();
13843 // Default isolate is always, well, 'default current'.
13844 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13845 // Still working since default isolate is auto-entering any thread
13846 // that has no isolate and attempts to execute V8 APIs.
13847 ExpectString("'still working 3'", "still working 3");
13848}
13849
13850TEST(DisposeDefaultIsolate) {
13851 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13852
13853 // Run some V8 code to trigger default isolate to become 'current'.
13854 v8::HandleScope scope;
13855 LocalContext context;
13856 ExpectString("'run some V8'", "run some V8");
13857
13858 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13859 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13860 last_location = last_message = NULL;
13861 isolate->Dispose();
13862 // It is not possible to dispose default isolate via Isolate API.
13863 CHECK_NE(last_location, NULL);
13864 CHECK_NE(last_message, NULL);
13865}
13866
13867TEST(RunDefaultAndAnotherIsolate) {
13868 v8::HandleScope scope;
13869 LocalContext context;
13870
13871 // Enter new isolate.
13872 v8::Isolate* isolate = v8::Isolate::New();
13873 CHECK(isolate);
13874 isolate->Enter();
13875 { // Need this block because subsequent Exit() will deallocate Heap,
13876 // so we need all scope objects to be deconstructed when it happens.
13877 v8::HandleScope scope_new;
13878 LocalContext context_new;
13879
13880 // Run something in new isolate.
13881 CompileRun("var foo = 153;");
13882 ExpectTrue("function f() { return foo == 153; }; f()");
13883 }
13884 isolate->Exit();
13885
13886 // This runs automatically in default isolate.
13887 // Variables in another isolate should be not available.
13888 ExpectTrue("function f() {"
13889 " try {"
13890 " foo;"
13891 " return false;"
13892 " } catch(e) {"
13893 " return true;"
13894 " }"
13895 "};"
13896 "var bar = 371;"
13897 "f()");
13898
13899 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13900 last_location = last_message = NULL;
13901 isolate->Dispose();
13902 CHECK_EQ(last_location, NULL);
13903 CHECK_EQ(last_message, NULL);
13904
13905 // Check that default isolate still runs.
13906 ExpectTrue("function f() { return bar == 371; }; f()");
13907}
13908
13909TEST(DisposeIsolateWhenInUse) {
13910 v8::Isolate* isolate = v8::Isolate::New();
13911 CHECK(isolate);
13912 isolate->Enter();
13913 v8::HandleScope scope;
13914 LocalContext context;
13915 // Run something in this isolate.
13916 ExpectTrue("true");
13917 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13918 last_location = last_message = NULL;
13919 // Still entered, should fail.
13920 isolate->Dispose();
13921 CHECK_NE(last_location, NULL);
13922 CHECK_NE(last_message, NULL);
13923}
13924
13925TEST(RunTwoIsolatesOnSingleThread) {
13926 // Run isolate 1.
13927 v8::Isolate* isolate1 = v8::Isolate::New();
13928 isolate1->Enter();
13929 v8::Persistent<v8::Context> context1 = v8::Context::New();
13930
13931 {
13932 v8::Context::Scope cscope(context1);
13933 v8::HandleScope scope;
13934 // Run something in new isolate.
13935 CompileRun("var foo = 'isolate 1';");
13936 ExpectString("function f() { return foo; }; f()", "isolate 1");
13937 }
13938
13939 // Run isolate 2.
13940 v8::Isolate* isolate2 = v8::Isolate::New();
13941 v8::Persistent<v8::Context> context2;
13942
13943 {
13944 v8::Isolate::Scope iscope(isolate2);
13945 context2 = v8::Context::New();
13946 v8::Context::Scope cscope(context2);
13947 v8::HandleScope scope;
13948
13949 // Run something in new isolate.
13950 CompileRun("var foo = 'isolate 2';");
13951 ExpectString("function f() { return foo; }; f()", "isolate 2");
13952 }
13953
13954 {
13955 v8::Context::Scope cscope(context1);
13956 v8::HandleScope scope;
13957 // Now again in isolate 1
13958 ExpectString("function f() { return foo; }; f()", "isolate 1");
13959 }
13960
13961 isolate1->Exit();
13962
13963 // Run some stuff in default isolate.
13964 v8::Persistent<v8::Context> context_default = v8::Context::New();
13965
13966 {
13967 v8::Context::Scope cscope(context_default);
13968 v8::HandleScope scope;
13969 // Variables in other isolates should be not available, verify there
13970 // is an exception.
13971 ExpectTrue("function f() {"
13972 " try {"
13973 " foo;"
13974 " return false;"
13975 " } catch(e) {"
13976 " return true;"
13977 " }"
13978 "};"
13979 "var isDefaultIsolate = true;"
13980 "f()");
13981 }
13982
13983 isolate1->Enter();
13984
13985 {
13986 v8::Isolate::Scope iscope(isolate2);
13987 v8::Context::Scope cscope(context2);
13988 v8::HandleScope scope;
13989 ExpectString("function f() { return foo; }; f()", "isolate 2");
13990 }
13991
13992 {
13993 v8::Context::Scope cscope(context1);
13994 v8::HandleScope scope;
13995 ExpectString("function f() { return foo; }; f()", "isolate 1");
13996 }
13997
13998 {
13999 v8::Isolate::Scope iscope(isolate2);
14000 context2.Dispose();
14001 }
14002
14003 context1.Dispose();
14004 isolate1->Exit();
14005
14006 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14007 last_location = last_message = NULL;
14008
14009 isolate1->Dispose();
14010 CHECK_EQ(last_location, NULL);
14011 CHECK_EQ(last_message, NULL);
14012
14013 isolate2->Dispose();
14014 CHECK_EQ(last_location, NULL);
14015 CHECK_EQ(last_message, NULL);
14016
14017 // Check that default isolate still runs.
14018 {
14019 v8::Context::Scope cscope(context_default);
14020 v8::HandleScope scope;
14021 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14022 }
14023}
14024
14025static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14026 v8::Isolate::Scope isolate_scope(isolate);
14027 v8::HandleScope scope;
14028 LocalContext context;
14029 i::ScopedVector<char> code(1024);
14030 i::OS::SNPrintF(code, "function fib(n) {"
14031 " if (n <= 2) return 1;"
14032 " return fib(n-1) + fib(n-2);"
14033 "}"
14034 "fib(%d)", limit);
14035 Local<Value> value = CompileRun(code.start());
14036 CHECK(value->IsNumber());
14037 return static_cast<int>(value->NumberValue());
14038}
14039
14040class IsolateThread : public v8::internal::Thread {
14041 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014042 IsolateThread(v8::Isolate* isolate, int fib_limit)
14043 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014044 isolate_(isolate),
14045 fib_limit_(fib_limit),
14046 result_(0) { }
14047
14048 void Run() {
14049 result_ = CalcFibonacci(isolate_, fib_limit_);
14050 }
14051
14052 int result() { return result_; }
14053
14054 private:
14055 v8::Isolate* isolate_;
14056 int fib_limit_;
14057 int result_;
14058};
14059
14060TEST(MultipleIsolatesOnIndividualThreads) {
14061 v8::Isolate* isolate1 = v8::Isolate::New();
14062 v8::Isolate* isolate2 = v8::Isolate::New();
14063
14064 IsolateThread thread1(isolate1, 21);
14065 IsolateThread thread2(isolate2, 12);
14066
14067 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14068 thread1.Start();
14069 thread2.Start();
14070
14071 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14072 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14073
14074 thread1.Join();
14075 thread2.Join();
14076
14077 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14078 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14079 CHECK_EQ(result1, 10946);
14080 CHECK_EQ(result2, 144);
14081 CHECK_EQ(result1, thread1.result());
14082 CHECK_EQ(result2, thread2.result());
14083
14084 isolate1->Dispose();
14085 isolate2->Dispose();
14086}
14087
lrn@chromium.org1c092762011-05-09 09:42:16 +000014088TEST(IsolateDifferentContexts) {
14089 v8::Isolate* isolate = v8::Isolate::New();
14090 Persistent<v8::Context> context;
14091 {
14092 v8::Isolate::Scope isolate_scope(isolate);
14093 v8::HandleScope handle_scope;
14094 context = v8::Context::New();
14095 v8::Context::Scope context_scope(context);
14096 Local<Value> v = CompileRun("2");
14097 CHECK(v->IsNumber());
14098 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14099 }
14100 {
14101 v8::Isolate::Scope isolate_scope(isolate);
14102 v8::HandleScope handle_scope;
14103 context = v8::Context::New();
14104 v8::Context::Scope context_scope(context);
14105 Local<Value> v = CompileRun("22");
14106 CHECK(v->IsNumber());
14107 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14108 }
14109}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014110
14111class InitDefaultIsolateThread : public v8::internal::Thread {
14112 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014113 enum TestCase {
14114 IgnoreOOM,
14115 SetResourceConstraints,
14116 SetFatalHandler,
14117 SetCounterFunction,
14118 SetCreateHistogramFunction,
14119 SetAddHistogramSampleFunction
14120 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014121
14122 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014123 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014124 testCase_(testCase),
14125 result_(false) { }
14126
14127 void Run() {
14128 switch (testCase_) {
14129 case IgnoreOOM:
14130 v8::V8::IgnoreOutOfMemoryException();
14131 break;
14132
14133 case SetResourceConstraints: {
14134 static const int K = 1024;
14135 v8::ResourceConstraints constraints;
14136 constraints.set_max_young_space_size(256 * K);
14137 constraints.set_max_old_space_size(4 * K * K);
14138 v8::SetResourceConstraints(&constraints);
14139 break;
14140 }
14141
14142 case SetFatalHandler:
14143 v8::V8::SetFatalErrorHandler(NULL);
14144 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014145
14146 case SetCounterFunction:
14147 v8::V8::SetCounterFunction(NULL);
14148 break;
14149
14150 case SetCreateHistogramFunction:
14151 v8::V8::SetCreateHistogramFunction(NULL);
14152 break;
14153
14154 case SetAddHistogramSampleFunction:
14155 v8::V8::SetAddHistogramSampleFunction(NULL);
14156 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014157 }
14158 result_ = true;
14159 }
14160
14161 bool result() { return result_; }
14162
14163 private:
14164 TestCase testCase_;
14165 bool result_;
14166};
14167
14168
14169static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14170 InitDefaultIsolateThread thread(testCase);
14171 thread.Start();
14172 thread.Join();
14173 CHECK_EQ(thread.result(), true);
14174}
14175
14176TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14177 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14178}
14179
14180TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14181 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14182}
14183
14184TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14185 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14186}
14187
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014188TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14189 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14190}
14191
14192TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14193 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14194}
14195
14196TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14197 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14198}
14199
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014200
14201TEST(StringCheckMultipleContexts) {
14202 const char* code =
14203 "(function() { return \"a\".charAt(0); })()";
14204
14205 {
14206 // Run the code twice in the first context to initialize the call IC.
14207 v8::HandleScope scope;
14208 LocalContext context1;
14209 ExpectString(code, "a");
14210 ExpectString(code, "a");
14211 }
14212
14213 {
14214 // Change the String.prototype in the second context and check
14215 // that the right function gets called.
14216 v8::HandleScope scope;
14217 LocalContext context2;
14218 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14219 ExpectString(code, "not a");
14220 }
14221}
14222
14223
14224TEST(NumberCheckMultipleContexts) {
14225 const char* code =
14226 "(function() { return (42).toString(); })()";
14227
14228 {
14229 // Run the code twice in the first context to initialize the call IC.
14230 v8::HandleScope scope;
14231 LocalContext context1;
14232 ExpectString(code, "42");
14233 ExpectString(code, "42");
14234 }
14235
14236 {
14237 // Change the Number.prototype in the second context and check
14238 // that the right function gets called.
14239 v8::HandleScope scope;
14240 LocalContext context2;
14241 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14242 ExpectString(code, "not 42");
14243 }
14244}
14245
14246
14247TEST(BooleanCheckMultipleContexts) {
14248 const char* code =
14249 "(function() { return true.toString(); })()";
14250
14251 {
14252 // Run the code twice in the first context to initialize the call IC.
14253 v8::HandleScope scope;
14254 LocalContext context1;
14255 ExpectString(code, "true");
14256 ExpectString(code, "true");
14257 }
14258
14259 {
14260 // Change the Boolean.prototype in the second context and check
14261 // that the right function gets called.
14262 v8::HandleScope scope;
14263 LocalContext context2;
14264 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14265 ExpectString(code, "");
14266 }
14267}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014268
14269
14270TEST(DontDeleteCellLoadIC) {
14271 const char* function_code =
14272 "function readCell() { while (true) { return cell; } }";
14273
14274 {
14275 // Run the code twice in the first context to initialize the load
14276 // IC for a don't delete cell.
14277 v8::HandleScope scope;
14278 LocalContext context1;
14279 CompileRun("var cell = \"first\";");
14280 ExpectBoolean("delete cell", false);
14281 CompileRun(function_code);
14282 ExpectString("readCell()", "first");
14283 ExpectString("readCell()", "first");
14284 }
14285
14286 {
14287 // Use a deletable cell in the second context.
14288 v8::HandleScope scope;
14289 LocalContext context2;
14290 CompileRun("cell = \"second\";");
14291 CompileRun(function_code);
14292 ExpectString("readCell()", "second");
14293 ExpectBoolean("delete cell", true);
14294 ExpectString("(function() {"
14295 " try {"
14296 " return readCell();"
14297 " } catch(e) {"
14298 " return e.toString();"
14299 " }"
14300 "})()",
14301 "ReferenceError: cell is not defined");
14302 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014303 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014304 ExpectString("readCell()", "new_second");
14305 ExpectString("readCell()", "new_second");
14306 }
14307}
14308
14309
14310TEST(DontDeleteCellLoadICForceDelete) {
14311 const char* function_code =
14312 "function readCell() { while (true) { return cell; } }";
14313
14314 // Run the code twice to initialize the load IC for a don't delete
14315 // cell.
14316 v8::HandleScope scope;
14317 LocalContext context;
14318 CompileRun("var cell = \"value\";");
14319 ExpectBoolean("delete cell", false);
14320 CompileRun(function_code);
14321 ExpectString("readCell()", "value");
14322 ExpectString("readCell()", "value");
14323
14324 // Delete the cell using the API and check the inlined code works
14325 // correctly.
14326 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14327 ExpectString("(function() {"
14328 " try {"
14329 " return readCell();"
14330 " } catch(e) {"
14331 " return e.toString();"
14332 " }"
14333 "})()",
14334 "ReferenceError: cell is not defined");
14335}
14336
14337
14338TEST(DontDeleteCellLoadICAPI) {
14339 const char* function_code =
14340 "function readCell() { while (true) { return cell; } }";
14341
14342 // Run the code twice to initialize the load IC for a don't delete
14343 // cell created using the API.
14344 v8::HandleScope scope;
14345 LocalContext context;
14346 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14347 ExpectBoolean("delete cell", false);
14348 CompileRun(function_code);
14349 ExpectString("readCell()", "value");
14350 ExpectString("readCell()", "value");
14351
14352 // Delete the cell using the API and check the inlined code works
14353 // correctly.
14354 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14355 ExpectString("(function() {"
14356 " try {"
14357 " return readCell();"
14358 " } catch(e) {"
14359 " return e.toString();"
14360 " }"
14361 "})()",
14362 "ReferenceError: cell is not defined");
14363}
14364
14365
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014366TEST(RegExp) {
14367 v8::HandleScope scope;
14368 LocalContext context;
14369
14370 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14371 CHECK(re->IsRegExp());
14372 CHECK(re->GetSource()->Equals(v8_str("foo")));
14373 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14374
14375 re = v8::RegExp::New(v8_str("bar"),
14376 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14377 v8::RegExp::kGlobal));
14378 CHECK(re->IsRegExp());
14379 CHECK(re->GetSource()->Equals(v8_str("bar")));
14380 CHECK_EQ(static_cast<int>(re->GetFlags()),
14381 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14382
14383 re = v8::RegExp::New(v8_str("baz"),
14384 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14385 v8::RegExp::kMultiline));
14386 CHECK(re->IsRegExp());
14387 CHECK(re->GetSource()->Equals(v8_str("baz")));
14388 CHECK_EQ(static_cast<int>(re->GetFlags()),
14389 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14390
14391 re = CompileRun("/quux/").As<v8::RegExp>();
14392 CHECK(re->IsRegExp());
14393 CHECK(re->GetSource()->Equals(v8_str("quux")));
14394 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14395
14396 re = CompileRun("/quux/gm").As<v8::RegExp>();
14397 CHECK(re->IsRegExp());
14398 CHECK(re->GetSource()->Equals(v8_str("quux")));
14399 CHECK_EQ(static_cast<int>(re->GetFlags()),
14400 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14401
14402 // Override the RegExp constructor and check the API constructor
14403 // still works.
14404 CompileRun("RegExp = function() {}");
14405
14406 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14407 CHECK(re->IsRegExp());
14408 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14409 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14410
14411 re = v8::RegExp::New(v8_str("foobarbaz"),
14412 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14413 v8::RegExp::kMultiline));
14414 CHECK(re->IsRegExp());
14415 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14416 CHECK_EQ(static_cast<int>(re->GetFlags()),
14417 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14418
14419 context->Global()->Set(v8_str("re"), re);
14420 ExpectTrue("re.test('FoobarbaZ')");
14421
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014422 // RegExps are objects on which you can set properties.
14423 re->Set(v8_str("property"), v8::Integer::New(32));
14424 v8::Handle<v8::Value> value = CompileRun("re.property");
14425 ASSERT_EQ(32, value->Int32Value());
14426
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014427 v8::TryCatch try_catch;
14428 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14429 CHECK(re.IsEmpty());
14430 CHECK(try_catch.HasCaught());
14431 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14432 ExpectTrue("ex instanceof SyntaxError");
14433}
14434
14435
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014436THREADED_TEST(Equals) {
14437 v8::HandleScope handleScope;
14438 LocalContext localContext;
14439
14440 v8::Handle<v8::Object> globalProxy = localContext->Global();
14441 v8::Handle<Value> global = globalProxy->GetPrototype();
14442
14443 CHECK(global->StrictEquals(global));
14444 CHECK(!global->StrictEquals(globalProxy));
14445 CHECK(!globalProxy->StrictEquals(global));
14446 CHECK(globalProxy->StrictEquals(globalProxy));
14447
14448 CHECK(global->Equals(global));
14449 CHECK(!global->Equals(globalProxy));
14450 CHECK(!globalProxy->Equals(global));
14451 CHECK(globalProxy->Equals(globalProxy));
14452}
14453
14454
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014455static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14456 const v8::AccessorInfo& info ) {
14457 return v8_str("42!");
14458}
14459
14460
14461static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14462 v8::Handle<v8::Array> result = v8::Array::New();
14463 result->Set(0, v8_str("universalAnswer"));
14464 return result;
14465}
14466
14467
14468TEST(NamedEnumeratorAndForIn) {
14469 v8::HandleScope handle_scope;
14470 LocalContext context;
14471 v8::Context::Scope context_scope(context.local());
14472
14473 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14474 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14475 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14476 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14477 "var result = []; for (var k in o) result.push(k); result"));
14478 CHECK_EQ(1, result->Length());
14479 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14480}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000014481
14482
14483TEST(DefinePropertyPostDetach) {
14484 v8::HandleScope scope;
14485 LocalContext context;
14486 v8::Handle<v8::Object> proxy = context->Global();
14487 v8::Handle<v8::Function> define_property =
14488 CompileRun("(function() {"
14489 " Object.defineProperty("
14490 " this,"
14491 " 1,"
14492 " { configurable: true, enumerable: true, value: 3 });"
14493 "})").As<Function>();
14494 context->DetachGlobal();
14495 define_property->Call(proxy, 0, NULL);
14496}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014497
14498
14499static void InstallContextId(v8::Handle<Context> context, int id) {
14500 Context::Scope scope(context);
14501 CompileRun("Object.prototype").As<Object>()->
14502 Set(v8_str("context_id"), v8::Integer::New(id));
14503}
14504
14505
14506static void CheckContextId(v8::Handle<Object> object, int expected) {
14507 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14508}
14509
14510
14511THREADED_TEST(CreationContext) {
14512 HandleScope handle_scope;
14513 Persistent<Context> context1 = Context::New();
14514 InstallContextId(context1, 1);
14515 Persistent<Context> context2 = Context::New();
14516 InstallContextId(context2, 2);
14517 Persistent<Context> context3 = Context::New();
14518 InstallContextId(context3, 3);
14519
14520 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14521
14522 Local<Object> object1;
14523 Local<Function> func1;
14524 {
14525 Context::Scope scope(context1);
14526 object1 = Object::New();
14527 func1 = tmpl->GetFunction();
14528 }
14529
14530 Local<Object> object2;
14531 Local<Function> func2;
14532 {
14533 Context::Scope scope(context2);
14534 object2 = Object::New();
14535 func2 = tmpl->GetFunction();
14536 }
14537
14538 Local<Object> instance1;
14539 Local<Object> instance2;
14540
14541 {
14542 Context::Scope scope(context3);
14543 instance1 = func1->NewInstance();
14544 instance2 = func2->NewInstance();
14545 }
14546
14547 CHECK(object1->CreationContext() == context1);
14548 CheckContextId(object1, 1);
14549 CHECK(func1->CreationContext() == context1);
14550 CheckContextId(func1, 1);
14551 CHECK(instance1->CreationContext() == context1);
14552 CheckContextId(instance1, 1);
14553 CHECK(object2->CreationContext() == context2);
14554 CheckContextId(object2, 2);
14555 CHECK(func2->CreationContext() == context2);
14556 CheckContextId(func2, 2);
14557 CHECK(instance2->CreationContext() == context2);
14558 CheckContextId(instance2, 2);
14559
14560 {
14561 Context::Scope scope(context1);
14562 CHECK(object1->CreationContext() == context1);
14563 CheckContextId(object1, 1);
14564 CHECK(func1->CreationContext() == context1);
14565 CheckContextId(func1, 1);
14566 CHECK(instance1->CreationContext() == context1);
14567 CheckContextId(instance1, 1);
14568 CHECK(object2->CreationContext() == context2);
14569 CheckContextId(object2, 2);
14570 CHECK(func2->CreationContext() == context2);
14571 CheckContextId(func2, 2);
14572 CHECK(instance2->CreationContext() == context2);
14573 CheckContextId(instance2, 2);
14574 }
14575
14576 {
14577 Context::Scope scope(context2);
14578 CHECK(object1->CreationContext() == context1);
14579 CheckContextId(object1, 1);
14580 CHECK(func1->CreationContext() == context1);
14581 CheckContextId(func1, 1);
14582 CHECK(instance1->CreationContext() == context1);
14583 CheckContextId(instance1, 1);
14584 CHECK(object2->CreationContext() == context2);
14585 CheckContextId(object2, 2);
14586 CHECK(func2->CreationContext() == context2);
14587 CheckContextId(func2, 2);
14588 CHECK(instance2->CreationContext() == context2);
14589 CheckContextId(instance2, 2);
14590 }
14591
14592 context1.Dispose();
14593 context2.Dispose();
14594 context3.Dispose();
14595}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014596
14597
14598Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14599 const AccessorInfo& info) {
14600 if (index == 42) return v8_str("yes");
14601 return Handle<v8::Integer>();
14602}
14603
14604
14605Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14606 const AccessorInfo& info) {
14607 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14608 return Handle<Value>();
14609}
14610
14611
14612Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14613 uint32_t index, const AccessorInfo& info) {
14614 if (index == 42) return v8_num(1).As<v8::Integer>();
14615 return Handle<v8::Integer>();
14616}
14617
14618
14619Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14620 Local<String> property, const AccessorInfo& info) {
14621 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14622 return Handle<v8::Integer>();
14623}
14624
14625
14626Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14627 Local<String> property, const AccessorInfo& info) {
14628 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14629 return Handle<v8::Integer>();
14630}
14631
14632
14633Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14634 const AccessorInfo& info) {
14635 return v8_str("yes");
14636}
14637
14638
14639TEST(HasOwnProperty) {
14640 v8::HandleScope scope;
14641 LocalContext env;
14642 { // Check normal properties and defined getters.
14643 Handle<Value> value = CompileRun(
14644 "function Foo() {"
14645 " this.foo = 11;"
14646 " this.__defineGetter__('baz', function() { return 1; });"
14647 "};"
14648 "function Bar() { "
14649 " this.bar = 13;"
14650 " this.__defineGetter__('bla', function() { return 2; });"
14651 "};"
14652 "Bar.prototype = new Foo();"
14653 "new Bar();");
14654 CHECK(value->IsObject());
14655 Handle<Object> object = value->ToObject();
14656 CHECK(object->Has(v8_str("foo")));
14657 CHECK(!object->HasOwnProperty(v8_str("foo")));
14658 CHECK(object->HasOwnProperty(v8_str("bar")));
14659 CHECK(object->Has(v8_str("baz")));
14660 CHECK(!object->HasOwnProperty(v8_str("baz")));
14661 CHECK(object->HasOwnProperty(v8_str("bla")));
14662 }
14663 { // Check named getter interceptors.
14664 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14665 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14666 Handle<Object> instance = templ->NewInstance();
14667 CHECK(!instance->HasOwnProperty(v8_str("42")));
14668 CHECK(instance->HasOwnProperty(v8_str("foo")));
14669 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14670 }
14671 { // Check indexed getter interceptors.
14672 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14673 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14674 Handle<Object> instance = templ->NewInstance();
14675 CHECK(instance->HasOwnProperty(v8_str("42")));
14676 CHECK(!instance->HasOwnProperty(v8_str("43")));
14677 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14678 }
14679 { // Check named query interceptors.
14680 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14681 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14682 Handle<Object> instance = templ->NewInstance();
14683 CHECK(instance->HasOwnProperty(v8_str("foo")));
14684 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14685 }
14686 { // Check indexed query interceptors.
14687 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14688 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14689 Handle<Object> instance = templ->NewInstance();
14690 CHECK(instance->HasOwnProperty(v8_str("42")));
14691 CHECK(!instance->HasOwnProperty(v8_str("41")));
14692 }
14693 { // Check callbacks.
14694 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14695 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14696 Handle<Object> instance = templ->NewInstance();
14697 CHECK(instance->HasOwnProperty(v8_str("foo")));
14698 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14699 }
14700 { // Check that query wins on disagreement.
14701 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14702 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14703 0,
14704 HasOwnPropertyNamedPropertyQuery2);
14705 Handle<Object> instance = templ->NewInstance();
14706 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14707 CHECK(instance->HasOwnProperty(v8_str("bar")));
14708 }
14709}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014710
14711
14712void CheckCodeGenerationAllowed() {
14713 Handle<Value> result = CompileRun("eval('42')");
14714 CHECK_EQ(42, result->Int32Value());
14715 result = CompileRun("(function(e) { return e('42'); })(eval)");
14716 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014717 result = CompileRun("var f = new Function('return 42'); f()");
14718 CHECK_EQ(42, result->Int32Value());
14719}
14720
14721
14722void CheckCodeGenerationDisallowed() {
14723 TryCatch try_catch;
14724
14725 Handle<Value> result = CompileRun("eval('42')");
14726 CHECK(result.IsEmpty());
14727 CHECK(try_catch.HasCaught());
14728 try_catch.Reset();
14729
14730 result = CompileRun("(function(e) { return e('42'); })(eval)");
14731 CHECK(result.IsEmpty());
14732 CHECK(try_catch.HasCaught());
14733 try_catch.Reset();
14734
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014735 result = CompileRun("var f = new Function('return 42'); f()");
14736 CHECK(result.IsEmpty());
14737 CHECK(try_catch.HasCaught());
14738}
14739
14740
14741bool CodeGenerationAllowed(Local<Context> context) {
14742 ApiTestFuzzer::Fuzz();
14743 return true;
14744}
14745
14746
14747bool CodeGenerationDisallowed(Local<Context> context) {
14748 ApiTestFuzzer::Fuzz();
14749 return false;
14750}
14751
14752
14753THREADED_TEST(AllowCodeGenFromStrings) {
14754 v8::HandleScope scope;
14755 LocalContext context;
14756
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014757 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014758 CheckCodeGenerationAllowed();
14759
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014760 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014761 context->AllowCodeGenerationFromStrings(false);
14762 CheckCodeGenerationDisallowed();
14763
14764 // Allow again.
14765 context->AllowCodeGenerationFromStrings(true);
14766 CheckCodeGenerationAllowed();
14767
14768 // Disallow but setting a global callback that will allow the calls.
14769 context->AllowCodeGenerationFromStrings(false);
14770 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14771 CheckCodeGenerationAllowed();
14772
14773 // Set a callback that disallows the code generation.
14774 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14775 CheckCodeGenerationDisallowed();
14776}
lrn@chromium.org1c092762011-05-09 09:42:16 +000014777
14778
14779static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14780 return v8::Undefined();
14781}
14782
14783
14784THREADED_TEST(CallAPIFunctionOnNonObject) {
14785 v8::HandleScope scope;
14786 LocalContext context;
14787 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14788 Handle<Function> function = templ->GetFunction();
14789 context->Global()->Set(v8_str("f"), function);
14790 TryCatch try_catch;
14791 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000014792}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014793
14794
14795// Regression test for issue 1470.
14796THREADED_TEST(ReadOnlyIndexedProperties) {
14797 v8::HandleScope scope;
14798 Local<ObjectTemplate> templ = ObjectTemplate::New();
14799
14800 LocalContext context;
14801 Local<v8::Object> obj = templ->NewInstance();
14802 context->Global()->Set(v8_str("obj"), obj);
14803 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14804 obj->Set(v8_str("1"), v8_str("foobar"));
14805 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14806 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14807 obj->Set(v8_num(2), v8_str("foobar"));
14808 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14809
14810 // Test non-smi case.
14811 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14812 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14813 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14814}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014815
14816
14817THREADED_TEST(Regress1516) {
14818 v8::HandleScope scope;
14819
14820 LocalContext context;
14821 { v8::HandleScope temp_scope;
14822 CompileRun("({'a': 0})");
14823 }
14824
14825 int elements;
14826 { i::MapCache* map_cache =
14827 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14828 elements = map_cache->NumberOfElements();
14829 CHECK_LE(1, elements);
14830 }
14831
14832 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14833 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14834 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14835 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14836 CHECK_GT(elements, map_cache->NumberOfElements());
14837 }
14838 }
14839}