blob: eb9edd21896882a5013d3a845d351f279264a6ae [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
ager@chromium.org04921a82011-06-27 13:21:41 +00007058THREADED_TEST(SetPrototypeProperties) {
7059 v8::HandleScope handle_scope;
7060 LocalContext context;
7061
7062 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7063 t1->SetPrototypeAttributes(v8::DontDelete);
7064 context->Global()->Set(v8_str("func1"), t1->GetFunction());
7065 CHECK(CompileRun(
7066 "(function() {"
7067 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7068 " return (descriptor['writable'] == true) &&"
7069 " (descriptor['enumerable'] == true) &&"
7070 " (descriptor['configurable'] == false);"
7071 "})()")->BooleanValue());
7072
7073 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7074 t2->SetPrototypeAttributes(v8::DontEnum);
7075 context->Global()->Set(v8_str("func2"), t2->GetFunction());
7076 CHECK(CompileRun(
7077 "(function() {"
7078 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7079 " return (descriptor['writable'] == true) &&"
7080 " (descriptor['enumerable'] == false) &&"
7081 " (descriptor['configurable'] == true);"
7082 "})()")->BooleanValue());
7083
7084 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7085 t3->SetPrototypeAttributes(v8::ReadOnly);
7086 context->Global()->Set(v8_str("func3"), t3->GetFunction());
7087 CHECK(CompileRun(
7088 "(function() {"
7089 " descriptor = Object.getOwnPropertyDescriptor(func3, 'prototype');"
7090 " return (descriptor['writable'] == false) &&"
7091 " (descriptor['enumerable'] == true) &&"
7092 " (descriptor['configurable'] == true);"
7093 "})()")->BooleanValue());
7094
7095 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
7096 t4->SetPrototypeAttributes(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
7097 context->Global()->Set(v8_str("func4"), t4->GetFunction());
7098 CHECK(CompileRun(
7099 "(function() {"
7100 " descriptor = Object.getOwnPropertyDescriptor(func4, 'prototype');"
7101 " return (descriptor['writable'] == false) &&"
7102 " (descriptor['enumerable'] == false) &&"
7103 " (descriptor['configurable'] == false);"
7104 "})()")->BooleanValue());
7105}
7106
7107
ager@chromium.org5c838252010-02-19 08:53:10 +00007108THREADED_TEST(SetPrototypeThrows) {
7109 v8::HandleScope handle_scope;
7110 LocalContext context;
7111
7112 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7113
7114 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7115 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7116
7117 CHECK(o0->SetPrototype(o1));
7118 // If setting the prototype leads to the cycle, SetPrototype should
7119 // return false and keep VM in sane state.
7120 v8::TryCatch try_catch;
7121 CHECK(!o1->SetPrototype(o0));
7122 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007123 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007124
7125 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7126}
7127
7128
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007129THREADED_TEST(GetterSetterExceptions) {
7130 v8::HandleScope handle_scope;
7131 LocalContext context;
7132 CompileRun(
7133 "function Foo() { };"
7134 "function Throw() { throw 5; };"
7135 "var x = { };"
7136 "x.__defineSetter__('set', Throw);"
7137 "x.__defineGetter__('get', Throw);");
7138 Local<v8::Object> x =
7139 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7140 v8::TryCatch try_catch;
7141 x->Set(v8_str("set"), v8::Integer::New(8));
7142 x->Get(v8_str("get"));
7143 x->Set(v8_str("set"), v8::Integer::New(8));
7144 x->Get(v8_str("get"));
7145 x->Set(v8_str("set"), v8::Integer::New(8));
7146 x->Get(v8_str("get"));
7147 x->Set(v8_str("set"), v8::Integer::New(8));
7148 x->Get(v8_str("get"));
7149}
7150
7151
7152THREADED_TEST(Constructor) {
7153 v8::HandleScope handle_scope;
7154 LocalContext context;
7155 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7156 templ->SetClassName(v8_str("Fun"));
7157 Local<Function> cons = templ->GetFunction();
7158 context->Global()->Set(v8_str("Fun"), cons);
7159 Local<v8::Object> inst = cons->NewInstance();
7160 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7161 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7162 CHECK(value->BooleanValue());
7163}
7164
lrn@chromium.org1c092762011-05-09 09:42:16 +00007165
7166static Handle<Value> ConstructorCallback(const Arguments& args) {
7167 ApiTestFuzzer::Fuzz();
7168 Local<Object> This;
7169
7170 if (args.IsConstructCall()) {
7171 Local<Object> Holder = args.Holder();
7172 This = Object::New();
7173 Local<Value> proto = Holder->GetPrototype();
7174 if (proto->IsObject()) {
7175 This->SetPrototype(proto);
7176 }
7177 } else {
7178 This = args.This();
7179 }
7180
7181 This->Set(v8_str("a"), args[0]);
7182 return This;
7183}
7184
7185
7186static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7187 ApiTestFuzzer::Fuzz();
7188 return args[0];
7189}
7190
7191
7192THREADED_TEST(ConstructorForObject) {
7193 v8::HandleScope handle_scope;
7194 LocalContext context;
7195
7196 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7197 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7198 Local<Object> instance = instance_template->NewInstance();
7199 context->Global()->Set(v8_str("obj"), instance);
7200 v8::TryCatch try_catch;
7201 Local<Value> value;
7202 CHECK(!try_catch.HasCaught());
7203
7204 // Call the Object's constructor with a 32-bit signed integer.
7205 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7206 CHECK(!try_catch.HasCaught());
7207 CHECK(value->IsInt32());
7208 CHECK_EQ(28, value->Int32Value());
7209
7210 Local<Value> args1[] = { v8_num(28) };
7211 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7212 CHECK(value_obj1->IsObject());
7213 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7214 value = object1->Get(v8_str("a"));
7215 CHECK(value->IsInt32());
7216 CHECK(!try_catch.HasCaught());
7217 CHECK_EQ(28, value->Int32Value());
7218
7219 // Call the Object's constructor with a String.
7220 value = CompileRun(
7221 "(function() { var o = new obj('tipli'); return o.a; })()");
7222 CHECK(!try_catch.HasCaught());
7223 CHECK(value->IsString());
7224 String::AsciiValue string_value1(value->ToString());
7225 CHECK_EQ("tipli", *string_value1);
7226
7227 Local<Value> args2[] = { v8_str("tipli") };
7228 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7229 CHECK(value_obj2->IsObject());
7230 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7231 value = object2->Get(v8_str("a"));
7232 CHECK(!try_catch.HasCaught());
7233 CHECK(value->IsString());
7234 String::AsciiValue string_value2(value->ToString());
7235 CHECK_EQ("tipli", *string_value2);
7236
7237 // Call the Object's constructor with a Boolean.
7238 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7239 CHECK(!try_catch.HasCaught());
7240 CHECK(value->IsBoolean());
7241 CHECK_EQ(true, value->BooleanValue());
7242
7243 Handle<Value> args3[] = { v8::Boolean::New(true) };
7244 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7245 CHECK(value_obj3->IsObject());
7246 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7247 value = object3->Get(v8_str("a"));
7248 CHECK(!try_catch.HasCaught());
7249 CHECK(value->IsBoolean());
7250 CHECK_EQ(true, value->BooleanValue());
7251
7252 // Call the Object's constructor with undefined.
7253 Handle<Value> args4[] = { v8::Undefined() };
7254 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7255 CHECK(value_obj4->IsObject());
7256 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7257 value = object4->Get(v8_str("a"));
7258 CHECK(!try_catch.HasCaught());
7259 CHECK(value->IsUndefined());
7260
7261 // Call the Object's constructor with null.
7262 Handle<Value> args5[] = { v8::Null() };
7263 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7264 CHECK(value_obj5->IsObject());
7265 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7266 value = object5->Get(v8_str("a"));
7267 CHECK(!try_catch.HasCaught());
7268 CHECK(value->IsNull());
7269 }
7270
7271 // Check exception handling when there is no constructor set for the Object.
7272 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7273 Local<Object> instance = instance_template->NewInstance();
7274 context->Global()->Set(v8_str("obj2"), instance);
7275 v8::TryCatch try_catch;
7276 Local<Value> value;
7277 CHECK(!try_catch.HasCaught());
7278
7279 value = CompileRun("new obj2(28)");
7280 CHECK(try_catch.HasCaught());
7281 String::AsciiValue exception_value1(try_catch.Exception());
7282 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7283 try_catch.Reset();
7284
7285 Local<Value> args[] = { v8_num(29) };
7286 value = instance->CallAsConstructor(1, args);
7287 CHECK(try_catch.HasCaught());
7288 String::AsciiValue exception_value2(try_catch.Exception());
7289 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7290 try_catch.Reset();
7291 }
7292
7293 // Check the case when constructor throws exception.
7294 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7295 instance_template->SetCallAsFunctionHandler(ThrowValue);
7296 Local<Object> instance = instance_template->NewInstance();
7297 context->Global()->Set(v8_str("obj3"), instance);
7298 v8::TryCatch try_catch;
7299 Local<Value> value;
7300 CHECK(!try_catch.HasCaught());
7301
7302 value = CompileRun("new obj3(22)");
7303 CHECK(try_catch.HasCaught());
7304 String::AsciiValue exception_value1(try_catch.Exception());
7305 CHECK_EQ("22", *exception_value1);
7306 try_catch.Reset();
7307
7308 Local<Value> args[] = { v8_num(23) };
7309 value = instance->CallAsConstructor(1, args);
7310 CHECK(try_catch.HasCaught());
7311 String::AsciiValue exception_value2(try_catch.Exception());
7312 CHECK_EQ("23", *exception_value2);
7313 try_catch.Reset();
7314 }
7315
7316 // Check whether constructor returns with an object or non-object.
7317 { Local<FunctionTemplate> function_template =
7318 FunctionTemplate::New(FakeConstructorCallback);
7319 Local<Function> function = function_template->GetFunction();
7320 Local<Object> instance1 = function;
7321 context->Global()->Set(v8_str("obj4"), instance1);
7322 v8::TryCatch try_catch;
7323 Local<Value> value;
7324 CHECK(!try_catch.HasCaught());
7325
7326 CHECK(instance1->IsObject());
7327 CHECK(instance1->IsFunction());
7328
7329 value = CompileRun("new obj4(28)");
7330 CHECK(!try_catch.HasCaught());
7331 CHECK(value->IsObject());
7332
7333 Local<Value> args1[] = { v8_num(28) };
7334 value = instance1->CallAsConstructor(1, args1);
7335 CHECK(!try_catch.HasCaught());
7336 CHECK(value->IsObject());
7337
7338 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7339 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7340 Local<Object> instance2 = instance_template->NewInstance();
7341 context->Global()->Set(v8_str("obj5"), instance2);
7342 CHECK(!try_catch.HasCaught());
7343
7344 CHECK(instance2->IsObject());
7345 CHECK(!instance2->IsFunction());
7346
7347 value = CompileRun("new obj5(28)");
7348 CHECK(!try_catch.HasCaught());
7349 CHECK(!value->IsObject());
7350
7351 Local<Value> args2[] = { v8_num(28) };
7352 value = instance2->CallAsConstructor(1, args2);
7353 CHECK(!try_catch.HasCaught());
7354 CHECK(!value->IsObject());
7355 }
7356}
7357
7358
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007359THREADED_TEST(FunctionDescriptorException) {
7360 v8::HandleScope handle_scope;
7361 LocalContext context;
7362 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7363 templ->SetClassName(v8_str("Fun"));
7364 Local<Function> cons = templ->GetFunction();
7365 context->Global()->Set(v8_str("Fun"), cons);
7366 Local<Value> value = CompileRun(
7367 "function test() {"
7368 " try {"
7369 " (new Fun()).blah()"
7370 " } catch (e) {"
7371 " var str = String(e);"
7372 " if (str.indexOf('TypeError') == -1) return 1;"
7373 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007374 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007375 " return 0;"
7376 " }"
7377 " return 4;"
7378 "}"
7379 "test();");
7380 CHECK_EQ(0, value->Int32Value());
7381}
7382
7383
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007384THREADED_TEST(EvalAliasedDynamic) {
7385 v8::HandleScope scope;
7386 LocalContext current;
7387
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007388 // Tests where aliased eval can only be resolved dynamically.
7389 Local<Script> script =
7390 Script::Compile(v8_str("function f(x) { "
7391 " var foo = 2;"
7392 " with (x) { return eval('foo'); }"
7393 "}"
7394 "foo = 0;"
7395 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007396 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007397 "var x = new Object();"
7398 "x.eval = function(x) { return 1; };"
7399 "result3 = f(x);"));
7400 script->Run();
7401 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7402 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7403 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7404
7405 v8::TryCatch try_catch;
7406 script =
7407 Script::Compile(v8_str("function f(x) { "
7408 " var bar = 2;"
7409 " with (x) { return eval('bar'); }"
7410 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007411 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007412 script->Run();
7413 CHECK(try_catch.HasCaught());
7414 try_catch.Reset();
7415}
7416
7417
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007418THREADED_TEST(CrossEval) {
7419 v8::HandleScope scope;
7420 LocalContext other;
7421 LocalContext current;
7422
7423 Local<String> token = v8_str("<security token>");
7424 other->SetSecurityToken(token);
7425 current->SetSecurityToken(token);
7426
7427 // Setup reference from current to other.
7428 current->Global()->Set(v8_str("other"), other->Global());
7429
7430 // Check that new variables are introduced in other context.
7431 Local<Script> script =
7432 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7433 script->Run();
7434 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7435 CHECK_EQ(1234, foo->Int32Value());
7436 CHECK(!current->Global()->Has(v8_str("foo")));
7437
7438 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007439 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007440 script =
7441 Script::Compile(v8_str("other.eval('na = 1234')"));
7442 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007443 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7444 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007445
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007446 // Check that global variables in current context are not visible in other
7447 // context.
7448 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007449 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007450 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007451 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007452 CHECK(try_catch.HasCaught());
7453 try_catch.Reset();
7454
7455 // Check that local variables in current context are not visible in other
7456 // context.
7457 script =
7458 Script::Compile(v8_str("(function() { "
7459 " var baz = 87;"
7460 " return other.eval('baz');"
7461 "})();"));
7462 result = script->Run();
7463 CHECK(try_catch.HasCaught());
7464 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007465
7466 // Check that global variables in the other environment are visible
7467 // when evaluting code.
7468 other->Global()->Set(v8_str("bis"), v8_num(1234));
7469 script = Script::Compile(v8_str("other.eval('bis')"));
7470 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007471 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007472
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007473 // Check that the 'this' pointer points to the global object evaluating
7474 // code.
7475 other->Global()->Set(v8_str("t"), other->Global());
7476 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007477 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007478 CHECK(result->IsTrue());
7479 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007480
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007481 // Check that variables introduced in with-statement are not visible in
7482 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007483 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007484 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007485 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007486 CHECK(try_catch.HasCaught());
7487 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007488
7489 // Check that you cannot use 'eval.call' with another object than the
7490 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007491 script =
7492 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7493 result = script->Run();
7494 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007495}
7496
7497
ager@chromium.orge2902be2009-06-08 12:21:35 +00007498// Test that calling eval in a context which has been detached from
7499// its global throws an exception. This behavior is consistent with
7500// other JavaScript implementations.
7501THREADED_TEST(EvalInDetachedGlobal) {
7502 v8::HandleScope scope;
7503
7504 v8::Persistent<Context> context0 = Context::New();
7505 v8::Persistent<Context> context1 = Context::New();
7506
7507 // Setup function in context0 that uses eval from context0.
7508 context0->Enter();
7509 v8::Handle<v8::Value> fun =
7510 CompileRun("var x = 42;"
7511 "(function() {"
7512 " var e = eval;"
7513 " return function(s) { return e(s); }"
7514 "})()");
7515 context0->Exit();
7516
7517 // Put the function into context1 and call it before and after
7518 // detaching the global. Before detaching, the call succeeds and
7519 // after detaching and exception is thrown.
7520 context1->Enter();
7521 context1->Global()->Set(v8_str("fun"), fun);
7522 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7523 CHECK_EQ(42, x_value->Int32Value());
7524 context0->DetachGlobal();
7525 v8::TryCatch catcher;
7526 x_value = CompileRun("fun('x')");
7527 CHECK(x_value.IsEmpty());
7528 CHECK(catcher.HasCaught());
7529 context1->Exit();
7530
7531 context1.Dispose();
7532 context0.Dispose();
7533}
7534
7535
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007536THREADED_TEST(CrossLazyLoad) {
7537 v8::HandleScope scope;
7538 LocalContext other;
7539 LocalContext current;
7540
7541 Local<String> token = v8_str("<security token>");
7542 other->SetSecurityToken(token);
7543 current->SetSecurityToken(token);
7544
7545 // Setup reference from current to other.
7546 current->Global()->Set(v8_str("other"), other->Global());
7547
7548 // Trigger lazy loading in other context.
7549 Local<Script> script =
7550 Script::Compile(v8_str("other.eval('new Date(42)')"));
7551 Local<Value> value = script->Run();
7552 CHECK_EQ(42.0, value->NumberValue());
7553}
7554
7555
7556static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7557 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007558 if (args.IsConstructCall()) {
7559 if (args[0]->IsInt32()) {
7560 return v8_num(-args[0]->Int32Value());
7561 }
7562 }
7563
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007564 return args[0];
7565}
7566
7567
7568// Test that a call handler can be set for objects which will allow
7569// non-function objects created through the API to be called as
7570// functions.
7571THREADED_TEST(CallAsFunction) {
7572 v8::HandleScope scope;
7573 LocalContext context;
7574
lrn@chromium.org1c092762011-05-09 09:42:16 +00007575 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7576 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7577 instance_template->SetCallAsFunctionHandler(call_as_function);
7578 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7579 context->Global()->Set(v8_str("obj"), instance);
7580 v8::TryCatch try_catch;
7581 Local<Value> value;
7582 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007583
lrn@chromium.org1c092762011-05-09 09:42:16 +00007584 value = CompileRun("obj(42)");
7585 CHECK(!try_catch.HasCaught());
7586 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007587
lrn@chromium.org1c092762011-05-09 09:42:16 +00007588 value = CompileRun("(function(o){return o(49)})(obj)");
7589 CHECK(!try_catch.HasCaught());
7590 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007591
lrn@chromium.org1c092762011-05-09 09:42:16 +00007592 // test special case of call as function
7593 value = CompileRun("[obj]['0'](45)");
7594 CHECK(!try_catch.HasCaught());
7595 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007596
lrn@chromium.org1c092762011-05-09 09:42:16 +00007597 value = CompileRun("obj.call = Function.prototype.call;"
7598 "obj.call(null, 87)");
7599 CHECK(!try_catch.HasCaught());
7600 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007601
lrn@chromium.org1c092762011-05-09 09:42:16 +00007602 // Regression tests for bug #1116356: Calling call through call/apply
7603 // must work for non-function receivers.
7604 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7605 value = CompileRun(apply_99);
7606 CHECK(!try_catch.HasCaught());
7607 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007608
lrn@chromium.org1c092762011-05-09 09:42:16 +00007609 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7610 value = CompileRun(call_17);
7611 CHECK(!try_catch.HasCaught());
7612 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007613
lrn@chromium.org1c092762011-05-09 09:42:16 +00007614 // Check that the call-as-function handler can be called through
7615 // new.
7616 value = CompileRun("new obj(43)");
7617 CHECK(!try_catch.HasCaught());
7618 CHECK_EQ(-43, value->Int32Value());
7619
7620 // Check that the call-as-function handler can be called through
7621 // the API.
7622 v8::Handle<Value> args[] = { v8_num(28) };
7623 value = instance->CallAsFunction(instance, 1, args);
7624 CHECK(!try_catch.HasCaught());
7625 CHECK_EQ(28, value->Int32Value());
7626 }
7627
7628 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7629 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7630 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7631 context->Global()->Set(v8_str("obj2"), instance);
7632 v8::TryCatch try_catch;
7633 Local<Value> value;
7634 CHECK(!try_catch.HasCaught());
7635
7636 // Call an object without call-as-function handler through the JS
7637 value = CompileRun("obj2(28)");
7638 CHECK(value.IsEmpty());
7639 CHECK(try_catch.HasCaught());
7640 String::AsciiValue exception_value1(try_catch.Exception());
7641 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7642 *exception_value1);
7643 try_catch.Reset();
7644
7645 // Call an object without call-as-function handler through the API
7646 value = CompileRun("obj2(28)");
7647 v8::Handle<Value> args[] = { v8_num(28) };
7648 value = instance->CallAsFunction(instance, 1, args);
7649 CHECK(value.IsEmpty());
7650 CHECK(try_catch.HasCaught());
7651 String::AsciiValue exception_value2(try_catch.Exception());
7652 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7653 try_catch.Reset();
7654 }
7655
7656 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7657 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7658 instance_template->SetCallAsFunctionHandler(ThrowValue);
7659 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7660 context->Global()->Set(v8_str("obj3"), instance);
7661 v8::TryCatch try_catch;
7662 Local<Value> value;
7663 CHECK(!try_catch.HasCaught());
7664
7665 // Catch the exception which is thrown by call-as-function handler
7666 value = CompileRun("obj3(22)");
7667 CHECK(try_catch.HasCaught());
7668 String::AsciiValue exception_value1(try_catch.Exception());
7669 CHECK_EQ("22", *exception_value1);
7670 try_catch.Reset();
7671
7672 v8::Handle<Value> args[] = { v8_num(23) };
7673 value = instance->CallAsFunction(instance, 1, args);
7674 CHECK(try_catch.HasCaught());
7675 String::AsciiValue exception_value2(try_catch.Exception());
7676 CHECK_EQ("23", *exception_value2);
7677 try_catch.Reset();
7678 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007679}
7680
7681
karlklose@chromium.org83a47282011-05-11 11:54:09 +00007682// Check whether a non-function object is callable.
7683THREADED_TEST(CallableObject) {
7684 v8::HandleScope scope;
7685 LocalContext context;
7686
7687 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7688 instance_template->SetCallAsFunctionHandler(call_as_function);
7689 Local<Object> instance = instance_template->NewInstance();
7690 v8::TryCatch try_catch;
7691
7692 CHECK(instance->IsCallable());
7693 CHECK(!try_catch.HasCaught());
7694 }
7695
7696 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7697 Local<Object> instance = instance_template->NewInstance();
7698 v8::TryCatch try_catch;
7699
7700 CHECK(!instance->IsCallable());
7701 CHECK(!try_catch.HasCaught());
7702 }
7703
7704 { Local<FunctionTemplate> function_template =
7705 FunctionTemplate::New(call_as_function);
7706 Local<Function> function = function_template->GetFunction();
7707 Local<Object> instance = function;
7708 v8::TryCatch try_catch;
7709
7710 CHECK(instance->IsCallable());
7711 CHECK(!try_catch.HasCaught());
7712 }
7713
7714 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7715 Local<Function> function = function_template->GetFunction();
7716 Local<Object> instance = function;
7717 v8::TryCatch try_catch;
7718
7719 CHECK(instance->IsCallable());
7720 CHECK(!try_catch.HasCaught());
7721 }
7722}
7723
7724
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007725static int CountHandles() {
7726 return v8::HandleScope::NumberOfHandles();
7727}
7728
7729
7730static int Recurse(int depth, int iterations) {
7731 v8::HandleScope scope;
7732 if (depth == 0) return CountHandles();
7733 for (int i = 0; i < iterations; i++) {
7734 Local<v8::Number> n = v8::Integer::New(42);
7735 }
7736 return Recurse(depth - 1, iterations);
7737}
7738
7739
7740THREADED_TEST(HandleIteration) {
7741 static const int kIterations = 500;
7742 static const int kNesting = 200;
7743 CHECK_EQ(0, CountHandles());
7744 {
7745 v8::HandleScope scope1;
7746 CHECK_EQ(0, CountHandles());
7747 for (int i = 0; i < kIterations; i++) {
7748 Local<v8::Number> n = v8::Integer::New(42);
7749 CHECK_EQ(i + 1, CountHandles());
7750 }
7751
7752 CHECK_EQ(kIterations, CountHandles());
7753 {
7754 v8::HandleScope scope2;
7755 for (int j = 0; j < kIterations; j++) {
7756 Local<v8::Number> n = v8::Integer::New(42);
7757 CHECK_EQ(j + 1 + kIterations, CountHandles());
7758 }
7759 }
7760 CHECK_EQ(kIterations, CountHandles());
7761 }
7762 CHECK_EQ(0, CountHandles());
7763 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7764}
7765
7766
7767static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7768 Local<String> name,
7769 const AccessorInfo& info) {
7770 ApiTestFuzzer::Fuzz();
7771 return v8::Handle<Value>();
7772}
7773
7774
7775THREADED_TEST(InterceptorHasOwnProperty) {
7776 v8::HandleScope scope;
7777 LocalContext context;
7778 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7779 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7780 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7781 Local<Function> function = fun_templ->GetFunction();
7782 context->Global()->Set(v8_str("constructor"), function);
7783 v8::Handle<Value> value = CompileRun(
7784 "var o = new constructor();"
7785 "o.hasOwnProperty('ostehaps');");
7786 CHECK_EQ(false, value->BooleanValue());
7787 value = CompileRun(
7788 "o.ostehaps = 42;"
7789 "o.hasOwnProperty('ostehaps');");
7790 CHECK_EQ(true, value->BooleanValue());
7791 value = CompileRun(
7792 "var p = new constructor();"
7793 "p.hasOwnProperty('ostehaps');");
7794 CHECK_EQ(false, value->BooleanValue());
7795}
7796
7797
ager@chromium.org9085a012009-05-11 19:22:57 +00007798static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7799 Local<String> name,
7800 const AccessorInfo& info) {
7801 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007802 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007803 return v8::Handle<Value>();
7804}
7805
7806
7807THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7808 v8::HandleScope scope;
7809 LocalContext context;
7810 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7811 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7812 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7813 Local<Function> function = fun_templ->GetFunction();
7814 context->Global()->Set(v8_str("constructor"), function);
7815 // Let's first make some stuff so we can be sure to get a good GC.
7816 CompileRun(
7817 "function makestr(size) {"
7818 " switch (size) {"
7819 " case 1: return 'f';"
7820 " case 2: return 'fo';"
7821 " case 3: return 'foo';"
7822 " }"
7823 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7824 "}"
7825 "var x = makestr(12345);"
7826 "x = makestr(31415);"
7827 "x = makestr(23456);");
7828 v8::Handle<Value> value = CompileRun(
7829 "var o = new constructor();"
7830 "o.__proto__ = new String(x);"
7831 "o.hasOwnProperty('ostehaps');");
7832 CHECK_EQ(false, value->BooleanValue());
7833}
7834
7835
ager@chromium.orge2902be2009-06-08 12:21:35 +00007836typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7837 const AccessorInfo& info);
7838
7839
7840static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7841 const char* source,
7842 int expected) {
7843 v8::HandleScope scope;
7844 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007845 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007846 LocalContext context;
7847 context->Global()->Set(v8_str("o"), templ->NewInstance());
7848 v8::Handle<Value> value = CompileRun(source);
7849 CHECK_EQ(expected, value->Int32Value());
7850}
7851
7852
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007853static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7854 const AccessorInfo& info) {
7855 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007856 CHECK_EQ(v8_str("data"), info.Data());
7857 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007858 return v8::Integer::New(42);
7859}
7860
7861
7862// This test should hit the load IC for the interceptor case.
7863THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007864 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007865 "var result = 0;"
7866 "for (var i = 0; i < 1000; i++) {"
7867 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007868 "}",
7869 42);
7870}
7871
7872
7873// Below go several tests which verify that JITing for various
7874// configurations of interceptor and explicit fields works fine
7875// (those cases are special cased to get better performance).
7876
7877static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7878 const AccessorInfo& info) {
7879 ApiTestFuzzer::Fuzz();
7880 return v8_str("x")->Equals(name)
7881 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7882}
7883
7884
7885THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7886 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7887 "var result = 0;"
7888 "o.y = 239;"
7889 "for (var i = 0; i < 1000; i++) {"
7890 " result = o.y;"
7891 "}",
7892 239);
7893}
7894
7895
7896THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7897 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7898 "var result = 0;"
7899 "o.__proto__ = { 'y': 239 };"
7900 "for (var i = 0; i < 1000; i++) {"
7901 " result = o.y + o.x;"
7902 "}",
7903 239 + 42);
7904}
7905
7906
7907THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7908 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7909 "var result = 0;"
7910 "o.__proto__.y = 239;"
7911 "for (var i = 0; i < 1000; i++) {"
7912 " result = o.y + o.x;"
7913 "}",
7914 239 + 42);
7915}
7916
7917
7918THREADED_TEST(InterceptorLoadICUndefined) {
7919 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7920 "var result = 0;"
7921 "for (var i = 0; i < 1000; i++) {"
7922 " result = (o.y == undefined) ? 239 : 42;"
7923 "}",
7924 239);
7925}
7926
7927
7928THREADED_TEST(InterceptorLoadICWithOverride) {
7929 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7930 "fst = new Object(); fst.__proto__ = o;"
7931 "snd = new Object(); snd.__proto__ = fst;"
7932 "var result1 = 0;"
7933 "for (var i = 0; i < 1000; i++) {"
7934 " result1 = snd.x;"
7935 "}"
7936 "fst.x = 239;"
7937 "var result = 0;"
7938 "for (var i = 0; i < 1000; i++) {"
7939 " result = snd.x;"
7940 "}"
7941 "result + result1",
7942 239 + 42);
7943}
7944
7945
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007946// Test the case when we stored field into
7947// a stub, but interceptor produced value on its own.
7948THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7949 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7950 "proto = new Object();"
7951 "o.__proto__ = proto;"
7952 "proto.x = 239;"
7953 "for (var i = 0; i < 1000; i++) {"
7954 " o.x;"
7955 // Now it should be ICed and keep a reference to x defined on proto
7956 "}"
7957 "var result = 0;"
7958 "for (var i = 0; i < 1000; i++) {"
7959 " result += o.x;"
7960 "}"
7961 "result;",
7962 42 * 1000);
7963}
7964
7965
7966// Test the case when we stored field into
7967// a stub, but it got invalidated later on.
7968THREADED_TEST(InterceptorLoadICInvalidatedField) {
7969 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7970 "proto1 = new Object();"
7971 "proto2 = new Object();"
7972 "o.__proto__ = proto1;"
7973 "proto1.__proto__ = proto2;"
7974 "proto2.y = 239;"
7975 "for (var i = 0; i < 1000; i++) {"
7976 " o.y;"
7977 // Now it should be ICed and keep a reference to y defined on proto2
7978 "}"
7979 "proto1.y = 42;"
7980 "var result = 0;"
7981 "for (var i = 0; i < 1000; i++) {"
7982 " result += o.y;"
7983 "}"
7984 "result;",
7985 42 * 1000);
7986}
7987
7988
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007989static int interceptor_load_not_handled_calls = 0;
7990static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7991 const AccessorInfo& info) {
7992 ++interceptor_load_not_handled_calls;
7993 return v8::Handle<v8::Value>();
7994}
7995
7996
7997// Test how post-interceptor lookups are done in the non-cacheable
7998// case: the interceptor should not be invoked during this lookup.
7999THREADED_TEST(InterceptorLoadICPostInterceptor) {
8000 interceptor_load_not_handled_calls = 0;
8001 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8002 "receiver = new Object();"
8003 "receiver.__proto__ = o;"
8004 "proto = new Object();"
8005 "/* Make proto a slow-case object. */"
8006 "for (var i = 0; i < 1000; i++) {"
8007 " proto[\"xxxxxxxx\" + i] = [];"
8008 "}"
8009 "proto.x = 17;"
8010 "o.__proto__ = proto;"
8011 "var result = 0;"
8012 "for (var i = 0; i < 1000; i++) {"
8013 " result += receiver.x;"
8014 "}"
8015 "result;",
8016 17 * 1000);
8017 CHECK_EQ(1000, interceptor_load_not_handled_calls);
8018}
8019
8020
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008021// Test the case when we stored field into
8022// a stub, but it got invalidated later on due to override on
8023// global object which is between interceptor and fields' holders.
8024THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8025 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8026 "o.__proto__ = this;" // set a global to be a proto of o.
8027 "this.__proto__.y = 239;"
8028 "for (var i = 0; i < 10; i++) {"
8029 " if (o.y != 239) throw 'oops: ' + o.y;"
8030 // Now it should be ICed and keep a reference to y defined on field_holder.
8031 "}"
8032 "this.y = 42;" // Assign on a global.
8033 "var result = 0;"
8034 "for (var i = 0; i < 10; i++) {"
8035 " result += o.y;"
8036 "}"
8037 "result;",
8038 42 * 10);
8039}
8040
8041
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008042static void SetOnThis(Local<String> name,
8043 Local<Value> value,
8044 const AccessorInfo& info) {
8045 info.This()->ForceSet(name, value);
8046}
8047
8048
8049THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8050 v8::HandleScope scope;
8051 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8052 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8053 templ->SetAccessor(v8_str("y"), Return239);
8054 LocalContext context;
8055 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008056
8057 // Check the case when receiver and interceptor's holder
8058 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008059 v8::Handle<Value> value = CompileRun(
8060 "var result = 0;"
8061 "for (var i = 0; i < 7; i++) {"
8062 " result = o.y;"
8063 "}");
8064 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008065
8066 // Check the case when interceptor's holder is in proto chain
8067 // of receiver.
8068 value = CompileRun(
8069 "r = { __proto__: o };"
8070 "var result = 0;"
8071 "for (var i = 0; i < 7; i++) {"
8072 " result = r.y;"
8073 "}");
8074 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008075}
8076
8077
8078THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8079 v8::HandleScope scope;
8080 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8081 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8082 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8083 templ_p->SetAccessor(v8_str("y"), Return239);
8084
8085 LocalContext context;
8086 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8087 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8088
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008089 // Check the case when receiver and interceptor's holder
8090 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008091 v8::Handle<Value> value = CompileRun(
8092 "o.__proto__ = p;"
8093 "var result = 0;"
8094 "for (var i = 0; i < 7; i++) {"
8095 " result = o.x + o.y;"
8096 "}");
8097 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008098
8099 // Check the case when interceptor's holder is in proto chain
8100 // of receiver.
8101 value = CompileRun(
8102 "r = { __proto__: o };"
8103 "var result = 0;"
8104 "for (var i = 0; i < 7; i++) {"
8105 " result = r.x + r.y;"
8106 "}");
8107 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008108}
8109
8110
8111THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8112 v8::HandleScope scope;
8113 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8114 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8115 templ->SetAccessor(v8_str("y"), Return239);
8116
8117 LocalContext context;
8118 context->Global()->Set(v8_str("o"), templ->NewInstance());
8119
8120 v8::Handle<Value> value = CompileRun(
8121 "fst = new Object(); fst.__proto__ = o;"
8122 "snd = new Object(); snd.__proto__ = fst;"
8123 "var result1 = 0;"
8124 "for (var i = 0; i < 7; i++) {"
8125 " result1 = snd.x;"
8126 "}"
8127 "fst.x = 239;"
8128 "var result = 0;"
8129 "for (var i = 0; i < 7; i++) {"
8130 " result = snd.x;"
8131 "}"
8132 "result + result1");
8133 CHECK_EQ(239 + 42, value->Int32Value());
8134}
8135
8136
8137// Test the case when we stored callback into
8138// a stub, but interceptor produced value on its own.
8139THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8140 v8::HandleScope scope;
8141 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8142 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8143 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8144 templ_p->SetAccessor(v8_str("y"), Return239);
8145
8146 LocalContext context;
8147 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8148 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8149
8150 v8::Handle<Value> value = CompileRun(
8151 "o.__proto__ = p;"
8152 "for (var i = 0; i < 7; i++) {"
8153 " o.x;"
8154 // Now it should be ICed and keep a reference to x defined on p
8155 "}"
8156 "var result = 0;"
8157 "for (var i = 0; i < 7; i++) {"
8158 " result += o.x;"
8159 "}"
8160 "result");
8161 CHECK_EQ(42 * 7, value->Int32Value());
8162}
8163
8164
8165// Test the case when we stored callback into
8166// a stub, but it got invalidated later on.
8167THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8168 v8::HandleScope scope;
8169 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8170 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8171 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8172 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8173
8174 LocalContext context;
8175 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8176 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8177
8178 v8::Handle<Value> value = CompileRun(
8179 "inbetween = new Object();"
8180 "o.__proto__ = inbetween;"
8181 "inbetween.__proto__ = p;"
8182 "for (var i = 0; i < 10; i++) {"
8183 " o.y;"
8184 // Now it should be ICed and keep a reference to y defined on p
8185 "}"
8186 "inbetween.y = 42;"
8187 "var result = 0;"
8188 "for (var i = 0; i < 10; i++) {"
8189 " result += o.y;"
8190 "}"
8191 "result");
8192 CHECK_EQ(42 * 10, value->Int32Value());
8193}
8194
8195
8196// Test the case when we stored callback into
8197// a stub, but it got invalidated later on due to override on
8198// global object which is between interceptor and callbacks' holders.
8199THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8200 v8::HandleScope scope;
8201 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8202 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8203 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8204 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8205
8206 LocalContext context;
8207 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8208 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8209
8210 v8::Handle<Value> value = CompileRun(
8211 "o.__proto__ = this;"
8212 "this.__proto__ = p;"
8213 "for (var i = 0; i < 10; i++) {"
8214 " if (o.y != 239) throw 'oops: ' + o.y;"
8215 // Now it should be ICed and keep a reference to y defined on p
8216 "}"
8217 "this.y = 42;"
8218 "var result = 0;"
8219 "for (var i = 0; i < 10; i++) {"
8220 " result += o.y;"
8221 "}"
8222 "result");
8223 CHECK_EQ(42 * 10, value->Int32Value());
8224}
8225
8226
ager@chromium.orge2902be2009-06-08 12:21:35 +00008227static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8228 const AccessorInfo& info) {
8229 ApiTestFuzzer::Fuzz();
8230 CHECK(v8_str("x")->Equals(name));
8231 return v8::Integer::New(0);
8232}
8233
8234
8235THREADED_TEST(InterceptorReturningZero) {
8236 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8237 "o.x == undefined ? 1 : 0",
8238 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008239}
8240
8241
8242static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008243 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008244 CHECK(v8_str("x")->Equals(key));
8245 CHECK_EQ(42, value->Int32Value());
8246 return value;
8247}
8248
8249
8250// This test should hit the store IC for the interceptor case.
8251THREADED_TEST(InterceptorStoreIC) {
8252 v8::HandleScope scope;
8253 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8254 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008255 InterceptorStoreICSetter,
8256 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008257 LocalContext context;
8258 context->Global()->Set(v8_str("o"), templ->NewInstance());
8259 v8::Handle<Value> value = CompileRun(
8260 "for (var i = 0; i < 1000; i++) {"
8261 " o.x = 42;"
8262 "}");
8263}
8264
8265
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008266THREADED_TEST(InterceptorStoreICWithNoSetter) {
8267 v8::HandleScope scope;
8268 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8269 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8270 LocalContext context;
8271 context->Global()->Set(v8_str("o"), templ->NewInstance());
8272 v8::Handle<Value> value = CompileRun(
8273 "for (var i = 0; i < 1000; i++) {"
8274 " o.y = 239;"
8275 "}"
8276 "42 + o.y");
8277 CHECK_EQ(239 + 42, value->Int32Value());
8278}
8279
8280
8281
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008282
8283v8::Handle<Value> call_ic_function;
8284v8::Handle<Value> call_ic_function2;
8285v8::Handle<Value> call_ic_function3;
8286
8287static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8288 const AccessorInfo& info) {
8289 ApiTestFuzzer::Fuzz();
8290 CHECK(v8_str("x")->Equals(name));
8291 return call_ic_function;
8292}
8293
8294
8295// This test should hit the call IC for the interceptor case.
8296THREADED_TEST(InterceptorCallIC) {
8297 v8::HandleScope scope;
8298 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8299 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8300 LocalContext context;
8301 context->Global()->Set(v8_str("o"), templ->NewInstance());
8302 call_ic_function =
8303 v8_compile("function f(x) { return x + 1; }; f")->Run();
8304 v8::Handle<Value> value = CompileRun(
8305 "var result = 0;"
8306 "for (var i = 0; i < 1000; i++) {"
8307 " result = o.x(41);"
8308 "}");
8309 CHECK_EQ(42, value->Int32Value());
8310}
8311
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008312
8313// This test checks that if interceptor doesn't provide
8314// a value, we can fetch regular value.
8315THREADED_TEST(InterceptorCallICSeesOthers) {
8316 v8::HandleScope scope;
8317 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8318 templ->SetNamedPropertyHandler(NoBlockGetterX);
8319 LocalContext context;
8320 context->Global()->Set(v8_str("o"), templ->NewInstance());
8321 v8::Handle<Value> value = CompileRun(
8322 "o.x = function f(x) { return x + 1; };"
8323 "var result = 0;"
8324 "for (var i = 0; i < 7; i++) {"
8325 " result = o.x(41);"
8326 "}");
8327 CHECK_EQ(42, value->Int32Value());
8328}
8329
8330
8331static v8::Handle<Value> call_ic_function4;
8332static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8333 const AccessorInfo& info) {
8334 ApiTestFuzzer::Fuzz();
8335 CHECK(v8_str("x")->Equals(name));
8336 return call_ic_function4;
8337}
8338
8339
8340// This test checks that if interceptor provides a function,
8341// even if we cached shadowed variant, interceptor's function
8342// is invoked
8343THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8344 v8::HandleScope scope;
8345 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8346 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8347 LocalContext context;
8348 context->Global()->Set(v8_str("o"), templ->NewInstance());
8349 call_ic_function4 =
8350 v8_compile("function f(x) { return x - 1; }; f")->Run();
8351 v8::Handle<Value> value = CompileRun(
8352 "o.__proto__.x = function(x) { return x + 1; };"
8353 "var result = 0;"
8354 "for (var i = 0; i < 1000; i++) {"
8355 " result = o.x(42);"
8356 "}");
8357 CHECK_EQ(41, value->Int32Value());
8358}
8359
8360
8361// Test the case when we stored cacheable lookup into
8362// a stub, but it got invalidated later on
8363THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8364 v8::HandleScope scope;
8365 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8366 templ->SetNamedPropertyHandler(NoBlockGetterX);
8367 LocalContext context;
8368 context->Global()->Set(v8_str("o"), templ->NewInstance());
8369 v8::Handle<Value> value = CompileRun(
8370 "proto1 = new Object();"
8371 "proto2 = new Object();"
8372 "o.__proto__ = proto1;"
8373 "proto1.__proto__ = proto2;"
8374 "proto2.y = function(x) { return x + 1; };"
8375 // Invoke it many times to compile a stub
8376 "for (var i = 0; i < 7; i++) {"
8377 " o.y(42);"
8378 "}"
8379 "proto1.y = function(x) { return x - 1; };"
8380 "var result = 0;"
8381 "for (var i = 0; i < 7; i++) {"
8382 " result += o.y(42);"
8383 "}");
8384 CHECK_EQ(41 * 7, value->Int32Value());
8385}
8386
8387
8388static v8::Handle<Value> call_ic_function5;
8389static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8390 const AccessorInfo& info) {
8391 ApiTestFuzzer::Fuzz();
8392 if (v8_str("x")->Equals(name))
8393 return call_ic_function5;
8394 else
8395 return Local<Value>();
8396}
8397
8398
8399// This test checks that if interceptor doesn't provide a function,
8400// cached constant function is used
8401THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8402 v8::HandleScope scope;
8403 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8404 templ->SetNamedPropertyHandler(NoBlockGetterX);
8405 LocalContext context;
8406 context->Global()->Set(v8_str("o"), templ->NewInstance());
8407 v8::Handle<Value> value = CompileRun(
8408 "function inc(x) { return x + 1; };"
8409 "inc(1);"
8410 "o.x = inc;"
8411 "var result = 0;"
8412 "for (var i = 0; i < 1000; i++) {"
8413 " result = o.x(42);"
8414 "}");
8415 CHECK_EQ(43, value->Int32Value());
8416}
8417
8418
8419// This test checks that if interceptor provides a function,
8420// even if we cached constant function, interceptor's function
8421// is invoked
8422THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8423 v8::HandleScope scope;
8424 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8425 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8426 LocalContext context;
8427 context->Global()->Set(v8_str("o"), templ->NewInstance());
8428 call_ic_function5 =
8429 v8_compile("function f(x) { return x - 1; }; f")->Run();
8430 v8::Handle<Value> value = CompileRun(
8431 "function inc(x) { return x + 1; };"
8432 "inc(1);"
8433 "o.x = inc;"
8434 "var result = 0;"
8435 "for (var i = 0; i < 1000; i++) {"
8436 " result = o.x(42);"
8437 "}");
8438 CHECK_EQ(41, value->Int32Value());
8439}
8440
8441
8442// Test the case when we stored constant function into
8443// a stub, but it got invalidated later on
8444THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8445 v8::HandleScope scope;
8446 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8447 templ->SetNamedPropertyHandler(NoBlockGetterX);
8448 LocalContext context;
8449 context->Global()->Set(v8_str("o"), templ->NewInstance());
8450 v8::Handle<Value> value = CompileRun(
8451 "function inc(x) { return x + 1; };"
8452 "inc(1);"
8453 "proto1 = new Object();"
8454 "proto2 = new Object();"
8455 "o.__proto__ = proto1;"
8456 "proto1.__proto__ = proto2;"
8457 "proto2.y = inc;"
8458 // Invoke it many times to compile a stub
8459 "for (var i = 0; i < 7; i++) {"
8460 " o.y(42);"
8461 "}"
8462 "proto1.y = function(x) { return x - 1; };"
8463 "var result = 0;"
8464 "for (var i = 0; i < 7; i++) {"
8465 " result += o.y(42);"
8466 "}");
8467 CHECK_EQ(41 * 7, value->Int32Value());
8468}
8469
8470
8471// Test the case when we stored constant function into
8472// a stub, but it got invalidated later on due to override on
8473// global object which is between interceptor and constant function' holders.
8474THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8475 v8::HandleScope scope;
8476 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8477 templ->SetNamedPropertyHandler(NoBlockGetterX);
8478 LocalContext context;
8479 context->Global()->Set(v8_str("o"), templ->NewInstance());
8480 v8::Handle<Value> value = CompileRun(
8481 "function inc(x) { return x + 1; };"
8482 "inc(1);"
8483 "o.__proto__ = this;"
8484 "this.__proto__.y = inc;"
8485 // Invoke it many times to compile a stub
8486 "for (var i = 0; i < 7; i++) {"
8487 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8488 "}"
8489 "this.y = function(x) { return x - 1; };"
8490 "var result = 0;"
8491 "for (var i = 0; i < 7; i++) {"
8492 " result += o.y(42);"
8493 "}");
8494 CHECK_EQ(41 * 7, value->Int32Value());
8495}
8496
8497
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008498// Test the case when actual function to call sits on global object.
8499THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8500 v8::HandleScope scope;
8501 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8502 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8503
8504 LocalContext context;
8505 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8506
8507 v8::Handle<Value> value = CompileRun(
8508 "try {"
8509 " o.__proto__ = this;"
8510 " for (var i = 0; i < 10; i++) {"
8511 " var v = o.parseFloat('239');"
8512 " if (v != 239) throw v;"
8513 // Now it should be ICed and keep a reference to parseFloat.
8514 " }"
8515 " var result = 0;"
8516 " for (var i = 0; i < 10; i++) {"
8517 " result += o.parseFloat('239');"
8518 " }"
8519 " result"
8520 "} catch(e) {"
8521 " e"
8522 "};");
8523 CHECK_EQ(239 * 10, value->Int32Value());
8524}
8525
ager@chromium.org5c838252010-02-19 08:53:10 +00008526static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8527 const AccessorInfo& info) {
8528 ApiTestFuzzer::Fuzz();
8529 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8530 ++(*call_count);
8531 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00008533 }
8534 return v8::Handle<Value>();
8535}
8536
8537static v8::Handle<Value> FastApiCallback_TrivialSignature(
8538 const v8::Arguments& args) {
8539 ApiTestFuzzer::Fuzz();
8540 CHECK_EQ(args.This(), args.Holder());
8541 CHECK(args.Data()->Equals(v8_str("method_data")));
8542 return v8::Integer::New(args[0]->Int32Value() + 1);
8543}
8544
8545static v8::Handle<Value> FastApiCallback_SimpleSignature(
8546 const v8::Arguments& args) {
8547 ApiTestFuzzer::Fuzz();
8548 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8549 CHECK(args.Data()->Equals(v8_str("method_data")));
8550 // Note, we're using HasRealNamedProperty instead of Has to avoid
8551 // invoking the interceptor again.
8552 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8553 return v8::Integer::New(args[0]->Int32Value() + 1);
8554}
8555
8556// Helper to maximize the odds of object moving.
8557static void GenerateSomeGarbage() {
8558 CompileRun(
8559 "var garbage;"
8560 "for (var i = 0; i < 1000; i++) {"
8561 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8562 "}"
8563 "garbage = undefined;");
8564}
8565
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008566
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008567v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8568 static int count = 0;
8569 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008571 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8572 }
8573 return v8::Handle<v8::Value>();
8574}
8575
8576
8577THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8578 v8::HandleScope scope;
8579 LocalContext context;
8580 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8581 nativeobject_templ->Set("callback",
8582 v8::FunctionTemplate::New(DirectApiCallback));
8583 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8584 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8585 // call the api function multiple times to ensure direct call stub creation.
8586 CompileRun(
8587 "function f() {"
8588 " for (var i = 1; i <= 30; i++) {"
8589 " nativeobject.callback();"
8590 " }"
8591 "}"
8592 "f();");
8593}
8594
8595
8596v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8597 return v8::ThrowException(v8_str("g"));
8598}
8599
8600
8601THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8602 v8::HandleScope scope;
8603 LocalContext context;
8604 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8605 nativeobject_templ->Set("callback",
8606 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8607 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8608 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8609 // call the api function multiple times to ensure direct call stub creation.
8610 v8::Handle<Value> result = CompileRun(
8611 "var result = '';"
8612 "function f() {"
8613 " for (var i = 1; i <= 5; i++) {"
8614 " try { nativeobject.callback(); } catch (e) { result += e; }"
8615 " }"
8616 "}"
8617 "f(); result;");
8618 CHECK_EQ(v8_str("ggggg"), result);
8619}
8620
8621
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008622v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8623 const v8::AccessorInfo& info) {
8624 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008625 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008626 GenerateSomeGarbage();
8627 }
8628 return v8::Handle<v8::Value>();
8629}
8630
8631
8632THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8633 v8::HandleScope scope;
8634 LocalContext context;
8635 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8636 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8637 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8638 p_getter_count = 0;
8639 CompileRun(
8640 "function f() {"
8641 " for (var i = 0; i < 30; i++) o1.p1;"
8642 "}"
8643 "f();");
8644 CHECK_EQ(30, p_getter_count);
8645}
8646
8647
8648v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8649 Local<String> name, const v8::AccessorInfo& info) {
8650 return v8::ThrowException(v8_str("g"));
8651}
8652
8653
8654THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8655 v8::HandleScope scope;
8656 LocalContext context;
8657 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8658 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8659 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8660 v8::Handle<Value> result = CompileRun(
8661 "var result = '';"
8662 "for (var i = 0; i < 5; i++) {"
8663 " try { o1.p1; } catch (e) { result += e; }"
8664 "}"
8665 "result;");
8666 CHECK_EQ(v8_str("ggggg"), result);
8667}
8668
8669
ager@chromium.org5c838252010-02-19 08:53:10 +00008670THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8671 int interceptor_call_count = 0;
8672 v8::HandleScope scope;
8673 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8674 v8::Handle<v8::FunctionTemplate> method_templ =
8675 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8676 v8_str("method_data"),
8677 v8::Handle<v8::Signature>());
8678 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8679 proto_templ->Set(v8_str("method"), method_templ);
8680 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8681 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8682 NULL, NULL, NULL, NULL,
8683 v8::External::Wrap(&interceptor_call_count));
8684 LocalContext context;
8685 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8686 GenerateSomeGarbage();
8687 context->Global()->Set(v8_str("o"), fun->NewInstance());
8688 v8::Handle<Value> value = CompileRun(
8689 "var result = 0;"
8690 "for (var i = 0; i < 100; i++) {"
8691 " result = o.method(41);"
8692 "}");
8693 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8694 CHECK_EQ(100, interceptor_call_count);
8695}
8696
8697THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8698 int interceptor_call_count = 0;
8699 v8::HandleScope scope;
8700 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8701 v8::Handle<v8::FunctionTemplate> method_templ =
8702 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8703 v8_str("method_data"),
8704 v8::Signature::New(fun_templ));
8705 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8706 proto_templ->Set(v8_str("method"), method_templ);
8707 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8708 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8709 NULL, NULL, NULL, NULL,
8710 v8::External::Wrap(&interceptor_call_count));
8711 LocalContext context;
8712 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8713 GenerateSomeGarbage();
8714 context->Global()->Set(v8_str("o"), fun->NewInstance());
8715 v8::Handle<Value> value = CompileRun(
8716 "o.foo = 17;"
8717 "var receiver = {};"
8718 "receiver.__proto__ = o;"
8719 "var result = 0;"
8720 "for (var i = 0; i < 100; i++) {"
8721 " result = receiver.method(41);"
8722 "}");
8723 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8724 CHECK_EQ(100, interceptor_call_count);
8725}
8726
8727THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8728 int interceptor_call_count = 0;
8729 v8::HandleScope scope;
8730 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8731 v8::Handle<v8::FunctionTemplate> method_templ =
8732 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8733 v8_str("method_data"),
8734 v8::Signature::New(fun_templ));
8735 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8736 proto_templ->Set(v8_str("method"), method_templ);
8737 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8738 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8739 NULL, NULL, NULL, NULL,
8740 v8::External::Wrap(&interceptor_call_count));
8741 LocalContext context;
8742 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8743 GenerateSomeGarbage();
8744 context->Global()->Set(v8_str("o"), fun->NewInstance());
8745 v8::Handle<Value> value = CompileRun(
8746 "o.foo = 17;"
8747 "var receiver = {};"
8748 "receiver.__proto__ = o;"
8749 "var result = 0;"
8750 "var saved_result = 0;"
8751 "for (var i = 0; i < 100; i++) {"
8752 " result = receiver.method(41);"
8753 " if (i == 50) {"
8754 " saved_result = result;"
8755 " receiver = {method: function(x) { return x - 1 }};"
8756 " }"
8757 "}");
8758 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8759 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8760 CHECK_GE(interceptor_call_count, 50);
8761}
8762
8763THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8764 int interceptor_call_count = 0;
8765 v8::HandleScope scope;
8766 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8767 v8::Handle<v8::FunctionTemplate> method_templ =
8768 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8769 v8_str("method_data"),
8770 v8::Signature::New(fun_templ));
8771 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8772 proto_templ->Set(v8_str("method"), method_templ);
8773 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8774 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8775 NULL, NULL, NULL, NULL,
8776 v8::External::Wrap(&interceptor_call_count));
8777 LocalContext context;
8778 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8779 GenerateSomeGarbage();
8780 context->Global()->Set(v8_str("o"), fun->NewInstance());
8781 v8::Handle<Value> value = CompileRun(
8782 "o.foo = 17;"
8783 "var receiver = {};"
8784 "receiver.__proto__ = o;"
8785 "var result = 0;"
8786 "var saved_result = 0;"
8787 "for (var i = 0; i < 100; i++) {"
8788 " result = receiver.method(41);"
8789 " if (i == 50) {"
8790 " saved_result = result;"
8791 " o.method = function(x) { return x - 1 };"
8792 " }"
8793 "}");
8794 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8795 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8796 CHECK_GE(interceptor_call_count, 50);
8797}
8798
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008799THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8800 int interceptor_call_count = 0;
8801 v8::HandleScope scope;
8802 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8803 v8::Handle<v8::FunctionTemplate> method_templ =
8804 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8805 v8_str("method_data"),
8806 v8::Signature::New(fun_templ));
8807 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8808 proto_templ->Set(v8_str("method"), method_templ);
8809 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8810 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8811 NULL, NULL, NULL, NULL,
8812 v8::External::Wrap(&interceptor_call_count));
8813 LocalContext context;
8814 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8815 GenerateSomeGarbage();
8816 context->Global()->Set(v8_str("o"), fun->NewInstance());
8817 v8::TryCatch try_catch;
8818 v8::Handle<Value> value = CompileRun(
8819 "o.foo = 17;"
8820 "var receiver = {};"
8821 "receiver.__proto__ = o;"
8822 "var result = 0;"
8823 "var saved_result = 0;"
8824 "for (var i = 0; i < 100; i++) {"
8825 " result = receiver.method(41);"
8826 " if (i == 50) {"
8827 " saved_result = result;"
8828 " receiver = 333;"
8829 " }"
8830 "}");
8831 CHECK(try_catch.HasCaught());
8832 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8833 try_catch.Exception()->ToString());
8834 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8835 CHECK_GE(interceptor_call_count, 50);
8836}
8837
ager@chromium.org5c838252010-02-19 08:53:10 +00008838THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8839 int interceptor_call_count = 0;
8840 v8::HandleScope scope;
8841 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8842 v8::Handle<v8::FunctionTemplate> method_templ =
8843 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8844 v8_str("method_data"),
8845 v8::Signature::New(fun_templ));
8846 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8847 proto_templ->Set(v8_str("method"), method_templ);
8848 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8849 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8850 NULL, NULL, NULL, NULL,
8851 v8::External::Wrap(&interceptor_call_count));
8852 LocalContext context;
8853 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8854 GenerateSomeGarbage();
8855 context->Global()->Set(v8_str("o"), fun->NewInstance());
8856 v8::TryCatch try_catch;
8857 v8::Handle<Value> value = CompileRun(
8858 "o.foo = 17;"
8859 "var receiver = {};"
8860 "receiver.__proto__ = o;"
8861 "var result = 0;"
8862 "var saved_result = 0;"
8863 "for (var i = 0; i < 100; i++) {"
8864 " result = receiver.method(41);"
8865 " if (i == 50) {"
8866 " saved_result = result;"
8867 " receiver = {method: receiver.method};"
8868 " }"
8869 "}");
8870 CHECK(try_catch.HasCaught());
8871 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8872 try_catch.Exception()->ToString());
8873 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8874 CHECK_GE(interceptor_call_count, 50);
8875}
8876
8877THREADED_TEST(CallICFastApi_TrivialSignature) {
8878 v8::HandleScope scope;
8879 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8880 v8::Handle<v8::FunctionTemplate> method_templ =
8881 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8882 v8_str("method_data"),
8883 v8::Handle<v8::Signature>());
8884 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8885 proto_templ->Set(v8_str("method"), method_templ);
8886 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8887 LocalContext context;
8888 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8889 GenerateSomeGarbage();
8890 context->Global()->Set(v8_str("o"), fun->NewInstance());
8891 v8::Handle<Value> value = CompileRun(
8892 "var result = 0;"
8893 "for (var i = 0; i < 100; i++) {"
8894 " result = o.method(41);"
8895 "}");
8896
8897 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8898}
8899
8900THREADED_TEST(CallICFastApi_SimpleSignature) {
8901 v8::HandleScope scope;
8902 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8903 v8::Handle<v8::FunctionTemplate> method_templ =
8904 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8905 v8_str("method_data"),
8906 v8::Signature::New(fun_templ));
8907 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8908 proto_templ->Set(v8_str("method"), method_templ);
8909 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8910 LocalContext context;
8911 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8912 GenerateSomeGarbage();
8913 context->Global()->Set(v8_str("o"), fun->NewInstance());
8914 v8::Handle<Value> value = CompileRun(
8915 "o.foo = 17;"
8916 "var receiver = {};"
8917 "receiver.__proto__ = o;"
8918 "var result = 0;"
8919 "for (var i = 0; i < 100; i++) {"
8920 " result = receiver.method(41);"
8921 "}");
8922
8923 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8924}
8925
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008926THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008927 v8::HandleScope scope;
8928 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8929 v8::Handle<v8::FunctionTemplate> method_templ =
8930 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8931 v8_str("method_data"),
8932 v8::Signature::New(fun_templ));
8933 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8934 proto_templ->Set(v8_str("method"), method_templ);
8935 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8936 LocalContext context;
8937 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8938 GenerateSomeGarbage();
8939 context->Global()->Set(v8_str("o"), fun->NewInstance());
8940 v8::Handle<Value> value = CompileRun(
8941 "o.foo = 17;"
8942 "var receiver = {};"
8943 "receiver.__proto__ = o;"
8944 "var result = 0;"
8945 "var saved_result = 0;"
8946 "for (var i = 0; i < 100; i++) {"
8947 " result = receiver.method(41);"
8948 " if (i == 50) {"
8949 " saved_result = result;"
8950 " receiver = {method: function(x) { return x - 1 }};"
8951 " }"
8952 "}");
8953 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8954 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8955}
8956
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008957THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8958 v8::HandleScope scope;
8959 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8960 v8::Handle<v8::FunctionTemplate> method_templ =
8961 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8962 v8_str("method_data"),
8963 v8::Signature::New(fun_templ));
8964 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8965 proto_templ->Set(v8_str("method"), method_templ);
8966 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8967 LocalContext context;
8968 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8969 GenerateSomeGarbage();
8970 context->Global()->Set(v8_str("o"), fun->NewInstance());
8971 v8::TryCatch try_catch;
8972 v8::Handle<Value> value = CompileRun(
8973 "o.foo = 17;"
8974 "var receiver = {};"
8975 "receiver.__proto__ = o;"
8976 "var result = 0;"
8977 "var saved_result = 0;"
8978 "for (var i = 0; i < 100; i++) {"
8979 " result = receiver.method(41);"
8980 " if (i == 50) {"
8981 " saved_result = result;"
8982 " receiver = 333;"
8983 " }"
8984 "}");
8985 CHECK(try_catch.HasCaught());
8986 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8987 try_catch.Exception()->ToString());
8988 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8989}
8990
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008991
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008992v8::Handle<Value> keyed_call_ic_function;
8993
8994static v8::Handle<Value> InterceptorKeyedCallICGetter(
8995 Local<String> name, const AccessorInfo& info) {
8996 ApiTestFuzzer::Fuzz();
8997 if (v8_str("x")->Equals(name)) {
8998 return keyed_call_ic_function;
8999 }
9000 return v8::Handle<Value>();
9001}
9002
9003
9004// Test the case when we stored cacheable lookup into
9005// a stub, but the function name changed (to another cacheable function).
9006THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9007 v8::HandleScope scope;
9008 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9009 templ->SetNamedPropertyHandler(NoBlockGetterX);
9010 LocalContext context;
9011 context->Global()->Set(v8_str("o"), templ->NewInstance());
9012 v8::Handle<Value> value = CompileRun(
9013 "proto = new Object();"
9014 "proto.y = function(x) { return x + 1; };"
9015 "proto.z = function(x) { return x - 1; };"
9016 "o.__proto__ = proto;"
9017 "var result = 0;"
9018 "var method = 'y';"
9019 "for (var i = 0; i < 10; i++) {"
9020 " if (i == 5) { method = 'z'; };"
9021 " result += o[method](41);"
9022 "}");
9023 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9024}
9025
9026
9027// Test the case when we stored cacheable lookup into
9028// a stub, but the function name changed (and the new function is present
9029// both before and after the interceptor in the prototype chain).
9030THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9031 v8::HandleScope scope;
9032 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9033 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9034 LocalContext context;
9035 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9036 keyed_call_ic_function =
9037 v8_compile("function f(x) { return x - 1; }; f")->Run();
9038 v8::Handle<Value> value = CompileRun(
9039 "o = new Object();"
9040 "proto2 = new Object();"
9041 "o.y = function(x) { return x + 1; };"
9042 "proto2.y = function(x) { return x + 2; };"
9043 "o.__proto__ = proto1;"
9044 "proto1.__proto__ = proto2;"
9045 "var result = 0;"
9046 "var method = 'x';"
9047 "for (var i = 0; i < 10; i++) {"
9048 " if (i == 5) { method = 'y'; };"
9049 " result += o[method](41);"
9050 "}");
9051 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9052}
9053
9054
9055// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9056// on the global object.
9057THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9058 v8::HandleScope scope;
9059 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9060 templ->SetNamedPropertyHandler(NoBlockGetterX);
9061 LocalContext context;
9062 context->Global()->Set(v8_str("o"), templ->NewInstance());
9063 v8::Handle<Value> value = CompileRun(
9064 "function inc(x) { return x + 1; };"
9065 "inc(1);"
9066 "function dec(x) { return x - 1; };"
9067 "dec(1);"
9068 "o.__proto__ = this;"
9069 "this.__proto__.x = inc;"
9070 "this.__proto__.y = dec;"
9071 "var result = 0;"
9072 "var method = 'x';"
9073 "for (var i = 0; i < 10; i++) {"
9074 " if (i == 5) { method = 'y'; };"
9075 " result += o[method](41);"
9076 "}");
9077 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9078}
9079
9080
9081// Test the case when actual function to call sits on global object.
9082THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9083 v8::HandleScope scope;
9084 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9085 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9086 LocalContext context;
9087 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9088
9089 v8::Handle<Value> value = CompileRun(
9090 "function len(x) { return x.length; };"
9091 "o.__proto__ = this;"
9092 "var m = 'parseFloat';"
9093 "var result = 0;"
9094 "for (var i = 0; i < 10; i++) {"
9095 " if (i == 5) {"
9096 " m = 'len';"
9097 " saved_result = result;"
9098 " };"
9099 " result = o[m]('239');"
9100 "}");
9101 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9102 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9103}
9104
9105// Test the map transition before the interceptor.
9106THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9107 v8::HandleScope scope;
9108 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9109 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9110 LocalContext context;
9111 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9112
9113 v8::Handle<Value> value = CompileRun(
9114 "var o = new Object();"
9115 "o.__proto__ = proto;"
9116 "o.method = function(x) { return x + 1; };"
9117 "var m = 'method';"
9118 "var result = 0;"
9119 "for (var i = 0; i < 10; i++) {"
9120 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9121 " result += o[m](41);"
9122 "}");
9123 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9124}
9125
9126
9127// Test the map transition after the interceptor.
9128THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9129 v8::HandleScope scope;
9130 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9131 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9132 LocalContext context;
9133 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9134
9135 v8::Handle<Value> value = CompileRun(
9136 "var proto = new Object();"
9137 "o.__proto__ = proto;"
9138 "proto.method = function(x) { return x + 1; };"
9139 "var m = 'method';"
9140 "var result = 0;"
9141 "for (var i = 0; i < 10; i++) {"
9142 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9143 " result += o[m](41);"
9144 "}");
9145 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9146}
9147
9148
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009149static int interceptor_call_count = 0;
9150
9151static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9152 const AccessorInfo& info) {
9153 ApiTestFuzzer::Fuzz();
9154 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9155 return call_ic_function2;
9156 }
9157 return v8::Handle<Value>();
9158}
9159
9160
9161// This test should hit load and call ICs for the interceptor case.
9162// Once in a while, the interceptor will reply that a property was not
9163// found in which case we should get a reference error.
9164THREADED_TEST(InterceptorICReferenceErrors) {
9165 v8::HandleScope scope;
9166 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9167 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9168 LocalContext context(0, templ, v8::Handle<Value>());
9169 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9170 v8::Handle<Value> value = CompileRun(
9171 "function f() {"
9172 " for (var i = 0; i < 1000; i++) {"
9173 " try { x; } catch(e) { return true; }"
9174 " }"
9175 " return false;"
9176 "};"
9177 "f();");
9178 CHECK_EQ(true, value->BooleanValue());
9179 interceptor_call_count = 0;
9180 value = CompileRun(
9181 "function g() {"
9182 " for (var i = 0; i < 1000; i++) {"
9183 " try { x(42); } catch(e) { return true; }"
9184 " }"
9185 " return false;"
9186 "};"
9187 "g();");
9188 CHECK_EQ(true, value->BooleanValue());
9189}
9190
9191
9192static int interceptor_ic_exception_get_count = 0;
9193
9194static v8::Handle<Value> InterceptorICExceptionGetter(
9195 Local<String> name,
9196 const AccessorInfo& info) {
9197 ApiTestFuzzer::Fuzz();
9198 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9199 return call_ic_function3;
9200 }
9201 if (interceptor_ic_exception_get_count == 20) {
9202 return v8::ThrowException(v8_num(42));
9203 }
9204 // Do not handle get for properties other than x.
9205 return v8::Handle<Value>();
9206}
9207
9208// Test interceptor load/call IC where the interceptor throws an
9209// exception once in a while.
9210THREADED_TEST(InterceptorICGetterExceptions) {
9211 interceptor_ic_exception_get_count = 0;
9212 v8::HandleScope scope;
9213 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9214 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9215 LocalContext context(0, templ, v8::Handle<Value>());
9216 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9217 v8::Handle<Value> value = CompileRun(
9218 "function f() {"
9219 " for (var i = 0; i < 100; i++) {"
9220 " try { x; } catch(e) { return true; }"
9221 " }"
9222 " return false;"
9223 "};"
9224 "f();");
9225 CHECK_EQ(true, value->BooleanValue());
9226 interceptor_ic_exception_get_count = 0;
9227 value = CompileRun(
9228 "function f() {"
9229 " for (var i = 0; i < 100; i++) {"
9230 " try { x(42); } catch(e) { return true; }"
9231 " }"
9232 " return false;"
9233 "};"
9234 "f();");
9235 CHECK_EQ(true, value->BooleanValue());
9236}
9237
9238
9239static int interceptor_ic_exception_set_count = 0;
9240
9241static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009242 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009243 ApiTestFuzzer::Fuzz();
9244 if (++interceptor_ic_exception_set_count > 20) {
9245 return v8::ThrowException(v8_num(42));
9246 }
9247 // Do not actually handle setting.
9248 return v8::Handle<Value>();
9249}
9250
9251// Test interceptor store IC where the interceptor throws an exception
9252// once in a while.
9253THREADED_TEST(InterceptorICSetterExceptions) {
9254 interceptor_ic_exception_set_count = 0;
9255 v8::HandleScope scope;
9256 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9257 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9258 LocalContext context(0, templ, v8::Handle<Value>());
9259 v8::Handle<Value> value = CompileRun(
9260 "function f() {"
9261 " for (var i = 0; i < 100; i++) {"
9262 " try { x = 42; } catch(e) { return true; }"
9263 " }"
9264 " return false;"
9265 "};"
9266 "f();");
9267 CHECK_EQ(true, value->BooleanValue());
9268}
9269
9270
9271// Test that we ignore null interceptors.
9272THREADED_TEST(NullNamedInterceptor) {
9273 v8::HandleScope scope;
9274 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9275 templ->SetNamedPropertyHandler(0);
9276 LocalContext context;
9277 templ->Set("x", v8_num(42));
9278 v8::Handle<v8::Object> obj = templ->NewInstance();
9279 context->Global()->Set(v8_str("obj"), obj);
9280 v8::Handle<Value> value = CompileRun("obj.x");
9281 CHECK(value->IsInt32());
9282 CHECK_EQ(42, value->Int32Value());
9283}
9284
9285
9286// Test that we ignore null interceptors.
9287THREADED_TEST(NullIndexedInterceptor) {
9288 v8::HandleScope scope;
9289 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9290 templ->SetIndexedPropertyHandler(0);
9291 LocalContext context;
9292 templ->Set("42", v8_num(42));
9293 v8::Handle<v8::Object> obj = templ->NewInstance();
9294 context->Global()->Set(v8_str("obj"), obj);
9295 v8::Handle<Value> value = CompileRun("obj[42]");
9296 CHECK(value->IsInt32());
9297 CHECK_EQ(42, value->Int32Value());
9298}
9299
9300
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009301THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9302 v8::HandleScope scope;
9303 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9304 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9305 LocalContext env;
9306 env->Global()->Set(v8_str("obj"),
9307 templ->GetFunction()->NewInstance());
9308 ExpectTrue("obj.x === 42");
9309 ExpectTrue("!obj.propertyIsEnumerable('x')");
9310}
9311
9312
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009313static Handle<Value> ThrowingGetter(Local<String> name,
9314 const AccessorInfo& info) {
9315 ApiTestFuzzer::Fuzz();
9316 ThrowException(Handle<Value>());
9317 return Undefined();
9318}
9319
9320
9321THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9322 HandleScope scope;
9323 LocalContext context;
9324
9325 Local<FunctionTemplate> templ = FunctionTemplate::New();
9326 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9327 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9328
9329 Local<Object> instance = templ->GetFunction()->NewInstance();
9330
9331 Local<Object> another = Object::New();
9332 another->SetPrototype(instance);
9333
9334 Local<Object> with_js_getter = CompileRun(
9335 "o = {};\n"
9336 "o.__defineGetter__('f', function() { throw undefined; });\n"
9337 "o\n").As<Object>();
9338 CHECK(!with_js_getter.IsEmpty());
9339
9340 TryCatch try_catch;
9341
9342 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9343 CHECK(try_catch.HasCaught());
9344 try_catch.Reset();
9345 CHECK(result.IsEmpty());
9346
9347 result = another->GetRealNamedProperty(v8_str("f"));
9348 CHECK(try_catch.HasCaught());
9349 try_catch.Reset();
9350 CHECK(result.IsEmpty());
9351
9352 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9353 CHECK(try_catch.HasCaught());
9354 try_catch.Reset();
9355 CHECK(result.IsEmpty());
9356
9357 result = another->Get(v8_str("f"));
9358 CHECK(try_catch.HasCaught());
9359 try_catch.Reset();
9360 CHECK(result.IsEmpty());
9361
9362 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9363 CHECK(try_catch.HasCaught());
9364 try_catch.Reset();
9365 CHECK(result.IsEmpty());
9366
9367 result = with_js_getter->Get(v8_str("f"));
9368 CHECK(try_catch.HasCaught());
9369 try_catch.Reset();
9370 CHECK(result.IsEmpty());
9371}
9372
9373
9374static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9375 TryCatch try_catch;
9376 // Verboseness is important: it triggers message delivery which can call into
9377 // external code.
9378 try_catch.SetVerbose(true);
9379 CompileRun("throw 'from JS';");
9380 CHECK(try_catch.HasCaught());
9381 CHECK(!i::Isolate::Current()->has_pending_exception());
9382 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9383 return Undefined();
9384}
9385
9386
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009387static int call_depth;
9388
9389
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009390static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9391 TryCatch try_catch;
9392}
9393
9394
9395static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009396 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009397}
9398
9399
9400static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009401 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009402}
9403
9404
9405static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9406 Handle<String> errorMessageString = message->Get();
9407 CHECK(!errorMessageString.IsEmpty());
9408 message->GetStackTrace();
9409 message->GetScriptResourceName();
9410}
9411
9412THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9413 HandleScope scope;
9414 LocalContext context;
9415
9416 Local<Function> func =
9417 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9418 context->Global()->Set(v8_str("func"), func);
9419
9420 MessageCallback callbacks[] =
9421 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9422 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9423 MessageCallback callback = callbacks[i];
9424 if (callback != NULL) {
9425 V8::AddMessageListener(callback);
9426 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009427 // Some small number to control number of times message handler should
9428 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009429 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009430 ExpectFalse(
9431 "var thrown = false;\n"
9432 "try { func(); } catch(e) { thrown = true; }\n"
9433 "thrown\n");
9434 if (callback != NULL) {
9435 V8::RemoveMessageListeners(callback);
9436 }
9437 }
9438}
9439
9440
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009441static v8::Handle<Value> ParentGetter(Local<String> name,
9442 const AccessorInfo& info) {
9443 ApiTestFuzzer::Fuzz();
9444 return v8_num(1);
9445}
9446
9447
9448static v8::Handle<Value> ChildGetter(Local<String> name,
9449 const AccessorInfo& info) {
9450 ApiTestFuzzer::Fuzz();
9451 return v8_num(42);
9452}
9453
9454
9455THREADED_TEST(Overriding) {
9456 v8::HandleScope scope;
9457 LocalContext context;
9458
9459 // Parent template.
9460 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9461 Local<ObjectTemplate> parent_instance_templ =
9462 parent_templ->InstanceTemplate();
9463 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9464
9465 // Template that inherits from the parent template.
9466 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9467 Local<ObjectTemplate> child_instance_templ =
9468 child_templ->InstanceTemplate();
9469 child_templ->Inherit(parent_templ);
9470 // Override 'f'. The child version of 'f' should get called for child
9471 // instances.
9472 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9473 // Add 'g' twice. The 'g' added last should get called for instances.
9474 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9475 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9476
9477 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9478 // so 'h' can be shadowed on the instance object.
9479 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9480 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9481 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9482
9483 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9484 // but the attribute does not have effect because it is duplicated with
9485 // NULL setter.
9486 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9487 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9488
9489
9490
9491 // Instantiate the child template.
9492 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9493
9494 // Check that the child function overrides the parent one.
9495 context->Global()->Set(v8_str("o"), instance);
9496 Local<Value> value = v8_compile("o.f")->Run();
9497 // Check that the 'g' that was added last is hit.
9498 CHECK_EQ(42, value->Int32Value());
9499 value = v8_compile("o.g")->Run();
9500 CHECK_EQ(42, value->Int32Value());
9501
9502 // Check 'h' can be shadowed.
9503 value = v8_compile("o.h = 3; o.h")->Run();
9504 CHECK_EQ(3, value->Int32Value());
9505
9506 // Check 'i' is cannot be shadowed or changed.
9507 value = v8_compile("o.i = 3; o.i")->Run();
9508 CHECK_EQ(42, value->Int32Value());
9509}
9510
9511
9512static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9513 ApiTestFuzzer::Fuzz();
9514 if (args.IsConstructCall()) {
9515 return v8::Boolean::New(true);
9516 }
9517 return v8::Boolean::New(false);
9518}
9519
9520
9521THREADED_TEST(IsConstructCall) {
9522 v8::HandleScope scope;
9523
9524 // Function template with call handler.
9525 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9526 templ->SetCallHandler(IsConstructHandler);
9527
9528 LocalContext context;
9529
9530 context->Global()->Set(v8_str("f"), templ->GetFunction());
9531 Local<Value> value = v8_compile("f()")->Run();
9532 CHECK(!value->BooleanValue());
9533 value = v8_compile("new f()")->Run();
9534 CHECK(value->BooleanValue());
9535}
9536
9537
9538THREADED_TEST(ObjectProtoToString) {
9539 v8::HandleScope scope;
9540 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9541 templ->SetClassName(v8_str("MyClass"));
9542
9543 LocalContext context;
9544
9545 Local<String> customized_tostring = v8_str("customized toString");
9546
9547 // Replace Object.prototype.toString
9548 v8_compile("Object.prototype.toString = function() {"
9549 " return 'customized toString';"
9550 "}")->Run();
9551
9552 // Normal ToString call should call replaced Object.prototype.toString
9553 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9554 Local<String> value = instance->ToString();
9555 CHECK(value->IsString() && value->Equals(customized_tostring));
9556
9557 // ObjectProtoToString should not call replace toString function.
9558 value = instance->ObjectProtoToString();
9559 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9560
9561 // Check global
9562 value = context->Global()->ObjectProtoToString();
9563 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9564
9565 // Check ordinary object
9566 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009567 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009568 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9569}
9570
9571
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009572THREADED_TEST(ObjectGetConstructorName) {
9573 v8::HandleScope scope;
9574 LocalContext context;
9575 v8_compile("function Parent() {};"
9576 "function Child() {};"
9577 "Child.prototype = new Parent();"
9578 "var outer = { inner: function() { } };"
9579 "var p = new Parent();"
9580 "var c = new Child();"
9581 "var x = new outer.inner();")->Run();
9582
9583 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9584 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9585 v8_str("Parent")));
9586
9587 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9588 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9589 v8_str("Child")));
9590
9591 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9592 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9593 v8_str("outer.inner")));
9594}
9595
9596
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009597bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009598i::Semaphore* ApiTestFuzzer::all_tests_done_=
9599 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009600int ApiTestFuzzer::active_tests_;
9601int ApiTestFuzzer::tests_being_run_;
9602int ApiTestFuzzer::current_;
9603
9604
9605// We are in a callback and want to switch to another thread (if we
9606// are currently running the thread fuzzing test).
9607void ApiTestFuzzer::Fuzz() {
9608 if (!fuzzing_) return;
9609 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9610 test->ContextSwitch();
9611}
9612
9613
9614// Let the next thread go. Since it is also waiting on the V8 lock it may
9615// not start immediately.
9616bool ApiTestFuzzer::NextThread() {
9617 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009618 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009619 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009620 if (kLogThreading)
9621 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009622 return false;
9623 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009624 if (kLogThreading) {
9625 printf("Switch from %s to %s\n",
9626 test_name,
9627 RegisterThreadedTest::nth(test_position)->name());
9628 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009629 current_ = test_position;
9630 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9631 return true;
9632}
9633
9634
9635void ApiTestFuzzer::Run() {
9636 // When it is our turn...
9637 gate_->Wait();
9638 {
9639 // ... get the V8 lock and start running the test.
9640 v8::Locker locker;
9641 CallTest();
9642 }
9643 // This test finished.
9644 active_ = false;
9645 active_tests_--;
9646 // If it was the last then signal that fact.
9647 if (active_tests_ == 0) {
9648 all_tests_done_->Signal();
9649 } else {
9650 // Otherwise select a new test and start that.
9651 NextThread();
9652 }
9653}
9654
9655
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009656static unsigned linear_congruential_generator;
9657
9658
9659void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009660 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009661 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +00009662 int count = RegisterThreadedTest::count();
9663 int start = count * part / (LAST_PART + 1);
9664 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9665 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009666 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009667 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009668 }
9669 for (int i = 0; i < active_tests_; i++) {
9670 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9671 }
9672}
9673
9674
9675static void CallTestNumber(int test_number) {
9676 (RegisterThreadedTest::nth(test_number)->callback())();
9677}
9678
9679
9680void ApiTestFuzzer::RunAllTests() {
9681 // Set off the first test.
9682 current_ = -1;
9683 NextThread();
9684 // Wait till they are all done.
9685 all_tests_done_->Wait();
9686}
9687
9688
9689int ApiTestFuzzer::GetNextTestNumber() {
9690 int next_test;
9691 do {
9692 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9693 linear_congruential_generator *= 1664525u;
9694 linear_congruential_generator += 1013904223u;
9695 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9696 return next_test;
9697}
9698
9699
9700void ApiTestFuzzer::ContextSwitch() {
9701 // If the new thread is the same as the current thread there is nothing to do.
9702 if (NextThread()) {
9703 // Now it can start.
9704 v8::Unlocker unlocker;
9705 // Wait till someone starts us again.
9706 gate_->Wait();
9707 // And we're off.
9708 }
9709}
9710
9711
9712void ApiTestFuzzer::TearDown() {
9713 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009714 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9715 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9716 if (fuzzer != NULL) fuzzer->Join();
9717 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009718}
9719
9720
9721// Lets not be needlessly self-referential.
9722TEST(Threading) {
9723 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9724 ApiTestFuzzer::RunAllTests();
9725 ApiTestFuzzer::TearDown();
9726}
9727
9728TEST(Threading2) {
9729 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9730 ApiTestFuzzer::RunAllTests();
9731 ApiTestFuzzer::TearDown();
9732}
9733
lrn@chromium.org1c092762011-05-09 09:42:16 +00009734TEST(Threading3) {
9735 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9736 ApiTestFuzzer::RunAllTests();
9737 ApiTestFuzzer::TearDown();
9738}
9739
9740TEST(Threading4) {
9741 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9742 ApiTestFuzzer::RunAllTests();
9743 ApiTestFuzzer::TearDown();
9744}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009745
9746void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009747 if (kLogThreading)
9748 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009749 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009750 if (kLogThreading)
9751 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009752}
9753
9754
9755static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009756 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009757 ApiTestFuzzer::Fuzz();
9758 v8::Unlocker unlocker;
9759 const char* code = "throw 7;";
9760 {
9761 v8::Locker nested_locker;
9762 v8::HandleScope scope;
9763 v8::Handle<Value> exception;
9764 { v8::TryCatch try_catch;
9765 v8::Handle<Value> value = CompileRun(code);
9766 CHECK(value.IsEmpty());
9767 CHECK(try_catch.HasCaught());
9768 // Make sure to wrap the exception in a new handle because
9769 // the handle returned from the TryCatch is destroyed
9770 // when the TryCatch is destroyed.
9771 exception = Local<Value>::New(try_catch.Exception());
9772 }
9773 return v8::ThrowException(exception);
9774 }
9775}
9776
9777
9778static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009779 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009780 ApiTestFuzzer::Fuzz();
9781 v8::Unlocker unlocker;
9782 const char* code = "throw 7;";
9783 {
9784 v8::Locker nested_locker;
9785 v8::HandleScope scope;
9786 v8::Handle<Value> value = CompileRun(code);
9787 CHECK(value.IsEmpty());
9788 return v8_str("foo");
9789 }
9790}
9791
9792
9793// These are locking tests that don't need to be run again
9794// as part of the locking aggregation tests.
9795TEST(NestedLockers) {
9796 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009797 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009798 v8::HandleScope scope;
9799 LocalContext env;
9800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9801 Local<Function> fun = fun_templ->GetFunction();
9802 env->Global()->Set(v8_str("throw_in_js"), fun);
9803 Local<Script> script = v8_compile("(function () {"
9804 " try {"
9805 " throw_in_js();"
9806 " return 42;"
9807 " } catch (e) {"
9808 " return e * 13;"
9809 " }"
9810 "})();");
9811 CHECK_EQ(91, script->Run()->Int32Value());
9812}
9813
9814
9815// These are locking tests that don't need to be run again
9816// as part of the locking aggregation tests.
9817TEST(NestedLockersNoTryCatch) {
9818 v8::Locker locker;
9819 v8::HandleScope scope;
9820 LocalContext env;
9821 Local<v8::FunctionTemplate> fun_templ =
9822 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9823 Local<Function> fun = fun_templ->GetFunction();
9824 env->Global()->Set(v8_str("throw_in_js"), fun);
9825 Local<Script> script = v8_compile("(function () {"
9826 " try {"
9827 " throw_in_js();"
9828 " return 42;"
9829 " } catch (e) {"
9830 " return e * 13;"
9831 " }"
9832 "})();");
9833 CHECK_EQ(91, script->Run()->Int32Value());
9834}
9835
9836
9837THREADED_TEST(RecursiveLocking) {
9838 v8::Locker locker;
9839 {
9840 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009841 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009842 }
9843}
9844
9845
9846static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9847 ApiTestFuzzer::Fuzz();
9848 v8::Unlocker unlocker;
9849 return v8::Undefined();
9850}
9851
9852
9853THREADED_TEST(LockUnlockLock) {
9854 {
9855 v8::Locker locker;
9856 v8::HandleScope scope;
9857 LocalContext env;
9858 Local<v8::FunctionTemplate> fun_templ =
9859 v8::FunctionTemplate::New(UnlockForAMoment);
9860 Local<Function> fun = fun_templ->GetFunction();
9861 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9862 Local<Script> script = v8_compile("(function () {"
9863 " unlock_for_a_moment();"
9864 " return 42;"
9865 "})();");
9866 CHECK_EQ(42, script->Run()->Int32Value());
9867 }
9868 {
9869 v8::Locker locker;
9870 v8::HandleScope scope;
9871 LocalContext env;
9872 Local<v8::FunctionTemplate> fun_templ =
9873 v8::FunctionTemplate::New(UnlockForAMoment);
9874 Local<Function> fun = fun_templ->GetFunction();
9875 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9876 Local<Script> script = v8_compile("(function () {"
9877 " unlock_for_a_moment();"
9878 " return 42;"
9879 "})();");
9880 CHECK_EQ(42, script->Run()->Int32Value());
9881 }
9882}
9883
9884
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009885static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009886 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009887 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009888 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9889 if (object->IsJSGlobalObject()) count++;
9890 return count;
9891}
9892
9893
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009894static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009895 // We need to collect all garbage twice to be sure that everything
9896 // has been collected. This is because inline caches are cleared in
9897 // the first garbage collection but some of the maps have already
9898 // been marked at that point. Therefore some of the maps are not
9899 // collected until the second garbage collection.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009900 HEAP->global_context_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009901 HEAP->CollectAllGarbage(false);
9902 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009903 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009904#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009905 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009906#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009907 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009908}
9909
9910
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009911TEST(DontLeakGlobalObjects) {
9912 // Regression test for issues 1139850 and 1174891.
9913
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009914 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009915
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009916 for (int i = 0; i < 5; i++) {
9917 { v8::HandleScope scope;
9918 LocalContext context;
9919 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009920 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009921
9922 { v8::HandleScope scope;
9923 LocalContext context;
9924 v8_compile("Date")->Run();
9925 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009926 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009927
9928 { v8::HandleScope scope;
9929 LocalContext context;
9930 v8_compile("/aaa/")->Run();
9931 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009932 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009933
9934 { v8::HandleScope scope;
9935 const char* extension_list[] = { "v8/gc" };
9936 v8::ExtensionConfiguration extensions(1, extension_list);
9937 LocalContext context(&extensions);
9938 v8_compile("gc();")->Run();
9939 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009940 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009941 }
9942}
9943
9944
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009945v8::Persistent<v8::Object> some_object;
9946v8::Persistent<v8::Object> bad_handle;
9947
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009948void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009949 v8::HandleScope scope;
9950 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009951 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009952}
9953
9954
9955THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9956 LocalContext context;
9957
9958 v8::Persistent<v8::Object> handle1, handle2;
9959 {
9960 v8::HandleScope scope;
9961 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9962 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9963 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9964 }
9965 // Note: order is implementation dependent alas: currently
9966 // global handle nodes are processed by PostGarbageCollectionProcessing
9967 // in reverse allocation order, so if second allocated handle is deleted,
9968 // weak callback of the first handle would be able to 'reallocate' it.
9969 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9970 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009972}
9973
9974
9975v8::Persistent<v8::Object> to_be_disposed;
9976
9977void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9978 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009979 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009980 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009981}
9982
9983
9984THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9985 LocalContext context;
9986
9987 v8::Persistent<v8::Object> handle1, handle2;
9988 {
9989 v8::HandleScope scope;
9990 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9991 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9992 }
9993 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9994 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009996}
9997
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009998void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9999 handle.Dispose();
10000}
10001
10002void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10003 v8::HandleScope scope;
10004 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000010005 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010006}
10007
10008
10009THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10010 LocalContext context;
10011
10012 v8::Persistent<v8::Object> handle1, handle2, handle3;
10013 {
10014 v8::HandleScope scope;
10015 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10016 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10017 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10018 }
10019 handle2.MakeWeak(NULL, DisposingCallback);
10020 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010022}
10023
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010024
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010025THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010026 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010027
10028 const int nof = 2;
10029 const char* sources[nof] = {
10030 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10031 "Object()"
10032 };
10033
10034 for (int i = 0; i < nof; i++) {
10035 const char* source = sources[i];
10036 { v8::HandleScope scope;
10037 LocalContext context;
10038 CompileRun(source);
10039 }
10040 { v8::HandleScope scope;
10041 LocalContext context;
10042 CompileRun(source);
10043 }
10044 }
10045}
10046
10047
10048static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10049 v8::HandleScope inner;
10050 env->Enter();
10051 v8::Handle<Value> three = v8_num(3);
10052 v8::Handle<Value> value = inner.Close(three);
10053 env->Exit();
10054 return value;
10055}
10056
10057
10058THREADED_TEST(NestedHandleScopeAndContexts) {
10059 v8::HandleScope outer;
10060 v8::Persistent<Context> env = Context::New();
10061 env->Enter();
10062 v8::Handle<Value> value = NestedScope(env);
10063 v8::Handle<String> str = value->ToString();
10064 env->Exit();
10065 env.Dispose();
10066}
10067
10068
10069THREADED_TEST(ExternalAllocatedMemory) {
10070 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010071 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010072 const int kSize = 1024*1024;
10073 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10074 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10075}
10076
10077
10078THREADED_TEST(DisposeEnteredContext) {
10079 v8::HandleScope scope;
10080 LocalContext outer;
10081 { v8::Persistent<v8::Context> inner = v8::Context::New();
10082 inner->Enter();
10083 inner.Dispose();
10084 inner.Clear();
10085 inner->Exit();
10086 }
10087}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010088
10089
10090// Regression test for issue 54, object templates with internal fields
10091// but no accessors or interceptors did not get their internal field
10092// count set on instances.
10093THREADED_TEST(Regress54) {
10094 v8::HandleScope outer;
10095 LocalContext context;
10096 static v8::Persistent<v8::ObjectTemplate> templ;
10097 if (templ.IsEmpty()) {
10098 v8::HandleScope inner;
10099 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10100 local->SetInternalFieldCount(1);
10101 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10102 }
10103 v8::Handle<v8::Object> result = templ->NewInstance();
10104 CHECK_EQ(1, result->InternalFieldCount());
10105}
10106
10107
10108// If part of the threaded tests, this test makes ThreadingTest fail
10109// on mac.
10110TEST(CatchStackOverflow) {
10111 v8::HandleScope scope;
10112 LocalContext context;
10113 v8::TryCatch try_catch;
10114 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10115 "function f() {"
10116 " return f();"
10117 "}"
10118 ""
10119 "f();"));
10120 v8::Handle<v8::Value> result = script->Run();
10121 CHECK(result.IsEmpty());
10122}
10123
10124
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010125static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10126 const char* resource_name,
10127 int line_offset) {
10128 v8::HandleScope scope;
10129 v8::TryCatch try_catch;
10130 v8::Handle<v8::Value> result = script->Run();
10131 CHECK(result.IsEmpty());
10132 CHECK(try_catch.HasCaught());
10133 v8::Handle<v8::Message> message = try_catch.Message();
10134 CHECK(!message.IsEmpty());
10135 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10136 CHECK_EQ(91, message->GetStartPosition());
10137 CHECK_EQ(92, message->GetEndPosition());
10138 CHECK_EQ(2, message->GetStartColumn());
10139 CHECK_EQ(3, message->GetEndColumn());
10140 v8::String::AsciiValue line(message->GetSourceLine());
10141 CHECK_EQ(" throw 'nirk';", *line);
10142 v8::String::AsciiValue name(message->GetScriptResourceName());
10143 CHECK_EQ(resource_name, *name);
10144}
10145
10146
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010147THREADED_TEST(TryCatchSourceInfo) {
10148 v8::HandleScope scope;
10149 LocalContext context;
10150 v8::Handle<v8::String> source = v8::String::New(
10151 "function Foo() {\n"
10152 " return Bar();\n"
10153 "}\n"
10154 "\n"
10155 "function Bar() {\n"
10156 " return Baz();\n"
10157 "}\n"
10158 "\n"
10159 "function Baz() {\n"
10160 " throw 'nirk';\n"
10161 "}\n"
10162 "\n"
10163 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010164
10165 const char* resource_name;
10166 v8::Handle<v8::Script> script;
10167 resource_name = "test.js";
10168 script = v8::Script::Compile(source, v8::String::New(resource_name));
10169 CheckTryCatchSourceInfo(script, resource_name, 0);
10170
10171 resource_name = "test1.js";
10172 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10173 script = v8::Script::Compile(source, &origin1);
10174 CheckTryCatchSourceInfo(script, resource_name, 0);
10175
10176 resource_name = "test2.js";
10177 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10178 script = v8::Script::Compile(source, &origin2);
10179 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010180}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010181
10182
10183THREADED_TEST(CompilationCache) {
10184 v8::HandleScope scope;
10185 LocalContext context;
10186 v8::Handle<v8::String> source0 = v8::String::New("1234");
10187 v8::Handle<v8::String> source1 = v8::String::New("1234");
10188 v8::Handle<v8::Script> script0 =
10189 v8::Script::Compile(source0, v8::String::New("test.js"));
10190 v8::Handle<v8::Script> script1 =
10191 v8::Script::Compile(source1, v8::String::New("test.js"));
10192 v8::Handle<v8::Script> script2 =
10193 v8::Script::Compile(source0); // different origin
10194 CHECK_EQ(1234, script0->Run()->Int32Value());
10195 CHECK_EQ(1234, script1->Run()->Int32Value());
10196 CHECK_EQ(1234, script2->Run()->Int32Value());
10197}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010198
10199
10200static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10201 ApiTestFuzzer::Fuzz();
10202 return v8_num(42);
10203}
10204
10205
10206THREADED_TEST(CallbackFunctionName) {
10207 v8::HandleScope scope;
10208 LocalContext context;
10209 Local<ObjectTemplate> t = ObjectTemplate::New();
10210 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10211 context->Global()->Set(v8_str("obj"), t->NewInstance());
10212 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10213 CHECK(value->IsString());
10214 v8::String::AsciiValue name(value);
10215 CHECK_EQ("asdf", *name);
10216}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010217
10218
10219THREADED_TEST(DateAccess) {
10220 v8::HandleScope scope;
10221 LocalContext context;
10222 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10223 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010224 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010225}
10226
10227
10228void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010229 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010230 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10231 CHECK_EQ(elmc, props->Length());
10232 for (int i = 0; i < elmc; i++) {
10233 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10234 CHECK_EQ(elmv[i], *elm);
10235 }
10236}
10237
10238
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010239void CheckOwnProperties(v8::Handle<v8::Value> val,
10240 int elmc,
10241 const char* elmv[]) {
10242 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10243 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10244 CHECK_EQ(elmc, props->Length());
10245 for (int i = 0; i < elmc; i++) {
10246 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10247 CHECK_EQ(elmv[i], *elm);
10248 }
10249}
10250
10251
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010252THREADED_TEST(PropertyEnumeration) {
10253 v8::HandleScope scope;
10254 LocalContext context;
10255 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10256 "var result = [];"
10257 "result[0] = {};"
10258 "result[1] = {a: 1, b: 2};"
10259 "result[2] = [1, 2, 3];"
10260 "var proto = {x: 1, y: 2, z: 3};"
10261 "var x = { __proto__: proto, w: 0, z: 1 };"
10262 "result[3] = x;"
10263 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010264 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010265 CHECK_EQ(4, elms->Length());
10266 int elmc0 = 0;
10267 const char** elmv0 = NULL;
10268 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010269 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010270 int elmc1 = 2;
10271 const char* elmv1[] = {"a", "b"};
10272 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010273 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010274 int elmc2 = 3;
10275 const char* elmv2[] = {"0", "1", "2"};
10276 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010277 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010278 int elmc3 = 4;
10279 const char* elmv3[] = {"w", "z", "x", "y"};
10280 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010281 int elmc4 = 2;
10282 const char* elmv4[] = {"w", "z"};
10283 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010284}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286THREADED_TEST(PropertyEnumeration2) {
10287 v8::HandleScope scope;
10288 LocalContext context;
10289 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10290 "var result = [];"
10291 "result[0] = {};"
10292 "result[1] = {a: 1, b: 2};"
10293 "result[2] = [1, 2, 3];"
10294 "var proto = {x: 1, y: 2, z: 3};"
10295 "var x = { __proto__: proto, w: 0, z: 1 };"
10296 "result[3] = x;"
10297 "result;"))->Run();
10298 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10299 CHECK_EQ(4, elms->Length());
10300 int elmc0 = 0;
10301 const char** elmv0 = NULL;
10302 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10303
10304 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10305 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10306 CHECK_EQ(0, props->Length());
10307 for (uint32_t i = 0; i < props->Length(); i++) {
10308 printf("p[%d]\n", i);
10309 }
10310}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010311
ager@chromium.org870a0b62008-11-04 11:43:05 +000010312static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10313 Local<Value> name,
10314 v8::AccessType type,
10315 Local<Value> data) {
10316 return type != v8::ACCESS_SET;
10317}
10318
10319
10320static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10321 uint32_t key,
10322 v8::AccessType type,
10323 Local<Value> data) {
10324 return type != v8::ACCESS_SET;
10325}
10326
10327
10328THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10329 v8::HandleScope scope;
10330 LocalContext context;
10331 Local<ObjectTemplate> templ = ObjectTemplate::New();
10332 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10333 IndexedSetAccessBlocker);
10334 templ->Set(v8_str("x"), v8::True());
10335 Local<v8::Object> instance = templ->NewInstance();
10336 context->Global()->Set(v8_str("obj"), instance);
10337 Local<Value> value = CompileRun("obj.x");
10338 CHECK(value->BooleanValue());
10339}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010340
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010341
ager@chromium.org32912102009-01-16 10:38:43 +000010342static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10343 Local<Value> name,
10344 v8::AccessType type,
10345 Local<Value> data) {
10346 return false;
10347}
10348
10349
10350static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10351 uint32_t key,
10352 v8::AccessType type,
10353 Local<Value> data) {
10354 return false;
10355}
10356
10357
10358
10359THREADED_TEST(AccessChecksReenabledCorrectly) {
10360 v8::HandleScope scope;
10361 LocalContext context;
10362 Local<ObjectTemplate> templ = ObjectTemplate::New();
10363 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10364 IndexedGetAccessBlocker);
10365 templ->Set(v8_str("a"), v8_str("a"));
10366 // Add more than 8 (see kMaxFastProperties) properties
10367 // so that the constructor will force copying map.
10368 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010369 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010370 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010371 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010372 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010373 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010374 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010375 buf[2] = k;
10376 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010377 templ->Set(v8_str(buf), v8::Number::New(k));
10378 }
10379 }
10380 }
10381
10382 Local<v8::Object> instance_1 = templ->NewInstance();
10383 context->Global()->Set(v8_str("obj_1"), instance_1);
10384
10385 Local<Value> value_1 = CompileRun("obj_1.a");
10386 CHECK(value_1->IsUndefined());
10387
10388 Local<v8::Object> instance_2 = templ->NewInstance();
10389 context->Global()->Set(v8_str("obj_2"), instance_2);
10390
10391 Local<Value> value_2 = CompileRun("obj_2.a");
10392 CHECK(value_2->IsUndefined());
10393}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010394
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010395
ager@chromium.org8bb60582008-12-11 12:02:20 +000010396// This tests that access check information remains on the global
10397// object template when creating contexts.
10398THREADED_TEST(AccessControlRepeatedContextCreation) {
10399 v8::HandleScope handle_scope;
10400 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10401 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10402 IndexedSetAccessBlocker);
10403 i::Handle<i::ObjectTemplateInfo> internal_template =
10404 v8::Utils::OpenHandle(*global_template);
10405 CHECK(!internal_template->constructor()->IsUndefined());
10406 i::Handle<i::FunctionTemplateInfo> constructor(
10407 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10408 CHECK(!constructor->access_check_info()->IsUndefined());
10409 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10410 CHECK(!constructor->access_check_info()->IsUndefined());
10411}
10412
10413
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010414THREADED_TEST(TurnOnAccessCheck) {
10415 v8::HandleScope handle_scope;
10416
10417 // Create an environment with access check to the global object disabled by
10418 // default.
10419 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10420 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10421 IndexedGetAccessBlocker,
10422 v8::Handle<v8::Value>(),
10423 false);
10424 v8::Persistent<Context> context = Context::New(NULL, global_template);
10425 Context::Scope context_scope(context);
10426
10427 // Set up a property and a number of functions.
10428 context->Global()->Set(v8_str("a"), v8_num(1));
10429 CompileRun("function f1() {return a;}"
10430 "function f2() {return a;}"
10431 "function g1() {return h();}"
10432 "function g2() {return h();}"
10433 "function h() {return 1;}");
10434 Local<Function> f1 =
10435 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10436 Local<Function> f2 =
10437 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10438 Local<Function> g1 =
10439 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10440 Local<Function> g2 =
10441 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10442 Local<Function> h =
10443 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10444
10445 // Get the global object.
10446 v8::Handle<v8::Object> global = context->Global();
10447
10448 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10449 // uses the runtime system to retreive property a whereas f2 uses global load
10450 // inline cache.
10451 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10452 for (int i = 0; i < 4; i++) {
10453 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10454 }
10455
10456 // Same for g1 and g2.
10457 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10458 for (int i = 0; i < 4; i++) {
10459 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10460 }
10461
10462 // Detach the global and turn on access check.
10463 context->DetachGlobal();
10464 context->Global()->TurnOnAccessCheck();
10465
10466 // Failing access check to property get results in undefined.
10467 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10468 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10469
10470 // Failing access check to function call results in exception.
10471 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10472 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10473
10474 // No failing access check when just returning a constant.
10475 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10476}
10477
10478
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010479v8::Handle<v8::String> a;
10480v8::Handle<v8::String> h;
10481
10482static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10483 Local<Value> name,
10484 v8::AccessType type,
10485 Local<Value> data) {
10486 return !(name->Equals(a) || name->Equals(h));
10487}
10488
10489
10490THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10491 v8::HandleScope handle_scope;
10492
10493 // Create an environment with access check to the global object disabled by
10494 // default. When the registered access checker will block access to properties
10495 // a and h
10496 a = v8_str("a");
10497 h = v8_str("h");
10498 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10499 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10500 IndexedGetAccessBlocker,
10501 v8::Handle<v8::Value>(),
10502 false);
10503 v8::Persistent<Context> context = Context::New(NULL, global_template);
10504 Context::Scope context_scope(context);
10505
10506 // Set up a property and a number of functions.
10507 context->Global()->Set(v8_str("a"), v8_num(1));
10508 static const char* source = "function f1() {return a;}"
10509 "function f2() {return a;}"
10510 "function g1() {return h();}"
10511 "function g2() {return h();}"
10512 "function h() {return 1;}";
10513
10514 CompileRun(source);
10515 Local<Function> f1;
10516 Local<Function> f2;
10517 Local<Function> g1;
10518 Local<Function> g2;
10519 Local<Function> h;
10520 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10521 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10522 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10523 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10524 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10525
10526 // Get the global object.
10527 v8::Handle<v8::Object> global = context->Global();
10528
10529 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10530 // uses the runtime system to retreive property a whereas f2 uses global load
10531 // inline cache.
10532 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10533 for (int i = 0; i < 4; i++) {
10534 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10535 }
10536
10537 // Same for g1 and g2.
10538 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10539 for (int i = 0; i < 4; i++) {
10540 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10541 }
10542
10543 // Detach the global and turn on access check now blocking access to property
10544 // a and function h.
10545 context->DetachGlobal();
10546 context->Global()->TurnOnAccessCheck();
10547
10548 // Failing access check to property get results in undefined.
10549 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10550 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10551
10552 // Failing access check to function call results in exception.
10553 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10554 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10555
10556 // No failing access check when just returning a constant.
10557 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10558
10559 // Now compile the source again. And get the newly compiled functions, except
10560 // for h for which access is blocked.
10561 CompileRun(source);
10562 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10563 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10564 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10565 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10566 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10567
10568 // Failing access check to property get results in undefined.
10569 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10570 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10571
10572 // Failing access check to function call results in exception.
10573 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10574 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10575}
10576
10577
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010578// This test verifies that pre-compilation (aka preparsing) can be called
10579// without initializing the whole VM. Thus we cannot run this test in a
10580// multi-threaded setup.
10581TEST(PreCompile) {
10582 // TODO(155): This test would break without the initialization of V8. This is
10583 // a workaround for now to make this test not fail.
10584 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010585 const char* script = "function foo(a) { return a+1; }";
10586 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010587 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010588 CHECK_NE(sd->Length(), 0);
10589 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010590 CHECK(!sd->HasError());
10591 delete sd;
10592}
10593
10594
10595TEST(PreCompileWithError) {
10596 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010597 const char* script = "function foo(a) { return 1 * * 2; }";
10598 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010599 v8::ScriptData::PreCompile(script, i::StrLength(script));
10600 CHECK(sd->HasError());
10601 delete sd;
10602}
10603
10604
10605TEST(Regress31661) {
10606 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010607 const char* script = " The Definintive Guide";
10608 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010609 v8::ScriptData::PreCompile(script, i::StrLength(script));
10610 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010611 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010612}
10613
10614
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010615// Tests that ScriptData can be serialized and deserialized.
10616TEST(PreCompileSerialization) {
10617 v8::V8::Initialize();
10618 const char* script = "function foo(a) { return a+1; }";
10619 v8::ScriptData* sd =
10620 v8::ScriptData::PreCompile(script, i::StrLength(script));
10621
10622 // Serialize.
10623 int serialized_data_length = sd->Length();
10624 char* serialized_data = i::NewArray<char>(serialized_data_length);
10625 memcpy(serialized_data, sd->Data(), serialized_data_length);
10626
10627 // Deserialize.
10628 v8::ScriptData* deserialized_sd =
10629 v8::ScriptData::New(serialized_data, serialized_data_length);
10630
10631 // Verify that the original is the same as the deserialized.
10632 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10633 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10634 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10635
10636 delete sd;
10637 delete deserialized_sd;
10638}
10639
10640
10641// Attempts to deserialize bad data.
10642TEST(PreCompileDeserializationError) {
10643 v8::V8::Initialize();
10644 const char* data = "DONT CARE";
10645 int invalid_size = 3;
10646 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10647
10648 CHECK_EQ(0, sd->Length());
10649
10650 delete sd;
10651}
10652
10653
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010654// Attempts to deserialize bad data.
10655TEST(PreCompileInvalidPreparseDataError) {
10656 v8::V8::Initialize();
10657 v8::HandleScope scope;
10658 LocalContext context;
10659
10660 const char* script = "function foo(){ return 5;}\n"
10661 "function bar(){ return 6 + 7;} foo();";
10662 v8::ScriptData* sd =
10663 v8::ScriptData::PreCompile(script, i::StrLength(script));
10664 CHECK(!sd->HasError());
10665 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010666 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000010667 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010668 const int kFunctionEntryStartOffset = 0;
10669 const int kFunctionEntryEndOffset = 1;
10670 unsigned* sd_data =
10671 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010672
10673 // Overwrite function bar's end position with 0.
10674 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10675 v8::TryCatch try_catch;
10676
10677 Local<String> source = String::New(script);
10678 Local<Script> compiled_script = Script::New(source, NULL, sd);
10679 CHECK(try_catch.HasCaught());
10680 String::AsciiValue exception_value(try_catch.Message()->Get());
10681 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10682 *exception_value);
10683
10684 try_catch.Reset();
10685 // Overwrite function bar's start position with 200. The function entry
10686 // will not be found when searching for it by position.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000010687 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10688 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010689 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10690 200;
10691 compiled_script = Script::New(source, NULL, sd);
10692 CHECK(try_catch.HasCaught());
10693 String::AsciiValue second_exception_value(try_catch.Message()->Get());
10694 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10695 *second_exception_value);
10696
10697 delete sd;
10698}
10699
10700
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010701// Verifies that the Handle<String> and const char* versions of the API produce
10702// the same results (at least for one trivial case).
10703TEST(PreCompileAPIVariationsAreSame) {
10704 v8::V8::Initialize();
10705 v8::HandleScope scope;
10706
10707 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010708
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010709 v8::ScriptData* sd_from_cstring =
10710 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10711
10712 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010713 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010714 v8::String::NewExternal(resource));
10715
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010716 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10717 v8::String::New(cstring));
10718
10719 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010720 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010721 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010722 sd_from_cstring->Length()));
10723
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010724 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10725 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10726 sd_from_string->Data(),
10727 sd_from_cstring->Length()));
10728
10729
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010730 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010731 delete sd_from_external_string;
10732 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010733}
10734
10735
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010736// This tests that we do not allow dictionary load/call inline caches
10737// to use functions that have not yet been compiled. The potential
10738// problem of loading a function that has not yet been compiled can
10739// arise because we share code between contexts via the compilation
10740// cache.
10741THREADED_TEST(DictionaryICLoadedFunction) {
10742 v8::HandleScope scope;
10743 // Test LoadIC.
10744 for (int i = 0; i < 2; i++) {
10745 LocalContext context;
10746 context->Global()->Set(v8_str("tmp"), v8::True());
10747 context->Global()->Delete(v8_str("tmp"));
10748 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10749 }
10750 // Test CallIC.
10751 for (int i = 0; i < 2; i++) {
10752 LocalContext context;
10753 context->Global()->Set(v8_str("tmp"), v8::True());
10754 context->Global()->Delete(v8_str("tmp"));
10755 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10756 }
10757}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010758
10759
10760// Test that cross-context new calls use the context of the callee to
10761// create the new JavaScript object.
10762THREADED_TEST(CrossContextNew) {
10763 v8::HandleScope scope;
10764 v8::Persistent<Context> context0 = Context::New();
10765 v8::Persistent<Context> context1 = Context::New();
10766
10767 // Allow cross-domain access.
10768 Local<String> token = v8_str("<security token>");
10769 context0->SetSecurityToken(token);
10770 context1->SetSecurityToken(token);
10771
10772 // Set an 'x' property on the Object prototype and define a
10773 // constructor function in context0.
10774 context0->Enter();
10775 CompileRun("Object.prototype.x = 42; function C() {};");
10776 context0->Exit();
10777
10778 // Call the constructor function from context0 and check that the
10779 // result has the 'x' property.
10780 context1->Enter();
10781 context1->Global()->Set(v8_str("other"), context0->Global());
10782 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10783 CHECK(value->IsInt32());
10784 CHECK_EQ(42, value->Int32Value());
10785 context1->Exit();
10786
10787 // Dispose the contexts to allow them to be garbage collected.
10788 context0.Dispose();
10789 context1.Dispose();
10790}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010791
10792
10793class RegExpInterruptTest {
10794 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010795 RegExpInterruptTest() : block_(NULL) {}
10796 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010797 void RunTest() {
10798 block_ = i::OS::CreateSemaphore(0);
10799 gc_count_ = 0;
10800 gc_during_regexp_ = 0;
10801 regexp_success_ = false;
10802 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010803 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010804 gc_thread.Start();
10805 v8::Locker::StartPreemption(1);
10806
10807 LongRunningRegExp();
10808 {
10809 v8::Unlocker unlock;
10810 gc_thread.Join();
10811 }
10812 v8::Locker::StopPreemption();
10813 CHECK(regexp_success_);
10814 CHECK(gc_success_);
10815 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010816
ager@chromium.org381abbb2009-02-25 13:23:22 +000010817 private:
10818 // Number of garbage collections required.
10819 static const int kRequiredGCs = 5;
10820
10821 class GCThread : public i::Thread {
10822 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010823 explicit GCThread(RegExpInterruptTest* test)
10824 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010825 virtual void Run() {
10826 test_->CollectGarbage();
10827 }
10828 private:
10829 RegExpInterruptTest* test_;
10830 };
10831
10832 void CollectGarbage() {
10833 block_->Wait();
10834 while (gc_during_regexp_ < kRequiredGCs) {
10835 {
10836 v8::Locker lock;
10837 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010839 gc_count_++;
10840 }
10841 i::OS::Sleep(1);
10842 }
10843 gc_success_ = true;
10844 }
10845
10846 void LongRunningRegExp() {
10847 block_->Signal(); // Enable garbage collection thread on next preemption.
10848 int rounds = 0;
10849 while (gc_during_regexp_ < kRequiredGCs) {
10850 int gc_before = gc_count_;
10851 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010852 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010853 const char* c_source =
10854 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10855 ".exec('aaaaaaaaaaaaaaab') === null";
10856 Local<String> source = String::New(c_source);
10857 Local<Script> script = Script::Compile(source);
10858 Local<Value> result = script->Run();
10859 if (!result->BooleanValue()) {
10860 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10861 return;
10862 }
10863 }
10864 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010865 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010866 const char* c_source =
10867 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10868 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10869 Local<String> source = String::New(c_source);
10870 Local<Script> script = Script::Compile(source);
10871 Local<Value> result = script->Run();
10872 if (!result->BooleanValue()) {
10873 gc_during_regexp_ = kRequiredGCs;
10874 return;
10875 }
10876 }
10877 int gc_after = gc_count_;
10878 gc_during_regexp_ += gc_after - gc_before;
10879 rounds++;
10880 i::OS::Sleep(1);
10881 }
10882 regexp_success_ = true;
10883 }
10884
10885 i::Semaphore* block_;
10886 int gc_count_;
10887 int gc_during_regexp_;
10888 bool regexp_success_;
10889 bool gc_success_;
10890};
10891
10892
10893// Test that a regular expression execution can be interrupted and
10894// survive a garbage collection.
10895TEST(RegExpInterruption) {
10896 v8::Locker lock;
10897 v8::V8::Initialize();
10898 v8::HandleScope scope;
10899 Local<Context> local_env;
10900 {
10901 LocalContext env;
10902 local_env = env.local();
10903 }
10904
10905 // Local context should still be live.
10906 CHECK(!local_env.IsEmpty());
10907 local_env->Enter();
10908
10909 // Should complete without problems.
10910 RegExpInterruptTest().RunTest();
10911
10912 local_env->Exit();
10913}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010914
10915
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010916class ApplyInterruptTest {
10917 public:
10918 ApplyInterruptTest() : block_(NULL) {}
10919 ~ApplyInterruptTest() { delete block_; }
10920 void RunTest() {
10921 block_ = i::OS::CreateSemaphore(0);
10922 gc_count_ = 0;
10923 gc_during_apply_ = 0;
10924 apply_success_ = false;
10925 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010926 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010927 gc_thread.Start();
10928 v8::Locker::StartPreemption(1);
10929
10930 LongRunningApply();
10931 {
10932 v8::Unlocker unlock;
10933 gc_thread.Join();
10934 }
10935 v8::Locker::StopPreemption();
10936 CHECK(apply_success_);
10937 CHECK(gc_success_);
10938 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010939
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010940 private:
10941 // Number of garbage collections required.
10942 static const int kRequiredGCs = 2;
10943
10944 class GCThread : public i::Thread {
10945 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010946 explicit GCThread(ApplyInterruptTest* test)
10947 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010948 virtual void Run() {
10949 test_->CollectGarbage();
10950 }
10951 private:
10952 ApplyInterruptTest* test_;
10953 };
10954
10955 void CollectGarbage() {
10956 block_->Wait();
10957 while (gc_during_apply_ < kRequiredGCs) {
10958 {
10959 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010961 gc_count_++;
10962 }
10963 i::OS::Sleep(1);
10964 }
10965 gc_success_ = true;
10966 }
10967
10968 void LongRunningApply() {
10969 block_->Signal();
10970 int rounds = 0;
10971 while (gc_during_apply_ < kRequiredGCs) {
10972 int gc_before = gc_count_;
10973 {
10974 const char* c_source =
10975 "function do_very_little(bar) {"
10976 " this.foo = bar;"
10977 "}"
10978 "for (var i = 0; i < 100000; i++) {"
10979 " do_very_little.apply(this, ['bar']);"
10980 "}";
10981 Local<String> source = String::New(c_source);
10982 Local<Script> script = Script::Compile(source);
10983 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010984 // Check that no exception was thrown.
10985 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010986 }
10987 int gc_after = gc_count_;
10988 gc_during_apply_ += gc_after - gc_before;
10989 rounds++;
10990 }
10991 apply_success_ = true;
10992 }
10993
10994 i::Semaphore* block_;
10995 int gc_count_;
10996 int gc_during_apply_;
10997 bool apply_success_;
10998 bool gc_success_;
10999};
11000
11001
11002// Test that nothing bad happens if we get a preemption just when we were
11003// about to do an apply().
11004TEST(ApplyInterruption) {
11005 v8::Locker lock;
11006 v8::V8::Initialize();
11007 v8::HandleScope scope;
11008 Local<Context> local_env;
11009 {
11010 LocalContext env;
11011 local_env = env.local();
11012 }
11013
11014 // Local context should still be live.
11015 CHECK(!local_env.IsEmpty());
11016 local_env->Enter();
11017
11018 // Should complete without problems.
11019 ApplyInterruptTest().RunTest();
11020
11021 local_env->Exit();
11022}
11023
11024
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011025// Verify that we can clone an object
11026TEST(ObjectClone) {
11027 v8::HandleScope scope;
11028 LocalContext env;
11029
11030 const char* sample =
11031 "var rv = {};" \
11032 "rv.alpha = 'hello';" \
11033 "rv.beta = 123;" \
11034 "rv;";
11035
11036 // Create an object, verify basics.
11037 Local<Value> val = CompileRun(sample);
11038 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011039 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011040 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11041
11042 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11043 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11044 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11045
11046 // Clone it.
11047 Local<v8::Object> clone = obj->Clone();
11048 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11049 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11050 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11051
11052 // Set a property on the clone, verify each object.
11053 clone->Set(v8_str("beta"), v8::Integer::New(456));
11054 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11055 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11056}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011057
11058
ager@chromium.org5ec48922009-05-05 07:25:34 +000011059class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11060 public:
11061 explicit AsciiVectorResource(i::Vector<const char> vector)
11062 : data_(vector) {}
11063 virtual ~AsciiVectorResource() {}
11064 virtual size_t length() const { return data_.length(); }
11065 virtual const char* data() const { return data_.start(); }
11066 private:
11067 i::Vector<const char> data_;
11068};
11069
11070
11071class UC16VectorResource : public v8::String::ExternalStringResource {
11072 public:
11073 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11074 : data_(vector) {}
11075 virtual ~UC16VectorResource() {}
11076 virtual size_t length() const { return data_.length(); }
11077 virtual const i::uc16* data() const { return data_.start(); }
11078 private:
11079 i::Vector<const i::uc16> data_;
11080};
11081
11082
11083static void MorphAString(i::String* string,
11084 AsciiVectorResource* ascii_resource,
11085 UC16VectorResource* uc16_resource) {
11086 CHECK(i::StringShape(string).IsExternal());
11087 if (string->IsAsciiRepresentation()) {
11088 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011089 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011090 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011091 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011092 i::ExternalTwoByteString* morphed =
11093 i::ExternalTwoByteString::cast(string);
11094 morphed->set_resource(uc16_resource);
11095 } else {
11096 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011097 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011098 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011100 i::ExternalAsciiString* morphed =
11101 i::ExternalAsciiString::cast(string);
11102 morphed->set_resource(ascii_resource);
11103 }
11104}
11105
11106
11107// Test that we can still flatten a string if the components it is built up
11108// from have been turned into 16 bit strings in the mean time.
11109THREADED_TEST(MorphCompositeStringTest) {
11110 const char* c_string = "Now is the time for all good men"
11111 " to come to the aid of the party";
11112 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11113 {
11114 v8::HandleScope scope;
11115 LocalContext env;
11116 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011117 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011118 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011119 i::Vector<const uint16_t>(two_byte_string,
11120 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011121
11122 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011124 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011125 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011126
11127 env->Global()->Set(v8_str("lhs"), lhs);
11128 env->Global()->Set(v8_str("rhs"), rhs);
11129
11130 CompileRun(
11131 "var cons = lhs + rhs;"
11132 "var slice = lhs.substring(1, lhs.length - 1);"
11133 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11134
11135 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11136 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11137
11138 // Now do some stuff to make sure the strings are flattened, etc.
11139 CompileRun(
11140 "/[^a-z]/.test(cons);"
11141 "/[^a-z]/.test(slice);"
11142 "/[^a-z]/.test(slice_on_cons);");
11143 const char* expected_cons =
11144 "Now is the time for all good men to come to the aid of the party"
11145 "Now is the time for all good men to come to the aid of the party";
11146 const char* expected_slice =
11147 "ow is the time for all good men to come to the aid of the part";
11148 const char* expected_slice_on_cons =
11149 "ow is the time for all good men to come to the aid of the party"
11150 "Now is the time for all good men to come to the aid of the part";
11151 CHECK_EQ(String::New(expected_cons),
11152 env->Global()->Get(v8_str("cons")));
11153 CHECK_EQ(String::New(expected_slice),
11154 env->Global()->Get(v8_str("slice")));
11155 CHECK_EQ(String::New(expected_slice_on_cons),
11156 env->Global()->Get(v8_str("slice_on_cons")));
11157 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011158 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011159}
11160
11161
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011162TEST(CompileExternalTwoByteSource) {
11163 v8::HandleScope scope;
11164 LocalContext context;
11165
11166 // This is a very short list of sources, which currently is to check for a
11167 // regression caused by r2703.
11168 const char* ascii_sources[] = {
11169 "0.5",
11170 "-0.5", // This mainly testes PushBack in the Scanner.
11171 "--0.5", // This mainly testes PushBack in the Scanner.
11172 NULL
11173 };
11174
11175 // Compile the sources as external two byte strings.
11176 for (int i = 0; ascii_sources[i] != NULL; i++) {
11177 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11178 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011179 i::Vector<const uint16_t>(two_byte_string,
11180 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011181 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11182 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011183 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011184 }
11185}
11186
11187
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011188class RegExpStringModificationTest {
11189 public:
11190 RegExpStringModificationTest()
11191 : block_(i::OS::CreateSemaphore(0)),
11192 morphs_(0),
11193 morphs_during_regexp_(0),
11194 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11195 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11196 ~RegExpStringModificationTest() { delete block_; }
11197 void RunTest() {
11198 regexp_success_ = false;
11199 morph_success_ = false;
11200
11201 // Initialize the contents of two_byte_content_ to be a uc16 representation
11202 // of "aaaaaaaaaaaaaab".
11203 for (int i = 0; i < 14; i++) {
11204 two_byte_content_[i] = 'a';
11205 }
11206 two_byte_content_[14] = 'b';
11207
11208 // Create the input string for the regexp - the one we are going to change
11209 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011210 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011211
11212 // Inject the input as a global variable.
11213 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11215 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011216 *input_name,
11217 *input_,
11218 NONE,
11219 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011220
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011221 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011222 morph_thread.Start();
11223 v8::Locker::StartPreemption(1);
11224 LongRunningRegExp();
11225 {
11226 v8::Unlocker unlock;
11227 morph_thread.Join();
11228 }
11229 v8::Locker::StopPreemption();
11230 CHECK(regexp_success_);
11231 CHECK(morph_success_);
11232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011233
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011234 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011235 // Number of string modifications required.
11236 static const int kRequiredModifications = 5;
11237 static const int kMaxModifications = 100;
11238
11239 class MorphThread : public i::Thread {
11240 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011241 explicit MorphThread(RegExpStringModificationTest* test)
11242 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011243 virtual void Run() {
11244 test_->MorphString();
11245 }
11246 private:
11247 RegExpStringModificationTest* test_;
11248 };
11249
11250 void MorphString() {
11251 block_->Wait();
11252 while (morphs_during_regexp_ < kRequiredModifications &&
11253 morphs_ < kMaxModifications) {
11254 {
11255 v8::Locker lock;
11256 // Swap string between ascii and two-byte representation.
11257 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011258 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011259 morphs_++;
11260 }
11261 i::OS::Sleep(1);
11262 }
11263 morph_success_ = true;
11264 }
11265
11266 void LongRunningRegExp() {
11267 block_->Signal(); // Enable morphing thread on next preemption.
11268 while (morphs_during_regexp_ < kRequiredModifications &&
11269 morphs_ < kMaxModifications) {
11270 int morphs_before = morphs_;
11271 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011272 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011273 // Match 15-30 "a"'s against 14 and a "b".
11274 const char* c_source =
11275 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11276 ".exec(input) === null";
11277 Local<String> source = String::New(c_source);
11278 Local<Script> script = Script::Compile(source);
11279 Local<Value> result = script->Run();
11280 CHECK(result->IsTrue());
11281 }
11282 int morphs_after = morphs_;
11283 morphs_during_regexp_ += morphs_after - morphs_before;
11284 }
11285 regexp_success_ = true;
11286 }
11287
11288 i::uc16 two_byte_content_[15];
11289 i::Semaphore* block_;
11290 int morphs_;
11291 int morphs_during_regexp_;
11292 bool regexp_success_;
11293 bool morph_success_;
11294 i::Handle<i::String> input_;
11295 AsciiVectorResource ascii_resource_;
11296 UC16VectorResource uc16_resource_;
11297};
11298
11299
11300// Test that a regular expression execution can be interrupted and
11301// the string changed without failing.
11302TEST(RegExpStringModification) {
11303 v8::Locker lock;
11304 v8::V8::Initialize();
11305 v8::HandleScope scope;
11306 Local<Context> local_env;
11307 {
11308 LocalContext env;
11309 local_env = env.local();
11310 }
11311
11312 // Local context should still be live.
11313 CHECK(!local_env.IsEmpty());
11314 local_env->Enter();
11315
11316 // Should complete without problems.
11317 RegExpStringModificationTest().RunTest();
11318
11319 local_env->Exit();
11320}
11321
11322
11323// Test that we can set a property on the global object even if there
11324// is a read-only property in the prototype chain.
11325TEST(ReadOnlyPropertyInGlobalProto) {
11326 v8::HandleScope scope;
11327 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11328 LocalContext context(0, templ);
11329 v8::Handle<v8::Object> global = context->Global();
11330 v8::Handle<v8::Object> global_proto =
11331 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11332 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11333 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11334 // Check without 'eval' or 'with'.
11335 v8::Handle<v8::Value> res =
11336 CompileRun("function f() { x = 42; return x; }; f()");
11337 // Check with 'eval'.
11338 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11339 CHECK_EQ(v8::Integer::New(42), res);
11340 // Check with 'with'.
11341 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11342 CHECK_EQ(v8::Integer::New(42), res);
11343}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011344
11345static int force_set_set_count = 0;
11346static int force_set_get_count = 0;
11347bool pass_on_get = false;
11348
11349static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11350 const v8::AccessorInfo& info) {
11351 force_set_get_count++;
11352 if (pass_on_get) {
11353 return v8::Handle<v8::Value>();
11354 } else {
11355 return v8::Int32::New(3);
11356 }
11357}
11358
11359static void ForceSetSetter(v8::Local<v8::String> name,
11360 v8::Local<v8::Value> value,
11361 const v8::AccessorInfo& info) {
11362 force_set_set_count++;
11363}
11364
11365static v8::Handle<v8::Value> ForceSetInterceptSetter(
11366 v8::Local<v8::String> name,
11367 v8::Local<v8::Value> value,
11368 const v8::AccessorInfo& info) {
11369 force_set_set_count++;
11370 return v8::Undefined();
11371}
11372
11373TEST(ForceSet) {
11374 force_set_get_count = 0;
11375 force_set_set_count = 0;
11376 pass_on_get = false;
11377
11378 v8::HandleScope scope;
11379 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11380 v8::Handle<v8::String> access_property = v8::String::New("a");
11381 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11382 LocalContext context(NULL, templ);
11383 v8::Handle<v8::Object> global = context->Global();
11384
11385 // Ordinary properties
11386 v8::Handle<v8::String> simple_property = v8::String::New("p");
11387 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11388 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11389 // This should fail because the property is read-only
11390 global->Set(simple_property, v8::Int32::New(5));
11391 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11392 // This should succeed even though the property is read-only
11393 global->ForceSet(simple_property, v8::Int32::New(6));
11394 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11395
11396 // Accessors
11397 CHECK_EQ(0, force_set_set_count);
11398 CHECK_EQ(0, force_set_get_count);
11399 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11400 // CHECK_EQ the property shouldn't override it, just call the setter
11401 // which in this case does nothing.
11402 global->Set(access_property, v8::Int32::New(7));
11403 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11404 CHECK_EQ(1, force_set_set_count);
11405 CHECK_EQ(2, force_set_get_count);
11406 // Forcing the property to be set should override the accessor without
11407 // calling it
11408 global->ForceSet(access_property, v8::Int32::New(8));
11409 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11410 CHECK_EQ(1, force_set_set_count);
11411 CHECK_EQ(2, force_set_get_count);
11412}
11413
11414TEST(ForceSetWithInterceptor) {
11415 force_set_get_count = 0;
11416 force_set_set_count = 0;
11417 pass_on_get = false;
11418
11419 v8::HandleScope scope;
11420 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11421 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11422 LocalContext context(NULL, templ);
11423 v8::Handle<v8::Object> global = context->Global();
11424
11425 v8::Handle<v8::String> some_property = v8::String::New("a");
11426 CHECK_EQ(0, force_set_set_count);
11427 CHECK_EQ(0, force_set_get_count);
11428 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11429 // Setting the property shouldn't override it, just call the setter
11430 // which in this case does nothing.
11431 global->Set(some_property, v8::Int32::New(7));
11432 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11433 CHECK_EQ(1, force_set_set_count);
11434 CHECK_EQ(2, force_set_get_count);
11435 // Getting the property when the interceptor returns an empty handle
11436 // should yield undefined, since the property isn't present on the
11437 // object itself yet.
11438 pass_on_get = true;
11439 CHECK(global->Get(some_property)->IsUndefined());
11440 CHECK_EQ(1, force_set_set_count);
11441 CHECK_EQ(3, force_set_get_count);
11442 // Forcing the property to be set should cause the value to be
11443 // set locally without calling the interceptor.
11444 global->ForceSet(some_property, v8::Int32::New(8));
11445 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11446 CHECK_EQ(1, force_set_set_count);
11447 CHECK_EQ(4, force_set_get_count);
11448 // Reenabling the interceptor should cause it to take precedence over
11449 // the property
11450 pass_on_get = false;
11451 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11452 CHECK_EQ(1, force_set_set_count);
11453 CHECK_EQ(5, force_set_get_count);
11454 // The interceptor should also work for other properties
11455 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11456 CHECK_EQ(1, force_set_set_count);
11457 CHECK_EQ(6, force_set_get_count);
11458}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011459
11460
ager@chromium.orge2902be2009-06-08 12:21:35 +000011461THREADED_TEST(ForceDelete) {
11462 v8::HandleScope scope;
11463 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11464 LocalContext context(NULL, templ);
11465 v8::Handle<v8::Object> global = context->Global();
11466
11467 // Ordinary properties
11468 v8::Handle<v8::String> simple_property = v8::String::New("p");
11469 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11470 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11471 // This should fail because the property is dont-delete.
11472 CHECK(!global->Delete(simple_property));
11473 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11474 // This should succeed even though the property is dont-delete.
11475 CHECK(global->ForceDelete(simple_property));
11476 CHECK(global->Get(simple_property)->IsUndefined());
11477}
11478
11479
11480static int force_delete_interceptor_count = 0;
11481static bool pass_on_delete = false;
11482
11483
11484static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11485 v8::Local<v8::String> name,
11486 const v8::AccessorInfo& info) {
11487 force_delete_interceptor_count++;
11488 if (pass_on_delete) {
11489 return v8::Handle<v8::Boolean>();
11490 } else {
11491 return v8::True();
11492 }
11493}
11494
11495
11496THREADED_TEST(ForceDeleteWithInterceptor) {
11497 force_delete_interceptor_count = 0;
11498 pass_on_delete = false;
11499
11500 v8::HandleScope scope;
11501 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11502 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11503 LocalContext context(NULL, templ);
11504 v8::Handle<v8::Object> global = context->Global();
11505
11506 v8::Handle<v8::String> some_property = v8::String::New("a");
11507 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11508
11509 // Deleting a property should get intercepted and nothing should
11510 // happen.
11511 CHECK_EQ(0, force_delete_interceptor_count);
11512 CHECK(global->Delete(some_property));
11513 CHECK_EQ(1, force_delete_interceptor_count);
11514 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11515 // Deleting the property when the interceptor returns an empty
11516 // handle should not delete the property since it is DontDelete.
11517 pass_on_delete = true;
11518 CHECK(!global->Delete(some_property));
11519 CHECK_EQ(2, force_delete_interceptor_count);
11520 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11521 // Forcing the property to be deleted should delete the value
11522 // without calling the interceptor.
11523 CHECK(global->ForceDelete(some_property));
11524 CHECK(global->Get(some_property)->IsUndefined());
11525 CHECK_EQ(2, force_delete_interceptor_count);
11526}
11527
11528
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011529// Make sure that forcing a delete invalidates any IC stubs, so we
11530// don't read the hole value.
11531THREADED_TEST(ForceDeleteIC) {
11532 v8::HandleScope scope;
11533 LocalContext context;
11534 // Create a DontDelete variable on the global object.
11535 CompileRun("this.__proto__ = { foo: 'horse' };"
11536 "var foo = 'fish';"
11537 "function f() { return foo.length; }");
11538 // Initialize the IC for foo in f.
11539 CompileRun("for (var i = 0; i < 4; i++) f();");
11540 // Make sure the value of foo is correct before the deletion.
11541 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11542 // Force the deletion of foo.
11543 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11544 // Make sure the value for foo is read from the prototype, and that
11545 // we don't get in trouble with reading the deleted cell value
11546 // sentinel.
11547 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11548}
11549
11550
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011551v8::Persistent<Context> calling_context0;
11552v8::Persistent<Context> calling_context1;
11553v8::Persistent<Context> calling_context2;
11554
11555
11556// Check that the call to the callback is initiated in
11557// calling_context2, the directly calling context is calling_context1
11558// and the callback itself is in calling_context0.
11559static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11560 ApiTestFuzzer::Fuzz();
11561 CHECK(Context::GetCurrent() == calling_context0);
11562 CHECK(Context::GetCalling() == calling_context1);
11563 CHECK(Context::GetEntered() == calling_context2);
11564 return v8::Integer::New(42);
11565}
11566
11567
11568THREADED_TEST(GetCallingContext) {
11569 v8::HandleScope scope;
11570
11571 calling_context0 = Context::New();
11572 calling_context1 = Context::New();
11573 calling_context2 = Context::New();
11574
11575 // Allow cross-domain access.
11576 Local<String> token = v8_str("<security token>");
11577 calling_context0->SetSecurityToken(token);
11578 calling_context1->SetSecurityToken(token);
11579 calling_context2->SetSecurityToken(token);
11580
11581 // Create an object with a C++ callback in context0.
11582 calling_context0->Enter();
11583 Local<v8::FunctionTemplate> callback_templ =
11584 v8::FunctionTemplate::New(GetCallingContextCallback);
11585 calling_context0->Global()->Set(v8_str("callback"),
11586 callback_templ->GetFunction());
11587 calling_context0->Exit();
11588
11589 // Expose context0 in context1 and setup a function that calls the
11590 // callback function.
11591 calling_context1->Enter();
11592 calling_context1->Global()->Set(v8_str("context0"),
11593 calling_context0->Global());
11594 CompileRun("function f() { context0.callback() }");
11595 calling_context1->Exit();
11596
11597 // Expose context1 in context2 and call the callback function in
11598 // context0 indirectly through f in context1.
11599 calling_context2->Enter();
11600 calling_context2->Global()->Set(v8_str("context1"),
11601 calling_context1->Global());
11602 CompileRun("context1.f()");
11603 calling_context2->Exit();
11604
11605 // Dispose the contexts to allow them to be garbage collected.
11606 calling_context0.Dispose();
11607 calling_context1.Dispose();
11608 calling_context2.Dispose();
11609 calling_context0.Clear();
11610 calling_context1.Clear();
11611 calling_context2.Clear();
11612}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011613
11614
11615// Check that a variable declaration with no explicit initialization
11616// value does not shadow an existing property in the prototype chain.
11617//
11618// This is consistent with Firefox and Safari.
11619//
11620// See http://crbug.com/12548.
11621THREADED_TEST(InitGlobalVarInProtoChain) {
11622 v8::HandleScope scope;
11623 LocalContext context;
11624 // Introduce a variable in the prototype chain.
11625 CompileRun("__proto__.x = 42");
11626 v8::Handle<v8::Value> result = CompileRun("var x; x");
11627 CHECK(!result->IsUndefined());
11628 CHECK_EQ(42, result->Int32Value());
11629}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011630
11631
11632// Regression test for issue 398.
11633// If a function is added to an object, creating a constant function
11634// field, and the result is cloned, replacing the constant function on the
11635// original should not affect the clone.
11636// See http://code.google.com/p/v8/issues/detail?id=398
11637THREADED_TEST(ReplaceConstantFunction) {
11638 v8::HandleScope scope;
11639 LocalContext context;
11640 v8::Handle<v8::Object> obj = v8::Object::New();
11641 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11642 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11643 obj->Set(foo_string, func_templ->GetFunction());
11644 v8::Handle<v8::Object> obj_clone = obj->Clone();
11645 obj_clone->Set(foo_string, v8::String::New("Hello"));
11646 CHECK(!obj->Get(foo_string)->IsUndefined());
11647}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000011648
11649
11650// Regression test for http://crbug.com/16276.
11651THREADED_TEST(Regress16276) {
11652 v8::HandleScope scope;
11653 LocalContext context;
11654 // Force the IC in f to be a dictionary load IC.
11655 CompileRun("function f(obj) { return obj.x; }\n"
11656 "var obj = { x: { foo: 42 }, y: 87 };\n"
11657 "var x = obj.x;\n"
11658 "delete obj.y;\n"
11659 "for (var i = 0; i < 5; i++) f(obj);");
11660 // Detach the global object to make 'this' refer directly to the
11661 // global object (not the proxy), and make sure that the dictionary
11662 // load IC doesn't mess up loading directly from the global object.
11663 context->DetachGlobal();
11664 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11665}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011666
11667
11668THREADED_TEST(PixelArray) {
11669 v8::HandleScope scope;
11670 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011671 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011672 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011673 i::Handle<i::ExternalPixelArray> pixels =
11674 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011676 v8::kExternalPixelArray,
11677 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011679 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011680 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011681 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011683 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011684 CHECK_EQ(i % 256, pixels->get(i));
11685 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011686 }
11687
11688 v8::Handle<v8::Object> obj = v8::Object::New();
11689 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11690 // Set the elements to be the pixels.
11691 // jsobj->set_elements(*pixels);
11692 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011693 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011694 obj->Set(v8_str("field"), v8::Int32::New(1503));
11695 context->Global()->Set(v8_str("pixels"), obj);
11696 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11697 CHECK_EQ(1503, result->Int32Value());
11698 result = CompileRun("pixels[1]");
11699 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011700
11701 result = CompileRun("var sum = 0;"
11702 "for (var i = 0; i < 8; i++) {"
11703 " sum += pixels[i] = pixels[i] = -i;"
11704 "}"
11705 "sum;");
11706 CHECK_EQ(-28, result->Int32Value());
11707
11708 result = CompileRun("var sum = 0;"
11709 "for (var i = 0; i < 8; i++) {"
11710 " sum += pixels[i] = pixels[i] = 0;"
11711 "}"
11712 "sum;");
11713 CHECK_EQ(0, result->Int32Value());
11714
11715 result = CompileRun("var sum = 0;"
11716 "for (var i = 0; i < 8; i++) {"
11717 " sum += pixels[i] = pixels[i] = 255;"
11718 "}"
11719 "sum;");
11720 CHECK_EQ(8 * 255, result->Int32Value());
11721
11722 result = CompileRun("var sum = 0;"
11723 "for (var i = 0; i < 8; i++) {"
11724 " sum += pixels[i] = pixels[i] = 256 + i;"
11725 "}"
11726 "sum;");
11727 CHECK_EQ(2076, result->Int32Value());
11728
11729 result = CompileRun("var sum = 0;"
11730 "for (var i = 0; i < 8; i++) {"
11731 " sum += pixels[i] = pixels[i] = i;"
11732 "}"
11733 "sum;");
11734 CHECK_EQ(28, result->Int32Value());
11735
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011736 result = CompileRun("var sum = 0;"
11737 "for (var i = 0; i < 8; i++) {"
11738 " sum += pixels[i];"
11739 "}"
11740 "sum;");
11741 CHECK_EQ(28, result->Int32Value());
11742
11743 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011744 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011745 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011746 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011747 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011748 CHECK_EQ(255,
11749 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011750 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011751 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011752 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011753
11754 result = CompileRun("for (var i = 0; i < 8; i++) {"
11755 " pixels[i] = (i * 65) - 109;"
11756 "}"
11757 "pixels[1] + pixels[6];");
11758 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011759 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11760 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11761 CHECK_EQ(21,
11762 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11763 CHECK_EQ(86,
11764 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11765 CHECK_EQ(151,
11766 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11767 CHECK_EQ(216,
11768 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11769 CHECK_EQ(255,
11770 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11771 CHECK_EQ(255,
11772 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011773 result = CompileRun("var sum = 0;"
11774 "for (var i = 0; i < 8; i++) {"
11775 " sum += pixels[i];"
11776 "}"
11777 "sum;");
11778 CHECK_EQ(984, result->Int32Value());
11779
11780 result = CompileRun("for (var i = 0; i < 8; i++) {"
11781 " pixels[i] = (i * 1.1);"
11782 "}"
11783 "pixels[1] + pixels[6];");
11784 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011785 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11786 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11787 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11788 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11789 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11790 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11791 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11792 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011793
11794 result = CompileRun("for (var i = 0; i < 8; i++) {"
11795 " pixels[7] = undefined;"
11796 "}"
11797 "pixels[7];");
11798 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011799 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011800
11801 result = CompileRun("for (var i = 0; i < 8; i++) {"
11802 " pixels[6] = '2.3';"
11803 "}"
11804 "pixels[6];");
11805 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011806 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011807
11808 result = CompileRun("for (var i = 0; i < 8; i++) {"
11809 " pixels[5] = NaN;"
11810 "}"
11811 "pixels[5];");
11812 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011813 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011814
11815 result = CompileRun("for (var i = 0; i < 8; i++) {"
11816 " pixels[8] = Infinity;"
11817 "}"
11818 "pixels[8];");
11819 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011820 CHECK_EQ(255,
11821 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011822
11823 result = CompileRun("for (var i = 0; i < 8; i++) {"
11824 " pixels[9] = -Infinity;"
11825 "}"
11826 "pixels[9];");
11827 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011828 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011829
11830 result = CompileRun("pixels[3] = 33;"
11831 "delete pixels[3];"
11832 "pixels[3];");
11833 CHECK_EQ(33, result->Int32Value());
11834
11835 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11836 "pixels[2] = 12; pixels[3] = 13;"
11837 "pixels.__defineGetter__('2',"
11838 "function() { return 120; });"
11839 "pixels[2];");
11840 CHECK_EQ(12, result->Int32Value());
11841
11842 result = CompileRun("var js_array = new Array(40);"
11843 "js_array[0] = 77;"
11844 "js_array;");
11845 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11846
11847 result = CompileRun("pixels[1] = 23;"
11848 "pixels.__proto__ = [];"
11849 "js_array.__proto__ = pixels;"
11850 "js_array.concat(pixels);");
11851 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11852 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11853
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011854 result = CompileRun("pixels[1] = 23;");
11855 CHECK_EQ(23, result->Int32Value());
11856
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011857 // Test for index greater than 255. Regression test for:
11858 // http://code.google.com/p/chromium/issues/detail?id=26337.
11859 result = CompileRun("pixels[256] = 255;");
11860 CHECK_EQ(255, result->Int32Value());
11861 result = CompileRun("var i = 0;"
11862 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11863 "i");
11864 CHECK_EQ(255, result->Int32Value());
11865
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011866 // Make sure that pixel array ICs recognize when a non-pixel array
11867 // is passed to it.
11868 result = CompileRun("function pa_load(p) {"
11869 " var sum = 0;"
11870 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11871 " return sum;"
11872 "}"
11873 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11874 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11875 "just_ints = new Object();"
11876 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11877 "for (var i = 0; i < 10; ++i) {"
11878 " result = pa_load(just_ints);"
11879 "}"
11880 "result");
11881 CHECK_EQ(32640, result->Int32Value());
11882
11883 // Make sure that pixel array ICs recognize out-of-bound accesses.
11884 result = CompileRun("function pa_load(p, start) {"
11885 " var sum = 0;"
11886 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11887 " return sum;"
11888 "}"
11889 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11890 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11891 "for (var i = 0; i < 10; ++i) {"
11892 " result = pa_load(pixels,-10);"
11893 "}"
11894 "result");
11895 CHECK_EQ(0, result->Int32Value());
11896
11897 // Make sure that generic ICs properly handles a pixel array.
11898 result = CompileRun("function pa_load(p) {"
11899 " var sum = 0;"
11900 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11901 " return sum;"
11902 "}"
11903 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11904 "just_ints = new Object();"
11905 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11906 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11907 "for (var i = 0; i < 10; ++i) {"
11908 " result = pa_load(pixels);"
11909 "}"
11910 "result");
11911 CHECK_EQ(32640, result->Int32Value());
11912
11913 // Make sure that generic load ICs recognize out-of-bound accesses in
11914 // pixel arrays.
11915 result = CompileRun("function pa_load(p, start) {"
11916 " var sum = 0;"
11917 " for (var j = start; 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,0); }"
11924 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11925 "for (var i = 0; i < 10; ++i) {"
11926 " result = pa_load(pixels,-10);"
11927 "}"
11928 "result");
11929 CHECK_EQ(0, result->Int32Value());
11930
11931 // Make sure that generic ICs properly handles other types than pixel
11932 // arrays (that the inlined fast pixel array test leaves the right information
11933 // in the right registers).
11934 result = CompileRun("function pa_load(p) {"
11935 " var sum = 0;"
11936 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11937 " return sum;"
11938 "}"
11939 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11940 "just_ints = new Object();"
11941 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11942 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11943 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11944 "sparse_array = new Object();"
11945 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11946 "sparse_array[1000000] = 3;"
11947 "for (var i = 0; i < 10; ++i) {"
11948 " result = pa_load(sparse_array);"
11949 "}"
11950 "result");
11951 CHECK_EQ(32640, result->Int32Value());
11952
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011953 // Make sure that pixel array store ICs clamp values correctly.
11954 result = CompileRun("function pa_store(p) {"
11955 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11956 "}"
11957 "pa_store(pixels);"
11958 "var sum = 0;"
11959 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11960 "sum");
11961 CHECK_EQ(48896, result->Int32Value());
11962
11963 // Make sure that pixel array stores correctly handle accesses outside
11964 // of the pixel array..
11965 result = CompileRun("function pa_store(p,start) {"
11966 " for (var j = 0; j < 256; j++) {"
11967 " p[j+start] = j * 2;"
11968 " }"
11969 "}"
11970 "pa_store(pixels,0);"
11971 "pa_store(pixels,-128);"
11972 "var sum = 0;"
11973 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11974 "sum");
11975 CHECK_EQ(65280, result->Int32Value());
11976
11977 // Make sure that the generic store stub correctly handle accesses outside
11978 // of the pixel array..
11979 result = CompileRun("function pa_store(p,start) {"
11980 " for (var j = 0; j < 256; j++) {"
11981 " p[j+start] = j * 2;"
11982 " }"
11983 "}"
11984 "pa_store(pixels,0);"
11985 "just_ints = new Object();"
11986 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11987 "pa_store(just_ints, 0);"
11988 "pa_store(pixels,-128);"
11989 "var sum = 0;"
11990 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11991 "sum");
11992 CHECK_EQ(65280, result->Int32Value());
11993
11994 // Make sure that the generic keyed store stub clamps pixel array values
11995 // correctly.
11996 result = CompileRun("function pa_store(p) {"
11997 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11998 "}"
11999 "pa_store(pixels);"
12000 "just_ints = new Object();"
12001 "pa_store(just_ints);"
12002 "pa_store(pixels);"
12003 "var sum = 0;"
12004 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12005 "sum");
12006 CHECK_EQ(48896, result->Int32Value());
12007
12008 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012009 result = CompileRun("function pa_load(p) {"
12010 " var sum = 0;"
12011 " for (var i=0; i<256; ++i) {"
12012 " sum += p[i];"
12013 " }"
12014 " return sum; "
12015 "}"
12016 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012017 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012018 " result = pa_load(pixels);"
12019 "}"
12020 "result");
12021 CHECK_EQ(32640, result->Int32Value());
12022
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012023 // Make sure that pixel array stores are optimized by crankshaft.
12024 result = CompileRun("function pa_init(p) {"
12025 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12026 "}"
12027 "function pa_load(p) {"
12028 " var sum = 0;"
12029 " for (var i=0; i<256; ++i) {"
12030 " sum += p[i];"
12031 " }"
12032 " return sum; "
12033 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012034 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012035 " pa_init(pixels);"
12036 "}"
12037 "result = pa_load(pixels);"
12038 "result");
12039 CHECK_EQ(32640, result->Int32Value());
12040
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012041 free(pixel_data);
12042}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012043
ager@chromium.org96c75b52009-08-26 09:13:16 +000012044
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012045THREADED_TEST(PixelArrayInfo) {
12046 v8::HandleScope scope;
12047 LocalContext context;
12048 for (int size = 0; size < 100; size += 10) {
12049 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12050 v8::Handle<v8::Object> obj = v8::Object::New();
12051 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12052 CHECK(obj->HasIndexedPropertiesInPixelData());
12053 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12054 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12055 free(pixel_data);
12056 }
12057}
12058
12059
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012060static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12061 uint32_t index,
12062 const AccessorInfo& info) {
12063 ApiTestFuzzer::Fuzz();
12064 return v8::Handle<Value>();
12065}
12066
12067
12068static v8::Handle<Value> NotHandledIndexedPropertySetter(
12069 uint32_t index,
12070 Local<Value> value,
12071 const AccessorInfo& info) {
12072 ApiTestFuzzer::Fuzz();
12073 return v8::Handle<Value>();
12074}
12075
12076
12077THREADED_TEST(PixelArrayWithInterceptor) {
12078 v8::HandleScope scope;
12079 LocalContext context;
12080 const int kElementCount = 260;
12081 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012082 i::Handle<i::ExternalPixelArray> pixels =
12083 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012084 FACTORY->NewExternalArray(kElementCount,
12085 v8::kExternalPixelArray,
12086 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012087 for (int i = 0; i < kElementCount; i++) {
12088 pixels->set(i, i % 256);
12089 }
12090 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12091 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12092 NotHandledIndexedPropertySetter);
12093 v8::Handle<v8::Object> obj = templ->NewInstance();
12094 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12095 context->Global()->Set(v8_str("pixels"), obj);
12096 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12097 CHECK_EQ(1, result->Int32Value());
12098 result = CompileRun("var sum = 0;"
12099 "for (var i = 0; i < 8; i++) {"
12100 " sum += pixels[i] = pixels[i] = -i;"
12101 "}"
12102 "sum;");
12103 CHECK_EQ(-28, result->Int32Value());
12104 result = CompileRun("pixels.hasOwnProperty('1')");
12105 CHECK(result->BooleanValue());
12106 free(pixel_data);
12107}
12108
12109
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012110static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12111 switch (array_type) {
12112 case v8::kExternalByteArray:
12113 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012114 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012115 return 1;
12116 break;
12117 case v8::kExternalShortArray:
12118 case v8::kExternalUnsignedShortArray:
12119 return 2;
12120 break;
12121 case v8::kExternalIntArray:
12122 case v8::kExternalUnsignedIntArray:
12123 case v8::kExternalFloatArray:
12124 return 4;
12125 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012126 case v8::kExternalDoubleArray:
12127 return 8;
12128 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012129 default:
12130 UNREACHABLE();
12131 return -1;
12132 }
12133 UNREACHABLE();
12134 return -1;
12135}
12136
12137
ager@chromium.org3811b432009-10-28 14:53:37 +000012138template <class ExternalArrayClass, class ElementType>
12139static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12140 int64_t low,
12141 int64_t high) {
12142 v8::HandleScope scope;
12143 LocalContext context;
12144 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012145 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012146 ElementType* array_data =
12147 static_cast<ElementType*>(malloc(kElementCount * element_size));
12148 i::Handle<ExternalArrayClass> array =
12149 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12151 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012152 for (int i = 0; i < kElementCount; i++) {
12153 array->set(i, static_cast<ElementType>(i));
12154 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012156 for (int i = 0; i < kElementCount; i++) {
12157 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
12158 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12159 }
12160
12161 v8::Handle<v8::Object> obj = v8::Object::New();
12162 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12163 // Set the elements to be the external array.
12164 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12165 array_type,
12166 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012167 CHECK_EQ(
12168 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012169 obj->Set(v8_str("field"), v8::Int32::New(1503));
12170 context->Global()->Set(v8_str("ext_array"), obj);
12171 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12172 CHECK_EQ(1503, result->Int32Value());
12173 result = CompileRun("ext_array[1]");
12174 CHECK_EQ(1, result->Int32Value());
12175
12176 // Check pass through of assigned smis
12177 result = CompileRun("var sum = 0;"
12178 "for (var i = 0; i < 8; i++) {"
12179 " sum += ext_array[i] = ext_array[i] = -i;"
12180 "}"
12181 "sum;");
12182 CHECK_EQ(-28, result->Int32Value());
12183
12184 // Check assigned smis
12185 result = CompileRun("for (var i = 0; i < 8; i++) {"
12186 " ext_array[i] = i;"
12187 "}"
12188 "var sum = 0;"
12189 "for (var i = 0; i < 8; i++) {"
12190 " sum += ext_array[i];"
12191 "}"
12192 "sum;");
12193 CHECK_EQ(28, result->Int32Value());
12194
12195 // Check assigned smis in reverse order
12196 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12197 " ext_array[i] = i;"
12198 "}"
12199 "var sum = 0;"
12200 "for (var i = 0; i < 8; i++) {"
12201 " sum += ext_array[i];"
12202 "}"
12203 "sum;");
12204 CHECK_EQ(28, result->Int32Value());
12205
12206 // Check pass through of assigned HeapNumbers
12207 result = CompileRun("var sum = 0;"
12208 "for (var i = 0; i < 16; i+=2) {"
12209 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12210 "}"
12211 "sum;");
12212 CHECK_EQ(-28, result->Int32Value());
12213
12214 // Check assigned HeapNumbers
12215 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12216 " ext_array[i] = (i * 0.5);"
12217 "}"
12218 "var sum = 0;"
12219 "for (var i = 0; i < 16; i+=2) {"
12220 " sum += ext_array[i];"
12221 "}"
12222 "sum;");
12223 CHECK_EQ(28, result->Int32Value());
12224
12225 // Check assigned HeapNumbers in reverse order
12226 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12227 " ext_array[i] = (i * 0.5);"
12228 "}"
12229 "var sum = 0;"
12230 "for (var i = 0; i < 16; i+=2) {"
12231 " sum += ext_array[i];"
12232 "}"
12233 "sum;");
12234 CHECK_EQ(28, result->Int32Value());
12235
12236 i::ScopedVector<char> test_buf(1024);
12237
12238 // Check legal boundary conditions.
12239 // The repeated loads and stores ensure the ICs are exercised.
12240 const char* boundary_program =
12241 "var res = 0;"
12242 "for (var i = 0; i < 16; i++) {"
12243 " ext_array[i] = %lld;"
12244 " if (i > 8) {"
12245 " res = ext_array[i];"
12246 " }"
12247 "}"
12248 "res;";
12249 i::OS::SNPrintF(test_buf,
12250 boundary_program,
12251 low);
12252 result = CompileRun(test_buf.start());
12253 CHECK_EQ(low, result->IntegerValue());
12254
12255 i::OS::SNPrintF(test_buf,
12256 boundary_program,
12257 high);
12258 result = CompileRun(test_buf.start());
12259 CHECK_EQ(high, result->IntegerValue());
12260
12261 // Check misprediction of type in IC.
12262 result = CompileRun("var tmp_array = ext_array;"
12263 "var sum = 0;"
12264 "for (var i = 0; i < 8; i++) {"
12265 " tmp_array[i] = i;"
12266 " sum += tmp_array[i];"
12267 " if (i == 4) {"
12268 " tmp_array = {};"
12269 " }"
12270 "}"
12271 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012273 CHECK_EQ(28, result->Int32Value());
12274
12275 // Make sure out-of-range loads do not throw.
12276 i::OS::SNPrintF(test_buf,
12277 "var caught_exception = false;"
12278 "try {"
12279 " ext_array[%d];"
12280 "} catch (e) {"
12281 " caught_exception = true;"
12282 "}"
12283 "caught_exception;",
12284 kElementCount);
12285 result = CompileRun(test_buf.start());
12286 CHECK_EQ(false, result->BooleanValue());
12287
12288 // Make sure out-of-range stores do not throw.
12289 i::OS::SNPrintF(test_buf,
12290 "var caught_exception = false;"
12291 "try {"
12292 " ext_array[%d] = 1;"
12293 "} catch (e) {"
12294 " caught_exception = true;"
12295 "}"
12296 "caught_exception;",
12297 kElementCount);
12298 result = CompileRun(test_buf.start());
12299 CHECK_EQ(false, result->BooleanValue());
12300
12301 // Check other boundary conditions, values and operations.
12302 result = CompileRun("for (var i = 0; i < 8; i++) {"
12303 " ext_array[7] = undefined;"
12304 "}"
12305 "ext_array[7];");
12306 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012307 CHECK_EQ(
12308 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012309
12310 result = CompileRun("for (var i = 0; i < 8; i++) {"
12311 " ext_array[6] = '2.3';"
12312 "}"
12313 "ext_array[6];");
12314 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012315 CHECK_EQ(
12316 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012317
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012318 if (array_type != v8::kExternalFloatArray &&
12319 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012320 // Though the specification doesn't state it, be explicit about
12321 // converting NaNs and +/-Infinity to zero.
12322 result = CompileRun("for (var i = 0; i < 8; i++) {"
12323 " ext_array[i] = 5;"
12324 "}"
12325 "for (var i = 0; i < 8; i++) {"
12326 " ext_array[i] = NaN;"
12327 "}"
12328 "ext_array[5];");
12329 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012330 CHECK_EQ(0,
12331 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012332
12333 result = CompileRun("for (var i = 0; i < 8; i++) {"
12334 " ext_array[i] = 5;"
12335 "}"
12336 "for (var i = 0; i < 8; i++) {"
12337 " ext_array[i] = Infinity;"
12338 "}"
12339 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012340 int expected_value =
12341 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12342 CHECK_EQ(expected_value, result->Int32Value());
12343 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012344 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012345
12346 result = CompileRun("for (var i = 0; i < 8; i++) {"
12347 " ext_array[i] = 5;"
12348 "}"
12349 "for (var i = 0; i < 8; i++) {"
12350 " ext_array[i] = -Infinity;"
12351 "}"
12352 "ext_array[5];");
12353 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012354 CHECK_EQ(0,
12355 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012356
12357 // Check truncation behavior of integral arrays.
12358 const char* unsigned_data =
12359 "var source_data = [0.6, 10.6];"
12360 "var expected_results = [0, 10];";
12361 const char* signed_data =
12362 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12363 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012364 const char* pixel_data =
12365 "var source_data = [0.6, 10.6];"
12366 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012367 bool is_unsigned =
12368 (array_type == v8::kExternalUnsignedByteArray ||
12369 array_type == v8::kExternalUnsignedShortArray ||
12370 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012371 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012372
12373 i::OS::SNPrintF(test_buf,
12374 "%s"
12375 "var all_passed = true;"
12376 "for (var i = 0; i < source_data.length; i++) {"
12377 " for (var j = 0; j < 8; j++) {"
12378 " ext_array[j] = source_data[i];"
12379 " }"
12380 " all_passed = all_passed &&"
12381 " (ext_array[5] == expected_results[i]);"
12382 "}"
12383 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012384 (is_unsigned ?
12385 unsigned_data :
12386 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012387 result = CompileRun(test_buf.start());
12388 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012389 }
12390
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012391 for (int i = 0; i < kElementCount; i++) {
12392 array->set(i, static_cast<ElementType>(i));
12393 }
12394 // Test complex assignments
12395 result = CompileRun("function ee_op_test_complex_func(sum) {"
12396 " for (var i = 0; i < 40; ++i) {"
12397 " sum += (ext_array[i] += 1);"
12398 " sum += (ext_array[i] -= 1);"
12399 " } "
12400 " return sum;"
12401 "}"
12402 "sum=0;"
12403 "for (var i=0;i<10000;++i) {"
12404 " sum=ee_op_test_complex_func(sum);"
12405 "}"
12406 "sum;");
12407 CHECK_EQ(16000000, result->Int32Value());
12408
12409 // Test count operations
12410 result = CompileRun("function ee_op_test_count_func(sum) {"
12411 " for (var i = 0; i < 40; ++i) {"
12412 " sum += (++ext_array[i]);"
12413 " sum += (--ext_array[i]);"
12414 " } "
12415 " return sum;"
12416 "}"
12417 "sum=0;"
12418 "for (var i=0;i<10000;++i) {"
12419 " sum=ee_op_test_count_func(sum);"
12420 "}"
12421 "sum;");
12422 CHECK_EQ(16000000, result->Int32Value());
12423
ager@chromium.org3811b432009-10-28 14:53:37 +000012424 result = CompileRun("ext_array[3] = 33;"
12425 "delete ext_array[3];"
12426 "ext_array[3];");
12427 CHECK_EQ(33, result->Int32Value());
12428
12429 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12430 "ext_array[2] = 12; ext_array[3] = 13;"
12431 "ext_array.__defineGetter__('2',"
12432 "function() { return 120; });"
12433 "ext_array[2];");
12434 CHECK_EQ(12, result->Int32Value());
12435
12436 result = CompileRun("var js_array = new Array(40);"
12437 "js_array[0] = 77;"
12438 "js_array;");
12439 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12440
12441 result = CompileRun("ext_array[1] = 23;"
12442 "ext_array.__proto__ = [];"
12443 "js_array.__proto__ = ext_array;"
12444 "js_array.concat(ext_array);");
12445 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12446 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12447
12448 result = CompileRun("ext_array[1] = 23;");
12449 CHECK_EQ(23, result->Int32Value());
12450
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012451 // Test more complex manipulations which cause eax to contain values
12452 // that won't be completely overwritten by loads from the arrays.
12453 // This catches bugs in the instructions used for the KeyedLoadIC
12454 // for byte and word types.
12455 {
12456 const int kXSize = 300;
12457 const int kYSize = 300;
12458 const int kLargeElementCount = kXSize * kYSize * 4;
12459 ElementType* large_array_data =
12460 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12461 i::Handle<ExternalArrayClass> large_array =
12462 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012463 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012464 array_type,
12465 array_data));
12466 v8::Handle<v8::Object> large_obj = v8::Object::New();
12467 // Set the elements to be the external array.
12468 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12469 array_type,
12470 kLargeElementCount);
12471 context->Global()->Set(v8_str("large_array"), large_obj);
12472 // Initialize contents of a few rows.
12473 for (int x = 0; x < 300; x++) {
12474 int row = 0;
12475 int offset = row * 300 * 4;
12476 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12477 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12478 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12479 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12480 row = 150;
12481 offset = row * 300 * 4;
12482 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12483 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12484 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12485 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12486 row = 298;
12487 offset = row * 300 * 4;
12488 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12489 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12490 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12491 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12492 }
12493 // The goal of the code below is to make "offset" large enough
12494 // that the computation of the index (which goes into eax) has
12495 // high bits set which will not be overwritten by a byte or short
12496 // load.
12497 result = CompileRun("var failed = false;"
12498 "var offset = 0;"
12499 "for (var i = 0; i < 300; i++) {"
12500 " if (large_array[4 * i] != 127 ||"
12501 " large_array[4 * i + 1] != 0 ||"
12502 " large_array[4 * i + 2] != 0 ||"
12503 " large_array[4 * i + 3] != 127) {"
12504 " failed = true;"
12505 " }"
12506 "}"
12507 "offset = 150 * 300 * 4;"
12508 "for (var i = 0; i < 300; i++) {"
12509 " if (large_array[offset + 4 * i] != 127 ||"
12510 " large_array[offset + 4 * i + 1] != 0 ||"
12511 " large_array[offset + 4 * i + 2] != 0 ||"
12512 " large_array[offset + 4 * i + 3] != 127) {"
12513 " failed = true;"
12514 " }"
12515 "}"
12516 "offset = 298 * 300 * 4;"
12517 "for (var i = 0; i < 300; i++) {"
12518 " if (large_array[offset + 4 * i] != 127 ||"
12519 " large_array[offset + 4 * i + 1] != 0 ||"
12520 " large_array[offset + 4 * i + 2] != 0 ||"
12521 " large_array[offset + 4 * i + 3] != 127) {"
12522 " failed = true;"
12523 " }"
12524 "}"
12525 "!failed;");
12526 CHECK_EQ(true, result->BooleanValue());
12527 free(large_array_data);
12528 }
12529
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012530 // The "" property descriptor is overloaded to store information about
12531 // the external array. Ensure that setting and accessing the "" property
12532 // works (it should overwrite the information cached about the external
12533 // array in the DescriptorArray) in various situations.
12534 result = CompileRun("ext_array[''] = 23; ext_array['']");
12535 CHECK_EQ(23, result->Int32Value());
12536
12537 // Property "" set after the external array is associated with the object.
12538 {
12539 v8::Handle<v8::Object> obj2 = v8::Object::New();
12540 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12541 obj2->Set(v8_str(""), v8::Int32::New(1503));
12542 // Set the elements to be the external array.
12543 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12544 array_type,
12545 kElementCount);
12546 context->Global()->Set(v8_str("ext_array"), obj2);
12547 result = CompileRun("ext_array['']");
12548 CHECK_EQ(1503, result->Int32Value());
12549 }
12550
12551 // Property "" set after the external array is associated with the object.
12552 {
12553 v8::Handle<v8::Object> obj2 = v8::Object::New();
12554 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12555 // Set the elements to be the external array.
12556 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12557 array_type,
12558 kElementCount);
12559 obj2->Set(v8_str(""), v8::Int32::New(1503));
12560 context->Global()->Set(v8_str("ext_array"), obj2);
12561 result = CompileRun("ext_array['']");
12562 CHECK_EQ(1503, result->Int32Value());
12563 }
12564
12565 // Should reuse the map from previous test.
12566 {
12567 v8::Handle<v8::Object> obj2 = v8::Object::New();
12568 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12569 // Set the elements to be the external array. Should re-use the map
12570 // from previous test.
12571 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12572 array_type,
12573 kElementCount);
12574 context->Global()->Set(v8_str("ext_array"), obj2);
12575 result = CompileRun("ext_array['']");
12576 }
12577
12578 // Property "" is a constant function that shouldn't not be interfered with
12579 // when an external array is set.
12580 {
12581 v8::Handle<v8::Object> obj2 = v8::Object::New();
12582 // Start
12583 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12584
12585 // Add a constant function to an object.
12586 context->Global()->Set(v8_str("ext_array"), obj2);
12587 result = CompileRun("ext_array[''] = function() {return 1503;};"
12588 "ext_array['']();");
12589
12590 // Add an external array transition to the same map that
12591 // has the constant transition.
12592 v8::Handle<v8::Object> obj3 = v8::Object::New();
12593 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12594 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12595 array_type,
12596 kElementCount);
12597 context->Global()->Set(v8_str("ext_array"), obj3);
12598 }
12599
12600 // If a external array transition is in the map, it should get clobbered
12601 // by a constant function.
12602 {
12603 // Add an external array transition.
12604 v8::Handle<v8::Object> obj3 = v8::Object::New();
12605 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12606 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12607 array_type,
12608 kElementCount);
12609
12610 // Add a constant function to the same map that just got an external array
12611 // transition.
12612 v8::Handle<v8::Object> obj2 = v8::Object::New();
12613 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12614 context->Global()->Set(v8_str("ext_array"), obj2);
12615 result = CompileRun("ext_array[''] = function() {return 1503;};"
12616 "ext_array['']();");
12617 }
12618
ager@chromium.org3811b432009-10-28 14:53:37 +000012619 free(array_data);
12620}
12621
12622
12623THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012624 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012625 v8::kExternalByteArray,
12626 -128,
12627 127);
12628}
12629
12630
12631THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012632 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012633 v8::kExternalUnsignedByteArray,
12634 0,
12635 255);
12636}
12637
12638
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012639THREADED_TEST(ExternalPixelArray) {
12640 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12641 v8::kExternalPixelArray,
12642 0,
12643 255);
12644}
12645
12646
ager@chromium.org3811b432009-10-28 14:53:37 +000012647THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012648 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012649 v8::kExternalShortArray,
12650 -32768,
12651 32767);
12652}
12653
12654
12655THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012656 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012657 v8::kExternalUnsignedShortArray,
12658 0,
12659 65535);
12660}
12661
12662
12663THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012664 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012665 v8::kExternalIntArray,
12666 INT_MIN, // -2147483648
12667 INT_MAX); // 2147483647
12668}
12669
12670
12671THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012672 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012673 v8::kExternalUnsignedIntArray,
12674 0,
12675 UINT_MAX); // 4294967295
12676}
12677
12678
12679THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012680 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012681 v8::kExternalFloatArray,
12682 -500,
12683 500);
12684}
12685
12686
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012687THREADED_TEST(ExternalDoubleArray) {
12688 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12689 v8::kExternalDoubleArray,
12690 -500,
12691 500);
12692}
12693
12694
ager@chromium.org3811b432009-10-28 14:53:37 +000012695THREADED_TEST(ExternalArrays) {
12696 TestExternalByteArray();
12697 TestExternalUnsignedByteArray();
12698 TestExternalShortArray();
12699 TestExternalUnsignedShortArray();
12700 TestExternalIntArray();
12701 TestExternalUnsignedIntArray();
12702 TestExternalFloatArray();
12703}
12704
12705
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012706void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12707 v8::HandleScope scope;
12708 LocalContext context;
12709 for (int size = 0; size < 100; size += 10) {
12710 int element_size = ExternalArrayElementSize(array_type);
12711 void* external_data = malloc(size * element_size);
12712 v8::Handle<v8::Object> obj = v8::Object::New();
12713 obj->SetIndexedPropertiesToExternalArrayData(
12714 external_data, array_type, size);
12715 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12716 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12717 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12718 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12719 free(external_data);
12720 }
12721}
12722
12723
12724THREADED_TEST(ExternalArrayInfo) {
12725 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12726 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12727 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12728 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12729 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12730 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12731 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012732 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012733 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012734}
12735
12736
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012737THREADED_TEST(ScriptContextDependence) {
12738 v8::HandleScope scope;
12739 LocalContext c1;
12740 const char *source = "foo";
12741 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12742 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12743 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12744 CHECK_EQ(dep->Run()->Int32Value(), 100);
12745 CHECK_EQ(indep->Run()->Int32Value(), 100);
12746 LocalContext c2;
12747 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12748 CHECK_EQ(dep->Run()->Int32Value(), 100);
12749 CHECK_EQ(indep->Run()->Int32Value(), 101);
12750}
12751
ager@chromium.org96c75b52009-08-26 09:13:16 +000012752
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012753THREADED_TEST(StackTrace) {
12754 v8::HandleScope scope;
12755 LocalContext context;
12756 v8::TryCatch try_catch;
12757 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12758 v8::Handle<v8::String> src = v8::String::New(source);
12759 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12760 v8::Script::New(src, origin)->Run();
12761 CHECK(try_catch.HasCaught());
12762 v8::String::Utf8Value stack(try_catch.StackTrace());
12763 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12764}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012765
12766
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012767// Checks that a StackFrame has certain expected values.
12768void checkStackFrame(const char* expected_script_name,
12769 const char* expected_func_name, int expected_line_number,
12770 int expected_column, bool is_eval, bool is_constructor,
12771 v8::Handle<v8::StackFrame> frame) {
12772 v8::HandleScope scope;
12773 v8::String::Utf8Value func_name(frame->GetFunctionName());
12774 v8::String::Utf8Value script_name(frame->GetScriptName());
12775 if (*script_name == NULL) {
12776 // The situation where there is no associated script, like for evals.
12777 CHECK(expected_script_name == NULL);
12778 } else {
12779 CHECK(strstr(*script_name, expected_script_name) != NULL);
12780 }
12781 CHECK(strstr(*func_name, expected_func_name) != NULL);
12782 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12783 CHECK_EQ(expected_column, frame->GetColumn());
12784 CHECK_EQ(is_eval, frame->IsEval());
12785 CHECK_EQ(is_constructor, frame->IsConstructor());
12786}
12787
12788
12789v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12790 v8::HandleScope scope;
12791 const char* origin = "capture-stack-trace-test";
12792 const int kOverviewTest = 1;
12793 const int kDetailedTest = 2;
12794
12795 ASSERT(args.Length() == 1);
12796
12797 int testGroup = args[0]->Int32Value();
12798 if (testGroup == kOverviewTest) {
12799 v8::Handle<v8::StackTrace> stackTrace =
12800 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12801 CHECK_EQ(4, stackTrace->GetFrameCount());
12802 checkStackFrame(origin, "bar", 2, 10, false, false,
12803 stackTrace->GetFrame(0));
12804 checkStackFrame(origin, "foo", 6, 3, false, false,
12805 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012806 // This is the source string inside the eval which has the call to foo.
12807 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012808 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012809 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012810 checkStackFrame(origin, "", 8, 7, false, false,
12811 stackTrace->GetFrame(3));
12812
12813 CHECK(stackTrace->AsArray()->IsArray());
12814 } else if (testGroup == kDetailedTest) {
12815 v8::Handle<v8::StackTrace> stackTrace =
12816 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12817 CHECK_EQ(4, stackTrace->GetFrameCount());
12818 checkStackFrame(origin, "bat", 4, 22, false, false,
12819 stackTrace->GetFrame(0));
12820 checkStackFrame(origin, "baz", 8, 3, false, true,
12821 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012822#ifdef ENABLE_DEBUGGER_SUPPORT
12823 bool is_eval = true;
12824#else // ENABLE_DEBUGGER_SUPPORT
12825 bool is_eval = false;
12826#endif // ENABLE_DEBUGGER_SUPPORT
12827
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012828 // This is the source string inside the eval which has the call to baz.
12829 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012830 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012831 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012832 checkStackFrame(origin, "", 10, 1, false, false,
12833 stackTrace->GetFrame(3));
12834
12835 CHECK(stackTrace->AsArray()->IsArray());
12836 }
12837 return v8::Undefined();
12838}
12839
12840
12841// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012842// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12843// THREADED_TEST(CaptureStackTrace) {
12844TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012845 v8::HandleScope scope;
12846 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12847 Local<ObjectTemplate> templ = ObjectTemplate::New();
12848 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12849 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12850 LocalContext context(0, templ);
12851
12852 // Test getting OVERVIEW information. Should ignore information that is not
12853 // script name, function name, line number, and column offset.
12854 const char *overview_source =
12855 "function bar() {\n"
12856 " var y; AnalyzeStackInNativeCode(1);\n"
12857 "}\n"
12858 "function foo() {\n"
12859 "\n"
12860 " bar();\n"
12861 "}\n"
12862 "var x;eval('new foo();');";
12863 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12864 v8::Handle<Value> overview_result =
12865 v8::Script::New(overview_src, origin)->Run();
12866 ASSERT(!overview_result.IsEmpty());
12867 ASSERT(overview_result->IsObject());
12868
12869 // Test getting DETAILED information.
12870 const char *detailed_source =
12871 "function bat() {AnalyzeStackInNativeCode(2);\n"
12872 "}\n"
12873 "\n"
12874 "function baz() {\n"
12875 " bat();\n"
12876 "}\n"
12877 "eval('new baz();');";
12878 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12879 // Make the script using a non-zero line and column offset.
12880 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12881 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12882 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12883 v8::Handle<v8::Script> detailed_script(
12884 v8::Script::New(detailed_src, &detailed_origin));
12885 v8::Handle<Value> detailed_result = detailed_script->Run();
12886 ASSERT(!detailed_result.IsEmpty());
12887 ASSERT(detailed_result->IsObject());
12888}
12889
12890
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012891static void StackTraceForUncaughtExceptionListener(
12892 v8::Handle<v8::Message> message,
12893 v8::Handle<Value>) {
12894 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12895 CHECK_EQ(2, stack_trace->GetFrameCount());
12896 checkStackFrame("origin", "foo", 2, 3, false, false,
12897 stack_trace->GetFrame(0));
12898 checkStackFrame("origin", "bar", 5, 3, false, false,
12899 stack_trace->GetFrame(1));
12900}
12901
12902TEST(CaptureStackTraceForUncaughtException) {
12903 report_count = 0;
12904 v8::HandleScope scope;
12905 LocalContext env;
12906 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12907 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12908
12909 Script::Compile(v8_str("function foo() {\n"
12910 " throw 1;\n"
12911 "};\n"
12912 "function bar() {\n"
12913 " foo();\n"
12914 "};"),
12915 v8_str("origin"))->Run();
12916 v8::Local<v8::Object> global = env->Global();
12917 Local<Value> trouble = global->Get(v8_str("bar"));
12918 CHECK(trouble->IsFunction());
12919 Function::Cast(*trouble)->Call(global, 0, NULL);
12920 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12921 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12922}
12923
12924
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012925TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12926 v8::HandleScope scope;
12927 LocalContext env;
12928 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12929 1024,
12930 v8::StackTrace::kDetailed);
12931
12932 CompileRun(
12933 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12934 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12935 " 'isConstructor'];\n"
12936 "for (var i = 0; i < setters.length; i++) {\n"
12937 " var prop = setters[i];\n"
12938 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12939 "}\n");
12940 CompileRun("throw 'exception';");
12941 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12942}
12943
12944
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012945v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12946 v8::HandleScope scope;
12947 v8::Handle<v8::StackTrace> stackTrace =
12948 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12949 CHECK_EQ(5, stackTrace->GetFrameCount());
12950 v8::Handle<v8::String> url = v8_str("eval_url");
12951 for (int i = 0; i < 3; i++) {
12952 v8::Handle<v8::String> name =
12953 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12954 CHECK(!name.IsEmpty());
12955 CHECK_EQ(url, name);
12956 }
12957 return v8::Undefined();
12958}
12959
12960
12961TEST(SourceURLInStackTrace) {
12962 v8::HandleScope scope;
12963 Local<ObjectTemplate> templ = ObjectTemplate::New();
12964 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12965 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12966 LocalContext context(0, templ);
12967
12968 const char *source =
12969 "function outer() {\n"
12970 "function bar() {\n"
12971 " AnalyzeStackOfEvalWithSourceURL();\n"
12972 "}\n"
12973 "function foo() {\n"
12974 "\n"
12975 " bar();\n"
12976 "}\n"
12977 "foo();\n"
12978 "}\n"
12979 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12980 CHECK(CompileRun(source)->IsUndefined());
12981}
12982
12983
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012984// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012985THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012986 bool rv = false;
12987 for (int i = 0; i < 100; i++) {
12988 rv = v8::V8::IdleNotification();
12989 if (rv)
12990 break;
12991 }
12992 CHECK(rv == true);
12993}
12994
12995
12996static uint32_t* stack_limit;
12997
12998static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 stack_limit = reinterpret_cast<uint32_t*>(
13000 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000013001 return v8::Undefined();
13002}
13003
13004
13005// Uses the address of a local variable to determine the stack top now.
13006// Given a size, returns an address that is that far from the current
13007// top of stack.
13008static uint32_t* ComputeStackLimit(uint32_t size) {
13009 uint32_t* answer = &size - (size / sizeof(size));
13010 // If the size is very large and the stack is very near the bottom of
13011 // memory then the calculation above may wrap around and give an address
13012 // that is above the (downwards-growing) stack. In that case we return
13013 // a very low address.
13014 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13015 return answer;
13016}
13017
13018
13019TEST(SetResourceConstraints) {
13020 static const int K = 1024;
13021 uint32_t* set_limit = ComputeStackLimit(128 * K);
13022
13023 // Set stack limit.
13024 v8::ResourceConstraints constraints;
13025 constraints.set_stack_limit(set_limit);
13026 CHECK(v8::SetResourceConstraints(&constraints));
13027
13028 // Execute a script.
13029 v8::HandleScope scope;
13030 LocalContext env;
13031 Local<v8::FunctionTemplate> fun_templ =
13032 v8::FunctionTemplate::New(GetStackLimitCallback);
13033 Local<Function> fun = fun_templ->GetFunction();
13034 env->Global()->Set(v8_str("get_stack_limit"), fun);
13035 CompileRun("get_stack_limit();");
13036
13037 CHECK(stack_limit == set_limit);
13038}
13039
13040
13041TEST(SetResourceConstraintsInThread) {
13042 uint32_t* set_limit;
13043 {
13044 v8::Locker locker;
13045 static const int K = 1024;
13046 set_limit = ComputeStackLimit(128 * K);
13047
13048 // Set stack limit.
13049 v8::ResourceConstraints constraints;
13050 constraints.set_stack_limit(set_limit);
13051 CHECK(v8::SetResourceConstraints(&constraints));
13052
13053 // Execute a script.
13054 v8::HandleScope scope;
13055 LocalContext env;
13056 Local<v8::FunctionTemplate> fun_templ =
13057 v8::FunctionTemplate::New(GetStackLimitCallback);
13058 Local<Function> fun = fun_templ->GetFunction();
13059 env->Global()->Set(v8_str("get_stack_limit"), fun);
13060 CompileRun("get_stack_limit();");
13061
13062 CHECK(stack_limit == set_limit);
13063 }
13064 {
13065 v8::Locker locker;
13066 CHECK(stack_limit == set_limit);
13067 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013068}
ager@chromium.org3811b432009-10-28 14:53:37 +000013069
13070
13071THREADED_TEST(GetHeapStatistics) {
13072 v8::HandleScope scope;
13073 LocalContext c1;
13074 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013075 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13076 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013077 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013078 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13079 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013080}
13081
13082
13083static double DoubleFromBits(uint64_t value) {
13084 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013085 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013086 return target;
13087}
13088
13089
13090static uint64_t DoubleToBits(double value) {
13091 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013092 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013093 return target;
13094}
13095
13096
13097static double DoubleToDateTime(double input) {
13098 double date_limit = 864e13;
13099 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13100 return i::OS::nan_value();
13101 }
13102 return (input < 0) ? -(floor(-input)) : floor(input);
13103}
13104
13105// We don't have a consistent way to write 64-bit constants syntactically, so we
13106// split them into two 32-bit constants and combine them programmatically.
13107static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13108 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13109}
13110
13111
13112THREADED_TEST(QuietSignalingNaNs) {
13113 v8::HandleScope scope;
13114 LocalContext context;
13115 v8::TryCatch try_catch;
13116
13117 // Special double values.
13118 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13119 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13120 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13121 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13122 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13123 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13124 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13125
13126 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13127 // on either side of the epoch.
13128 double date_limit = 864e13;
13129
13130 double test_values[] = {
13131 snan,
13132 qnan,
13133 infinity,
13134 max_normal,
13135 date_limit + 1,
13136 date_limit,
13137 min_normal,
13138 max_denormal,
13139 min_denormal,
13140 0,
13141 -0,
13142 -min_denormal,
13143 -max_denormal,
13144 -min_normal,
13145 -date_limit,
13146 -date_limit - 1,
13147 -max_normal,
13148 -infinity,
13149 -qnan,
13150 -snan
13151 };
13152 int num_test_values = 20;
13153
13154 for (int i = 0; i < num_test_values; i++) {
13155 double test_value = test_values[i];
13156
13157 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13158 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13159 double stored_number = number->NumberValue();
13160 if (!IsNaN(test_value)) {
13161 CHECK_EQ(test_value, stored_number);
13162 } else {
13163 uint64_t stored_bits = DoubleToBits(stored_number);
13164 // Check if quiet nan (bits 51..62 all set).
13165 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13166 }
13167
13168 // Check that Date::New preserves non-NaNs in the date range and
13169 // quiets SNaNs.
13170 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13171 double expected_stored_date = DoubleToDateTime(test_value);
13172 double stored_date = date->NumberValue();
13173 if (!IsNaN(expected_stored_date)) {
13174 CHECK_EQ(expected_stored_date, stored_date);
13175 } else {
13176 uint64_t stored_bits = DoubleToBits(stored_date);
13177 // Check if quiet nan (bits 51..62 all set).
13178 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13179 }
13180 }
13181}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013182
13183
13184static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13185 v8::HandleScope scope;
13186 v8::TryCatch tc;
13187 v8::Handle<v8::String> str = args[0]->ToString();
13188 if (tc.HasCaught())
13189 return tc.ReThrow();
13190 return v8::Undefined();
13191}
13192
13193
13194// Test that an exception can be propagated down through a spaghetti
13195// stack using ReThrow.
13196THREADED_TEST(SpaghettiStackReThrow) {
13197 v8::HandleScope scope;
13198 LocalContext context;
13199 context->Global()->Set(
13200 v8::String::New("s"),
13201 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13202 v8::TryCatch try_catch;
13203 CompileRun(
13204 "var i = 0;"
13205 "var o = {"
13206 " toString: function () {"
13207 " if (i == 10) {"
13208 " throw 'Hey!';"
13209 " } else {"
13210 " i++;"
13211 " return s(o);"
13212 " }"
13213 " }"
13214 "};"
13215 "s(o);");
13216 CHECK(try_catch.HasCaught());
13217 v8::String::Utf8Value value(try_catch.Exception());
13218 CHECK_EQ(0, strcmp(*value, "Hey!"));
13219}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013220
13221
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013222TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013223 v8::V8::Initialize();
13224
13225 v8::HandleScope scope;
13226 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013227 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013228 int gc_count;
13229
ager@chromium.org60121232009-12-03 11:25:37 +000013230 // Create a context used to keep the code from aging in the compilation
13231 // cache.
13232 other_context = Context::New();
13233
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013234 // Context-dependent context data creates reference from the compilation
13235 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013236 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013237 context = Context::New();
13238 {
13239 v8::HandleScope scope;
13240
13241 context->Enter();
13242 Local<v8::String> obj = v8::String::New("");
13243 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013244 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013245 context->Exit();
13246 }
13247 context.Dispose();
13248 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013249 other_context->Enter();
13250 CompileRun(source_simple);
13251 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013252 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013253 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013254 }
ager@chromium.org60121232009-12-03 11:25:37 +000013255 CHECK_GE(2, gc_count);
13256 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013257
13258 // Eval in a function creates reference from the compilation cache to the
13259 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013260 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013261 context = Context::New();
13262 {
13263 v8::HandleScope scope;
13264
13265 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013266 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013267 context->Exit();
13268 }
13269 context.Dispose();
13270 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013271 other_context->Enter();
13272 CompileRun(source_eval);
13273 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013274 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013275 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013276 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013277 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013278 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013279
13280 // Looking up the line number for an exception creates reference from the
13281 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013282 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013283 context = Context::New();
13284 {
13285 v8::HandleScope scope;
13286
13287 context->Enter();
13288 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013289 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013290 CHECK(try_catch.HasCaught());
13291 v8::Handle<v8::Message> message = try_catch.Message();
13292 CHECK(!message.IsEmpty());
13293 CHECK_EQ(1, message->GetLineNumber());
13294 context->Exit();
13295 }
13296 context.Dispose();
13297 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013298 other_context->Enter();
13299 CompileRun(source_exception);
13300 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013302 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013303 }
ager@chromium.org60121232009-12-03 11:25:37 +000013304 CHECK_GE(2, gc_count);
13305 CHECK_EQ(1, GetGlobalObjectsCount());
13306
13307 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013308}
ager@chromium.org5c838252010-02-19 08:53:10 +000013309
13310
13311THREADED_TEST(ScriptOrigin) {
13312 v8::HandleScope scope;
13313 LocalContext env;
13314 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13315 v8::Handle<v8::String> script = v8::String::New(
13316 "function f() {}\n\nfunction g() {}");
13317 v8::Script::Compile(script, &origin)->Run();
13318 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13319 env->Global()->Get(v8::String::New("f")));
13320 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13321 env->Global()->Get(v8::String::New("g")));
13322
13323 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13324 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13325 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13326
13327 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13328 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13329 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13330}
13331
13332
13333THREADED_TEST(ScriptLineNumber) {
13334 v8::HandleScope scope;
13335 LocalContext env;
13336 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13337 v8::Handle<v8::String> script = v8::String::New(
13338 "function f() {}\n\nfunction g() {}");
13339 v8::Script::Compile(script, &origin)->Run();
13340 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13341 env->Global()->Get(v8::String::New("f")));
13342 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13343 env->Global()->Get(v8::String::New("g")));
13344 CHECK_EQ(0, f->GetScriptLineNumber());
13345 CHECK_EQ(2, g->GetScriptLineNumber());
13346}
13347
13348
13349static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13350 const AccessorInfo& info) {
13351 return v8_num(42);
13352}
13353
13354
13355static void SetterWhichSetsYOnThisTo23(Local<String> name,
13356 Local<Value> value,
13357 const AccessorInfo& info) {
13358 info.This()->Set(v8_str("y"), v8_num(23));
13359}
13360
13361
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013362TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013363 v8::HandleScope scope;
13364 Local<ObjectTemplate> templ = ObjectTemplate::New();
13365 templ->SetAccessor(v8_str("x"),
13366 GetterWhichReturns42,
13367 SetterWhichSetsYOnThisTo23);
13368 LocalContext context;
13369 context->Global()->Set(v8_str("P"), templ->NewInstance());
13370 CompileRun("function C1() {"
13371 " this.x = 23;"
13372 "};"
13373 "C1.prototype = P;"
13374 "function C2() {"
13375 " this.x = 23"
13376 "};"
13377 "C2.prototype = { };"
13378 "C2.prototype.__proto__ = P;");
13379
13380 v8::Local<v8::Script> script;
13381 script = v8::Script::Compile(v8_str("new C1();"));
13382 for (int i = 0; i < 10; i++) {
13383 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13384 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13385 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13386 }
13387
13388 script = v8::Script::Compile(v8_str("new C2();"));
13389 for (int i = 0; i < 10; i++) {
13390 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13391 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13392 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13393 }
13394}
13395
13396
13397static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13398 Local<String> name, const AccessorInfo& info) {
13399 return v8_num(42);
13400}
13401
13402
13403static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13404 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13405 if (name->Equals(v8_str("x"))) {
13406 info.This()->Set(v8_str("y"), v8_num(23));
13407 }
13408 return v8::Handle<Value>();
13409}
13410
13411
13412THREADED_TEST(InterceptorOnConstructorPrototype) {
13413 v8::HandleScope scope;
13414 Local<ObjectTemplate> templ = ObjectTemplate::New();
13415 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13416 NamedPropertySetterWhichSetsYOnThisTo23);
13417 LocalContext context;
13418 context->Global()->Set(v8_str("P"), templ->NewInstance());
13419 CompileRun("function C1() {"
13420 " this.x = 23;"
13421 "};"
13422 "C1.prototype = P;"
13423 "function C2() {"
13424 " this.x = 23"
13425 "};"
13426 "C2.prototype = { };"
13427 "C2.prototype.__proto__ = P;");
13428
13429 v8::Local<v8::Script> script;
13430 script = v8::Script::Compile(v8_str("new C1();"));
13431 for (int i = 0; i < 10; i++) {
13432 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13433 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13434 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13435 }
13436
13437 script = v8::Script::Compile(v8_str("new C2();"));
13438 for (int i = 0; i < 10; i++) {
13439 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13440 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13441 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13442 }
13443}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013444
13445
13446TEST(Bug618) {
13447 const char* source = "function C1() {"
13448 " this.x = 23;"
13449 "};"
13450 "C1.prototype = P;";
13451
13452 v8::HandleScope scope;
13453 LocalContext context;
13454 v8::Local<v8::Script> script;
13455
13456 // Use a simple object as prototype.
13457 v8::Local<v8::Object> prototype = v8::Object::New();
13458 prototype->Set(v8_str("y"), v8_num(42));
13459 context->Global()->Set(v8_str("P"), prototype);
13460
13461 // This compile will add the code to the compilation cache.
13462 CompileRun(source);
13463
13464 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000013465 // Allow enough iterations for the inobject slack tracking logic
13466 // to finalize instance size and install the fast construct stub.
13467 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013468 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13469 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13470 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13471 }
13472
13473 // Use an API object with accessors as prototype.
13474 Local<ObjectTemplate> templ = ObjectTemplate::New();
13475 templ->SetAccessor(v8_str("x"),
13476 GetterWhichReturns42,
13477 SetterWhichSetsYOnThisTo23);
13478 context->Global()->Set(v8_str("P"), templ->NewInstance());
13479
13480 // This compile will get the code from the compilation cache.
13481 CompileRun(source);
13482
13483 script = v8::Script::Compile(v8_str("new C1();"));
13484 for (int i = 0; i < 10; i++) {
13485 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13486 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13487 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13488 }
13489}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013490
13491int prologue_call_count = 0;
13492int epilogue_call_count = 0;
13493int prologue_call_count_second = 0;
13494int epilogue_call_count_second = 0;
13495
13496void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13497 ++prologue_call_count;
13498}
13499
13500void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13501 ++epilogue_call_count;
13502}
13503
13504void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13505 ++prologue_call_count_second;
13506}
13507
13508void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13509 ++epilogue_call_count_second;
13510}
13511
13512TEST(GCCallbacks) {
13513 LocalContext context;
13514
13515 v8::V8::AddGCPrologueCallback(PrologueCallback);
13516 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13517 CHECK_EQ(0, prologue_call_count);
13518 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013519 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013520 CHECK_EQ(1, prologue_call_count);
13521 CHECK_EQ(1, epilogue_call_count);
13522 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13523 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013524 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013525 CHECK_EQ(2, prologue_call_count);
13526 CHECK_EQ(2, epilogue_call_count);
13527 CHECK_EQ(1, prologue_call_count_second);
13528 CHECK_EQ(1, epilogue_call_count_second);
13529 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13530 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013531 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013532 CHECK_EQ(2, prologue_call_count);
13533 CHECK_EQ(2, epilogue_call_count);
13534 CHECK_EQ(2, prologue_call_count_second);
13535 CHECK_EQ(2, epilogue_call_count_second);
13536 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13537 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013538 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013539 CHECK_EQ(2, prologue_call_count);
13540 CHECK_EQ(2, epilogue_call_count);
13541 CHECK_EQ(2, prologue_call_count_second);
13542 CHECK_EQ(2, epilogue_call_count_second);
13543}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013544
13545
13546THREADED_TEST(AddToJSFunctionResultCache) {
13547 i::FLAG_allow_natives_syntax = true;
13548 v8::HandleScope scope;
13549
13550 LocalContext context;
13551
13552 const char* code =
13553 "(function() {"
13554 " var key0 = 'a';"
13555 " var key1 = 'b';"
13556 " var r0 = %_GetFromCache(0, key0);"
13557 " var r1 = %_GetFromCache(0, key1);"
13558 " var r0_ = %_GetFromCache(0, key0);"
13559 " if (r0 !== r0_)"
13560 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13561 " var r1_ = %_GetFromCache(0, key1);"
13562 " if (r1 !== r1_)"
13563 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13564 " return 'PASSED';"
13565 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013566 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013567 ExpectString(code, "PASSED");
13568}
13569
13570
13571static const int k0CacheSize = 16;
13572
13573THREADED_TEST(FillJSFunctionResultCache) {
13574 i::FLAG_allow_natives_syntax = true;
13575 v8::HandleScope scope;
13576
13577 LocalContext context;
13578
13579 const char* code =
13580 "(function() {"
13581 " var k = 'a';"
13582 " var r = %_GetFromCache(0, k);"
13583 " for (var i = 0; i < 16; i++) {"
13584 " %_GetFromCache(0, 'a' + i);"
13585 " };"
13586 " if (r === %_GetFromCache(0, k))"
13587 " return 'FAILED: k0CacheSize is too small';"
13588 " return 'PASSED';"
13589 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013590 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013591 ExpectString(code, "PASSED");
13592}
13593
13594
13595THREADED_TEST(RoundRobinGetFromCache) {
13596 i::FLAG_allow_natives_syntax = true;
13597 v8::HandleScope scope;
13598
13599 LocalContext context;
13600
13601 const char* code =
13602 "(function() {"
13603 " var keys = [];"
13604 " for (var i = 0; i < 16; i++) keys.push(i);"
13605 " var values = [];"
13606 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13607 " for (var i = 0; i < 16; i++) {"
13608 " var v = %_GetFromCache(0, keys[i]);"
13609 " if (v !== values[i])"
13610 " return 'Wrong value for ' + "
13611 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13612 " };"
13613 " return 'PASSED';"
13614 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013615 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013616 ExpectString(code, "PASSED");
13617}
13618
13619
13620THREADED_TEST(ReverseGetFromCache) {
13621 i::FLAG_allow_natives_syntax = true;
13622 v8::HandleScope scope;
13623
13624 LocalContext context;
13625
13626 const char* code =
13627 "(function() {"
13628 " var keys = [];"
13629 " for (var i = 0; i < 16; i++) keys.push(i);"
13630 " var values = [];"
13631 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13632 " for (var i = 15; i >= 16; i--) {"
13633 " var v = %_GetFromCache(0, keys[i]);"
13634 " if (v !== values[i])"
13635 " return 'Wrong value for ' + "
13636 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13637 " };"
13638 " return 'PASSED';"
13639 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013640 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013641 ExpectString(code, "PASSED");
13642}
13643
13644
13645THREADED_TEST(TestEviction) {
13646 i::FLAG_allow_natives_syntax = true;
13647 v8::HandleScope scope;
13648
13649 LocalContext context;
13650
13651 const char* code =
13652 "(function() {"
13653 " for (var i = 0; i < 2*16; i++) {"
13654 " %_GetFromCache(0, 'a' + i);"
13655 " };"
13656 " return 'PASSED';"
13657 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013658 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013659 ExpectString(code, "PASSED");
13660}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013661
13662
13663THREADED_TEST(TwoByteStringInAsciiCons) {
13664 // See Chromium issue 47824.
13665 v8::HandleScope scope;
13666
13667 LocalContext context;
13668 const char* init_code =
13669 "var str1 = 'abelspendabel';"
13670 "var str2 = str1 + str1 + str1;"
13671 "str2;";
13672 Local<Value> result = CompileRun(init_code);
13673
13674 CHECK(result->IsString());
13675 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13676 int length = string->length();
13677 CHECK(string->IsAsciiRepresentation());
13678
13679 FlattenString(string);
13680 i::Handle<i::String> flat_string = FlattenGetString(string);
13681
13682 CHECK(string->IsAsciiRepresentation());
13683 CHECK(flat_string->IsAsciiRepresentation());
13684
13685 // Create external resource.
13686 uint16_t* uc16_buffer = new uint16_t[length + 1];
13687
13688 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13689 uc16_buffer[length] = 0;
13690
13691 TestResource resource(uc16_buffer);
13692
13693 flat_string->MakeExternal(&resource);
13694
13695 CHECK(flat_string->IsTwoByteRepresentation());
13696
13697 // At this point, we should have a Cons string which is flat and ASCII,
13698 // with a first half that is a two-byte string (although it only contains
13699 // ASCII characters). This is a valid sequence of steps, and it can happen
13700 // in real pages.
13701
13702 CHECK(string->IsAsciiRepresentation());
13703 i::ConsString* cons = i::ConsString::cast(*string);
13704 CHECK_EQ(0, cons->second()->length());
13705 CHECK(cons->first()->IsTwoByteRepresentation());
13706
13707 // Check that some string operations work.
13708
13709 // Atom RegExp.
13710 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13711 CHECK_EQ(6, reresult->Int32Value());
13712
13713 // Nonatom RegExp.
13714 reresult = CompileRun("str2.match(/abe./g).length;");
13715 CHECK_EQ(6, reresult->Int32Value());
13716
13717 reresult = CompileRun("str2.search(/bel/g);");
13718 CHECK_EQ(1, reresult->Int32Value());
13719
13720 reresult = CompileRun("str2.search(/be./g);");
13721 CHECK_EQ(1, reresult->Int32Value());
13722
13723 ExpectTrue("/bel/g.test(str2);");
13724
13725 ExpectTrue("/be./g.test(str2);");
13726
13727 reresult = CompileRun("/bel/g.exec(str2);");
13728 CHECK(!reresult->IsNull());
13729
13730 reresult = CompileRun("/be./g.exec(str2);");
13731 CHECK(!reresult->IsNull());
13732
13733 ExpectString("str2.substring(2, 10);", "elspenda");
13734
13735 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13736
13737 ExpectString("str2.charAt(2);", "e");
13738
13739 reresult = CompileRun("str2.charCodeAt(2);");
13740 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13741}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013742
13743
13744// Failed access check callback that performs a GC on each invocation.
13745void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13746 v8::AccessType type,
13747 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013748 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013749}
13750
13751
13752TEST(GCInFailedAccessCheckCallback) {
13753 // Install a failed access check callback that performs a GC on each
13754 // invocation. Then force the callback to be called from va
13755
13756 v8::V8::Initialize();
13757 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13758
13759 v8::HandleScope scope;
13760
13761 // Create an ObjectTemplate for global objects and install access
13762 // check callbacks that will block access.
13763 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13764 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13765 IndexedGetAccessBlocker,
13766 v8::Handle<v8::Value>(),
13767 false);
13768
13769 // Create a context and set an x property on it's global object.
13770 LocalContext context0(NULL, global_template);
13771 context0->Global()->Set(v8_str("x"), v8_num(42));
13772 v8::Handle<v8::Object> global0 = context0->Global();
13773
13774 // Create a context with a different security token so that the
13775 // failed access check callback will be called on each access.
13776 LocalContext context1(NULL, global_template);
13777 context1->Global()->Set(v8_str("other"), global0);
13778
13779 // Get property with failed access check.
13780 ExpectUndefined("other.x");
13781
13782 // Get element with failed access check.
13783 ExpectUndefined("other[0]");
13784
13785 // Set property with failed access check.
13786 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13787 CHECK(result->IsObject());
13788
13789 // Set element with failed access check.
13790 result = CompileRun("other[0] = new Object()");
13791 CHECK(result->IsObject());
13792
13793 // Get property attribute with failed access check.
13794 ExpectFalse("\'x\' in other");
13795
13796 // Get property attribute for element with failed access check.
13797 ExpectFalse("0 in other");
13798
13799 // Delete property.
13800 ExpectFalse("delete other.x");
13801
13802 // Delete element.
13803 CHECK_EQ(false, global0->Delete(0));
13804
13805 // DefineAccessor.
13806 CHECK_EQ(false,
13807 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13808
13809 // Define JavaScript accessor.
13810 ExpectUndefined("Object.prototype.__defineGetter__.call("
13811 " other, \'x\', function() { return 42; })");
13812
13813 // LookupAccessor.
13814 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13815 " other, \'x\')");
13816
13817 // HasLocalElement.
13818 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13819
13820 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13821 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13822 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13823
13824 // Reset the failed access check callback so it does not influence
13825 // the other tests.
13826 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13827}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013829TEST(DefaultIsolateGetCurrent) {
13830 CHECK(v8::Isolate::GetCurrent() != NULL);
13831 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13832 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13833 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13834}
13835
13836TEST(IsolateNewDispose) {
13837 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13838 v8::Isolate* isolate = v8::Isolate::New();
13839 CHECK(isolate != NULL);
13840 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13841 CHECK(current_isolate != isolate);
13842 CHECK(current_isolate == v8::Isolate::GetCurrent());
13843
13844 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13845 last_location = last_message = NULL;
13846 isolate->Dispose();
13847 CHECK_EQ(last_location, NULL);
13848 CHECK_EQ(last_message, NULL);
13849}
13850
13851TEST(IsolateEnterExitDefault) {
13852 v8::HandleScope scope;
13853 LocalContext context;
13854 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13855 CHECK(current_isolate != NULL); // Default isolate.
13856 ExpectString("'hello'", "hello");
13857 current_isolate->Enter();
13858 ExpectString("'still working'", "still working");
13859 current_isolate->Exit();
13860 ExpectString("'still working 2'", "still working 2");
13861 current_isolate->Exit();
13862 // Default isolate is always, well, 'default current'.
13863 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13864 // Still working since default isolate is auto-entering any thread
13865 // that has no isolate and attempts to execute V8 APIs.
13866 ExpectString("'still working 3'", "still working 3");
13867}
13868
13869TEST(DisposeDefaultIsolate) {
13870 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13871
13872 // Run some V8 code to trigger default isolate to become 'current'.
13873 v8::HandleScope scope;
13874 LocalContext context;
13875 ExpectString("'run some V8'", "run some V8");
13876
13877 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13878 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13879 last_location = last_message = NULL;
13880 isolate->Dispose();
13881 // It is not possible to dispose default isolate via Isolate API.
13882 CHECK_NE(last_location, NULL);
13883 CHECK_NE(last_message, NULL);
13884}
13885
13886TEST(RunDefaultAndAnotherIsolate) {
13887 v8::HandleScope scope;
13888 LocalContext context;
13889
13890 // Enter new isolate.
13891 v8::Isolate* isolate = v8::Isolate::New();
13892 CHECK(isolate);
13893 isolate->Enter();
13894 { // Need this block because subsequent Exit() will deallocate Heap,
13895 // so we need all scope objects to be deconstructed when it happens.
13896 v8::HandleScope scope_new;
13897 LocalContext context_new;
13898
13899 // Run something in new isolate.
13900 CompileRun("var foo = 153;");
13901 ExpectTrue("function f() { return foo == 153; }; f()");
13902 }
13903 isolate->Exit();
13904
13905 // This runs automatically in default isolate.
13906 // Variables in another isolate should be not available.
13907 ExpectTrue("function f() {"
13908 " try {"
13909 " foo;"
13910 " return false;"
13911 " } catch(e) {"
13912 " return true;"
13913 " }"
13914 "};"
13915 "var bar = 371;"
13916 "f()");
13917
13918 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13919 last_location = last_message = NULL;
13920 isolate->Dispose();
13921 CHECK_EQ(last_location, NULL);
13922 CHECK_EQ(last_message, NULL);
13923
13924 // Check that default isolate still runs.
13925 ExpectTrue("function f() { return bar == 371; }; f()");
13926}
13927
13928TEST(DisposeIsolateWhenInUse) {
13929 v8::Isolate* isolate = v8::Isolate::New();
13930 CHECK(isolate);
13931 isolate->Enter();
13932 v8::HandleScope scope;
13933 LocalContext context;
13934 // Run something in this isolate.
13935 ExpectTrue("true");
13936 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13937 last_location = last_message = NULL;
13938 // Still entered, should fail.
13939 isolate->Dispose();
13940 CHECK_NE(last_location, NULL);
13941 CHECK_NE(last_message, NULL);
13942}
13943
13944TEST(RunTwoIsolatesOnSingleThread) {
13945 // Run isolate 1.
13946 v8::Isolate* isolate1 = v8::Isolate::New();
13947 isolate1->Enter();
13948 v8::Persistent<v8::Context> context1 = v8::Context::New();
13949
13950 {
13951 v8::Context::Scope cscope(context1);
13952 v8::HandleScope scope;
13953 // Run something in new isolate.
13954 CompileRun("var foo = 'isolate 1';");
13955 ExpectString("function f() { return foo; }; f()", "isolate 1");
13956 }
13957
13958 // Run isolate 2.
13959 v8::Isolate* isolate2 = v8::Isolate::New();
13960 v8::Persistent<v8::Context> context2;
13961
13962 {
13963 v8::Isolate::Scope iscope(isolate2);
13964 context2 = v8::Context::New();
13965 v8::Context::Scope cscope(context2);
13966 v8::HandleScope scope;
13967
13968 // Run something in new isolate.
13969 CompileRun("var foo = 'isolate 2';");
13970 ExpectString("function f() { return foo; }; f()", "isolate 2");
13971 }
13972
13973 {
13974 v8::Context::Scope cscope(context1);
13975 v8::HandleScope scope;
13976 // Now again in isolate 1
13977 ExpectString("function f() { return foo; }; f()", "isolate 1");
13978 }
13979
13980 isolate1->Exit();
13981
13982 // Run some stuff in default isolate.
13983 v8::Persistent<v8::Context> context_default = v8::Context::New();
13984
13985 {
13986 v8::Context::Scope cscope(context_default);
13987 v8::HandleScope scope;
13988 // Variables in other isolates should be not available, verify there
13989 // is an exception.
13990 ExpectTrue("function f() {"
13991 " try {"
13992 " foo;"
13993 " return false;"
13994 " } catch(e) {"
13995 " return true;"
13996 " }"
13997 "};"
13998 "var isDefaultIsolate = true;"
13999 "f()");
14000 }
14001
14002 isolate1->Enter();
14003
14004 {
14005 v8::Isolate::Scope iscope(isolate2);
14006 v8::Context::Scope cscope(context2);
14007 v8::HandleScope scope;
14008 ExpectString("function f() { return foo; }; f()", "isolate 2");
14009 }
14010
14011 {
14012 v8::Context::Scope cscope(context1);
14013 v8::HandleScope scope;
14014 ExpectString("function f() { return foo; }; f()", "isolate 1");
14015 }
14016
14017 {
14018 v8::Isolate::Scope iscope(isolate2);
14019 context2.Dispose();
14020 }
14021
14022 context1.Dispose();
14023 isolate1->Exit();
14024
14025 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14026 last_location = last_message = NULL;
14027
14028 isolate1->Dispose();
14029 CHECK_EQ(last_location, NULL);
14030 CHECK_EQ(last_message, NULL);
14031
14032 isolate2->Dispose();
14033 CHECK_EQ(last_location, NULL);
14034 CHECK_EQ(last_message, NULL);
14035
14036 // Check that default isolate still runs.
14037 {
14038 v8::Context::Scope cscope(context_default);
14039 v8::HandleScope scope;
14040 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14041 }
14042}
14043
14044static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14045 v8::Isolate::Scope isolate_scope(isolate);
14046 v8::HandleScope scope;
14047 LocalContext context;
14048 i::ScopedVector<char> code(1024);
14049 i::OS::SNPrintF(code, "function fib(n) {"
14050 " if (n <= 2) return 1;"
14051 " return fib(n-1) + fib(n-2);"
14052 "}"
14053 "fib(%d)", limit);
14054 Local<Value> value = CompileRun(code.start());
14055 CHECK(value->IsNumber());
14056 return static_cast<int>(value->NumberValue());
14057}
14058
14059class IsolateThread : public v8::internal::Thread {
14060 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014061 IsolateThread(v8::Isolate* isolate, int fib_limit)
14062 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014063 isolate_(isolate),
14064 fib_limit_(fib_limit),
14065 result_(0) { }
14066
14067 void Run() {
14068 result_ = CalcFibonacci(isolate_, fib_limit_);
14069 }
14070
14071 int result() { return result_; }
14072
14073 private:
14074 v8::Isolate* isolate_;
14075 int fib_limit_;
14076 int result_;
14077};
14078
14079TEST(MultipleIsolatesOnIndividualThreads) {
14080 v8::Isolate* isolate1 = v8::Isolate::New();
14081 v8::Isolate* isolate2 = v8::Isolate::New();
14082
14083 IsolateThread thread1(isolate1, 21);
14084 IsolateThread thread2(isolate2, 12);
14085
14086 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14087 thread1.Start();
14088 thread2.Start();
14089
14090 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14091 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14092
14093 thread1.Join();
14094 thread2.Join();
14095
14096 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14097 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14098 CHECK_EQ(result1, 10946);
14099 CHECK_EQ(result2, 144);
14100 CHECK_EQ(result1, thread1.result());
14101 CHECK_EQ(result2, thread2.result());
14102
14103 isolate1->Dispose();
14104 isolate2->Dispose();
14105}
14106
lrn@chromium.org1c092762011-05-09 09:42:16 +000014107TEST(IsolateDifferentContexts) {
14108 v8::Isolate* isolate = v8::Isolate::New();
14109 Persistent<v8::Context> context;
14110 {
14111 v8::Isolate::Scope isolate_scope(isolate);
14112 v8::HandleScope handle_scope;
14113 context = v8::Context::New();
14114 v8::Context::Scope context_scope(context);
14115 Local<Value> v = CompileRun("2");
14116 CHECK(v->IsNumber());
14117 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14118 }
14119 {
14120 v8::Isolate::Scope isolate_scope(isolate);
14121 v8::HandleScope handle_scope;
14122 context = v8::Context::New();
14123 v8::Context::Scope context_scope(context);
14124 Local<Value> v = CompileRun("22");
14125 CHECK(v->IsNumber());
14126 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14127 }
14128}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014129
14130class InitDefaultIsolateThread : public v8::internal::Thread {
14131 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014132 enum TestCase {
14133 IgnoreOOM,
14134 SetResourceConstraints,
14135 SetFatalHandler,
14136 SetCounterFunction,
14137 SetCreateHistogramFunction,
14138 SetAddHistogramSampleFunction
14139 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014140
14141 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014142 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014143 testCase_(testCase),
14144 result_(false) { }
14145
14146 void Run() {
14147 switch (testCase_) {
14148 case IgnoreOOM:
14149 v8::V8::IgnoreOutOfMemoryException();
14150 break;
14151
14152 case SetResourceConstraints: {
14153 static const int K = 1024;
14154 v8::ResourceConstraints constraints;
14155 constraints.set_max_young_space_size(256 * K);
14156 constraints.set_max_old_space_size(4 * K * K);
14157 v8::SetResourceConstraints(&constraints);
14158 break;
14159 }
14160
14161 case SetFatalHandler:
14162 v8::V8::SetFatalErrorHandler(NULL);
14163 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014164
14165 case SetCounterFunction:
14166 v8::V8::SetCounterFunction(NULL);
14167 break;
14168
14169 case SetCreateHistogramFunction:
14170 v8::V8::SetCreateHistogramFunction(NULL);
14171 break;
14172
14173 case SetAddHistogramSampleFunction:
14174 v8::V8::SetAddHistogramSampleFunction(NULL);
14175 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014176 }
14177 result_ = true;
14178 }
14179
14180 bool result() { return result_; }
14181
14182 private:
14183 TestCase testCase_;
14184 bool result_;
14185};
14186
14187
14188static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14189 InitDefaultIsolateThread thread(testCase);
14190 thread.Start();
14191 thread.Join();
14192 CHECK_EQ(thread.result(), true);
14193}
14194
14195TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14196 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14197}
14198
14199TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14200 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14201}
14202
14203TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14204 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14205}
14206
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014207TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14208 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14209}
14210
14211TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14212 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14213}
14214
14215TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14216 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14217}
14218
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014219
14220TEST(StringCheckMultipleContexts) {
14221 const char* code =
14222 "(function() { return \"a\".charAt(0); })()";
14223
14224 {
14225 // Run the code twice in the first context to initialize the call IC.
14226 v8::HandleScope scope;
14227 LocalContext context1;
14228 ExpectString(code, "a");
14229 ExpectString(code, "a");
14230 }
14231
14232 {
14233 // Change the String.prototype in the second context and check
14234 // that the right function gets called.
14235 v8::HandleScope scope;
14236 LocalContext context2;
14237 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14238 ExpectString(code, "not a");
14239 }
14240}
14241
14242
14243TEST(NumberCheckMultipleContexts) {
14244 const char* code =
14245 "(function() { return (42).toString(); })()";
14246
14247 {
14248 // Run the code twice in the first context to initialize the call IC.
14249 v8::HandleScope scope;
14250 LocalContext context1;
14251 ExpectString(code, "42");
14252 ExpectString(code, "42");
14253 }
14254
14255 {
14256 // Change the Number.prototype in the second context and check
14257 // that the right function gets called.
14258 v8::HandleScope scope;
14259 LocalContext context2;
14260 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14261 ExpectString(code, "not 42");
14262 }
14263}
14264
14265
14266TEST(BooleanCheckMultipleContexts) {
14267 const char* code =
14268 "(function() { return true.toString(); })()";
14269
14270 {
14271 // Run the code twice in the first context to initialize the call IC.
14272 v8::HandleScope scope;
14273 LocalContext context1;
14274 ExpectString(code, "true");
14275 ExpectString(code, "true");
14276 }
14277
14278 {
14279 // Change the Boolean.prototype in the second context and check
14280 // that the right function gets called.
14281 v8::HandleScope scope;
14282 LocalContext context2;
14283 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14284 ExpectString(code, "");
14285 }
14286}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014287
14288
14289TEST(DontDeleteCellLoadIC) {
14290 const char* function_code =
14291 "function readCell() { while (true) { return cell; } }";
14292
14293 {
14294 // Run the code twice in the first context to initialize the load
14295 // IC for a don't delete cell.
14296 v8::HandleScope scope;
14297 LocalContext context1;
14298 CompileRun("var cell = \"first\";");
14299 ExpectBoolean("delete cell", false);
14300 CompileRun(function_code);
14301 ExpectString("readCell()", "first");
14302 ExpectString("readCell()", "first");
14303 }
14304
14305 {
14306 // Use a deletable cell in the second context.
14307 v8::HandleScope scope;
14308 LocalContext context2;
14309 CompileRun("cell = \"second\";");
14310 CompileRun(function_code);
14311 ExpectString("readCell()", "second");
14312 ExpectBoolean("delete cell", true);
14313 ExpectString("(function() {"
14314 " try {"
14315 " return readCell();"
14316 " } catch(e) {"
14317 " return e.toString();"
14318 " }"
14319 "})()",
14320 "ReferenceError: cell is not defined");
14321 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014322 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014323 ExpectString("readCell()", "new_second");
14324 ExpectString("readCell()", "new_second");
14325 }
14326}
14327
14328
14329TEST(DontDeleteCellLoadICForceDelete) {
14330 const char* function_code =
14331 "function readCell() { while (true) { return cell; } }";
14332
14333 // Run the code twice to initialize the load IC for a don't delete
14334 // cell.
14335 v8::HandleScope scope;
14336 LocalContext context;
14337 CompileRun("var cell = \"value\";");
14338 ExpectBoolean("delete cell", false);
14339 CompileRun(function_code);
14340 ExpectString("readCell()", "value");
14341 ExpectString("readCell()", "value");
14342
14343 // Delete the cell using the API and check the inlined code works
14344 // correctly.
14345 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14346 ExpectString("(function() {"
14347 " try {"
14348 " return readCell();"
14349 " } catch(e) {"
14350 " return e.toString();"
14351 " }"
14352 "})()",
14353 "ReferenceError: cell is not defined");
14354}
14355
14356
14357TEST(DontDeleteCellLoadICAPI) {
14358 const char* function_code =
14359 "function readCell() { while (true) { return cell; } }";
14360
14361 // Run the code twice to initialize the load IC for a don't delete
14362 // cell created using the API.
14363 v8::HandleScope scope;
14364 LocalContext context;
14365 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14366 ExpectBoolean("delete cell", false);
14367 CompileRun(function_code);
14368 ExpectString("readCell()", "value");
14369 ExpectString("readCell()", "value");
14370
14371 // Delete the cell using the API and check the inlined code works
14372 // correctly.
14373 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14374 ExpectString("(function() {"
14375 " try {"
14376 " return readCell();"
14377 " } catch(e) {"
14378 " return e.toString();"
14379 " }"
14380 "})()",
14381 "ReferenceError: cell is not defined");
14382}
14383
14384
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014385TEST(RegExp) {
14386 v8::HandleScope scope;
14387 LocalContext context;
14388
14389 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14390 CHECK(re->IsRegExp());
14391 CHECK(re->GetSource()->Equals(v8_str("foo")));
14392 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14393
14394 re = v8::RegExp::New(v8_str("bar"),
14395 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14396 v8::RegExp::kGlobal));
14397 CHECK(re->IsRegExp());
14398 CHECK(re->GetSource()->Equals(v8_str("bar")));
14399 CHECK_EQ(static_cast<int>(re->GetFlags()),
14400 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14401
14402 re = v8::RegExp::New(v8_str("baz"),
14403 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14404 v8::RegExp::kMultiline));
14405 CHECK(re->IsRegExp());
14406 CHECK(re->GetSource()->Equals(v8_str("baz")));
14407 CHECK_EQ(static_cast<int>(re->GetFlags()),
14408 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14409
14410 re = CompileRun("/quux/").As<v8::RegExp>();
14411 CHECK(re->IsRegExp());
14412 CHECK(re->GetSource()->Equals(v8_str("quux")));
14413 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14414
14415 re = CompileRun("/quux/gm").As<v8::RegExp>();
14416 CHECK(re->IsRegExp());
14417 CHECK(re->GetSource()->Equals(v8_str("quux")));
14418 CHECK_EQ(static_cast<int>(re->GetFlags()),
14419 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14420
14421 // Override the RegExp constructor and check the API constructor
14422 // still works.
14423 CompileRun("RegExp = function() {}");
14424
14425 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14426 CHECK(re->IsRegExp());
14427 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14428 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14429
14430 re = v8::RegExp::New(v8_str("foobarbaz"),
14431 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14432 v8::RegExp::kMultiline));
14433 CHECK(re->IsRegExp());
14434 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14435 CHECK_EQ(static_cast<int>(re->GetFlags()),
14436 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14437
14438 context->Global()->Set(v8_str("re"), re);
14439 ExpectTrue("re.test('FoobarbaZ')");
14440
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014441 // RegExps are objects on which you can set properties.
14442 re->Set(v8_str("property"), v8::Integer::New(32));
14443 v8::Handle<v8::Value> value = CompileRun("re.property");
14444 ASSERT_EQ(32, value->Int32Value());
14445
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014446 v8::TryCatch try_catch;
14447 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14448 CHECK(re.IsEmpty());
14449 CHECK(try_catch.HasCaught());
14450 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14451 ExpectTrue("ex instanceof SyntaxError");
14452}
14453
14454
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014455THREADED_TEST(Equals) {
14456 v8::HandleScope handleScope;
14457 LocalContext localContext;
14458
14459 v8::Handle<v8::Object> globalProxy = localContext->Global();
14460 v8::Handle<Value> global = globalProxy->GetPrototype();
14461
14462 CHECK(global->StrictEquals(global));
14463 CHECK(!global->StrictEquals(globalProxy));
14464 CHECK(!globalProxy->StrictEquals(global));
14465 CHECK(globalProxy->StrictEquals(globalProxy));
14466
14467 CHECK(global->Equals(global));
14468 CHECK(!global->Equals(globalProxy));
14469 CHECK(!globalProxy->Equals(global));
14470 CHECK(globalProxy->Equals(globalProxy));
14471}
14472
14473
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014474static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14475 const v8::AccessorInfo& info ) {
14476 return v8_str("42!");
14477}
14478
14479
14480static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14481 v8::Handle<v8::Array> result = v8::Array::New();
14482 result->Set(0, v8_str("universalAnswer"));
14483 return result;
14484}
14485
14486
14487TEST(NamedEnumeratorAndForIn) {
14488 v8::HandleScope handle_scope;
14489 LocalContext context;
14490 v8::Context::Scope context_scope(context.local());
14491
14492 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14493 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14494 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14495 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14496 "var result = []; for (var k in o) result.push(k); result"));
14497 CHECK_EQ(1, result->Length());
14498 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14499}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000014500
14501
14502TEST(DefinePropertyPostDetach) {
14503 v8::HandleScope scope;
14504 LocalContext context;
14505 v8::Handle<v8::Object> proxy = context->Global();
14506 v8::Handle<v8::Function> define_property =
14507 CompileRun("(function() {"
14508 " Object.defineProperty("
14509 " this,"
14510 " 1,"
14511 " { configurable: true, enumerable: true, value: 3 });"
14512 "})").As<Function>();
14513 context->DetachGlobal();
14514 define_property->Call(proxy, 0, NULL);
14515}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014516
14517
14518static void InstallContextId(v8::Handle<Context> context, int id) {
14519 Context::Scope scope(context);
14520 CompileRun("Object.prototype").As<Object>()->
14521 Set(v8_str("context_id"), v8::Integer::New(id));
14522}
14523
14524
14525static void CheckContextId(v8::Handle<Object> object, int expected) {
14526 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14527}
14528
14529
14530THREADED_TEST(CreationContext) {
14531 HandleScope handle_scope;
14532 Persistent<Context> context1 = Context::New();
14533 InstallContextId(context1, 1);
14534 Persistent<Context> context2 = Context::New();
14535 InstallContextId(context2, 2);
14536 Persistent<Context> context3 = Context::New();
14537 InstallContextId(context3, 3);
14538
14539 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14540
14541 Local<Object> object1;
14542 Local<Function> func1;
14543 {
14544 Context::Scope scope(context1);
14545 object1 = Object::New();
14546 func1 = tmpl->GetFunction();
14547 }
14548
14549 Local<Object> object2;
14550 Local<Function> func2;
14551 {
14552 Context::Scope scope(context2);
14553 object2 = Object::New();
14554 func2 = tmpl->GetFunction();
14555 }
14556
14557 Local<Object> instance1;
14558 Local<Object> instance2;
14559
14560 {
14561 Context::Scope scope(context3);
14562 instance1 = func1->NewInstance();
14563 instance2 = func2->NewInstance();
14564 }
14565
14566 CHECK(object1->CreationContext() == context1);
14567 CheckContextId(object1, 1);
14568 CHECK(func1->CreationContext() == context1);
14569 CheckContextId(func1, 1);
14570 CHECK(instance1->CreationContext() == context1);
14571 CheckContextId(instance1, 1);
14572 CHECK(object2->CreationContext() == context2);
14573 CheckContextId(object2, 2);
14574 CHECK(func2->CreationContext() == context2);
14575 CheckContextId(func2, 2);
14576 CHECK(instance2->CreationContext() == context2);
14577 CheckContextId(instance2, 2);
14578
14579 {
14580 Context::Scope scope(context1);
14581 CHECK(object1->CreationContext() == context1);
14582 CheckContextId(object1, 1);
14583 CHECK(func1->CreationContext() == context1);
14584 CheckContextId(func1, 1);
14585 CHECK(instance1->CreationContext() == context1);
14586 CheckContextId(instance1, 1);
14587 CHECK(object2->CreationContext() == context2);
14588 CheckContextId(object2, 2);
14589 CHECK(func2->CreationContext() == context2);
14590 CheckContextId(func2, 2);
14591 CHECK(instance2->CreationContext() == context2);
14592 CheckContextId(instance2, 2);
14593 }
14594
14595 {
14596 Context::Scope scope(context2);
14597 CHECK(object1->CreationContext() == context1);
14598 CheckContextId(object1, 1);
14599 CHECK(func1->CreationContext() == context1);
14600 CheckContextId(func1, 1);
14601 CHECK(instance1->CreationContext() == context1);
14602 CheckContextId(instance1, 1);
14603 CHECK(object2->CreationContext() == context2);
14604 CheckContextId(object2, 2);
14605 CHECK(func2->CreationContext() == context2);
14606 CheckContextId(func2, 2);
14607 CHECK(instance2->CreationContext() == context2);
14608 CheckContextId(instance2, 2);
14609 }
14610
14611 context1.Dispose();
14612 context2.Dispose();
14613 context3.Dispose();
14614}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014615
14616
14617Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14618 const AccessorInfo& info) {
14619 if (index == 42) return v8_str("yes");
14620 return Handle<v8::Integer>();
14621}
14622
14623
14624Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14625 const AccessorInfo& info) {
14626 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14627 return Handle<Value>();
14628}
14629
14630
14631Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14632 uint32_t index, const AccessorInfo& info) {
14633 if (index == 42) return v8_num(1).As<v8::Integer>();
14634 return Handle<v8::Integer>();
14635}
14636
14637
14638Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14639 Local<String> property, const AccessorInfo& info) {
14640 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14641 return Handle<v8::Integer>();
14642}
14643
14644
14645Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14646 Local<String> property, const AccessorInfo& info) {
14647 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14648 return Handle<v8::Integer>();
14649}
14650
14651
14652Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14653 const AccessorInfo& info) {
14654 return v8_str("yes");
14655}
14656
14657
14658TEST(HasOwnProperty) {
14659 v8::HandleScope scope;
14660 LocalContext env;
14661 { // Check normal properties and defined getters.
14662 Handle<Value> value = CompileRun(
14663 "function Foo() {"
14664 " this.foo = 11;"
14665 " this.__defineGetter__('baz', function() { return 1; });"
14666 "};"
14667 "function Bar() { "
14668 " this.bar = 13;"
14669 " this.__defineGetter__('bla', function() { return 2; });"
14670 "};"
14671 "Bar.prototype = new Foo();"
14672 "new Bar();");
14673 CHECK(value->IsObject());
14674 Handle<Object> object = value->ToObject();
14675 CHECK(object->Has(v8_str("foo")));
14676 CHECK(!object->HasOwnProperty(v8_str("foo")));
14677 CHECK(object->HasOwnProperty(v8_str("bar")));
14678 CHECK(object->Has(v8_str("baz")));
14679 CHECK(!object->HasOwnProperty(v8_str("baz")));
14680 CHECK(object->HasOwnProperty(v8_str("bla")));
14681 }
14682 { // Check named getter interceptors.
14683 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14684 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14685 Handle<Object> instance = templ->NewInstance();
14686 CHECK(!instance->HasOwnProperty(v8_str("42")));
14687 CHECK(instance->HasOwnProperty(v8_str("foo")));
14688 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14689 }
14690 { // Check indexed getter interceptors.
14691 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14692 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14693 Handle<Object> instance = templ->NewInstance();
14694 CHECK(instance->HasOwnProperty(v8_str("42")));
14695 CHECK(!instance->HasOwnProperty(v8_str("43")));
14696 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14697 }
14698 { // Check named query interceptors.
14699 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14700 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14701 Handle<Object> instance = templ->NewInstance();
14702 CHECK(instance->HasOwnProperty(v8_str("foo")));
14703 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14704 }
14705 { // Check indexed query interceptors.
14706 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14707 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14708 Handle<Object> instance = templ->NewInstance();
14709 CHECK(instance->HasOwnProperty(v8_str("42")));
14710 CHECK(!instance->HasOwnProperty(v8_str("41")));
14711 }
14712 { // Check callbacks.
14713 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14714 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14715 Handle<Object> instance = templ->NewInstance();
14716 CHECK(instance->HasOwnProperty(v8_str("foo")));
14717 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14718 }
14719 { // Check that query wins on disagreement.
14720 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14721 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14722 0,
14723 HasOwnPropertyNamedPropertyQuery2);
14724 Handle<Object> instance = templ->NewInstance();
14725 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14726 CHECK(instance->HasOwnProperty(v8_str("bar")));
14727 }
14728}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014729
14730
14731void CheckCodeGenerationAllowed() {
14732 Handle<Value> result = CompileRun("eval('42')");
14733 CHECK_EQ(42, result->Int32Value());
14734 result = CompileRun("(function(e) { return e('42'); })(eval)");
14735 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014736 result = CompileRun("var f = new Function('return 42'); f()");
14737 CHECK_EQ(42, result->Int32Value());
14738}
14739
14740
14741void CheckCodeGenerationDisallowed() {
14742 TryCatch try_catch;
14743
14744 Handle<Value> result = CompileRun("eval('42')");
14745 CHECK(result.IsEmpty());
14746 CHECK(try_catch.HasCaught());
14747 try_catch.Reset();
14748
14749 result = CompileRun("(function(e) { return e('42'); })(eval)");
14750 CHECK(result.IsEmpty());
14751 CHECK(try_catch.HasCaught());
14752 try_catch.Reset();
14753
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014754 result = CompileRun("var f = new Function('return 42'); f()");
14755 CHECK(result.IsEmpty());
14756 CHECK(try_catch.HasCaught());
14757}
14758
14759
14760bool CodeGenerationAllowed(Local<Context> context) {
14761 ApiTestFuzzer::Fuzz();
14762 return true;
14763}
14764
14765
14766bool CodeGenerationDisallowed(Local<Context> context) {
14767 ApiTestFuzzer::Fuzz();
14768 return false;
14769}
14770
14771
14772THREADED_TEST(AllowCodeGenFromStrings) {
14773 v8::HandleScope scope;
14774 LocalContext context;
14775
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014776 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014777 CheckCodeGenerationAllowed();
14778
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014779 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014780 context->AllowCodeGenerationFromStrings(false);
14781 CheckCodeGenerationDisallowed();
14782
14783 // Allow again.
14784 context->AllowCodeGenerationFromStrings(true);
14785 CheckCodeGenerationAllowed();
14786
14787 // Disallow but setting a global callback that will allow the calls.
14788 context->AllowCodeGenerationFromStrings(false);
14789 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14790 CheckCodeGenerationAllowed();
14791
14792 // Set a callback that disallows the code generation.
14793 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14794 CheckCodeGenerationDisallowed();
14795}
lrn@chromium.org1c092762011-05-09 09:42:16 +000014796
14797
14798static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14799 return v8::Undefined();
14800}
14801
14802
14803THREADED_TEST(CallAPIFunctionOnNonObject) {
14804 v8::HandleScope scope;
14805 LocalContext context;
14806 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14807 Handle<Function> function = templ->GetFunction();
14808 context->Global()->Set(v8_str("f"), function);
14809 TryCatch try_catch;
14810 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000014811}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014812
14813
14814// Regression test for issue 1470.
14815THREADED_TEST(ReadOnlyIndexedProperties) {
14816 v8::HandleScope scope;
14817 Local<ObjectTemplate> templ = ObjectTemplate::New();
14818
14819 LocalContext context;
14820 Local<v8::Object> obj = templ->NewInstance();
14821 context->Global()->Set(v8_str("obj"), obj);
14822 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14823 obj->Set(v8_str("1"), v8_str("foobar"));
14824 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14825 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14826 obj->Set(v8_num(2), v8_str("foobar"));
14827 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14828
14829 // Test non-smi case.
14830 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14831 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14832 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14833}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014834
14835
14836THREADED_TEST(Regress1516) {
14837 v8::HandleScope scope;
14838
14839 LocalContext context;
14840 { v8::HandleScope temp_scope;
14841 CompileRun("({'a': 0})");
14842 }
14843
14844 int elements;
14845 { i::MapCache* map_cache =
14846 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14847 elements = map_cache->NumberOfElements();
14848 CHECK_LE(1, elements);
14849 }
14850
14851 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14852 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14853 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14854 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14855 CHECK_GT(elements, map_cache->NumberOfElements());
14856 }
14857 }
14858}