blob: dad5e1b80340c70636cfd603fe3252fd04dd6c4f [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org3811b432009-10-28 14:53:37 +000028#include <limits.h>
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include "v8.h"
31
32#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000033#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000034#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000035#include "execution.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036#include "snapshot.h"
37#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000038#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000040#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000041#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000043static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000044
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000053using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000054using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000055using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000056using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000057using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000058using ::v8::FunctionTemplate;
59using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000060using ::v8::HandleScope;
61using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000062using ::v8::Message;
63using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000064using ::v8::Object;
65using ::v8::ObjectTemplate;
66using ::v8::Persistent;
67using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000068using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000069using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000070using ::v8::TryCatch;
71using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000072using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000073using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074
lrn@chromium.org32d961d2010-06-30 09:09:34 +000075namespace i = ::i;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000076
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000077
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000078static void ExpectString(const char* code, const char* expected) {
79 Local<Value> result = CompileRun(code);
80 CHECK(result->IsString());
81 String::AsciiValue ascii(result);
82 CHECK_EQ(expected, *ascii);
83}
84
85
86static void ExpectBoolean(const char* code, bool expected) {
87 Local<Value> result = CompileRun(code);
88 CHECK(result->IsBoolean());
89 CHECK_EQ(expected, result->BooleanValue());
90}
91
92
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000093static void ExpectTrue(const char* code) {
94 ExpectBoolean(code, true);
95}
96
97
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000098static void ExpectFalse(const char* code) {
99 ExpectBoolean(code, false);
100}
101
102
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000103static void ExpectObject(const char* code, Local<Value> expected) {
104 Local<Value> result = CompileRun(code);
105 CHECK(result->Equals(expected));
106}
107
108
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000109static void ExpectUndefined(const char* code) {
110 Local<Value> result = CompileRun(code);
111 CHECK(result->IsUndefined());
112}
113
114
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115static int signature_callback_count;
116static v8::Handle<Value> IncrementingSignatureCallback(
117 const v8::Arguments& args) {
118 ApiTestFuzzer::Fuzz();
119 signature_callback_count++;
120 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
121 for (int i = 0; i < args.Length(); i++)
122 result->Set(v8::Integer::New(i), args[i]);
123 return result;
124}
125
126
127static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
128 ApiTestFuzzer::Fuzz();
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++) {
131 result->Set(v8::Integer::New(i), args[i]);
132 }
133 return result;
134}
135
136
137THREADED_TEST(Handles) {
138 v8::HandleScope scope;
139 Local<Context> local_env;
140 {
141 LocalContext env;
142 local_env = env.local();
143 }
144
145 // Local context should still be live.
146 CHECK(!local_env.IsEmpty());
147 local_env->Enter();
148
149 v8::Handle<v8::Primitive> undef = v8::Undefined();
150 CHECK(!undef.IsEmpty());
151 CHECK(undef->IsUndefined());
152
153 const char* c_source = "1 + 2 + 3";
154 Local<String> source = String::New(c_source);
155 Local<Script> script = Script::Compile(source);
156 CHECK_EQ(6, script->Run()->Int32Value());
157
158 local_env->Exit();
159}
160
161
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162THREADED_TEST(ReceiverSignature) {
163 v8::HandleScope scope;
164 LocalContext env;
165 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
166 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
167 fun->PrototypeTemplate()->Set(
168 v8_str("m"),
169 v8::FunctionTemplate::New(IncrementingSignatureCallback,
170 v8::Handle<Value>(),
171 sig));
172 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
173 signature_callback_count = 0;
174 CompileRun(
175 "var o = new Fun();"
176 "o.m();");
177 CHECK_EQ(1, signature_callback_count);
178 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
179 sub_fun->Inherit(fun);
180 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
181 CompileRun(
182 "var o = new SubFun();"
183 "o.m();");
184 CHECK_EQ(2, signature_callback_count);
185
186 v8::TryCatch try_catch;
187 CompileRun(
188 "var o = { };"
189 "o.m = Fun.prototype.m;"
190 "o.m();");
191 CHECK_EQ(2, signature_callback_count);
192 CHECK(try_catch.HasCaught());
193 try_catch.Reset();
194 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
195 sub_fun->Inherit(fun);
196 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
197 CompileRun(
198 "var o = new UnrelFun();"
199 "o.m = Fun.prototype.m;"
200 "o.m();");
201 CHECK_EQ(2, signature_callback_count);
202 CHECK(try_catch.HasCaught());
203}
204
205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206THREADED_TEST(ArgumentSignature) {
207 v8::HandleScope scope;
208 LocalContext env;
209 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
210 cons->SetClassName(v8_str("Cons"));
211 v8::Handle<v8::Signature> sig =
212 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
213 v8::Handle<v8::FunctionTemplate> fun =
214 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
215 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
216 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
217
218 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000219 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
221 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000222 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
224 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000225 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
227 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
228 cons1->SetClassName(v8_str("Cons1"));
229 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
230 cons2->SetClassName(v8_str("Cons2"));
231 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
232 cons3->SetClassName(v8_str("Cons3"));
233
234 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
235 v8::Handle<v8::Signature> wsig =
236 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
237 v8::Handle<v8::FunctionTemplate> fun2 =
238 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
239
240 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
241 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
242 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
243 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
244 v8::Handle<Value> value4 = CompileRun(
245 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
246 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000247 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248
249 v8::Handle<Value> value5 = CompileRun(
250 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000251 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
253 v8::Handle<Value> value6 = CompileRun(
254 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000255 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256
257 v8::Handle<Value> value7 = CompileRun(
258 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
259 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000260 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000261
262 v8::Handle<Value> value8 = CompileRun(
263 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000264 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000265}
266
267
268THREADED_TEST(HulIgennem) {
269 v8::HandleScope scope;
270 LocalContext env;
271 v8::Handle<v8::Primitive> undef = v8::Undefined();
272 Local<String> undef_str = undef->ToString();
273 char* value = i::NewArray<char>(undef_str->Length() + 1);
274 undef_str->WriteAscii(value);
275 CHECK_EQ(0, strcmp(value, "undefined"));
276 i::DeleteArray(value);
277}
278
279
280THREADED_TEST(Access) {
281 v8::HandleScope scope;
282 LocalContext env;
283 Local<v8::Object> obj = v8::Object::New();
284 Local<Value> foo_before = obj->Get(v8_str("foo"));
285 CHECK(foo_before->IsUndefined());
286 Local<String> bar_str = v8_str("bar");
287 obj->Set(v8_str("foo"), bar_str);
288 Local<Value> foo_after = obj->Get(v8_str("foo"));
289 CHECK(!foo_after->IsUndefined());
290 CHECK(foo_after->IsString());
291 CHECK_EQ(bar_str, foo_after);
292}
293
294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000295THREADED_TEST(AccessElement) {
296 v8::HandleScope scope;
297 LocalContext env;
298 Local<v8::Object> obj = v8::Object::New();
299 Local<Value> before = obj->Get(1);
300 CHECK(before->IsUndefined());
301 Local<String> bar_str = v8_str("bar");
302 obj->Set(1, bar_str);
303 Local<Value> after = obj->Get(1);
304 CHECK(!after->IsUndefined());
305 CHECK(after->IsString());
306 CHECK_EQ(bar_str, after);
307
308 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
309 CHECK_EQ(v8_str("a"), value->Get(0));
310 CHECK_EQ(v8_str("b"), value->Get(1));
311}
312
313
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314THREADED_TEST(Script) {
315 v8::HandleScope scope;
316 LocalContext env;
317 const char* c_source = "1 + 2 + 3";
318 Local<String> source = String::New(c_source);
319 Local<Script> script = Script::Compile(source);
320 CHECK_EQ(6, script->Run()->Int32Value());
321}
322
323
324static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000325 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000326 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000327 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000328 return converted;
329}
330
331
332class TestResource: public String::ExternalStringResource {
333 public:
334 static int dispose_count;
335
336 explicit TestResource(uint16_t* data)
337 : data_(data), length_(0) {
338 while (data[length_]) ++length_;
339 }
340
341 ~TestResource() {
342 i::DeleteArray(data_);
343 ++dispose_count;
344 }
345
346 const uint16_t* data() const {
347 return data_;
348 }
349
350 size_t length() const {
351 return length_;
352 }
353 private:
354 uint16_t* data_;
355 size_t length_;
356};
357
358
359int TestResource::dispose_count = 0;
360
361
362class TestAsciiResource: public String::ExternalAsciiStringResource {
363 public:
364 static int dispose_count;
365
ager@chromium.org5ec48922009-05-05 07:25:34 +0000366 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367 : data_(data),
368 length_(strlen(data)) { }
369
370 ~TestAsciiResource() {
371 i::DeleteArray(data_);
372 ++dispose_count;
373 }
374
375 const char* data() const {
376 return data_;
377 }
378
379 size_t length() const {
380 return length_;
381 }
382 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000383 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384 size_t length_;
385};
386
387
388int TestAsciiResource::dispose_count = 0;
389
390
391THREADED_TEST(ScriptUsingStringResource) {
392 TestResource::dispose_count = 0;
393 const char* c_source = "1 + 2 * 3";
394 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
395 {
396 v8::HandleScope scope;
397 LocalContext env;
398 TestResource* resource = new TestResource(two_byte_source);
399 Local<String> source = String::NewExternal(resource);
400 Local<Script> script = Script::Compile(source);
401 Local<Value> value = script->Run();
402 CHECK(value->IsNumber());
403 CHECK_EQ(7, value->Int32Value());
404 CHECK(source->IsExternal());
405 CHECK_EQ(resource,
406 static_cast<TestResource*>(source->GetExternalStringResource()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408 CHECK_EQ(0, TestResource::dispose_count);
409 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000410 v8::internal::Isolate::Current()->compilation_cache()->Clear();
411 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000412 CHECK_EQ(1, TestResource::dispose_count);
413}
414
415
416THREADED_TEST(ScriptUsingAsciiStringResource) {
417 TestAsciiResource::dispose_count = 0;
418 const char* c_source = "1 + 2 * 3";
419 {
420 v8::HandleScope scope;
421 LocalContext env;
422 Local<String> source =
423 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
424 Local<Script> script = Script::Compile(source);
425 Local<Value> value = script->Run();
426 CHECK(value->IsNumber());
427 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000429 CHECK_EQ(0, TestAsciiResource::dispose_count);
430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 i::Isolate::Current()->compilation_cache()->Clear();
432 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000433 CHECK_EQ(1, TestAsciiResource::dispose_count);
434}
435
436
ager@chromium.org6f10e412009-02-13 10:11:16 +0000437THREADED_TEST(ScriptMakingExternalString) {
438 TestResource::dispose_count = 0;
439 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
440 {
441 v8::HandleScope scope;
442 LocalContext env;
443 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000444 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
446 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000447 bool success = source->MakeExternal(new TestResource(two_byte_source));
448 CHECK(success);
449 Local<Script> script = Script::Compile(source);
450 Local<Value> value = script->Run();
451 CHECK(value->IsNumber());
452 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000454 CHECK_EQ(0, TestResource::dispose_count);
455 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 i::Isolate::Current()->compilation_cache()->Clear();
457 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000458 CHECK_EQ(1, TestResource::dispose_count);
459}
460
461
462THREADED_TEST(ScriptMakingExternalAsciiString) {
463 TestAsciiResource::dispose_count = 0;
464 const char* c_source = "1 + 2 * 3";
465 {
466 v8::HandleScope scope;
467 LocalContext env;
468 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000469 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
471 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000472 bool success = source->MakeExternal(
473 new TestAsciiResource(i::StrDup(c_source)));
474 CHECK(success);
475 Local<Script> script = Script::Compile(source);
476 Local<Value> value = script->Run();
477 CHECK(value->IsNumber());
478 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000479 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000480 CHECK_EQ(0, TestAsciiResource::dispose_count);
481 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 i::Isolate::Current()->compilation_cache()->Clear();
483 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000484 CHECK_EQ(1, TestAsciiResource::dispose_count);
485}
486
487
ager@chromium.org5c838252010-02-19 08:53:10 +0000488TEST(MakingExternalStringConditions) {
489 v8::HandleScope scope;
490 LocalContext env;
491
492 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 HEAP->CollectGarbage(i::NEW_SPACE);
494 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000495
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000496 uint16_t* two_byte_string = AsciiToTwoByteString("small");
497 Local<String> small_string = String::New(two_byte_string);
498 i::DeleteArray(two_byte_string);
499
ager@chromium.org5c838252010-02-19 08:53:10 +0000500 // We should refuse to externalize newly created small string.
501 CHECK(!small_string->CanMakeExternal());
502 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
504 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000505 // Old space strings should be accepted.
506 CHECK(small_string->CanMakeExternal());
507
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000508 two_byte_string = AsciiToTwoByteString("small 2");
509 small_string = String::New(two_byte_string);
510 i::DeleteArray(two_byte_string);
511
ager@chromium.org5c838252010-02-19 08:53:10 +0000512 // We should refuse externalizing newly created small string.
513 CHECK(!small_string->CanMakeExternal());
514 for (int i = 0; i < 100; i++) {
515 String::Value value(small_string);
516 }
517 // Frequently used strings should be accepted.
518 CHECK(small_string->CanMakeExternal());
519
520 const int buf_size = 10 * 1024;
521 char* buf = i::NewArray<char>(buf_size);
522 memset(buf, 'a', buf_size);
523 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000524
525 two_byte_string = AsciiToTwoByteString(buf);
526 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000527 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000528 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000529 // Large strings should be immediately accepted.
530 CHECK(large_string->CanMakeExternal());
531}
532
533
534TEST(MakingExternalAsciiStringConditions) {
535 v8::HandleScope scope;
536 LocalContext env;
537
538 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HEAP->CollectGarbage(i::NEW_SPACE);
540 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000541
542 Local<String> small_string = String::New("small");
543 // We should refuse to externalize newly created small string.
544 CHECK(!small_string->CanMakeExternal());
545 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
547 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000548 // Old space strings should be accepted.
549 CHECK(small_string->CanMakeExternal());
550
551 small_string = String::New("small 2");
552 // We should refuse externalizing newly created small string.
553 CHECK(!small_string->CanMakeExternal());
554 for (int i = 0; i < 100; i++) {
555 String::Value value(small_string);
556 }
557 // Frequently used strings should be accepted.
558 CHECK(small_string->CanMakeExternal());
559
560 const int buf_size = 10 * 1024;
561 char* buf = i::NewArray<char>(buf_size);
562 memset(buf, 'a', buf_size);
563 buf[buf_size - 1] = '\0';
564 Local<String> large_string = String::New(buf);
565 i::DeleteArray(buf);
566 // Large strings should be immediately accepted.
567 CHECK(large_string->CanMakeExternal());
568}
569
570
ager@chromium.org6f10e412009-02-13 10:11:16 +0000571THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000572 {
573 v8::HandleScope scope;
574 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
575 Local<String> string =
576 String::NewExternal(new TestResource(two_byte_string));
577 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
578 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
580 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
581 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000582 CHECK(isymbol->IsSymbol());
583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HEAP->CollectAllGarbage(false);
585 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000586}
587
588
589THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000590 {
591 v8::HandleScope scope;
592 const char* one_byte_string = "test string";
593 Local<String> string = String::NewExternal(
594 new TestAsciiResource(i::StrDup(one_byte_string)));
595 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
596 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
598 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
599 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000600 CHECK(isymbol->IsSymbol());
601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 HEAP->CollectAllGarbage(false);
603 HEAP->CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000604}
605
606
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000607THREADED_TEST(ScavengeExternalString) {
608 TestResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000609 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 {
611 v8::HandleScope scope;
612 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
613 Local<String> string =
614 String::NewExternal(new TestResource(two_byte_string));
615 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 HEAP->CollectGarbage(i::NEW_SPACE);
617 in_new_space = HEAP->InNewSpace(*istring);
618 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 CHECK_EQ(0, TestResource::dispose_count);
620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CHECK_EQ(1, TestResource::dispose_count);
623}
624
625
626THREADED_TEST(ScavengeExternalAsciiString) {
627 TestAsciiResource::dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000628 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629 {
630 v8::HandleScope scope;
631 const char* one_byte_string = "test string";
632 Local<String> string = String::NewExternal(
633 new TestAsciiResource(i::StrDup(one_byte_string)));
634 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 HEAP->CollectGarbage(i::NEW_SPACE);
636 in_new_space = HEAP->InNewSpace(*istring);
637 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638 CHECK_EQ(0, TestAsciiResource::dispose_count);
639 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 CHECK_EQ(1, TestAsciiResource::dispose_count);
642}
643
644
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000645class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
646 public:
647 static int dispose_calls;
648
649 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
650 : TestAsciiResource(data),
651 dispose_(dispose) { }
652
653 void Dispose() {
654 ++dispose_calls;
655 if (dispose_) delete this;
656 }
657 private:
658 bool dispose_;
659};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000660
661
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000662int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000663
664
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000665TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000666 const char* c_source = "1 + 2 * 3";
667
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000668 // Use a stack allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000669 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000670 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
671 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000672 {
673 v8::HandleScope scope;
674 LocalContext env;
675 Local<String> source = String::NewExternal(&res_stack);
676 Local<Script> script = Script::Compile(source);
677 Local<Value> value = script->Run();
678 CHECK(value->IsNumber());
679 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000680 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000681 CHECK_EQ(0, TestAsciiResource::dispose_count);
682 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000683 i::Isolate::Current()->compilation_cache()->Clear();
684 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000685 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000686 CHECK_EQ(0, TestAsciiResource::dispose_count);
687
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688 // Use a heap allocated external string resource allocated object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000689 TestAsciiResource::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
691 TestAsciiResource* res_heap =
692 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000693 {
694 v8::HandleScope scope;
695 LocalContext env;
696 Local<String> source = String::NewExternal(res_heap);
697 Local<Script> script = Script::Compile(source);
698 Local<Value> value = script->Run();
699 CHECK(value->IsNumber());
700 CHECK_EQ(7, value->Int32Value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 HEAP->CollectAllGarbage(false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000702 CHECK_EQ(0, TestAsciiResource::dispose_count);
703 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000704 i::Isolate::Current()->compilation_cache()->Clear();
705 HEAP->CollectAllGarbage(false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000706 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000707 CHECK_EQ(1, TestAsciiResource::dispose_count);
708}
709
710
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000711THREADED_TEST(StringConcat) {
712 {
713 v8::HandleScope scope;
714 LocalContext env;
715 const char* one_byte_string_1 = "function a_times_t";
716 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
717 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
718 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
719 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
720 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
721 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
722 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000723
724 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
725 Local<String> right = String::New(two_byte_source);
726 i::DeleteArray(two_byte_source);
727
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000728 Local<String> source = String::Concat(left, right);
729 right = String::NewExternal(
730 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
731 source = String::Concat(source, right);
732 right = String::NewExternal(
733 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
734 source = String::Concat(source, right);
735 right = v8_str(one_byte_string_2);
736 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000737
738 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
739 right = String::New(two_byte_source);
740 i::DeleteArray(two_byte_source);
741
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000742 source = String::Concat(source, right);
743 right = String::NewExternal(
744 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
745 source = String::Concat(source, right);
746 Local<Script> script = Script::Compile(source);
747 Local<Value> value = script->Run();
748 CHECK(value->IsNumber());
749 CHECK_EQ(68, value->Int32Value());
750 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 i::Isolate::Current()->compilation_cache()->Clear();
752 HEAP->CollectAllGarbage(false);
753 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000754}
755
756
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757THREADED_TEST(GlobalProperties) {
758 v8::HandleScope scope;
759 LocalContext env;
760 v8::Handle<v8::Object> global = env->Global();
761 global->Set(v8_str("pi"), v8_num(3.1415926));
762 Local<Value> pi = global->Get(v8_str("pi"));
763 CHECK_EQ(3.1415926, pi->NumberValue());
764}
765
766
767static v8::Handle<Value> handle_call(const v8::Arguments& args) {
768 ApiTestFuzzer::Fuzz();
769 return v8_num(102);
770}
771
772
773static v8::Handle<Value> construct_call(const v8::Arguments& args) {
774 ApiTestFuzzer::Fuzz();
775 args.This()->Set(v8_str("x"), v8_num(1));
776 args.This()->Set(v8_str("y"), v8_num(2));
777 return args.This();
778}
779
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
781 ApiTestFuzzer::Fuzz();
782 return v8_num(239);
783}
784
785
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000786THREADED_TEST(FunctionTemplate) {
787 v8::HandleScope scope;
788 LocalContext env;
789 {
790 Local<v8::FunctionTemplate> fun_templ =
791 v8::FunctionTemplate::New(handle_call);
792 Local<Function> fun = fun_templ->GetFunction();
793 env->Global()->Set(v8_str("obj"), fun);
794 Local<Script> script = v8_compile("obj()");
795 CHECK_EQ(102, script->Run()->Int32Value());
796 }
797 // Use SetCallHandler to initialize a function template, should work like the
798 // previous one.
799 {
800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
801 fun_templ->SetCallHandler(handle_call);
802 Local<Function> fun = fun_templ->GetFunction();
803 env->Global()->Set(v8_str("obj"), fun);
804 Local<Script> script = v8_compile("obj()");
805 CHECK_EQ(102, script->Run()->Int32Value());
806 }
807 // Test constructor calls.
808 {
809 Local<v8::FunctionTemplate> fun_templ =
810 v8::FunctionTemplate::New(construct_call);
811 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000812 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813 Local<Function> fun = fun_templ->GetFunction();
814 env->Global()->Set(v8_str("obj"), fun);
815 Local<Script> script = v8_compile("var s = new obj(); s.x");
816 CHECK_EQ(1, script->Run()->Int32Value());
817
818 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
819 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000820
821 result = v8_compile("(new obj()).m")->Run();
822 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823 }
824}
825
826
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000827static void* expected_ptr;
828static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
829 void* ptr = v8::External::Unwrap(args.Data());
830 CHECK_EQ(expected_ptr, ptr);
831 return v8::Boolean::New(true);
832}
833
834
835static void TestExternalPointerWrapping() {
836 v8::HandleScope scope;
837 LocalContext env;
838
839 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
840
841 v8::Handle<v8::Object> obj = v8::Object::New();
842 obj->Set(v8_str("func"),
843 v8::FunctionTemplate::New(callback, data)->GetFunction());
844 env->Global()->Set(v8_str("obj"), obj);
845
846 CHECK(CompileRun(
847 "function foo() {\n"
848 " for (var i = 0; i < 13; i++) obj.func();\n"
849 "}\n"
850 "foo(), true")->BooleanValue());
851}
852
853
854THREADED_TEST(ExternalWrap) {
855 // Check heap allocated object.
856 int* ptr = new int;
857 expected_ptr = ptr;
858 TestExternalPointerWrapping();
859 delete ptr;
860
861 // Check stack allocated object.
862 int foo;
863 expected_ptr = &foo;
864 TestExternalPointerWrapping();
865
866 // Check not aligned addresses.
867 const int n = 100;
868 char* s = new char[n];
869 for (int i = 0; i < n; i++) {
870 expected_ptr = s + i;
871 TestExternalPointerWrapping();
872 }
873
874 delete[] s;
875
876 // Check several invalid addresses.
877 expected_ptr = reinterpret_cast<void*>(1);
878 TestExternalPointerWrapping();
879
880 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
881 TestExternalPointerWrapping();
882
883 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
884 TestExternalPointerWrapping();
885
886#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000887 // Check a value with a leading 1 bit in x64 Smi encoding.
888 expected_ptr = reinterpret_cast<void*>(0x400000000);
889 TestExternalPointerWrapping();
890
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000891 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
892 TestExternalPointerWrapping();
893
894 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
895 TestExternalPointerWrapping();
896#endif
897}
898
899
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000900THREADED_TEST(FindInstanceInPrototypeChain) {
901 v8::HandleScope scope;
902 LocalContext env;
903
904 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
905 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
906 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
907 derived->Inherit(base);
908
909 Local<v8::Function> base_function = base->GetFunction();
910 Local<v8::Function> derived_function = derived->GetFunction();
911 Local<v8::Function> other_function = other->GetFunction();
912
913 Local<v8::Object> base_instance = base_function->NewInstance();
914 Local<v8::Object> derived_instance = derived_function->NewInstance();
915 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
916 Local<v8::Object> other_instance = other_function->NewInstance();
917 derived_instance2->Set(v8_str("__proto__"), derived_instance);
918 other_instance->Set(v8_str("__proto__"), derived_instance2);
919
920 // base_instance is only an instance of base.
921 CHECK_EQ(base_instance,
922 base_instance->FindInstanceInPrototypeChain(base));
923 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
924 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
925
926 // derived_instance is an instance of base and derived.
927 CHECK_EQ(derived_instance,
928 derived_instance->FindInstanceInPrototypeChain(base));
929 CHECK_EQ(derived_instance,
930 derived_instance->FindInstanceInPrototypeChain(derived));
931 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
932
933 // other_instance is an instance of other and its immediate
934 // prototype derived_instance2 is an instance of base and derived.
935 // Note, derived_instance is an instance of base and derived too,
936 // but it comes after derived_instance2 in the prototype chain of
937 // other_instance.
938 CHECK_EQ(derived_instance2,
939 other_instance->FindInstanceInPrototypeChain(base));
940 CHECK_EQ(derived_instance2,
941 other_instance->FindInstanceInPrototypeChain(derived));
942 CHECK_EQ(other_instance,
943 other_instance->FindInstanceInPrototypeChain(other));
944}
945
946
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000947THREADED_TEST(TinyInteger) {
948 v8::HandleScope scope;
949 LocalContext env;
950 int32_t value = 239;
951 Local<v8::Integer> value_obj = v8::Integer::New(value);
952 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
953}
954
955
956THREADED_TEST(BigSmiInteger) {
957 v8::HandleScope scope;
958 LocalContext env;
959 int32_t value = i::Smi::kMaxValue;
960 // We cannot add one to a Smi::kMaxValue without wrapping.
961 if (i::kSmiValueSize < 32) {
962 CHECK(i::Smi::IsValid(value));
963 CHECK(!i::Smi::IsValid(value + 1));
964 Local<v8::Integer> value_obj = v8::Integer::New(value);
965 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
966 }
967}
968
969
970THREADED_TEST(BigInteger) {
971 v8::HandleScope scope;
972 LocalContext env;
973 // We cannot add one to a Smi::kMaxValue without wrapping.
974 if (i::kSmiValueSize < 32) {
975 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
976 // The code will not be run in that case, due to the "if" guard.
977 int32_t value =
978 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
979 CHECK(value > i::Smi::kMaxValue);
980 CHECK(!i::Smi::IsValid(value));
981 Local<v8::Integer> value_obj = v8::Integer::New(value);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
983 }
984}
985
986
987THREADED_TEST(TinyUnsignedInteger) {
988 v8::HandleScope scope;
989 LocalContext env;
990 uint32_t value = 239;
991 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
992 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
993}
994
995
996THREADED_TEST(BigUnsignedSmiInteger) {
997 v8::HandleScope scope;
998 LocalContext env;
999 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1000 CHECK(i::Smi::IsValid(value));
1001 CHECK(!i::Smi::IsValid(value + 1));
1002 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1003 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1004}
1005
1006
1007THREADED_TEST(BigUnsignedInteger) {
1008 v8::HandleScope scope;
1009 LocalContext env;
1010 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1011 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1012 CHECK(!i::Smi::IsValid(value));
1013 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1014 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1015}
1016
1017
1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1019 v8::HandleScope scope;
1020 LocalContext env;
1021 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1022 uint32_t value = INT32_MAX_AS_UINT + 1;
1023 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1024 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1026}
1027
1028
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001029THREADED_TEST(IsNativeError) {
1030 v8::HandleScope scope;
1031 LocalContext env;
1032 v8::Handle<Value> syntax_error = CompileRun(
1033 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1034 CHECK(syntax_error->IsNativeError());
1035 v8::Handle<Value> not_error = CompileRun("{a:42}");
1036 CHECK(!not_error->IsNativeError());
1037 v8::Handle<Value> not_object = CompileRun("42");
1038 CHECK(!not_object->IsNativeError());
1039}
1040
1041
1042THREADED_TEST(StringObject) {
1043 v8::HandleScope scope;
1044 LocalContext env;
1045 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1046 CHECK(boxed_string->IsStringObject());
1047 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1048 CHECK(!unboxed_string->IsStringObject());
1049 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1050 CHECK(!boxed_not_string->IsStringObject());
1051 v8::Handle<Value> not_object = CompileRun("0");
1052 CHECK(!not_object->IsStringObject());
1053 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1054 CHECK(!as_boxed.IsEmpty());
1055 Local<v8::String> the_string = as_boxed->StringValue();
1056 CHECK(!the_string.IsEmpty());
1057 ExpectObject("\"test\"", the_string);
1058 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1059 CHECK(new_boxed_string->IsStringObject());
1060 as_boxed = new_boxed_string.As<v8::StringObject>();
1061 the_string = as_boxed->StringValue();
1062 CHECK(!the_string.IsEmpty());
1063 ExpectObject("\"test\"", the_string);
1064}
1065
1066
1067THREADED_TEST(NumberObject) {
1068 v8::HandleScope scope;
1069 LocalContext env;
1070 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1071 CHECK(boxed_number->IsNumberObject());
1072 v8::Handle<Value> unboxed_number = CompileRun("42");
1073 CHECK(!unboxed_number->IsNumberObject());
1074 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1075 CHECK(!boxed_not_number->IsNumberObject());
1076 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1077 CHECK(!as_boxed.IsEmpty());
1078 double the_number = as_boxed->NumberValue();
1079 CHECK_EQ(42.0, the_number);
1080 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1081 CHECK(new_boxed_number->IsNumberObject());
1082 as_boxed = new_boxed_number.As<v8::NumberObject>();
1083 the_number = as_boxed->NumberValue();
1084 CHECK_EQ(43.0, the_number);
1085}
1086
1087
1088THREADED_TEST(BooleanObject) {
1089 v8::HandleScope scope;
1090 LocalContext env;
1091 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1092 CHECK(boxed_boolean->IsBooleanObject());
1093 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1094 CHECK(!unboxed_boolean->IsBooleanObject());
1095 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1096 CHECK(!boxed_not_boolean->IsBooleanObject());
1097 v8::Handle<v8::BooleanObject> as_boxed =
1098 boxed_boolean.As<v8::BooleanObject>();
1099 CHECK(!as_boxed.IsEmpty());
1100 bool the_boolean = as_boxed->BooleanValue();
1101 CHECK_EQ(true, the_boolean);
1102 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1103 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1104 CHECK(boxed_true->IsBooleanObject());
1105 CHECK(boxed_false->IsBooleanObject());
1106 as_boxed = boxed_true.As<v8::BooleanObject>();
1107 CHECK_EQ(true, as_boxed->BooleanValue());
1108 as_boxed = boxed_false.As<v8::BooleanObject>();
1109 CHECK_EQ(false, as_boxed->BooleanValue());
1110}
1111
1112
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001113THREADED_TEST(Number) {
1114 v8::HandleScope scope;
1115 LocalContext env;
1116 double PI = 3.1415926;
1117 Local<v8::Number> pi_obj = v8::Number::New(PI);
1118 CHECK_EQ(PI, pi_obj->NumberValue());
1119}
1120
1121
1122THREADED_TEST(ToNumber) {
1123 v8::HandleScope scope;
1124 LocalContext env;
1125 Local<String> str = v8_str("3.1415926");
1126 CHECK_EQ(3.1415926, str->NumberValue());
1127 v8::Handle<v8::Boolean> t = v8::True();
1128 CHECK_EQ(1.0, t->NumberValue());
1129 v8::Handle<v8::Boolean> f = v8::False();
1130 CHECK_EQ(0.0, f->NumberValue());
1131}
1132
1133
1134THREADED_TEST(Date) {
1135 v8::HandleScope scope;
1136 LocalContext env;
1137 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001138 Local<Value> date = v8::Date::New(PI);
1139 CHECK_EQ(3.0, date->NumberValue());
1140 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1141 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001142}
1143
1144
1145THREADED_TEST(Boolean) {
1146 v8::HandleScope scope;
1147 LocalContext env;
1148 v8::Handle<v8::Boolean> t = v8::True();
1149 CHECK(t->Value());
1150 v8::Handle<v8::Boolean> f = v8::False();
1151 CHECK(!f->Value());
1152 v8::Handle<v8::Primitive> u = v8::Undefined();
1153 CHECK(!u->BooleanValue());
1154 v8::Handle<v8::Primitive> n = v8::Null();
1155 CHECK(!n->BooleanValue());
1156 v8::Handle<String> str1 = v8_str("");
1157 CHECK(!str1->BooleanValue());
1158 v8::Handle<String> str2 = v8_str("x");
1159 CHECK(str2->BooleanValue());
1160 CHECK(!v8::Number::New(0)->BooleanValue());
1161 CHECK(v8::Number::New(-1)->BooleanValue());
1162 CHECK(v8::Number::New(1)->BooleanValue());
1163 CHECK(v8::Number::New(42)->BooleanValue());
1164 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1165}
1166
1167
1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1169 ApiTestFuzzer::Fuzz();
1170 return v8_num(13.4);
1171}
1172
1173
1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1175 ApiTestFuzzer::Fuzz();
1176 return v8_num(876);
1177}
1178
1179
1180THREADED_TEST(GlobalPrototype) {
1181 v8::HandleScope scope;
1182 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1183 func_templ->PrototypeTemplate()->Set(
1184 "dummy",
1185 v8::FunctionTemplate::New(DummyCallHandler));
1186 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1187 templ->Set("x", v8_num(200));
1188 templ->SetAccessor(v8_str("m"), GetM);
1189 LocalContext env(0, templ);
1190 v8::Handle<v8::Object> obj = env->Global();
1191 v8::Handle<Script> script = v8_compile("dummy()");
1192 v8::Handle<Value> result = script->Run();
1193 CHECK_EQ(13.4, result->NumberValue());
1194 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1195 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1196}
1197
1198
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199THREADED_TEST(ObjectTemplate) {
1200 v8::HandleScope scope;
1201 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1202 templ1->Set("x", v8_num(10));
1203 templ1->Set("y", v8_num(13));
1204 LocalContext env;
1205 Local<v8::Object> instance1 = templ1->NewInstance();
1206 env->Global()->Set(v8_str("p"), instance1);
1207 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1208 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1209 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1210 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1211 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1212 templ2->Set("a", v8_num(12));
1213 templ2->Set("b", templ1);
1214 Local<v8::Object> instance2 = templ2->NewInstance();
1215 env->Global()->Set(v8_str("q"), instance2);
1216 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1217 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1218 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1219 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1220}
1221
1222
1223static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1224 ApiTestFuzzer::Fuzz();
1225 return v8_num(17.2);
1226}
1227
1228
1229static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1230 ApiTestFuzzer::Fuzz();
1231 return v8_num(15.2);
1232}
1233
1234
1235THREADED_TEST(DescriptorInheritance) {
1236 v8::HandleScope scope;
1237 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1238 super->PrototypeTemplate()->Set("flabby",
1239 v8::FunctionTemplate::New(GetFlabby));
1240 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1241
1242 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1243
1244 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1245 base1->Inherit(super);
1246 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1247
1248 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1249 base2->Inherit(super);
1250 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1251
1252 LocalContext env;
1253
1254 env->Global()->Set(v8_str("s"), super->GetFunction());
1255 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1256 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1257
1258 // Checks right __proto__ chain.
1259 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1260 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1261
1262 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1263
1264 // Instance accessor should not be visible on function object or its prototype
1265 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1266 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1267 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1268
1269 env->Global()->Set(v8_str("obj"),
1270 base1->GetFunction()->NewInstance());
1271 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1272 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1273 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1274 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1275 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1276
1277 env->Global()->Set(v8_str("obj2"),
1278 base2->GetFunction()->NewInstance());
1279 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1280 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1281 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1282 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1283 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1284
1285 // base1 and base2 cannot cross reference to each's prototype
1286 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1287 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1288}
1289
1290
1291int echo_named_call_count;
1292
1293
1294static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1295 const AccessorInfo& info) {
1296 ApiTestFuzzer::Fuzz();
1297 CHECK_EQ(v8_str("data"), info.Data());
1298 echo_named_call_count++;
1299 return name;
1300}
1301
1302
1303THREADED_TEST(NamedPropertyHandlerGetter) {
1304 echo_named_call_count = 0;
1305 v8::HandleScope scope;
1306 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1307 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1308 0, 0, 0, 0,
1309 v8_str("data"));
1310 LocalContext env;
1311 env->Global()->Set(v8_str("obj"),
1312 templ->GetFunction()->NewInstance());
1313 CHECK_EQ(echo_named_call_count, 0);
1314 v8_compile("obj.x")->Run();
1315 CHECK_EQ(echo_named_call_count, 1);
1316 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1317 v8::Handle<Value> str = CompileRun(code);
1318 String::AsciiValue value(str);
1319 CHECK_EQ(*value, "oddlepoddle");
1320 // Check default behavior
1321 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1322 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1323 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1324}
1325
1326
1327int echo_indexed_call_count = 0;
1328
1329
1330static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1331 const AccessorInfo& info) {
1332 ApiTestFuzzer::Fuzz();
1333 CHECK_EQ(v8_num(637), info.Data());
1334 echo_indexed_call_count++;
1335 return v8_num(index);
1336}
1337
1338
1339THREADED_TEST(IndexedPropertyHandlerGetter) {
1340 v8::HandleScope scope;
1341 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1342 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1343 0, 0, 0, 0,
1344 v8_num(637));
1345 LocalContext env;
1346 env->Global()->Set(v8_str("obj"),
1347 templ->GetFunction()->NewInstance());
1348 Local<Script> script = v8_compile("obj[900]");
1349 CHECK_EQ(script->Run()->Int32Value(), 900);
1350}
1351
1352
1353v8::Handle<v8::Object> bottom;
1354
1355static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1356 uint32_t index,
1357 const AccessorInfo& info) {
1358 ApiTestFuzzer::Fuzz();
1359 CHECK(info.This()->Equals(bottom));
1360 return v8::Handle<Value>();
1361}
1362
1363static v8::Handle<Value> CheckThisNamedPropertyHandler(
1364 Local<String> name,
1365 const AccessorInfo& info) {
1366 ApiTestFuzzer::Fuzz();
1367 CHECK(info.This()->Equals(bottom));
1368 return v8::Handle<Value>();
1369}
1370
1371
1372v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1373 Local<Value> value,
1374 const AccessorInfo& info) {
1375 ApiTestFuzzer::Fuzz();
1376 CHECK(info.This()->Equals(bottom));
1377 return v8::Handle<Value>();
1378}
1379
1380
1381v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1382 Local<Value> value,
1383 const AccessorInfo& info) {
1384 ApiTestFuzzer::Fuzz();
1385 CHECK(info.This()->Equals(bottom));
1386 return v8::Handle<Value>();
1387}
1388
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001389v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001390 uint32_t index,
1391 const AccessorInfo& info) {
1392 ApiTestFuzzer::Fuzz();
1393 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001394 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001395}
1396
1397
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001398v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001399 const AccessorInfo& info) {
1400 ApiTestFuzzer::Fuzz();
1401 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001402 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001403}
1404
1405
1406v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1407 uint32_t index,
1408 const AccessorInfo& info) {
1409 ApiTestFuzzer::Fuzz();
1410 CHECK(info.This()->Equals(bottom));
1411 return v8::Handle<v8::Boolean>();
1412}
1413
1414
1415v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1416 Local<String> property,
1417 const AccessorInfo& info) {
1418 ApiTestFuzzer::Fuzz();
1419 CHECK(info.This()->Equals(bottom));
1420 return v8::Handle<v8::Boolean>();
1421}
1422
1423
1424v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1425 const AccessorInfo& info) {
1426 ApiTestFuzzer::Fuzz();
1427 CHECK(info.This()->Equals(bottom));
1428 return v8::Handle<v8::Array>();
1429}
1430
1431
1432v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1433 const AccessorInfo& info) {
1434 ApiTestFuzzer::Fuzz();
1435 CHECK(info.This()->Equals(bottom));
1436 return v8::Handle<v8::Array>();
1437}
1438
1439
1440THREADED_TEST(PropertyHandlerInPrototype) {
1441 v8::HandleScope scope;
1442 LocalContext env;
1443
1444 // Set up a prototype chain with three interceptors.
1445 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1446 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1447 CheckThisIndexedPropertyHandler,
1448 CheckThisIndexedPropertySetter,
1449 CheckThisIndexedPropertyQuery,
1450 CheckThisIndexedPropertyDeleter,
1451 CheckThisIndexedPropertyEnumerator);
1452
1453 templ->InstanceTemplate()->SetNamedPropertyHandler(
1454 CheckThisNamedPropertyHandler,
1455 CheckThisNamedPropertySetter,
1456 CheckThisNamedPropertyQuery,
1457 CheckThisNamedPropertyDeleter,
1458 CheckThisNamedPropertyEnumerator);
1459
1460 bottom = templ->GetFunction()->NewInstance();
1461 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1462 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1463
1464 bottom->Set(v8_str("__proto__"), middle);
1465 middle->Set(v8_str("__proto__"), top);
1466 env->Global()->Set(v8_str("obj"), bottom);
1467
1468 // Indexed and named get.
1469 Script::Compile(v8_str("obj[0]"))->Run();
1470 Script::Compile(v8_str("obj.x"))->Run();
1471
1472 // Indexed and named set.
1473 Script::Compile(v8_str("obj[1] = 42"))->Run();
1474 Script::Compile(v8_str("obj.y = 42"))->Run();
1475
1476 // Indexed and named query.
1477 Script::Compile(v8_str("0 in obj"))->Run();
1478 Script::Compile(v8_str("'x' in obj"))->Run();
1479
1480 // Indexed and named deleter.
1481 Script::Compile(v8_str("delete obj[0]"))->Run();
1482 Script::Compile(v8_str("delete obj.x"))->Run();
1483
1484 // Enumerators.
1485 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1486}
1487
1488
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001489static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1490 const AccessorInfo& info) {
1491 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001492 if (v8_str("pre")->Equals(key)) {
1493 return v8_str("PrePropertyHandler: pre");
1494 }
1495 return v8::Handle<String>();
1496}
1497
1498
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001499static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1500 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001501 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001502 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001503 }
1504
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001505 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001506}
1507
1508
1509THREADED_TEST(PrePropertyHandler) {
1510 v8::HandleScope scope;
1511 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1512 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1513 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001514 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001515 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001516 Script::Compile(v8_str(
1517 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1518 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1519 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1520 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1521 CHECK_EQ(v8_str("Object: on"), result_on);
1522 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1523 CHECK(result_post.IsEmpty());
1524}
1525
1526
ager@chromium.org870a0b62008-11-04 11:43:05 +00001527THREADED_TEST(UndefinedIsNotEnumerable) {
1528 v8::HandleScope scope;
1529 LocalContext env;
1530 v8::Handle<Value> result = Script::Compile(v8_str(
1531 "this.propertyIsEnumerable(undefined)"))->Run();
1532 CHECK(result->IsFalse());
1533}
1534
1535
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001536v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001537static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001538
1539
1540static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1541 ApiTestFuzzer::Fuzz();
1542 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1543 if (depth == kTargetRecursionDepth) return v8::Undefined();
1544 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1545 return call_recursively_script->Run();
1546}
1547
1548
1549static v8::Handle<Value> CallFunctionRecursivelyCall(
1550 const v8::Arguments& args) {
1551 ApiTestFuzzer::Fuzz();
1552 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1553 if (depth == kTargetRecursionDepth) {
1554 printf("[depth = %d]\n", depth);
1555 return v8::Undefined();
1556 }
1557 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1558 v8::Handle<Value> function =
1559 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001560 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001561}
1562
1563
1564THREADED_TEST(DeepCrossLanguageRecursion) {
1565 v8::HandleScope scope;
1566 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1567 global->Set(v8_str("callScriptRecursively"),
1568 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1569 global->Set(v8_str("callFunctionRecursively"),
1570 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1571 LocalContext env(NULL, global);
1572
1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1574 call_recursively_script = v8_compile("callScriptRecursively()");
1575 v8::Handle<Value> result = call_recursively_script->Run();
1576 call_recursively_script = v8::Handle<Script>();
1577
1578 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1579 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1580}
1581
1582
1583static v8::Handle<Value>
1584 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1585 ApiTestFuzzer::Fuzz();
1586 return v8::ThrowException(key);
1587}
1588
1589
1590static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1591 Local<Value>,
1592 const AccessorInfo&) {
1593 v8::ThrowException(key);
1594 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1595}
1596
1597
1598THREADED_TEST(CallbackExceptionRegression) {
1599 v8::HandleScope scope;
1600 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1601 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1602 ThrowingPropertyHandlerSet);
1603 LocalContext env;
1604 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1605 v8::Handle<Value> otto = Script::Compile(v8_str(
1606 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1607 CHECK_EQ(v8_str("otto"), otto);
1608 v8::Handle<Value> netto = Script::Compile(v8_str(
1609 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1610 CHECK_EQ(v8_str("netto"), netto);
1611}
1612
1613
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001614THREADED_TEST(FunctionPrototype) {
1615 v8::HandleScope scope;
1616 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1617 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1618 LocalContext env;
1619 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1620 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1621 CHECK_EQ(script->Run()->Int32Value(), 321);
1622}
1623
1624
1625THREADED_TEST(InternalFields) {
1626 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001627 LocalContext env;
1628
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001629 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1630 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1631 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001632 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1633 CHECK_EQ(1, obj->InternalFieldCount());
1634 CHECK(obj->GetInternalField(0)->IsUndefined());
1635 obj->SetInternalField(0, v8_num(17));
1636 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1637}
1638
1639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001640THREADED_TEST(GlobalObjectInternalFields) {
1641 v8::HandleScope scope;
1642 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1643 global_template->SetInternalFieldCount(1);
1644 LocalContext env(NULL, global_template);
1645 v8::Handle<v8::Object> global_proxy = env->Global();
1646 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1647 CHECK_EQ(1, global->InternalFieldCount());
1648 CHECK(global->GetInternalField(0)->IsUndefined());
1649 global->SetInternalField(0, v8_num(17));
1650 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1651}
1652
1653
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001654THREADED_TEST(InternalFieldsNativePointers) {
1655 v8::HandleScope scope;
1656 LocalContext env;
1657
1658 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1659 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1660 instance_templ->SetInternalFieldCount(1);
1661 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1662 CHECK_EQ(1, obj->InternalFieldCount());
1663 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1664
1665 char* data = new char[100];
1666
1667 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001668 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001669 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001670 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001671
1672 // Check reading and writing aligned pointers.
1673 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001674 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001675 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1676
1677 // Check reading and writing unaligned pointers.
1678 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HEAP->CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001680 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1681
1682 delete[] data;
1683}
1684
1685
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001686THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1687 v8::HandleScope scope;
1688 LocalContext env;
1689
1690 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1691 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1692 instance_templ->SetInternalFieldCount(1);
1693 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1694 CHECK_EQ(1, obj->InternalFieldCount());
1695 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1696
1697 char* data = new char[100];
1698
1699 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001700 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001701 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001702 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001703
1704 obj->SetPointerInInternalField(0, aligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001706 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1707
1708 obj->SetPointerInInternalField(0, unaligned);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001709 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001710 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1711
1712 obj->SetInternalField(0, v8::External::Wrap(aligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001714 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1715
1716 obj->SetInternalField(0, v8::External::Wrap(unaligned));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HEAP->CollectAllGarbage(false);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001718 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1719
1720 delete[] data;
1721}
1722
1723
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001724THREADED_TEST(IdentityHash) {
1725 v8::HandleScope scope;
1726 LocalContext env;
1727
1728 // Ensure that the test starts with an fresh heap to test whether the hash
1729 // code is based on the address.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001731 Local<v8::Object> obj = v8::Object::New();
1732 int hash = obj->GetIdentityHash();
1733 int hash1 = obj->GetIdentityHash();
1734 CHECK_EQ(hash, hash1);
1735 int hash2 = v8::Object::New()->GetIdentityHash();
1736 // Since the identity hash is essentially a random number two consecutive
1737 // objects should not be assigned the same hash code. If the test below fails
1738 // the random number generator should be evaluated.
1739 CHECK_NE(hash, hash2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001741 int hash3 = v8::Object::New()->GetIdentityHash();
1742 // Make sure that the identity hash is not based on the initial address of
1743 // the object alone. If the test below fails the random number generator
1744 // should be evaluated.
1745 CHECK_NE(hash, hash3);
1746 int hash4 = obj->GetIdentityHash();
1747 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001748
1749 // Check identity hashes behaviour in the presence of JS accessors.
1750 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1751 {
1752 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1753 Local<v8::Object> o1 = v8::Object::New();
1754 Local<v8::Object> o2 = v8::Object::New();
1755 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1756 }
1757 {
1758 CompileRun(
1759 "function cnst() { return 42; };\n"
1760 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1761 Local<v8::Object> o1 = v8::Object::New();
1762 Local<v8::Object> o2 = v8::Object::New();
1763 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1764 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001765}
1766
1767
1768THREADED_TEST(HiddenProperties) {
1769 v8::HandleScope scope;
1770 LocalContext env;
1771
1772 v8::Local<v8::Object> obj = v8::Object::New();
1773 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1774 v8::Local<v8::String> empty = v8_str("");
1775 v8::Local<v8::String> prop_name = v8_str("prop_name");
1776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001778
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001779 // Make sure delete of a non-existent hidden value works
1780 CHECK(obj->DeleteHiddenValue(key));
1781
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001782 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1783 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1784 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1785 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001788
1789 // Make sure we do not find the hidden property.
1790 CHECK(!obj->Has(empty));
1791 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1792 CHECK(obj->Get(empty)->IsUndefined());
1793 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1794 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1795 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1796 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001799
1800 // Add another property and delete it afterwards to force the object in
1801 // slow case.
1802 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1803 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1804 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1805 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1806 CHECK(obj->Delete(prop_name));
1807 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1808
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HEAP->CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001810
1811 CHECK(obj->DeleteHiddenValue(key));
1812 CHECK(obj->GetHiddenValue(key).IsEmpty());
1813}
1814
1815
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001816static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001817static v8::Handle<Value> InterceptorForHiddenProperties(
1818 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001819 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001820 return v8::Handle<Value>();
1821}
1822
1823
1824THREADED_TEST(HiddenPropertiesWithInterceptors) {
1825 v8::HandleScope scope;
1826 LocalContext context;
1827
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001828 interceptor_for_hidden_properties_called = false;
1829
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001830 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1831
1832 // Associate an interceptor with an object and start setting hidden values.
1833 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1834 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1835 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1836 Local<v8::Function> function = fun_templ->GetFunction();
1837 Local<v8::Object> obj = function->NewInstance();
1838 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1839 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001840 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001841}
1842
1843
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001844THREADED_TEST(External) {
1845 v8::HandleScope scope;
1846 int x = 3;
1847 Local<v8::External> ext = v8::External::New(&x);
1848 LocalContext env;
1849 env->Global()->Set(v8_str("ext"), ext);
1850 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001851 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001852 int* ptr = static_cast<int*>(reext->Value());
1853 CHECK_EQ(x, 3);
1854 *ptr = 10;
1855 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001856
1857 // Make sure unaligned pointers are wrapped properly.
1858 char* data = i::StrDup("0123456789");
1859 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1860 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1861 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1862 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1863
1864 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1865 CHECK_EQ('0', *char_ptr);
1866 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1867 CHECK_EQ('1', *char_ptr);
1868 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1869 CHECK_EQ('2', *char_ptr);
1870 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1871 CHECK_EQ('3', *char_ptr);
1872 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001873}
1874
1875
1876THREADED_TEST(GlobalHandle) {
1877 v8::Persistent<String> global;
1878 {
1879 v8::HandleScope scope;
1880 Local<String> str = v8_str("str");
1881 global = v8::Persistent<String>::New(str);
1882 }
1883 CHECK_EQ(global->Length(), 3);
1884 global.Dispose();
1885}
1886
1887
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001888static int NumberOfWeakCalls = 0;
1889static void WeakPointerCallback(Persistent<Value> handle, void* id) {
1890 CHECK_EQ(reinterpret_cast<void*>(1234), id);
1891 NumberOfWeakCalls++;
1892 handle.Dispose();
1893}
1894
1895THREADED_TEST(ApiObjectGroups) {
1896 HandleScope scope;
1897 LocalContext env;
1898
1899 NumberOfWeakCalls = 0;
1900
1901 Persistent<Object> g1s1;
1902 Persistent<Object> g1s2;
1903 Persistent<Object> g1c1;
1904 Persistent<Object> g2s1;
1905 Persistent<Object> g2s2;
1906 Persistent<Object> g2c1;
1907
1908 {
1909 HandleScope scope;
1910 g1s1 = Persistent<Object>::New(Object::New());
1911 g1s2 = Persistent<Object>::New(Object::New());
1912 g1c1 = Persistent<Object>::New(Object::New());
1913 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1914 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1915 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1916
1917 g2s1 = Persistent<Object>::New(Object::New());
1918 g2s2 = Persistent<Object>::New(Object::New());
1919 g2c1 = Persistent<Object>::New(Object::New());
1920 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1921 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1922 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1923 }
1924
1925 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
1926
1927 // Connect group 1 and 2, make a cycle.
1928 CHECK(g1s2->Set(0, g2s2));
1929 CHECK(g2s1->Set(0, g1s1));
1930
1931 {
1932 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1933 Persistent<Value> g1_children[] = { g1c1 };
1934 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1935 Persistent<Value> g2_children[] = { g2c1 };
1936 V8::AddObjectGroup(g1_objects, 2);
1937 V8::AddImplicitReferences(g1s1, g1_children, 1);
1938 V8::AddObjectGroup(g2_objects, 2);
1939 V8::AddImplicitReferences(g2s2, g2_children, 1);
1940 }
1941 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001943
1944 // All object should be alive.
1945 CHECK_EQ(0, NumberOfWeakCalls);
1946
1947 // Weaken the root.
1948 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1949 // But make children strong roots---all the objects (except for children)
1950 // should be collectable now.
1951 g1c1.ClearWeak();
1952 g2c1.ClearWeak();
1953
1954 // Groups are deleted, rebuild groups.
1955 {
1956 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
1957 Persistent<Value> g1_children[] = { g1c1 };
1958 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
1959 Persistent<Value> g2_children[] = { g2c1 };
1960 V8::AddObjectGroup(g1_objects, 2);
1961 V8::AddImplicitReferences(g1s1, g1_children, 1);
1962 V8::AddObjectGroup(g2_objects, 2);
1963 V8::AddImplicitReferences(g2s2, g2_children, 1);
1964 }
1965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001967
1968 // All objects should be gone. 5 global handles in total.
1969 CHECK_EQ(5, NumberOfWeakCalls);
1970
1971 // And now make children weak again and collect them.
1972 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1973 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001976 CHECK_EQ(7, NumberOfWeakCalls);
1977}
1978
1979
1980THREADED_TEST(ApiObjectGroupsCycle) {
1981 HandleScope scope;
1982 LocalContext env;
1983
1984 NumberOfWeakCalls = 0;
1985
1986 Persistent<Object> g1s1;
1987 Persistent<Object> g1s2;
1988 Persistent<Object> g2s1;
1989 Persistent<Object> g2s2;
1990 Persistent<Object> g3s1;
1991 Persistent<Object> g3s2;
1992
1993 {
1994 HandleScope scope;
1995 g1s1 = Persistent<Object>::New(Object::New());
1996 g1s2 = Persistent<Object>::New(Object::New());
1997 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1998 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
1999
2000 g2s1 = Persistent<Object>::New(Object::New());
2001 g2s2 = Persistent<Object>::New(Object::New());
2002 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2003 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2004
2005 g3s1 = Persistent<Object>::New(Object::New());
2006 g3s2 = Persistent<Object>::New(Object::New());
2007 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2008 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2009 }
2010
2011 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2012
2013 // Connect groups. We're building the following cycle:
2014 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2015 // groups.
2016 {
2017 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2018 Persistent<Value> g1_children[] = { g2s1 };
2019 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2020 Persistent<Value> g2_children[] = { g3s1 };
2021 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2022 Persistent<Value> g3_children[] = { g1s1 };
2023 V8::AddObjectGroup(g1_objects, 2);
2024 V8::AddImplicitReferences(g1s1, g1_children, 1);
2025 V8::AddObjectGroup(g2_objects, 2);
2026 V8::AddImplicitReferences(g2s1, g2_children, 1);
2027 V8::AddObjectGroup(g3_objects, 2);
2028 V8::AddImplicitReferences(g3s1, g3_children, 1);
2029 }
2030 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002032
2033 // All object should be alive.
2034 CHECK_EQ(0, NumberOfWeakCalls);
2035
2036 // Weaken the root.
2037 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
2038
2039 // Groups are deleted, rebuild groups.
2040 {
2041 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2042 Persistent<Value> g1_children[] = { g2s1 };
2043 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2044 Persistent<Value> g2_children[] = { g3s1 };
2045 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2046 Persistent<Value> g3_children[] = { g1s1 };
2047 V8::AddObjectGroup(g1_objects, 2);
2048 V8::AddImplicitReferences(g1s1, g1_children, 1);
2049 V8::AddObjectGroup(g2_objects, 2);
2050 V8::AddImplicitReferences(g2s1, g2_children, 1);
2051 V8::AddObjectGroup(g3_objects, 2);
2052 V8::AddImplicitReferences(g3s1, g3_children, 1);
2053 }
2054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 HEAP->CollectGarbage(i::OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002056
2057 // All objects should be gone. 7 global handles in total.
2058 CHECK_EQ(7, NumberOfWeakCalls);
2059}
2060
2061
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002062THREADED_TEST(ScriptException) {
2063 v8::HandleScope scope;
2064 LocalContext env;
2065 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2066 v8::TryCatch try_catch;
2067 Local<Value> result = script->Run();
2068 CHECK(result.IsEmpty());
2069 CHECK(try_catch.HasCaught());
2070 String::AsciiValue exception_value(try_catch.Exception());
2071 CHECK_EQ(*exception_value, "panama!");
2072}
2073
2074
2075bool message_received;
2076
2077
2078static void check_message(v8::Handle<v8::Message> message,
2079 v8::Handle<Value> data) {
2080 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002081 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002082 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002083 message_received = true;
2084}
2085
2086
2087THREADED_TEST(MessageHandlerData) {
2088 message_received = false;
2089 v8::HandleScope scope;
2090 CHECK(!message_received);
2091 v8::V8::AddMessageListener(check_message, v8_num(5.76));
2092 LocalContext context;
2093 v8::ScriptOrigin origin =
2094 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002095 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2096 &origin);
2097 script->SetData(v8_str("7.56"));
2098 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002099 CHECK(message_received);
2100 // clear out the message listener
2101 v8::V8::RemoveMessageListeners(check_message);
2102}
2103
2104
2105THREADED_TEST(GetSetProperty) {
2106 v8::HandleScope scope;
2107 LocalContext context;
2108 context->Global()->Set(v8_str("foo"), v8_num(14));
2109 context->Global()->Set(v8_str("12"), v8_num(92));
2110 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2111 context->Global()->Set(v8_num(13), v8_num(56));
2112 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2113 CHECK_EQ(14, foo->Int32Value());
2114 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2115 CHECK_EQ(92, twelve->Int32Value());
2116 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2117 CHECK_EQ(32, sixteen->Int32Value());
2118 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2119 CHECK_EQ(56, thirteen->Int32Value());
2120 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2121 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2122 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2123 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2124 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2125 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2126 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2127 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2128 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2129}
2130
2131
2132THREADED_TEST(PropertyAttributes) {
2133 v8::HandleScope scope;
2134 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002135 // none
2136 Local<String> prop = v8_str("none");
2137 context->Global()->Set(prop, v8_num(7));
2138 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002139 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002140 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002141 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2142 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002143 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002144 Script::Compile(v8_str("read_only = 9"))->Run();
2145 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2146 context->Global()->Set(prop, v8_num(10));
2147 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2148 // dont-delete
2149 prop = v8_str("dont_delete");
2150 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2151 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2152 Script::Compile(v8_str("delete dont_delete"))->Run();
2153 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002154 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2155 // dont-enum
2156 prop = v8_str("dont_enum");
2157 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2158 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2159 // absent
2160 prop = v8_str("absent");
2161 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2162 Local<Value> fake_prop = v8_num(1);
2163 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2164 // exception
2165 TryCatch try_catch;
2166 Local<Value> exception =
2167 CompileRun("({ toString: function() { throw 'exception';} })");
2168 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2169 CHECK(try_catch.HasCaught());
2170 String::AsciiValue exception_value(try_catch.Exception());
2171 CHECK_EQ("exception", *exception_value);
2172 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173}
2174
2175
2176THREADED_TEST(Array) {
2177 v8::HandleScope scope;
2178 LocalContext context;
2179 Local<v8::Array> array = v8::Array::New();
2180 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002181 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002182 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002183 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002184 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002185 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002186 CHECK_EQ(3, array->Length());
2187 CHECK(!array->Has(0));
2188 CHECK(!array->Has(1));
2189 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002190 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002191 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002192 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002193 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002194 CHECK_EQ(1, arr->Get(0)->Int32Value());
2195 CHECK_EQ(2, arr->Get(1)->Int32Value());
2196 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002197 array = v8::Array::New(27);
2198 CHECK_EQ(27, array->Length());
2199 array = v8::Array::New(-27);
2200 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002201}
2202
2203
2204v8::Handle<Value> HandleF(const v8::Arguments& args) {
2205 v8::HandleScope scope;
2206 ApiTestFuzzer::Fuzz();
2207 Local<v8::Array> result = v8::Array::New(args.Length());
2208 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002209 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002210 return scope.Close(result);
2211}
2212
2213
2214THREADED_TEST(Vector) {
2215 v8::HandleScope scope;
2216 Local<ObjectTemplate> global = ObjectTemplate::New();
2217 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2218 LocalContext context(0, global);
2219
2220 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002221 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002222 CHECK_EQ(0, a0->Length());
2223
2224 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002225 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002226 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002227 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002228
2229 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002230 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002231 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002232 CHECK_EQ(12, a2->Get(0)->Int32Value());
2233 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002234
2235 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002236 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002237 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002238 CHECK_EQ(14, a3->Get(0)->Int32Value());
2239 CHECK_EQ(15, a3->Get(1)->Int32Value());
2240 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002241
2242 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002243 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002244 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002245 CHECK_EQ(17, a4->Get(0)->Int32Value());
2246 CHECK_EQ(18, a4->Get(1)->Int32Value());
2247 CHECK_EQ(19, a4->Get(2)->Int32Value());
2248 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002249}
2250
2251
2252THREADED_TEST(FunctionCall) {
2253 v8::HandleScope scope;
2254 LocalContext context;
2255 CompileRun(
2256 "function Foo() {"
2257 " var result = [];"
2258 " for (var i = 0; i < arguments.length; i++) {"
2259 " result.push(arguments[i]);"
2260 " }"
2261 " return result;"
2262 "}");
2263 Local<Function> Foo =
2264 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2265
2266 v8::Handle<Value>* args0 = NULL;
2267 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2268 CHECK_EQ(0, a0->Length());
2269
2270 v8::Handle<Value> args1[] = { v8_num(1.1) };
2271 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2272 CHECK_EQ(1, a1->Length());
2273 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2274
2275 v8::Handle<Value> args2[] = { v8_num(2.2),
2276 v8_num(3.3) };
2277 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2278 CHECK_EQ(2, a2->Length());
2279 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2280 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2281
2282 v8::Handle<Value> args3[] = { v8_num(4.4),
2283 v8_num(5.5),
2284 v8_num(6.6) };
2285 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2286 CHECK_EQ(3, a3->Length());
2287 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2288 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2289 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2290
2291 v8::Handle<Value> args4[] = { v8_num(7.7),
2292 v8_num(8.8),
2293 v8_num(9.9),
2294 v8_num(10.11) };
2295 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2296 CHECK_EQ(4, a4->Length());
2297 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2298 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2299 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2300 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2301}
2302
2303
2304static const char* js_code_causing_out_of_memory =
2305 "var a = new Array(); while(true) a.push(a);";
2306
2307
2308// These tests run for a long time and prevent us from running tests
2309// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002310TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002311 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002312 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002313 // Set heap limits.
2314 static const int K = 1024;
2315 v8::ResourceConstraints constraints;
2316 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002317 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318 v8::SetResourceConstraints(&constraints);
2319
2320 // Execute a script that causes out of memory.
2321 v8::HandleScope scope;
2322 LocalContext context;
2323 v8::V8::IgnoreOutOfMemoryException();
2324 Local<Script> script =
2325 Script::Compile(String::New(js_code_causing_out_of_memory));
2326 Local<Value> result = script->Run();
2327
2328 // Check for out of memory state.
2329 CHECK(result.IsEmpty());
2330 CHECK(context->HasOutOfMemoryException());
2331}
2332
2333
2334v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2335 ApiTestFuzzer::Fuzz();
2336
2337 v8::HandleScope scope;
2338 LocalContext context;
2339 Local<Script> script =
2340 Script::Compile(String::New(js_code_causing_out_of_memory));
2341 Local<Value> result = script->Run();
2342
2343 // Check for out of memory state.
2344 CHECK(result.IsEmpty());
2345 CHECK(context->HasOutOfMemoryException());
2346
2347 return result;
2348}
2349
2350
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002351TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002352 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002353 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002354 // Set heap limits.
2355 static const int K = 1024;
2356 v8::ResourceConstraints constraints;
2357 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002358 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002359 v8::SetResourceConstraints(&constraints);
2360
2361 v8::HandleScope scope;
2362 Local<ObjectTemplate> templ = ObjectTemplate::New();
2363 templ->Set(v8_str("ProvokeOutOfMemory"),
2364 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2365 LocalContext context(0, templ);
2366 v8::V8::IgnoreOutOfMemoryException();
2367 Local<Value> result = CompileRun(
2368 "var thrown = false;"
2369 "try {"
2370 " ProvokeOutOfMemory();"
2371 "} catch (e) {"
2372 " thrown = true;"
2373 "}");
2374 // Check for out of memory state.
2375 CHECK(result.IsEmpty());
2376 CHECK(context->HasOutOfMemoryException());
2377}
2378
2379
2380TEST(HugeConsStringOutOfMemory) {
2381 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002382 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002383 // Set heap limits.
2384 static const int K = 1024;
2385 v8::ResourceConstraints constraints;
2386 constraints.set_max_young_space_size(256 * K);
2387 constraints.set_max_old_space_size(2 * K * K);
2388 v8::SetResourceConstraints(&constraints);
2389
2390 // Execute a script that causes out of memory.
2391 v8::V8::IgnoreOutOfMemoryException();
2392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002393 v8::HandleScope scope;
2394 LocalContext context;
2395
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002396 // Build huge string. This should fail with out of memory exception.
2397 Local<Value> result = CompileRun(
2398 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002399 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002400
2401 // Check for out of memory state.
2402 CHECK(result.IsEmpty());
2403 CHECK(context->HasOutOfMemoryException());
2404}
2405
2406
2407THREADED_TEST(ConstructCall) {
2408 v8::HandleScope scope;
2409 LocalContext context;
2410 CompileRun(
2411 "function Foo() {"
2412 " var result = [];"
2413 " for (var i = 0; i < arguments.length; i++) {"
2414 " result.push(arguments[i]);"
2415 " }"
2416 " return result;"
2417 "}");
2418 Local<Function> Foo =
2419 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2420
2421 v8::Handle<Value>* args0 = NULL;
2422 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2423 CHECK_EQ(0, a0->Length());
2424
2425 v8::Handle<Value> args1[] = { v8_num(1.1) };
2426 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2427 CHECK_EQ(1, a1->Length());
2428 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2429
2430 v8::Handle<Value> args2[] = { v8_num(2.2),
2431 v8_num(3.3) };
2432 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2433 CHECK_EQ(2, a2->Length());
2434 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2435 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2436
2437 v8::Handle<Value> args3[] = { v8_num(4.4),
2438 v8_num(5.5),
2439 v8_num(6.6) };
2440 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2441 CHECK_EQ(3, a3->Length());
2442 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2443 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2444 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2445
2446 v8::Handle<Value> args4[] = { v8_num(7.7),
2447 v8_num(8.8),
2448 v8_num(9.9),
2449 v8_num(10.11) };
2450 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2451 CHECK_EQ(4, a4->Length());
2452 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2453 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2454 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2455 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2456}
2457
2458
2459static void CheckUncle(v8::TryCatch* try_catch) {
2460 CHECK(try_catch->HasCaught());
2461 String::AsciiValue str_value(try_catch->Exception());
2462 CHECK_EQ(*str_value, "uncle?");
2463 try_catch->Reset();
2464}
2465
2466
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002467THREADED_TEST(ConversionNumber) {
2468 v8::HandleScope scope;
2469 LocalContext env;
2470 // Very large number.
2471 CompileRun("var obj = Math.pow(2,32) * 1237;");
2472 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2473 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2474 CHECK_EQ(0, obj->ToInt32()->Value());
2475 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2476 // Large number.
2477 CompileRun("var obj = -1234567890123;");
2478 obj = env->Global()->Get(v8_str("obj"));
2479 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2480 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2481 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2482 // Small positive integer.
2483 CompileRun("var obj = 42;");
2484 obj = env->Global()->Get(v8_str("obj"));
2485 CHECK_EQ(42.0, obj->ToNumber()->Value());
2486 CHECK_EQ(42, obj->ToInt32()->Value());
2487 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2488 // Negative integer.
2489 CompileRun("var obj = -37;");
2490 obj = env->Global()->Get(v8_str("obj"));
2491 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2492 CHECK_EQ(-37, obj->ToInt32()->Value());
2493 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2494 // Positive non-int32 integer.
2495 CompileRun("var obj = 0x81234567;");
2496 obj = env->Global()->Get(v8_str("obj"));
2497 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2498 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2499 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2500 // Fraction.
2501 CompileRun("var obj = 42.3;");
2502 obj = env->Global()->Get(v8_str("obj"));
2503 CHECK_EQ(42.3, obj->ToNumber()->Value());
2504 CHECK_EQ(42, obj->ToInt32()->Value());
2505 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2506 // Large negative fraction.
2507 CompileRun("var obj = -5726623061.75;");
2508 obj = env->Global()->Get(v8_str("obj"));
2509 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2510 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2511 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2512}
2513
2514
2515THREADED_TEST(isNumberType) {
2516 v8::HandleScope scope;
2517 LocalContext env;
2518 // Very large number.
2519 CompileRun("var obj = Math.pow(2,32) * 1237;");
2520 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2521 CHECK(!obj->IsInt32());
2522 CHECK(!obj->IsUint32());
2523 // Large negative number.
2524 CompileRun("var obj = -1234567890123;");
2525 obj = env->Global()->Get(v8_str("obj"));
2526 CHECK(!obj->IsInt32());
2527 CHECK(!obj->IsUint32());
2528 // Small positive integer.
2529 CompileRun("var obj = 42;");
2530 obj = env->Global()->Get(v8_str("obj"));
2531 CHECK(obj->IsInt32());
2532 CHECK(obj->IsUint32());
2533 // Negative integer.
2534 CompileRun("var obj = -37;");
2535 obj = env->Global()->Get(v8_str("obj"));
2536 CHECK(obj->IsInt32());
2537 CHECK(!obj->IsUint32());
2538 // Positive non-int32 integer.
2539 CompileRun("var obj = 0x81234567;");
2540 obj = env->Global()->Get(v8_str("obj"));
2541 CHECK(!obj->IsInt32());
2542 CHECK(obj->IsUint32());
2543 // Fraction.
2544 CompileRun("var obj = 42.3;");
2545 obj = env->Global()->Get(v8_str("obj"));
2546 CHECK(!obj->IsInt32());
2547 CHECK(!obj->IsUint32());
2548 // Large negative fraction.
2549 CompileRun("var obj = -5726623061.75;");
2550 obj = env->Global()->Get(v8_str("obj"));
2551 CHECK(!obj->IsInt32());
2552 CHECK(!obj->IsUint32());
2553}
2554
2555
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002556THREADED_TEST(ConversionException) {
2557 v8::HandleScope scope;
2558 LocalContext env;
2559 CompileRun(
2560 "function TestClass() { };"
2561 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2562 "var obj = new TestClass();");
2563 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2564
2565 v8::TryCatch try_catch;
2566
2567 Local<Value> to_string_result = obj->ToString();
2568 CHECK(to_string_result.IsEmpty());
2569 CheckUncle(&try_catch);
2570
2571 Local<Value> to_number_result = obj->ToNumber();
2572 CHECK(to_number_result.IsEmpty());
2573 CheckUncle(&try_catch);
2574
2575 Local<Value> to_integer_result = obj->ToInteger();
2576 CHECK(to_integer_result.IsEmpty());
2577 CheckUncle(&try_catch);
2578
2579 Local<Value> to_uint32_result = obj->ToUint32();
2580 CHECK(to_uint32_result.IsEmpty());
2581 CheckUncle(&try_catch);
2582
2583 Local<Value> to_int32_result = obj->ToInt32();
2584 CHECK(to_int32_result.IsEmpty());
2585 CheckUncle(&try_catch);
2586
2587 Local<Value> to_object_result = v8::Undefined()->ToObject();
2588 CHECK(to_object_result.IsEmpty());
2589 CHECK(try_catch.HasCaught());
2590 try_catch.Reset();
2591
2592 int32_t int32_value = obj->Int32Value();
2593 CHECK_EQ(0, int32_value);
2594 CheckUncle(&try_catch);
2595
2596 uint32_t uint32_value = obj->Uint32Value();
2597 CHECK_EQ(0, uint32_value);
2598 CheckUncle(&try_catch);
2599
2600 double number_value = obj->NumberValue();
2601 CHECK_NE(0, IsNaN(number_value));
2602 CheckUncle(&try_catch);
2603
2604 int64_t integer_value = obj->IntegerValue();
2605 CHECK_EQ(0.0, static_cast<double>(integer_value));
2606 CheckUncle(&try_catch);
2607}
2608
2609
2610v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2611 ApiTestFuzzer::Fuzz();
2612 return v8::ThrowException(v8_str("konto"));
2613}
2614
2615
ager@chromium.org8bb60582008-12-11 12:02:20 +00002616v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2617 if (args.Length() < 1) return v8::Boolean::New(false);
2618 v8::HandleScope scope;
2619 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002620 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2621 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002622 return v8::Boolean::New(try_catch.HasCaught());
2623}
2624
2625
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002626THREADED_TEST(APICatch) {
2627 v8::HandleScope scope;
2628 Local<ObjectTemplate> templ = ObjectTemplate::New();
2629 templ->Set(v8_str("ThrowFromC"),
2630 v8::FunctionTemplate::New(ThrowFromC));
2631 LocalContext context(0, templ);
2632 CompileRun(
2633 "var thrown = false;"
2634 "try {"
2635 " ThrowFromC();"
2636 "} catch (e) {"
2637 " thrown = true;"
2638 "}");
2639 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2640 CHECK(thrown->BooleanValue());
2641}
2642
2643
ager@chromium.org8bb60582008-12-11 12:02:20 +00002644THREADED_TEST(APIThrowTryCatch) {
2645 v8::HandleScope scope;
2646 Local<ObjectTemplate> templ = ObjectTemplate::New();
2647 templ->Set(v8_str("ThrowFromC"),
2648 v8::FunctionTemplate::New(ThrowFromC));
2649 LocalContext context(0, templ);
2650 v8::TryCatch try_catch;
2651 CompileRun("ThrowFromC();");
2652 CHECK(try_catch.HasCaught());
2653}
2654
2655
2656// Test that a try-finally block doesn't shadow a try-catch block
2657// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002658//
2659// BUG(271): Some of the exception propagation does not work on the
2660// ARM simulator because the simulator separates the C++ stack and the
2661// JS stack. This test therefore fails on the simulator. The test is
2662// not threaded to allow the threading tests to run on the simulator.
2663TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00002664 v8::HandleScope scope;
2665 Local<ObjectTemplate> templ = ObjectTemplate::New();
2666 templ->Set(v8_str("CCatcher"),
2667 v8::FunctionTemplate::New(CCatcher));
2668 LocalContext context(0, templ);
2669 Local<Value> result = CompileRun("try {"
2670 " try {"
2671 " CCatcher('throw 7;');"
2672 " } finally {"
2673 " }"
2674 "} catch (e) {"
2675 "}");
2676 CHECK(result->IsTrue());
2677}
2678
2679
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002680static void check_reference_error_message(
2681 v8::Handle<v8::Message> message,
2682 v8::Handle<v8::Value> data) {
2683 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2684 CHECK(message->Get()->Equals(v8_str(reference_error)));
2685}
2686
2687
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002688static v8::Handle<Value> Fail(const v8::Arguments& args) {
2689 ApiTestFuzzer::Fuzz();
2690 CHECK(false);
2691 return v8::Undefined();
2692}
2693
2694
2695// Test that overwritten methods are not invoked on uncaught exception
2696// formatting. However, they are invoked when performing normal error
2697// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002698TEST(APIThrowMessageOverwrittenToString) {
2699 v8::HandleScope scope;
2700 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002701 Local<ObjectTemplate> templ = ObjectTemplate::New();
2702 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2703 LocalContext context(NULL, templ);
2704 CompileRun("asdf;");
2705 CompileRun("var limit = {};"
2706 "limit.valueOf = fail;"
2707 "Error.stackTraceLimit = limit;");
2708 CompileRun("asdf");
2709 CompileRun("Array.prototype.pop = fail;");
2710 CompileRun("Object.prototype.hasOwnProperty = fail;");
2711 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002712 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2713 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002714 CompileRun("ReferenceError.prototype.toString ="
2715 " function() { return 'Whoops' }");
2716 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002717 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2718 CompileRun("asdf;");
2719 CompileRun("ReferenceError.prototype.constructor = void 0;");
2720 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002721 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2722 CompileRun("asdf;");
2723 CompileRun("ReferenceError.prototype = new Object();");
2724 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002725 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2726 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002727 CompileRun("ReferenceError.prototype.constructor = new Object();"
2728 "ReferenceError.prototype.constructor.name = 1;"
2729 "Number.prototype.toString = function() { return 'Whoops'; };"
2730 "ReferenceError.prototype.toString = Object.prototype.toString;");
2731 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002732 v8::V8::RemoveMessageListeners(check_message);
2733}
2734
2735
ager@chromium.org8bb60582008-12-11 12:02:20 +00002736static void receive_message(v8::Handle<v8::Message> message,
2737 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002738 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002739 message_received = true;
2740}
2741
2742
2743TEST(APIThrowMessage) {
2744 message_received = false;
2745 v8::HandleScope scope;
2746 v8::V8::AddMessageListener(receive_message);
2747 Local<ObjectTemplate> templ = ObjectTemplate::New();
2748 templ->Set(v8_str("ThrowFromC"),
2749 v8::FunctionTemplate::New(ThrowFromC));
2750 LocalContext context(0, templ);
2751 CompileRun("ThrowFromC();");
2752 CHECK(message_received);
2753 v8::V8::RemoveMessageListeners(check_message);
2754}
2755
2756
2757TEST(APIThrowMessageAndVerboseTryCatch) {
2758 message_received = false;
2759 v8::HandleScope scope;
2760 v8::V8::AddMessageListener(receive_message);
2761 Local<ObjectTemplate> templ = ObjectTemplate::New();
2762 templ->Set(v8_str("ThrowFromC"),
2763 v8::FunctionTemplate::New(ThrowFromC));
2764 LocalContext context(0, templ);
2765 v8::TryCatch try_catch;
2766 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002767 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002768 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002769 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002770 CHECK(message_received);
2771 v8::V8::RemoveMessageListeners(check_message);
2772}
2773
2774
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002775TEST(APIStackOverflowAndVerboseTryCatch) {
2776 message_received = false;
2777 v8::HandleScope scope;
2778 v8::V8::AddMessageListener(receive_message);
2779 LocalContext context;
2780 v8::TryCatch try_catch;
2781 try_catch.SetVerbose(true);
2782 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
2783 CHECK(try_catch.HasCaught());
2784 CHECK(result.IsEmpty());
2785 CHECK(message_received);
2786 v8::V8::RemoveMessageListeners(receive_message);
2787}
2788
2789
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002790THREADED_TEST(ExternalScriptException) {
2791 v8::HandleScope scope;
2792 Local<ObjectTemplate> templ = ObjectTemplate::New();
2793 templ->Set(v8_str("ThrowFromC"),
2794 v8::FunctionTemplate::New(ThrowFromC));
2795 LocalContext context(0, templ);
2796
2797 v8::TryCatch try_catch;
2798 Local<Script> script
2799 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2800 Local<Value> result = script->Run();
2801 CHECK(result.IsEmpty());
2802 CHECK(try_catch.HasCaught());
2803 String::AsciiValue exception_value(try_catch.Exception());
2804 CHECK_EQ("konto", *exception_value);
2805}
2806
2807
2808
2809v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2810 ApiTestFuzzer::Fuzz();
2811 CHECK_EQ(4, args.Length());
2812 int count = args[0]->Int32Value();
2813 int cInterval = args[2]->Int32Value();
2814 if (count == 0) {
2815 return v8::ThrowException(v8_str("FromC"));
2816 } else {
2817 Local<v8::Object> global = Context::GetCurrent()->Global();
2818 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2819 v8::Handle<Value> argv[] = { v8_num(count - 1),
2820 args[1],
2821 args[2],
2822 args[3] };
2823 if (count % cInterval == 0) {
2824 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002825 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002826 int expected = args[3]->Int32Value();
2827 if (try_catch.HasCaught()) {
2828 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002829 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002830 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002831 } else {
2832 CHECK_NE(expected, count);
2833 }
2834 return result;
2835 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002836 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002837 }
2838 }
2839}
2840
2841
2842v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2843 ApiTestFuzzer::Fuzz();
2844 CHECK_EQ(3, args.Length());
2845 bool equality = args[0]->BooleanValue();
2846 int count = args[1]->Int32Value();
2847 int expected = args[2]->Int32Value();
2848 if (equality) {
2849 CHECK_EQ(count, expected);
2850 } else {
2851 CHECK_NE(count, expected);
2852 }
2853 return v8::Undefined();
2854}
2855
2856
ager@chromium.org8bb60582008-12-11 12:02:20 +00002857THREADED_TEST(EvalInTryFinally) {
2858 v8::HandleScope scope;
2859 LocalContext context;
2860 v8::TryCatch try_catch;
2861 CompileRun("(function() {"
2862 " try {"
2863 " eval('asldkf (*&^&*^');"
2864 " } finally {"
2865 " return;"
2866 " }"
2867 "})()");
2868 CHECK(!try_catch.HasCaught());
2869}
2870
2871
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002872// This test works by making a stack of alternating JavaScript and C
2873// activations. These activations set up exception handlers with regular
2874// intervals, one interval for C activations and another for JavaScript
2875// activations. When enough activations have been created an exception is
2876// thrown and we check that the right activation catches the exception and that
2877// no other activations do. The right activation is always the topmost one with
2878// a handler, regardless of whether it is in JavaScript or C.
2879//
2880// The notation used to describe a test case looks like this:
2881//
2882// *JS[4] *C[3] @JS[2] C[1] JS[0]
2883//
2884// Each entry is an activation, either JS or C. The index is the count at that
2885// level. Stars identify activations with exception handlers, the @ identifies
2886// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002887//
2888// BUG(271): Some of the exception propagation does not work on the
2889// ARM simulator because the simulator separates the C++ stack and the
2890// JS stack. This test therefore fails on the simulator. The test is
2891// not threaded to allow the threading tests to run on the simulator.
2892TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002893 v8::HandleScope scope;
2894 Local<ObjectTemplate> templ = ObjectTemplate::New();
2895 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2896 templ->Set(v8_str("CThrowCountDown"),
2897 v8::FunctionTemplate::New(CThrowCountDown));
2898 LocalContext context(0, templ);
2899 CompileRun(
2900 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2901 " if (count == 0) throw 'FromJS';"
2902 " if (count % jsInterval == 0) {"
2903 " try {"
2904 " var value = CThrowCountDown(count - 1,"
2905 " jsInterval,"
2906 " cInterval,"
2907 " expected);"
2908 " check(false, count, expected);"
2909 " return value;"
2910 " } catch (e) {"
2911 " check(true, count, expected);"
2912 " }"
2913 " } else {"
2914 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2915 " }"
2916 "}");
2917 Local<Function> fun =
2918 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2919
2920 const int argc = 4;
2921 // count jsInterval cInterval expected
2922
2923 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2924 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2925 fun->Call(fun, argc, a0);
2926
2927 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2928 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2929 fun->Call(fun, argc, a1);
2930
2931 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2932 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2933 fun->Call(fun, argc, a2);
2934
2935 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2936 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2937 fun->Call(fun, argc, a3);
2938
2939 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2940 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2941 fun->Call(fun, argc, a4);
2942
2943 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2944 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2945 fun->Call(fun, argc, a5);
2946}
2947
2948
2949v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2950 ApiTestFuzzer::Fuzz();
2951 CHECK_EQ(1, args.Length());
2952 return v8::ThrowException(args[0]);
2953}
2954
2955
2956THREADED_TEST(ThrowValues) {
2957 v8::HandleScope scope;
2958 Local<ObjectTemplate> templ = ObjectTemplate::New();
2959 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2960 LocalContext context(0, templ);
2961 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2962 "function Run(obj) {"
2963 " try {"
2964 " Throw(obj);"
2965 " } catch (e) {"
2966 " return e;"
2967 " }"
2968 " return 'no exception';"
2969 "}"
2970 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2971 CHECK_EQ(5, result->Length());
2972 CHECK(result->Get(v8::Integer::New(0))->IsString());
2973 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2974 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2975 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2976 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2977 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2978 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2979}
2980
2981
2982THREADED_TEST(CatchZero) {
2983 v8::HandleScope scope;
2984 LocalContext context;
2985 v8::TryCatch try_catch;
2986 CHECK(!try_catch.HasCaught());
2987 Script::Compile(v8_str("throw 10"))->Run();
2988 CHECK(try_catch.HasCaught());
2989 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2990 try_catch.Reset();
2991 CHECK(!try_catch.HasCaught());
2992 Script::Compile(v8_str("throw 0"))->Run();
2993 CHECK(try_catch.HasCaught());
2994 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2995}
2996
2997
2998THREADED_TEST(CatchExceptionFromWith) {
2999 v8::HandleScope scope;
3000 LocalContext context;
3001 v8::TryCatch try_catch;
3002 CHECK(!try_catch.HasCaught());
3003 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3004 CHECK(try_catch.HasCaught());
3005}
3006
3007
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003008THREADED_TEST(TryCatchAndFinallyHidingException) {
3009 v8::HandleScope scope;
3010 LocalContext context;
3011 v8::TryCatch try_catch;
3012 CHECK(!try_catch.HasCaught());
3013 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3014 CompileRun("f({toString: function() { throw 42; }});");
3015 CHECK(!try_catch.HasCaught());
3016}
3017
3018
3019v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3020 v8::TryCatch try_catch;
3021 return v8::Undefined();
3022}
3023
3024
3025THREADED_TEST(TryCatchAndFinally) {
3026 v8::HandleScope scope;
3027 LocalContext context;
3028 context->Global()->Set(
3029 v8_str("native_with_try_catch"),
3030 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3031 v8::TryCatch try_catch;
3032 CHECK(!try_catch.HasCaught());
3033 CompileRun(
3034 "try {\n"
3035 " throw new Error('a');\n"
3036 "} finally {\n"
3037 " native_with_try_catch();\n"
3038 "}\n");
3039 CHECK(try_catch.HasCaught());
3040}
3041
3042
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003043THREADED_TEST(Equality) {
3044 v8::HandleScope scope;
3045 LocalContext context;
3046 // Check that equality works at all before relying on CHECK_EQ
3047 CHECK(v8_str("a")->Equals(v8_str("a")));
3048 CHECK(!v8_str("a")->Equals(v8_str("b")));
3049
3050 CHECK_EQ(v8_str("a"), v8_str("a"));
3051 CHECK_NE(v8_str("a"), v8_str("b"));
3052 CHECK_EQ(v8_num(1), v8_num(1));
3053 CHECK_EQ(v8_num(1.00), v8_num(1));
3054 CHECK_NE(v8_num(1), v8_num(2));
3055
3056 // Assume String is not symbol.
3057 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3058 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3059 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3060 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3061 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3062 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3063 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3064 CHECK(!not_a_number->StrictEquals(not_a_number));
3065 CHECK(v8::False()->StrictEquals(v8::False()));
3066 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3067
3068 v8::Handle<v8::Object> obj = v8::Object::New();
3069 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3070 CHECK(alias->StrictEquals(obj));
3071 alias.Dispose();
3072}
3073
3074
3075THREADED_TEST(MultiRun) {
3076 v8::HandleScope scope;
3077 LocalContext context;
3078 Local<Script> script = Script::Compile(v8_str("x"));
3079 for (int i = 0; i < 10; i++)
3080 script->Run();
3081}
3082
3083
3084static v8::Handle<Value> GetXValue(Local<String> name,
3085 const AccessorInfo& info) {
3086 ApiTestFuzzer::Fuzz();
3087 CHECK_EQ(info.Data(), v8_str("donut"));
3088 CHECK_EQ(name, v8_str("x"));
3089 return name;
3090}
3091
3092
3093THREADED_TEST(SimplePropertyRead) {
3094 v8::HandleScope scope;
3095 Local<ObjectTemplate> templ = ObjectTemplate::New();
3096 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3097 LocalContext context;
3098 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3099 Local<Script> script = Script::Compile(v8_str("obj.x"));
3100 for (int i = 0; i < 10; i++) {
3101 Local<Value> result = script->Run();
3102 CHECK_EQ(result, v8_str("x"));
3103 }
3104}
3105
ager@chromium.org5c838252010-02-19 08:53:10 +00003106THREADED_TEST(DefinePropertyOnAPIAccessor) {
3107 v8::HandleScope scope;
3108 Local<ObjectTemplate> templ = ObjectTemplate::New();
3109 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3110 LocalContext context;
3111 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3112
3113 // Uses getOwnPropertyDescriptor to check the configurable status
3114 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003115 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003116 "obj, 'x');"
3117 "prop.configurable;"));
3118 Local<Value> result = script_desc->Run();
3119 CHECK_EQ(result->BooleanValue(), true);
3120
3121 // Redefine get - but still configurable
3122 Local<Script> script_define
3123 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3124 " configurable: true };"
3125 "Object.defineProperty(obj, 'x', desc);"
3126 "obj.x"));
3127 result = script_define->Run();
3128 CHECK_EQ(result, v8_num(42));
3129
3130 // Check that the accessor is still configurable
3131 result = script_desc->Run();
3132 CHECK_EQ(result->BooleanValue(), true);
3133
3134 // Redefine to a non-configurable
3135 script_define
3136 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3137 " configurable: false };"
3138 "Object.defineProperty(obj, 'x', desc);"
3139 "obj.x"));
3140 result = script_define->Run();
3141 CHECK_EQ(result, v8_num(43));
3142 result = script_desc->Run();
3143 CHECK_EQ(result->BooleanValue(), false);
3144
3145 // Make sure that it is not possible to redefine again
3146 v8::TryCatch try_catch;
3147 result = script_define->Run();
3148 CHECK(try_catch.HasCaught());
3149 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003150 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003151}
3152
3153THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3154 v8::HandleScope scope;
3155 Local<ObjectTemplate> templ = ObjectTemplate::New();
3156 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3157 LocalContext context;
3158 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3159
3160 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3161 "Object.getOwnPropertyDescriptor( "
3162 "obj, 'x');"
3163 "prop.configurable;"));
3164 Local<Value> result = script_desc->Run();
3165 CHECK_EQ(result->BooleanValue(), true);
3166
3167 Local<Script> script_define =
3168 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3169 " configurable: true };"
3170 "Object.defineProperty(obj, 'x', desc);"
3171 "obj.x"));
3172 result = script_define->Run();
3173 CHECK_EQ(result, v8_num(42));
3174
3175
3176 result = script_desc->Run();
3177 CHECK_EQ(result->BooleanValue(), true);
3178
3179
3180 script_define =
3181 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3182 " configurable: false };"
3183 "Object.defineProperty(obj, 'x', desc);"
3184 "obj.x"));
3185 result = script_define->Run();
3186 CHECK_EQ(result, v8_num(43));
3187 result = script_desc->Run();
3188
3189 CHECK_EQ(result->BooleanValue(), false);
3190
3191 v8::TryCatch try_catch;
3192 result = script_define->Run();
3193 CHECK(try_catch.HasCaught());
3194 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003195 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003196}
3197
3198
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003199static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3200 char const* name) {
3201 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3202}
ager@chromium.org5c838252010-02-19 08:53:10 +00003203
3204
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003205THREADED_TEST(DefineAPIAccessorOnObject) {
3206 v8::HandleScope scope;
3207 Local<ObjectTemplate> templ = ObjectTemplate::New();
3208 LocalContext context;
3209
3210 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3211 CompileRun("var obj2 = {};");
3212
3213 CHECK(CompileRun("obj1.x")->IsUndefined());
3214 CHECK(CompileRun("obj2.x")->IsUndefined());
3215
3216 CHECK(GetGlobalProperty(&context, "obj1")->
3217 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3218
3219 ExpectString("obj1.x", "x");
3220 CHECK(CompileRun("obj2.x")->IsUndefined());
3221
3222 CHECK(GetGlobalProperty(&context, "obj2")->
3223 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3224
3225 ExpectString("obj1.x", "x");
3226 ExpectString("obj2.x", "x");
3227
3228 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3229 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3230
3231 CompileRun("Object.defineProperty(obj1, 'x',"
3232 "{ get: function() { return 'y'; }, configurable: true })");
3233
3234 ExpectString("obj1.x", "y");
3235 ExpectString("obj2.x", "x");
3236
3237 CompileRun("Object.defineProperty(obj2, 'x',"
3238 "{ get: function() { return 'y'; }, configurable: true })");
3239
3240 ExpectString("obj1.x", "y");
3241 ExpectString("obj2.x", "y");
3242
3243 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3244 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3245
3246 CHECK(GetGlobalProperty(&context, "obj1")->
3247 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3248 CHECK(GetGlobalProperty(&context, "obj2")->
3249 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3250
3251 ExpectString("obj1.x", "x");
3252 ExpectString("obj2.x", "x");
3253
3254 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3255 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3256
3257 // Define getters/setters, but now make them not configurable.
3258 CompileRun("Object.defineProperty(obj1, 'x',"
3259 "{ get: function() { return 'z'; }, configurable: false })");
3260 CompileRun("Object.defineProperty(obj2, 'x',"
3261 "{ get: function() { return 'z'; }, configurable: false })");
3262
3263 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3264 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3265
3266 ExpectString("obj1.x", "z");
3267 ExpectString("obj2.x", "z");
3268
3269 CHECK(!GetGlobalProperty(&context, "obj1")->
3270 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3271 CHECK(!GetGlobalProperty(&context, "obj2")->
3272 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3273
3274 ExpectString("obj1.x", "z");
3275 ExpectString("obj2.x", "z");
3276}
3277
3278
3279THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3280 v8::HandleScope scope;
3281 Local<ObjectTemplate> templ = ObjectTemplate::New();
3282 LocalContext context;
3283
3284 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3285 CompileRun("var obj2 = {};");
3286
3287 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3288 v8_str("x"),
3289 GetXValue, NULL,
3290 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3291 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3292 v8_str("x"),
3293 GetXValue, NULL,
3294 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3295
3296 ExpectString("obj1.x", "x");
3297 ExpectString("obj2.x", "x");
3298
3299 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3300 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3301
3302 CHECK(!GetGlobalProperty(&context, "obj1")->
3303 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3304 CHECK(!GetGlobalProperty(&context, "obj2")->
3305 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3306
3307 {
3308 v8::TryCatch try_catch;
3309 CompileRun("Object.defineProperty(obj1, 'x',"
3310 "{get: function() { return 'func'; }})");
3311 CHECK(try_catch.HasCaught());
3312 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003313 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003314 }
3315 {
3316 v8::TryCatch try_catch;
3317 CompileRun("Object.defineProperty(obj2, 'x',"
3318 "{get: function() { return 'func'; }})");
3319 CHECK(try_catch.HasCaught());
3320 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003321 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003322 }
3323}
3324
3325
3326static v8::Handle<Value> Get239Value(Local<String> name,
3327 const AccessorInfo& info) {
3328 ApiTestFuzzer::Fuzz();
3329 CHECK_EQ(info.Data(), v8_str("donut"));
3330 CHECK_EQ(name, v8_str("239"));
3331 return name;
3332}
3333
3334
3335THREADED_TEST(ElementAPIAccessor) {
3336 v8::HandleScope scope;
3337 Local<ObjectTemplate> templ = ObjectTemplate::New();
3338 LocalContext context;
3339
3340 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3341 CompileRun("var obj2 = {};");
3342
3343 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3344 v8_str("239"),
3345 Get239Value, NULL,
3346 v8_str("donut")));
3347 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3348 v8_str("239"),
3349 Get239Value, NULL,
3350 v8_str("donut")));
3351
3352 ExpectString("obj1[239]", "239");
3353 ExpectString("obj2[239]", "239");
3354 ExpectString("obj1['239']", "239");
3355 ExpectString("obj2['239']", "239");
3356}
3357
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003358
3359v8::Persistent<Value> xValue;
3360
3361
3362static void SetXValue(Local<String> name,
3363 Local<Value> value,
3364 const AccessorInfo& info) {
3365 CHECK_EQ(value, v8_num(4));
3366 CHECK_EQ(info.Data(), v8_str("donut"));
3367 CHECK_EQ(name, v8_str("x"));
3368 CHECK(xValue.IsEmpty());
3369 xValue = v8::Persistent<Value>::New(value);
3370}
3371
3372
3373THREADED_TEST(SimplePropertyWrite) {
3374 v8::HandleScope scope;
3375 Local<ObjectTemplate> templ = ObjectTemplate::New();
3376 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3377 LocalContext context;
3378 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3379 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3380 for (int i = 0; i < 10; i++) {
3381 CHECK(xValue.IsEmpty());
3382 script->Run();
3383 CHECK_EQ(v8_num(4), xValue);
3384 xValue.Dispose();
3385 xValue = v8::Persistent<Value>();
3386 }
3387}
3388
3389
3390static v8::Handle<Value> XPropertyGetter(Local<String> property,
3391 const AccessorInfo& info) {
3392 ApiTestFuzzer::Fuzz();
3393 CHECK(info.Data()->IsUndefined());
3394 return property;
3395}
3396
3397
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003398THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003399 v8::HandleScope scope;
3400 Local<ObjectTemplate> templ = ObjectTemplate::New();
3401 templ->SetNamedPropertyHandler(XPropertyGetter);
3402 LocalContext context;
3403 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3404 Local<Script> script = Script::Compile(v8_str("obj.x"));
3405 for (int i = 0; i < 10; i++) {
3406 Local<Value> result = script->Run();
3407 CHECK_EQ(result, v8_str("x"));
3408 }
3409}
3410
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003411
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00003412THREADED_TEST(NamedInterceptorDictionaryIC) {
3413 v8::HandleScope scope;
3414 Local<ObjectTemplate> templ = ObjectTemplate::New();
3415 templ->SetNamedPropertyHandler(XPropertyGetter);
3416 LocalContext context;
3417 // Create an object with a named interceptor.
3418 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3419 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3420 for (int i = 0; i < 10; i++) {
3421 Local<Value> result = script->Run();
3422 CHECK_EQ(result, v8_str("x"));
3423 }
3424 // Create a slow case object and a function accessing a property in
3425 // that slow case object (with dictionary probing in generated
3426 // code). Then force object with a named interceptor into slow-case,
3427 // pass it to the function, and check that the interceptor is called
3428 // instead of accessing the local property.
3429 Local<Value> result =
3430 CompileRun("function get_x(o) { return o.x; };"
3431 "var obj = { x : 42, y : 0 };"
3432 "delete obj.y;"
3433 "for (var i = 0; i < 10; i++) get_x(obj);"
3434 "interceptor_obj.x = 42;"
3435 "interceptor_obj.y = 10;"
3436 "delete interceptor_obj.y;"
3437 "get_x(interceptor_obj)");
3438 CHECK_EQ(result, v8_str("x"));
3439}
3440
3441
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003442THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3443 v8::HandleScope scope;
3444
3445 v8::Persistent<Context> context1 = Context::New();
3446
3447 context1->Enter();
3448 Local<ObjectTemplate> templ = ObjectTemplate::New();
3449 templ->SetNamedPropertyHandler(XPropertyGetter);
3450 // Create an object with a named interceptor.
3451 v8::Local<v8::Object> object = templ->NewInstance();
3452 context1->Global()->Set(v8_str("interceptor_obj"), object);
3453
3454 // Force the object into the slow case.
3455 CompileRun("interceptor_obj.y = 0;"
3456 "delete interceptor_obj.y;");
3457 context1->Exit();
3458
3459 {
3460 // Introduce the object into a different context.
3461 // Repeat named loads to exercise ICs.
3462 LocalContext context2;
3463 context2->Global()->Set(v8_str("interceptor_obj"), object);
3464 Local<Value> result =
3465 CompileRun("function get_x(o) { return o.x; }"
3466 "interceptor_obj.x = 42;"
3467 "for (var i=0; i != 10; i++) {"
3468 " get_x(interceptor_obj);"
3469 "}"
3470 "get_x(interceptor_obj)");
3471 // Check that the interceptor was actually invoked.
3472 CHECK_EQ(result, v8_str("x"));
3473 }
3474
3475 // Return to the original context and force some object to the slow case
3476 // to cause the NormalizedMapCache to verify.
3477 context1->Enter();
3478 CompileRun("var obj = { x : 0 }; delete obj.x;");
3479 context1->Exit();
3480
3481 context1.Dispose();
3482}
3483
3484
ager@chromium.org5c838252010-02-19 08:53:10 +00003485static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3486 const AccessorInfo& info) {
3487 // Set x on the prototype object and do not handle the get request.
3488 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003489 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00003490 return v8::Handle<Value>();
3491}
3492
3493
3494// This is a regression test for http://crbug.com/20104. Map
3495// transitions should not interfere with post interceptor lookup.
3496THREADED_TEST(NamedInterceptorMapTransitionRead) {
3497 v8::HandleScope scope;
3498 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3499 Local<v8::ObjectTemplate> instance_template
3500 = function_template->InstanceTemplate();
3501 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3502 LocalContext context;
3503 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3504 // Create an instance of F and introduce a map transition for x.
3505 CompileRun("var o = new F(); o.x = 23;");
3506 // Create an instance of F and invoke the getter. The result should be 23.
3507 Local<Value> result = CompileRun("o = new F(); o.x");
3508 CHECK_EQ(result->Int32Value(), 23);
3509}
3510
3511
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003512static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3513 const AccessorInfo& info) {
3514 ApiTestFuzzer::Fuzz();
3515 if (index == 37) {
3516 return v8::Handle<Value>(v8_num(625));
3517 }
3518 return v8::Handle<Value>();
3519}
3520
3521
3522static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3523 Local<Value> value,
3524 const AccessorInfo& info) {
3525 ApiTestFuzzer::Fuzz();
3526 if (index == 39) {
3527 return value;
3528 }
3529 return v8::Handle<Value>();
3530}
3531
3532
3533THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3534 v8::HandleScope scope;
3535 Local<ObjectTemplate> templ = ObjectTemplate::New();
3536 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3537 IndexedPropertySetter);
3538 LocalContext context;
3539 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3540 Local<Script> getter_script = Script::Compile(v8_str(
3541 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3542 Local<Script> setter_script = Script::Compile(v8_str(
3543 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3544 "obj[17] = 23;"
3545 "obj.foo;"));
3546 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3547 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3548 "obj[39] = 47;"
3549 "obj.foo;")); // This setter should not run, due to the interceptor.
3550 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3551 "obj[37];"));
3552 Local<Value> result = getter_script->Run();
3553 CHECK_EQ(v8_num(5), result);
3554 result = setter_script->Run();
3555 CHECK_EQ(v8_num(23), result);
3556 result = interceptor_setter_script->Run();
3557 CHECK_EQ(v8_num(23), result);
3558 result = interceptor_getter_script->Run();
3559 CHECK_EQ(v8_num(625), result);
3560}
3561
3562
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003563static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3564 uint32_t index,
3565 const AccessorInfo& info) {
3566 ApiTestFuzzer::Fuzz();
3567 if (index < 25) {
3568 return v8::Handle<Value>(v8_num(index));
3569 }
3570 return v8::Handle<Value>();
3571}
3572
3573
3574static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3575 uint32_t index,
3576 Local<Value> value,
3577 const AccessorInfo& info) {
3578 ApiTestFuzzer::Fuzz();
3579 if (index < 25) {
3580 return v8::Handle<Value>(v8_num(index));
3581 }
3582 return v8::Handle<Value>();
3583}
3584
3585
3586Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3587 const AccessorInfo& info) {
3588 // Force the list of returned keys to be stored in a FastDoubleArray.
3589 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3590 "keys = new Array(); keys[125000] = 1;"
3591 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3592 "keys.length = 25; keys;"));
3593 Local<Value> result = indexed_property_names_script->Run();
3594 return Local<v8::Array>(::v8::Array::Cast(*result));
3595}
3596
3597
3598// Make sure that the the interceptor code in the runtime properly handles
3599// merging property name lists for double-array-backed arrays.
3600THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3601 v8::HandleScope scope;
3602 Local<ObjectTemplate> templ = ObjectTemplate::New();
3603 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3604 UnboxedDoubleIndexedPropertySetter,
3605 0,
3606 0,
3607 UnboxedDoubleIndexedPropertyEnumerator);
3608 LocalContext context;
3609 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3610 // When obj is created, force it to be Stored in a FastDoubleArray.
3611 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3612 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3613 "key_count = 0; "
3614 "for (x in obj) {key_count++;};"
3615 "obj;"));
3616 Local<Value> result = create_unboxed_double_script->Run();
3617 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3618 Local<Script> key_count_check = Script::Compile(v8_str(
3619 "key_count;"));
3620 result = key_count_check->Run();
3621 CHECK_EQ(v8_num(40013), result);
3622}
3623
3624
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003625static v8::Handle<Value> IdentityIndexedPropertyGetter(
3626 uint32_t index,
3627 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003628 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003629}
3630
3631
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003632THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3633 v8::HandleScope scope;
3634 Local<ObjectTemplate> templ = ObjectTemplate::New();
3635 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3636
3637 LocalContext context;
3638 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639
3640 // Check fast object case.
3641 const char* fast_case_code =
3642 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3643 ExpectString(fast_case_code, "0");
3644
3645 // Check slow case.
3646 const char* slow_case_code =
3647 "obj.x = 1; delete obj.x;"
3648 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3649 ExpectString(slow_case_code, "1");
3650}
3651
3652
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003653THREADED_TEST(IndexedInterceptorWithNoSetter) {
3654 v8::HandleScope scope;
3655 Local<ObjectTemplate> templ = ObjectTemplate::New();
3656 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3657
3658 LocalContext context;
3659 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3660
3661 const char* code =
3662 "try {"
3663 " obj[0] = 239;"
3664 " for (var i = 0; i < 100; i++) {"
3665 " var v = obj[0];"
3666 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3667 " }"
3668 " 'PASSED'"
3669 "} catch(e) {"
3670 " e"
3671 "}";
3672 ExpectString(code, "PASSED");
3673}
3674
3675
ager@chromium.org5c838252010-02-19 08:53:10 +00003676THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3677 v8::HandleScope scope;
3678 Local<ObjectTemplate> templ = ObjectTemplate::New();
3679 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3680
3681 LocalContext context;
3682 Local<v8::Object> obj = templ->NewInstance();
3683 obj->TurnOnAccessCheck();
3684 context->Global()->Set(v8_str("obj"), obj);
3685
3686 const char* code =
3687 "try {"
3688 " for (var i = 0; i < 100; i++) {"
3689 " var v = obj[0];"
3690 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3691 " }"
3692 " 'PASSED'"
3693 "} catch(e) {"
3694 " e"
3695 "}";
3696 ExpectString(code, "PASSED");
3697}
3698
3699
3700THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3701 i::FLAG_allow_natives_syntax = true;
3702 v8::HandleScope scope;
3703 Local<ObjectTemplate> templ = ObjectTemplate::New();
3704 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3705
3706 LocalContext context;
3707 Local<v8::Object> obj = templ->NewInstance();
3708 context->Global()->Set(v8_str("obj"), obj);
3709
3710 const char* code =
3711 "try {"
3712 " for (var i = 0; i < 100; i++) {"
3713 " var expected = i;"
3714 " if (i == 5) {"
3715 " %EnableAccessChecks(obj);"
3716 " expected = undefined;"
3717 " }"
3718 " var v = obj[i];"
3719 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3720 " if (i == 5) %DisableAccessChecks(obj);"
3721 " }"
3722 " 'PASSED'"
3723 "} catch(e) {"
3724 " e"
3725 "}";
3726 ExpectString(code, "PASSED");
3727}
3728
3729
3730THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3731 v8::HandleScope scope;
3732 Local<ObjectTemplate> templ = ObjectTemplate::New();
3733 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3734
3735 LocalContext context;
3736 Local<v8::Object> obj = templ->NewInstance();
3737 context->Global()->Set(v8_str("obj"), obj);
3738
3739 const char* code =
3740 "try {"
3741 " for (var i = 0; i < 100; i++) {"
3742 " var v = obj[i];"
3743 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3744 " }"
3745 " 'PASSED'"
3746 "} catch(e) {"
3747 " e"
3748 "}";
3749 ExpectString(code, "PASSED");
3750}
3751
3752
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003753THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3754 v8::HandleScope scope;
3755 Local<ObjectTemplate> templ = ObjectTemplate::New();
3756 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3757
3758 LocalContext context;
3759 Local<v8::Object> obj = templ->NewInstance();
3760 context->Global()->Set(v8_str("obj"), obj);
3761
3762 const char* code =
3763 "try {"
3764 " for (var i = 0; i < 100; i++) {"
3765 " var expected = i;"
3766 " var key = i;"
3767 " if (i == 25) {"
3768 " key = -1;"
3769 " expected = undefined;"
3770 " }"
3771 " if (i == 50) {"
3772 " /* probe minimal Smi number on 32-bit platforms */"
3773 " key = -(1 << 30);"
3774 " expected = undefined;"
3775 " }"
3776 " if (i == 75) {"
3777 " /* probe minimal Smi number on 64-bit platforms */"
3778 " key = 1 << 31;"
3779 " expected = undefined;"
3780 " }"
3781 " var v = obj[key];"
3782 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3783 " }"
3784 " 'PASSED'"
3785 "} catch(e) {"
3786 " e"
3787 "}";
3788 ExpectString(code, "PASSED");
3789}
3790
3791
ager@chromium.org5c838252010-02-19 08:53:10 +00003792THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3793 v8::HandleScope scope;
3794 Local<ObjectTemplate> templ = ObjectTemplate::New();
3795 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3796
3797 LocalContext context;
3798 Local<v8::Object> obj = templ->NewInstance();
3799 context->Global()->Set(v8_str("obj"), obj);
3800
3801 const char* code =
3802 "try {"
3803 " for (var i = 0; i < 100; i++) {"
3804 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003805 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003807 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 " expected = undefined;"
3809 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003810 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00003811 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3812 " }"
3813 " 'PASSED'"
3814 "} catch(e) {"
3815 " e"
3816 "}";
3817 ExpectString(code, "PASSED");
3818}
3819
3820
3821THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3822 v8::HandleScope scope;
3823 Local<ObjectTemplate> templ = ObjectTemplate::New();
3824 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3825
3826 LocalContext context;
3827 Local<v8::Object> obj = templ->NewInstance();
3828 context->Global()->Set(v8_str("obj"), obj);
3829
3830 const char* code =
3831 "var original = obj;"
3832 "try {"
3833 " for (var i = 0; i < 100; i++) {"
3834 " var expected = i;"
3835 " if (i == 50) {"
3836 " obj = {50: 'foobar'};"
3837 " expected = 'foobar';"
3838 " }"
3839 " var v = obj[i];"
3840 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3841 " if (i == 50) obj = original;"
3842 " }"
3843 " 'PASSED'"
3844 "} catch(e) {"
3845 " e"
3846 "}";
3847 ExpectString(code, "PASSED");
3848}
3849
3850
3851THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3852 v8::HandleScope scope;
3853 Local<ObjectTemplate> templ = ObjectTemplate::New();
3854 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3855
3856 LocalContext context;
3857 Local<v8::Object> obj = templ->NewInstance();
3858 context->Global()->Set(v8_str("obj"), obj);
3859
3860 const char* code =
3861 "var original = obj;"
3862 "try {"
3863 " for (var i = 0; i < 100; i++) {"
3864 " var expected = i;"
3865 " if (i == 5) {"
3866 " obj = 239;"
3867 " expected = undefined;"
3868 " }"
3869 " var v = obj[i];"
3870 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3871 " if (i == 5) obj = original;"
3872 " }"
3873 " 'PASSED'"
3874 "} catch(e) {"
3875 " e"
3876 "}";
3877 ExpectString(code, "PASSED");
3878}
3879
3880
3881THREADED_TEST(IndexedInterceptorOnProto) {
3882 v8::HandleScope scope;
3883 Local<ObjectTemplate> templ = ObjectTemplate::New();
3884 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3885
3886 LocalContext context;
3887 Local<v8::Object> obj = templ->NewInstance();
3888 context->Global()->Set(v8_str("obj"), obj);
3889
3890 const char* code =
3891 "var o = {__proto__: obj};"
3892 "try {"
3893 " for (var i = 0; i < 100; i++) {"
3894 " var v = o[i];"
3895 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3896 " }"
3897 " 'PASSED'"
3898 "} catch(e) {"
3899 " e"
3900 "}";
3901 ExpectString(code, "PASSED");
3902}
3903
3904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003905THREADED_TEST(MultiContexts) {
3906 v8::HandleScope scope;
3907 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3908 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3909
3910 Local<String> password = v8_str("Password");
3911
3912 // Create an environment
3913 LocalContext context0(0, templ);
3914 context0->SetSecurityToken(password);
3915 v8::Handle<v8::Object> global0 = context0->Global();
3916 global0->Set(v8_str("custom"), v8_num(1234));
3917 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3918
3919 // Create an independent environment
3920 LocalContext context1(0, templ);
3921 context1->SetSecurityToken(password);
3922 v8::Handle<v8::Object> global1 = context1->Global();
3923 global1->Set(v8_str("custom"), v8_num(1234));
3924 CHECK_NE(global0, global1);
3925 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3926 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3927
3928 // Now create a new context with the old global
3929 LocalContext context2(0, templ, global1);
3930 context2->SetSecurityToken(password);
3931 v8::Handle<v8::Object> global2 = context2->Global();
3932 CHECK_EQ(global1, global2);
3933 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3934 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3935}
3936
3937
3938THREADED_TEST(FunctionPrototypeAcrossContexts) {
3939 // Make sure that functions created by cloning boilerplates cannot
3940 // communicate through their __proto__ field.
3941
3942 v8::HandleScope scope;
3943
3944 LocalContext env0;
3945 v8::Handle<v8::Object> global0 =
3946 env0->Global();
3947 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003948 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003949 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003950 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003951 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003952 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003953 proto0->Set(v8_str("custom"), v8_num(1234));
3954
3955 LocalContext env1;
3956 v8::Handle<v8::Object> global1 =
3957 env1->Global();
3958 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003959 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003961 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003962 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003963 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003964 CHECK(!proto1->Has(v8_str("custom")));
3965}
3966
3967
3968THREADED_TEST(Regress892105) {
3969 // Make sure that object and array literals created by cloning
3970 // boilerplates cannot communicate through their __proto__
3971 // field. This is rather difficult to check, but we try to add stuff
3972 // to Object.prototype and Array.prototype and create a new
3973 // environment. This should succeed.
3974
3975 v8::HandleScope scope;
3976
3977 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3978 "Array.prototype.arr = 4567;"
3979 "8901");
3980
3981 LocalContext env0;
3982 Local<Script> script0 = Script::Compile(source);
3983 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3984
3985 LocalContext env1;
3986 Local<Script> script1 = Script::Compile(source);
3987 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3988}
3989
3990
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003991THREADED_TEST(UndetectableObject) {
3992 v8::HandleScope scope;
3993 LocalContext env;
3994
3995 Local<v8::FunctionTemplate> desc =
3996 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3997 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3998
3999 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4000 env->Global()->Set(v8_str("undetectable"), obj);
4001
4002 ExpectString("undetectable.toString()", "[object Object]");
4003 ExpectString("typeof undetectable", "undefined");
4004 ExpectString("typeof(undetectable)", "undefined");
4005 ExpectBoolean("typeof undetectable == 'undefined'", true);
4006 ExpectBoolean("typeof undetectable == 'object'", false);
4007 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4008 ExpectBoolean("!undetectable", true);
4009
4010 ExpectObject("true&&undetectable", obj);
4011 ExpectBoolean("false&&undetectable", false);
4012 ExpectBoolean("true||undetectable", true);
4013 ExpectObject("false||undetectable", obj);
4014
4015 ExpectObject("undetectable&&true", obj);
4016 ExpectObject("undetectable&&false", obj);
4017 ExpectBoolean("undetectable||true", true);
4018 ExpectBoolean("undetectable||false", false);
4019
4020 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004021 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004022 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004023 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004024 ExpectBoolean("undetectable==undetectable", true);
4025
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004027 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004028 ExpectBoolean("null===undetectable", false);
4029 ExpectBoolean("undetectable===undefined", false);
4030 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 ExpectBoolean("undetectable===undetectable", true);
4032}
4033
4034
ager@chromium.org04921a82011-06-27 13:21:41 +00004035THREADED_TEST(VoidLiteral) {
4036 v8::HandleScope scope;
4037 LocalContext env;
4038
4039 Local<v8::FunctionTemplate> desc =
4040 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4041 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4042
4043 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4044 env->Global()->Set(v8_str("undetectable"), obj);
4045
4046 ExpectBoolean("undefined == void 0", true);
4047 ExpectBoolean("undetectable == void 0", true);
4048 ExpectBoolean("null == void 0", true);
4049 ExpectBoolean("undefined === void 0", true);
4050 ExpectBoolean("undetectable === void 0", false);
4051 ExpectBoolean("null === void 0", false);
4052
4053 ExpectBoolean("void 0 == undefined", true);
4054 ExpectBoolean("void 0 == undetectable", true);
4055 ExpectBoolean("void 0 == null", true);
4056 ExpectBoolean("void 0 === undefined", true);
4057 ExpectBoolean("void 0 === undetectable", false);
4058 ExpectBoolean("void 0 === null", false);
4059
4060 ExpectString("(function() {"
4061 " try {"
4062 " return x === void 0;"
4063 " } catch(e) {"
4064 " return e.toString();"
4065 " }"
4066 "})()",
4067 "ReferenceError: x is not defined");
4068 ExpectString("(function() {"
4069 " try {"
4070 " return void 0 === x;"
4071 " } catch(e) {"
4072 " return e.toString();"
4073 " }"
4074 "})()",
4075 "ReferenceError: x is not defined");
4076}
4077
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004078
4079THREADED_TEST(ExtensibleOnUndetectable) {
4080 v8::HandleScope scope;
4081 LocalContext env;
4082
4083 Local<v8::FunctionTemplate> desc =
4084 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4085 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4086
4087 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4088 env->Global()->Set(v8_str("undetectable"), obj);
4089
4090 Local<String> source = v8_str("undetectable.x = 42;"
4091 "undetectable.x");
4092
4093 Local<Script> script = Script::Compile(source);
4094
4095 CHECK_EQ(v8::Integer::New(42), script->Run());
4096
4097 ExpectBoolean("Object.isExtensible(undetectable)", true);
4098
4099 source = v8_str("Object.preventExtensions(undetectable);");
4100 script = Script::Compile(source);
4101 script->Run();
4102 ExpectBoolean("Object.isExtensible(undetectable)", false);
4103
4104 source = v8_str("undetectable.y = 2000;");
4105 script = Script::Compile(source);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004106 Local<Value> result = script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004107 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004108}
4109
4110
4111
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004112THREADED_TEST(UndetectableString) {
4113 v8::HandleScope scope;
4114 LocalContext env;
4115
4116 Local<String> obj = String::NewUndetectable("foo");
4117 env->Global()->Set(v8_str("undetectable"), obj);
4118
4119 ExpectString("undetectable", "foo");
4120 ExpectString("typeof undetectable", "undefined");
4121 ExpectString("typeof(undetectable)", "undefined");
4122 ExpectBoolean("typeof undetectable == 'undefined'", true);
4123 ExpectBoolean("typeof undetectable == 'string'", false);
4124 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4125 ExpectBoolean("!undetectable", true);
4126
4127 ExpectObject("true&&undetectable", obj);
4128 ExpectBoolean("false&&undetectable", false);
4129 ExpectBoolean("true||undetectable", true);
4130 ExpectObject("false||undetectable", obj);
4131
4132 ExpectObject("undetectable&&true", obj);
4133 ExpectObject("undetectable&&false", obj);
4134 ExpectBoolean("undetectable||true", true);
4135 ExpectBoolean("undetectable||false", false);
4136
4137 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004138 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004140 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004141 ExpectBoolean("undetectable==undetectable", true);
4142
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004143
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004145 ExpectBoolean("null===undetectable", false);
4146 ExpectBoolean("undetectable===undefined", false);
4147 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148 ExpectBoolean("undetectable===undetectable", true);
4149}
4150
4151
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004152TEST(UndetectableOptimized) {
4153 i::FLAG_allow_natives_syntax = true;
4154 v8::HandleScope scope;
4155 LocalContext env;
4156
4157 Local<String> obj = String::NewUndetectable("foo");
4158 env->Global()->Set(v8_str("undetectable"), obj);
4159 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4160
4161 ExpectString(
4162 "function testBranch() {"
4163 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4164 " if (%_IsUndetectableObject(detectable)) throw 2;"
4165 "}\n"
4166 "function testBool() {"
4167 " var b1 = !%_IsUndetectableObject(undetectable);"
4168 " var b2 = %_IsUndetectableObject(detectable);"
4169 " if (b1) throw 3;"
4170 " if (b2) throw 4;"
4171 " return b1 == b2;"
4172 "}\n"
4173 "%OptimizeFunctionOnNextCall(testBranch);"
4174 "%OptimizeFunctionOnNextCall(testBool);"
4175 "for (var i = 0; i < 10; i++) {"
4176 " testBranch();"
4177 " testBool();"
4178 "}\n"
4179 "\"PASS\"",
4180 "PASS");
4181}
4182
4183
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184template <typename T> static void USE(T) { }
4185
4186
4187// This test is not intended to be run, just type checked.
4188static void PersistentHandles() {
4189 USE(PersistentHandles);
4190 Local<String> str = v8_str("foo");
4191 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4192 USE(p_str);
4193 Local<Script> scr = Script::Compile(v8_str(""));
4194 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4195 USE(p_scr);
4196 Local<ObjectTemplate> templ = ObjectTemplate::New();
4197 v8::Persistent<ObjectTemplate> p_templ =
4198 v8::Persistent<ObjectTemplate>::New(templ);
4199 USE(p_templ);
4200}
4201
4202
4203static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4204 ApiTestFuzzer::Fuzz();
4205 return v8::Undefined();
4206}
4207
4208
4209THREADED_TEST(GlobalObjectTemplate) {
4210 v8::HandleScope handle_scope;
4211 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4212 global_template->Set(v8_str("JSNI_Log"),
4213 v8::FunctionTemplate::New(HandleLogDelegator));
4214 v8::Persistent<Context> context = Context::New(0, global_template);
4215 Context::Scope context_scope(context);
4216 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4217 context.Dispose();
4218}
4219
4220
4221static const char* kSimpleExtensionSource =
4222 "function Foo() {"
4223 " return 4;"
4224 "}";
4225
4226
4227THREADED_TEST(SimpleExtensions) {
4228 v8::HandleScope handle_scope;
4229 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4230 const char* extension_names[] = { "simpletest" };
4231 v8::ExtensionConfiguration extensions(1, extension_names);
4232 v8::Handle<Context> context = Context::New(&extensions);
4233 Context::Scope lock(context);
4234 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4235 CHECK_EQ(result, v8::Integer::New(4));
4236}
4237
4238
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004239static const char* kEvalExtensionSource1 =
4240 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004241 " var x = 42;"
4242 " return eval('x');"
4243 "}";
4244
4245
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004246static const char* kEvalExtensionSource2 =
4247 "(function() {"
4248 " var x = 42;"
4249 " function e() {"
4250 " return eval('x');"
4251 " }"
4252 " this.UseEval2 = e;"
4253 "})()";
4254
4255
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004256THREADED_TEST(UseEvalFromExtension) {
4257 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004258 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4259 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4260 const char* extension_names[] = { "evaltest1", "evaltest2" };
4261 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004262 v8::Handle<Context> context = Context::New(&extensions);
4263 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004264 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4265 CHECK_EQ(result, v8::Integer::New(42));
4266 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004267 CHECK_EQ(result, v8::Integer::New(42));
4268}
4269
4270
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004271static const char* kWithExtensionSource1 =
4272 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004273 " var x = 42;"
4274 " with({x:87}) { return x; }"
4275 "}";
4276
4277
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004278
4279static const char* kWithExtensionSource2 =
4280 "(function() {"
4281 " var x = 42;"
4282 " function e() {"
4283 " with ({x:87}) { return x; }"
4284 " }"
4285 " this.UseWith2 = e;"
4286 "})()";
4287
4288
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004289THREADED_TEST(UseWithFromExtension) {
4290 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004291 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4292 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4293 const char* extension_names[] = { "withtest1", "withtest2" };
4294 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004295 v8::Handle<Context> context = Context::New(&extensions);
4296 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004297 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4298 CHECK_EQ(result, v8::Integer::New(87));
4299 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004300 CHECK_EQ(result, v8::Integer::New(87));
4301}
4302
4303
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004304THREADED_TEST(AutoExtensions) {
4305 v8::HandleScope handle_scope;
4306 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4307 extension->set_auto_enable(true);
4308 v8::RegisterExtension(extension);
4309 v8::Handle<Context> context = Context::New();
4310 Context::Scope lock(context);
4311 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4312 CHECK_EQ(result, v8::Integer::New(4));
4313}
4314
4315
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004316static const char* kSyntaxErrorInExtensionSource =
4317 "[";
4318
4319
4320// Test that a syntax error in an extension does not cause a fatal
4321// error but results in an empty context.
4322THREADED_TEST(SyntaxErrorExtensions) {
4323 v8::HandleScope handle_scope;
4324 v8::RegisterExtension(new Extension("syntaxerror",
4325 kSyntaxErrorInExtensionSource));
4326 const char* extension_names[] = { "syntaxerror" };
4327 v8::ExtensionConfiguration extensions(1, extension_names);
4328 v8::Handle<Context> context = Context::New(&extensions);
4329 CHECK(context.IsEmpty());
4330}
4331
4332
4333static const char* kExceptionInExtensionSource =
4334 "throw 42";
4335
4336
4337// Test that an exception when installing an extension does not cause
4338// a fatal error but results in an empty context.
4339THREADED_TEST(ExceptionExtensions) {
4340 v8::HandleScope handle_scope;
4341 v8::RegisterExtension(new Extension("exception",
4342 kExceptionInExtensionSource));
4343 const char* extension_names[] = { "exception" };
4344 v8::ExtensionConfiguration extensions(1, extension_names);
4345 v8::Handle<Context> context = Context::New(&extensions);
4346 CHECK(context.IsEmpty());
4347}
4348
4349
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004350static const char* kNativeCallInExtensionSource =
4351 "function call_runtime_last_index_of(x) {"
4352 " return %StringLastIndexOf(x, 'bob', 10);"
4353 "}";
4354
4355
4356static const char* kNativeCallTest =
4357 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4358
4359// Test that a native runtime calls are supported in extensions.
4360THREADED_TEST(NativeCallInExtensions) {
4361 v8::HandleScope handle_scope;
4362 v8::RegisterExtension(new Extension("nativecall",
4363 kNativeCallInExtensionSource));
4364 const char* extension_names[] = { "nativecall" };
4365 v8::ExtensionConfiguration extensions(1, extension_names);
4366 v8::Handle<Context> context = Context::New(&extensions);
4367 Context::Scope lock(context);
4368 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4369 CHECK_EQ(result, v8::Integer::New(3));
4370}
4371
4372
whesse@chromium.org7b260152011-06-20 15:33:18 +00004373class NativeFunctionExtension : public Extension {
4374 public:
4375 NativeFunctionExtension(const char* name,
4376 const char* source,
4377 v8::InvocationCallback fun = &Echo)
4378 : Extension(name, source),
4379 function_(fun) { }
4380
4381 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4382 v8::Handle<v8::String> name) {
4383 return v8::FunctionTemplate::New(function_);
4384 }
4385
4386 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4387 if (args.Length() >= 1) return (args[0]);
4388 return v8::Undefined();
4389 }
4390 private:
4391 v8::InvocationCallback function_;
4392};
4393
4394
4395THREADED_TEST(NativeFunctionDeclaration) {
4396 v8::HandleScope handle_scope;
4397 const char* name = "nativedecl";
4398 v8::RegisterExtension(new NativeFunctionExtension(name,
4399 "native function foo();"));
4400 const char* extension_names[] = { name };
4401 v8::ExtensionConfiguration extensions(1, extension_names);
4402 v8::Handle<Context> context = Context::New(&extensions);
4403 Context::Scope lock(context);
4404 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4405 CHECK_EQ(result, v8::Integer::New(42));
4406}
4407
4408
4409THREADED_TEST(NativeFunctionDeclarationError) {
4410 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004411 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004412 // Syntax error in extension code.
4413 v8::RegisterExtension(new NativeFunctionExtension(name,
4414 "native\nfunction foo();"));
4415 const char* extension_names[] = { name };
4416 v8::ExtensionConfiguration extensions(1, extension_names);
4417 v8::Handle<Context> context = Context::New(&extensions);
4418 ASSERT(context.IsEmpty());
4419}
4420
4421THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4422 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00004423 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00004424 // Syntax error in extension code - escape code in "native" means that
4425 // it's not treated as a keyword.
4426 v8::RegisterExtension(new NativeFunctionExtension(
4427 name,
4428 "nativ\\u0065 function foo();"));
4429 const char* extension_names[] = { name };
4430 v8::ExtensionConfiguration extensions(1, extension_names);
4431 v8::Handle<Context> context = Context::New(&extensions);
4432 ASSERT(context.IsEmpty());
4433}
4434
4435
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004436static void CheckDependencies(const char* name, const char* expected) {
4437 v8::HandleScope handle_scope;
4438 v8::ExtensionConfiguration config(1, &name);
4439 LocalContext context(&config);
4440 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4441}
4442
4443
4444/*
4445 * Configuration:
4446 *
4447 * /-- B <--\
4448 * A <- -- D <-- E
4449 * \-- C <--/
4450 */
4451THREADED_TEST(ExtensionDependency) {
4452 static const char* kEDeps[] = { "D" };
4453 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4454 static const char* kDDeps[] = { "B", "C" };
4455 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4456 static const char* kBCDeps[] = { "A" };
4457 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4458 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4459 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4460 CheckDependencies("A", "undefinedA");
4461 CheckDependencies("B", "undefinedAB");
4462 CheckDependencies("C", "undefinedAC");
4463 CheckDependencies("D", "undefinedABCD");
4464 CheckDependencies("E", "undefinedABCDE");
4465 v8::HandleScope handle_scope;
4466 static const char* exts[2] = { "C", "E" };
4467 v8::ExtensionConfiguration config(2, exts);
4468 LocalContext context(&config);
4469 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4470}
4471
4472
4473static const char* kExtensionTestScript =
4474 "native function A();"
4475 "native function B();"
4476 "native function C();"
4477 "function Foo(i) {"
4478 " if (i == 0) return A();"
4479 " if (i == 1) return B();"
4480 " if (i == 2) return C();"
4481 "}";
4482
4483
4484static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4485 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004486 if (args.IsConstructCall()) {
4487 args.This()->Set(v8_str("data"), args.Data());
4488 return v8::Null();
4489 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004490 return args.Data();
4491}
4492
4493
4494class FunctionExtension : public Extension {
4495 public:
4496 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4497 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4498 v8::Handle<String> name);
4499};
4500
4501
4502static int lookup_count = 0;
4503v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4504 v8::Handle<String> name) {
4505 lookup_count++;
4506 if (name->Equals(v8_str("A"))) {
4507 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4508 } else if (name->Equals(v8_str("B"))) {
4509 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4510 } else if (name->Equals(v8_str("C"))) {
4511 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4512 } else {
4513 return v8::Handle<v8::FunctionTemplate>();
4514 }
4515}
4516
4517
4518THREADED_TEST(FunctionLookup) {
4519 v8::RegisterExtension(new FunctionExtension());
4520 v8::HandleScope handle_scope;
4521 static const char* exts[1] = { "functiontest" };
4522 v8::ExtensionConfiguration config(1, exts);
4523 LocalContext context(&config);
4524 CHECK_EQ(3, lookup_count);
4525 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4526 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4527 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4528}
4529
4530
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004531THREADED_TEST(NativeFunctionConstructCall) {
4532 v8::RegisterExtension(new FunctionExtension());
4533 v8::HandleScope handle_scope;
4534 static const char* exts[1] = { "functiontest" };
4535 v8::ExtensionConfiguration config(1, exts);
4536 LocalContext context(&config);
4537 for (int i = 0; i < 10; i++) {
4538 // Run a few times to ensure that allocation of objects doesn't
4539 // change behavior of a constructor function.
4540 CHECK_EQ(v8::Integer::New(8),
4541 Script::Compile(v8_str("(new A()).data"))->Run());
4542 CHECK_EQ(v8::Integer::New(7),
4543 Script::Compile(v8_str("(new B()).data"))->Run());
4544 CHECK_EQ(v8::Integer::New(6),
4545 Script::Compile(v8_str("(new C()).data"))->Run());
4546 }
4547}
4548
4549
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004550static const char* last_location;
4551static const char* last_message;
4552void StoringErrorCallback(const char* location, const char* message) {
4553 if (last_location == NULL) {
4554 last_location = location;
4555 last_message = message;
4556 }
4557}
4558
4559
4560// ErrorReporting creates a circular extensions configuration and
4561// tests that the fatal error handler gets called. This renders V8
4562// unusable and therefore this test cannot be run in parallel.
4563TEST(ErrorReporting) {
4564 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4565 static const char* aDeps[] = { "B" };
4566 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4567 static const char* bDeps[] = { "A" };
4568 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4569 last_location = NULL;
4570 v8::ExtensionConfiguration config(1, bDeps);
4571 v8::Handle<Context> context = Context::New(&config);
4572 CHECK(context.IsEmpty());
4573 CHECK_NE(last_location, NULL);
4574}
4575
4576
ager@chromium.org7c537e22008-10-16 08:43:32 +00004577static const char* js_code_causing_huge_string_flattening =
4578 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00004579 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00004580 " str = str + str;"
4581 "}"
4582 "str.match(/X/);";
4583
4584
4585void OOMCallback(const char* location, const char* message) {
4586 exit(0);
4587}
4588
4589
4590TEST(RegexpOutOfMemory) {
4591 // Execute a script that causes out of memory when flattening a string.
4592 v8::HandleScope scope;
4593 v8::V8::SetFatalErrorHandler(OOMCallback);
4594 LocalContext context;
4595 Local<Script> script =
4596 Script::Compile(String::New(js_code_causing_huge_string_flattening));
4597 last_location = NULL;
4598 Local<Value> result = script->Run();
4599
4600 CHECK(false); // Should not return.
4601}
4602
4603
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004604static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4605 v8::Handle<Value> data) {
4606 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004607 CHECK(message->GetScriptResourceName()->IsUndefined());
4608 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004609 message->GetLineNumber();
4610 message->GetSourceLine();
4611}
4612
4613
4614THREADED_TEST(ErrorWithMissingScriptInfo) {
4615 v8::HandleScope scope;
4616 LocalContext context;
4617 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4618 Script::Compile(v8_str("throw Error()"))->Run();
4619 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4620}
4621
4622
4623int global_index = 0;
4624
4625class Snorkel {
4626 public:
4627 Snorkel() { index_ = global_index++; }
4628 int index_;
4629};
4630
4631class Whammy {
4632 public:
4633 Whammy() {
4634 cursor_ = 0;
4635 }
4636 ~Whammy() {
4637 script_.Dispose();
4638 }
4639 v8::Handle<Script> getScript() {
4640 if (script_.IsEmpty())
4641 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4642 return Local<Script>(*script_);
4643 }
4644
4645 public:
4646 static const int kObjectCount = 256;
4647 int cursor_;
4648 v8::Persistent<v8::Object> objects_[kObjectCount];
4649 v8::Persistent<Script> script_;
4650};
4651
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004652static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004653 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4654 delete snorkel;
4655 obj.ClearWeak();
4656}
4657
4658v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4659 const AccessorInfo& info) {
4660 Whammy* whammy =
4661 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4662
4663 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4664
4665 v8::Handle<v8::Object> obj = v8::Object::New();
4666 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4667 if (!prev.IsEmpty()) {
4668 prev->Set(v8_str("next"), obj);
4669 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4670 whammy->objects_[whammy->cursor_].Clear();
4671 }
4672 whammy->objects_[whammy->cursor_] = global;
4673 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4674 return whammy->getScript()->Run();
4675}
4676
4677THREADED_TEST(WeakReference) {
4678 v8::HandleScope handle_scope;
4679 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004680 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004681 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
4682 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004683 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004684 const char* extension_list[] = { "v8/gc" };
4685 v8::ExtensionConfiguration extensions(1, extension_list);
4686 v8::Persistent<Context> context = Context::New(&extensions);
4687 Context::Scope context_scope(context);
4688
4689 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4690 context->Global()->Set(v8_str("whammy"), interceptor);
4691 const char* code =
4692 "var last;"
4693 "for (var i = 0; i < 10000; i++) {"
4694 " var obj = whammy.length;"
4695 " if (last) last.next = obj;"
4696 " last = obj;"
4697 "}"
4698 "gc();"
4699 "4";
4700 v8::Handle<Value> result = CompileRun(code);
4701 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00004702 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004703 context.Dispose();
4704}
4705
4706
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004707static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004708 obj.Dispose();
4709 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004710 *(reinterpret_cast<bool*>(data)) = true;
4711}
4712
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004713
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004714THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004715 v8::Persistent<Context> context = Context::New();
4716 Context::Scope context_scope(context);
4717
4718 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004719
4720 {
4721 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004722 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4723 }
4724
4725 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004726 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
4727 object_a.MarkIndependent();
4728 HEAP->PerformScavenge();
4729 CHECK(object_a_disposed);
4730}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004731
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004732
4733static void InvokeScavenge() {
4734 HEAP->PerformScavenge();
4735}
4736
4737
4738static void InvokeMarkSweep() {
4739 HEAP->CollectAllGarbage(false);
4740}
4741
4742
4743static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4744 obj.Dispose();
4745 obj.Clear();
4746 *(reinterpret_cast<bool*>(data)) = true;
4747 InvokeScavenge();
4748}
4749
4750
4751static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
4752 obj.Dispose();
4753 obj.Clear();
4754 *(reinterpret_cast<bool*>(data)) = true;
4755 InvokeMarkSweep();
4756}
4757
4758
4759THREADED_TEST(GCFromWeakCallbacks) {
4760 v8::Persistent<Context> context = Context::New();
4761 Context::Scope context_scope(context);
4762
4763 static const int kNumberOfGCTypes = 2;
4764 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
4765 {&ForceScavenge, &ForceMarkSweep};
4766
4767 typedef void (*GCInvoker)();
4768 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
4769
4770 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
4771 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
4772 v8::Persistent<v8::Object> object;
4773 {
4774 v8::HandleScope handle_scope;
4775 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4776 }
4777 bool disposed = false;
4778 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
4779 object.MarkIndependent();
4780 invoke_gc[outer_gc]();
4781 CHECK(disposed);
4782 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004783 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004784}
4785
4786
4787static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
4788 obj.ClearWeak();
4789 *(reinterpret_cast<bool*>(data)) = true;
4790}
4791
4792
4793THREADED_TEST(IndependentHandleRevival) {
4794 v8::Persistent<Context> context = Context::New();
4795 Context::Scope context_scope(context);
4796
4797 v8::Persistent<v8::Object> object;
4798 {
4799 v8::HandleScope handle_scope;
4800 object = v8::Persistent<v8::Object>::New(v8::Object::New());
4801 object->Set(v8_str("x"), v8::Integer::New(1));
4802 v8::Local<String> y_str = v8_str("y");
4803 object->Set(y_str, y_str);
4804 }
4805 bool revived = false;
4806 object.MakeWeak(&revived, &RevivingCallback);
4807 object.MarkIndependent();
4808 HEAP->PerformScavenge();
4809 CHECK(revived);
4810 HEAP->CollectAllGarbage(true);
4811 {
4812 v8::HandleScope handle_scope;
4813 v8::Local<String> y_str = v8_str("y");
4814 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
4815 CHECK(object->Get(y_str)->Equals(y_str));
4816 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004817}
4818
4819
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004820v8::Handle<Function> args_fun;
4821
4822
4823static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4824 ApiTestFuzzer::Fuzz();
4825 CHECK_EQ(args_fun, args.Callee());
4826 CHECK_EQ(3, args.Length());
4827 CHECK_EQ(v8::Integer::New(1), args[0]);
4828 CHECK_EQ(v8::Integer::New(2), args[1]);
4829 CHECK_EQ(v8::Integer::New(3), args[2]);
4830 CHECK_EQ(v8::Undefined(), args[3]);
4831 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 HEAP->CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004833 return v8::Undefined();
4834}
4835
4836
4837THREADED_TEST(Arguments) {
4838 v8::HandleScope scope;
4839 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4840 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4841 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004842 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004843 v8_compile("f(1, 2, 3)")->Run();
4844}
4845
4846
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004847static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4848 const AccessorInfo&) {
4849 return v8::Handle<Value>();
4850}
4851
4852
4853static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4854 const AccessorInfo&) {
4855 return v8::Handle<Value>();
4856}
4857
4858
4859static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4860 const AccessorInfo&) {
4861 if (!name->Equals(v8_str("foo"))) {
4862 return v8::Handle<v8::Boolean>(); // not intercepted
4863 }
4864
4865 return v8::False(); // intercepted, and don't delete the property
4866}
4867
4868
4869static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4870 if (index != 2) {
4871 return v8::Handle<v8::Boolean>(); // not intercepted
4872 }
4873
4874 return v8::False(); // intercepted, and don't delete the property
4875}
4876
4877
4878THREADED_TEST(Deleter) {
4879 v8::HandleScope scope;
4880 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4881 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4882 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4883 LocalContext context;
4884 context->Global()->Set(v8_str("k"), obj->NewInstance());
4885 CompileRun(
4886 "k.foo = 'foo';"
4887 "k.bar = 'bar';"
4888 "k[2] = 2;"
4889 "k[4] = 4;");
4890 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4891 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4892
4893 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4894 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4895
4896 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4897 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4898
4899 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4900 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4901}
4902
4903
4904static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4905 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004906 if (name->Equals(v8_str("foo")) ||
4907 name->Equals(v8_str("bar")) ||
4908 name->Equals(v8_str("baz"))) {
4909 return v8::Undefined();
4910 }
4911 return v8::Handle<Value>();
4912}
4913
4914
4915static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4916 ApiTestFuzzer::Fuzz();
4917 if (index == 0 || index == 1) return v8::Undefined();
4918 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004919}
4920
4921
4922static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4923 ApiTestFuzzer::Fuzz();
4924 v8::Handle<v8::Array> result = v8::Array::New(3);
4925 result->Set(v8::Integer::New(0), v8_str("foo"));
4926 result->Set(v8::Integer::New(1), v8_str("bar"));
4927 result->Set(v8::Integer::New(2), v8_str("baz"));
4928 return result;
4929}
4930
4931
4932static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4933 ApiTestFuzzer::Fuzz();
4934 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004935 result->Set(v8::Integer::New(0), v8_str("0"));
4936 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004937 return result;
4938}
4939
4940
4941THREADED_TEST(Enumerators) {
4942 v8::HandleScope scope;
4943 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4944 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004945 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004946 LocalContext context;
4947 context->Global()->Set(v8_str("k"), obj->NewInstance());
4948 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004949 "k[10] = 0;"
4950 "k.a = 0;"
4951 "k[5] = 0;"
4952 "k.b = 0;"
4953 "k[4294967295] = 0;"
4954 "k.c = 0;"
4955 "k[4294967296] = 0;"
4956 "k.d = 0;"
4957 "k[140000] = 0;"
4958 "k.e = 0;"
4959 "k[30000000000] = 0;"
4960 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004961 "var result = [];"
4962 "for (var prop in k) {"
4963 " result.push(prop);"
4964 "}"
4965 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004966 // Check that we get all the property names returned including the
4967 // ones from the enumerators in the right order: indexed properties
4968 // in numerical order, indexed interceptor properties, named
4969 // properties in insertion order, named interceptor properties.
4970 // This order is not mandated by the spec, so this test is just
4971 // documenting our behavior.
4972 CHECK_EQ(17, result->Length());
4973 // Indexed properties in numerical order.
4974 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4975 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4976 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4977 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4978 // Indexed interceptor properties in the order they are returned
4979 // from the enumerator interceptor.
4980 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4981 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4982 // Named properties in insertion order.
4983 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4984 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4985 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4986 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4987 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4988 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4989 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4990 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4991 // Named interceptor properties.
4992 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4993 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4994 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004995}
4996
4997
4998int p_getter_count;
4999int p_getter_count2;
5000
5001
5002static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5003 ApiTestFuzzer::Fuzz();
5004 p_getter_count++;
5005 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5006 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5007 if (name->Equals(v8_str("p1"))) {
5008 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5009 } else if (name->Equals(v8_str("p2"))) {
5010 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5011 } else if (name->Equals(v8_str("p3"))) {
5012 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5013 } else if (name->Equals(v8_str("p4"))) {
5014 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5015 }
5016 return v8::Undefined();
5017}
5018
5019
5020static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5021 ApiTestFuzzer::Fuzz();
5022 LocalContext context;
5023 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5024 CompileRun(
5025 "o1.__proto__ = { };"
5026 "var o2 = { __proto__: o1 };"
5027 "var o3 = { __proto__: o2 };"
5028 "var o4 = { __proto__: o3 };"
5029 "for (var i = 0; i < 10; i++) o4.p4;"
5030 "for (var i = 0; i < 10; i++) o3.p3;"
5031 "for (var i = 0; i < 10; i++) o2.p2;"
5032 "for (var i = 0; i < 10; i++) o1.p1;");
5033}
5034
5035
5036static v8::Handle<Value> PGetter2(Local<String> name,
5037 const AccessorInfo& info) {
5038 ApiTestFuzzer::Fuzz();
5039 p_getter_count2++;
5040 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5041 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5042 if (name->Equals(v8_str("p1"))) {
5043 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5044 } else if (name->Equals(v8_str("p2"))) {
5045 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5046 } else if (name->Equals(v8_str("p3"))) {
5047 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5048 } else if (name->Equals(v8_str("p4"))) {
5049 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5050 }
5051 return v8::Undefined();
5052}
5053
5054
5055THREADED_TEST(GetterHolders) {
5056 v8::HandleScope scope;
5057 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5058 obj->SetAccessor(v8_str("p1"), PGetter);
5059 obj->SetAccessor(v8_str("p2"), PGetter);
5060 obj->SetAccessor(v8_str("p3"), PGetter);
5061 obj->SetAccessor(v8_str("p4"), PGetter);
5062 p_getter_count = 0;
5063 RunHolderTest(obj);
5064 CHECK_EQ(40, p_getter_count);
5065}
5066
5067
5068THREADED_TEST(PreInterceptorHolders) {
5069 v8::HandleScope scope;
5070 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5071 obj->SetNamedPropertyHandler(PGetter2);
5072 p_getter_count2 = 0;
5073 RunHolderTest(obj);
5074 CHECK_EQ(40, p_getter_count2);
5075}
5076
5077
5078THREADED_TEST(ObjectInstantiation) {
5079 v8::HandleScope scope;
5080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5081 templ->SetAccessor(v8_str("t"), PGetter2);
5082 LocalContext context;
5083 context->Global()->Set(v8_str("o"), templ->NewInstance());
5084 for (int i = 0; i < 100; i++) {
5085 v8::HandleScope inner_scope;
5086 v8::Handle<v8::Object> obj = templ->NewInstance();
5087 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5088 context->Global()->Set(v8_str("o2"), obj);
5089 v8::Handle<Value> value =
5090 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5091 CHECK_EQ(v8::True(), value);
5092 context->Global()->Set(v8_str("o"), obj);
5093 }
5094}
5095
5096
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005097static int StrCmp16(uint16_t* a, uint16_t* b) {
5098 while (true) {
5099 if (*a == 0 && *b == 0) return 0;
5100 if (*a != *b) return 0 + *a - *b;
5101 a++;
5102 b++;
5103 }
5104}
5105
5106
5107static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5108 while (true) {
5109 if (n-- == 0) return 0;
5110 if (*a == 0 && *b == 0) return 0;
5111 if (*a != *b) return 0 + *a - *b;
5112 a++;
5113 b++;
5114 }
5115}
5116
5117
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005118THREADED_TEST(StringWrite) {
5119 v8::HandleScope scope;
5120 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005121 // abc<Icelandic eth><Unicode snowman>.
5122 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5123
5124 CHECK_EQ(5, str2->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005125
5126 char buf[100];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005127 char utf8buf[100];
5128 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005129 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005130 int charlen;
5131
5132 memset(utf8buf, 0x1, sizeof(utf8buf));
5133 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005134 CHECK_EQ(9, len);
5135 CHECK_EQ(5, charlen);
5136 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005137
5138 memset(utf8buf, 0x1, sizeof(utf8buf));
5139 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005140 CHECK_EQ(8, len);
5141 CHECK_EQ(5, charlen);
5142 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005143
5144 memset(utf8buf, 0x1, sizeof(utf8buf));
5145 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005146 CHECK_EQ(5, len);
5147 CHECK_EQ(4, charlen);
5148 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005149
5150 memset(utf8buf, 0x1, sizeof(utf8buf));
5151 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005152 CHECK_EQ(5, len);
5153 CHECK_EQ(4, charlen);
5154 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155
5156 memset(utf8buf, 0x1, sizeof(utf8buf));
5157 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005158 CHECK_EQ(5, len);
5159 CHECK_EQ(4, charlen);
5160 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005161
5162 memset(utf8buf, 0x1, sizeof(utf8buf));
5163 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005164 CHECK_EQ(3, len);
5165 CHECK_EQ(3, charlen);
5166 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005167
5168 memset(utf8buf, 0x1, sizeof(utf8buf));
5169 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005170 CHECK_EQ(3, len);
5171 CHECK_EQ(3, charlen);
5172 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005173
5174 memset(utf8buf, 0x1, sizeof(utf8buf));
5175 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005176 CHECK_EQ(2, len);
5177 CHECK_EQ(2, charlen);
5178 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005179
5180 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005181 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005182 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005183 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005184 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005185 CHECK_EQ(5, len);
5186 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005187 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005188 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005189
5190 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005191 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005192 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005193 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005195 CHECK_EQ(4, len);
5196 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005197 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005198 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005199
5200 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005201 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005202 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005203 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005204 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005205 CHECK_EQ(5, len);
5206 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005207 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005208 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005209
5210 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005211 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005212 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005213 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005214 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005215 CHECK_EQ(5, len);
5216 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005217 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005218 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005219
5220 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005222 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005223 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005225 CHECK_EQ(1, len);
5226 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005227 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005228 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005229
5230 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005231 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005232 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005233 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005234 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005235 CHECK_EQ(1, len);
5236 CHECK_EQ(0, strcmp("e", buf));
5237 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005238
5239 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005240 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005241 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005242 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005243 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005244 CHECK_EQ(1, len);
5245 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005246 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005247 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005248
5249 memset(buf, 0x1, sizeof(buf));
5250 memset(wbuf, 0x1, sizeof(wbuf));
5251 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005252 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005253 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005254 CHECK_EQ(1, len);
5255 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005256 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005257 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005258}
5259
5260
5261THREADED_TEST(ToArrayIndex) {
5262 v8::HandleScope scope;
5263 LocalContext context;
5264
5265 v8::Handle<String> str = v8_str("42");
5266 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5267 CHECK(!index.IsEmpty());
5268 CHECK_EQ(42.0, index->Uint32Value());
5269 str = v8_str("42asdf");
5270 index = str->ToArrayIndex();
5271 CHECK(index.IsEmpty());
5272 str = v8_str("-42");
5273 index = str->ToArrayIndex();
5274 CHECK(index.IsEmpty());
5275 str = v8_str("4294967295");
5276 index = str->ToArrayIndex();
5277 CHECK(!index.IsEmpty());
5278 CHECK_EQ(4294967295.0, index->Uint32Value());
5279 v8::Handle<v8::Number> num = v8::Number::New(1);
5280 index = num->ToArrayIndex();
5281 CHECK(!index.IsEmpty());
5282 CHECK_EQ(1.0, index->Uint32Value());
5283 num = v8::Number::New(-1);
5284 index = num->ToArrayIndex();
5285 CHECK(index.IsEmpty());
5286 v8::Handle<v8::Object> obj = v8::Object::New();
5287 index = obj->ToArrayIndex();
5288 CHECK(index.IsEmpty());
5289}
5290
5291
5292THREADED_TEST(ErrorConstruction) {
5293 v8::HandleScope scope;
5294 LocalContext context;
5295
5296 v8::Handle<String> foo = v8_str("foo");
5297 v8::Handle<String> message = v8_str("message");
5298 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5299 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005300 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
5301 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005302 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5303 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005304 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005305 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5306 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005307 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005308 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5309 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005310 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005311 v8::Handle<Value> error = v8::Exception::Error(foo);
5312 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005313 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005314}
5315
5316
5317static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5318 ApiTestFuzzer::Fuzz();
5319 return v8_num(10);
5320}
5321
5322
5323static void YSetter(Local<String> name,
5324 Local<Value> value,
5325 const AccessorInfo& info) {
5326 if (info.This()->Has(name)) {
5327 info.This()->Delete(name);
5328 }
5329 info.This()->Set(name, value);
5330}
5331
5332
5333THREADED_TEST(DeleteAccessor) {
5334 v8::HandleScope scope;
5335 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5336 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5337 LocalContext context;
5338 v8::Handle<v8::Object> holder = obj->NewInstance();
5339 context->Global()->Set(v8_str("holder"), holder);
5340 v8::Handle<Value> result = CompileRun(
5341 "holder.y = 11; holder.y = 12; holder.y");
5342 CHECK_EQ(12, result->Uint32Value());
5343}
5344
5345
5346THREADED_TEST(TypeSwitch) {
5347 v8::HandleScope scope;
5348 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5349 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5350 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5351 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5352 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5353 LocalContext context;
5354 v8::Handle<v8::Object> obj0 = v8::Object::New();
5355 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5356 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5357 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5358 for (int i = 0; i < 10; i++) {
5359 CHECK_EQ(0, type_switch->match(obj0));
5360 CHECK_EQ(1, type_switch->match(obj1));
5361 CHECK_EQ(2, type_switch->match(obj2));
5362 CHECK_EQ(3, type_switch->match(obj3));
5363 CHECK_EQ(3, type_switch->match(obj3));
5364 CHECK_EQ(2, type_switch->match(obj2));
5365 CHECK_EQ(1, type_switch->match(obj1));
5366 CHECK_EQ(0, type_switch->match(obj0));
5367 }
5368}
5369
5370
5371// For use within the TestSecurityHandler() test.
5372static bool g_security_callback_result = false;
5373static bool NamedSecurityTestCallback(Local<v8::Object> global,
5374 Local<Value> name,
5375 v8::AccessType type,
5376 Local<Value> data) {
5377 // Always allow read access.
5378 if (type == v8::ACCESS_GET)
5379 return true;
5380
5381 // Sometimes allow other access.
5382 return g_security_callback_result;
5383}
5384
5385
5386static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5387 uint32_t key,
5388 v8::AccessType type,
5389 Local<Value> data) {
5390 // Always allow read access.
5391 if (type == v8::ACCESS_GET)
5392 return true;
5393
5394 // Sometimes allow other access.
5395 return g_security_callback_result;
5396}
5397
5398
5399static int trouble_nesting = 0;
5400static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5401 ApiTestFuzzer::Fuzz();
5402 trouble_nesting++;
5403
5404 // Call a JS function that throws an uncaught exception.
5405 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5406 Local<Value> trouble_callee = (trouble_nesting == 3) ?
5407 arg_this->Get(v8_str("trouble_callee")) :
5408 arg_this->Get(v8_str("trouble_caller"));
5409 CHECK(trouble_callee->IsFunction());
5410 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5411}
5412
5413
5414static int report_count = 0;
5415static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5416 v8::Handle<Value>) {
5417 report_count++;
5418}
5419
5420
5421// Counts uncaught exceptions, but other tests running in parallel
5422// also have uncaught exceptions.
5423TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00005424 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005425 v8::HandleScope scope;
5426 LocalContext env;
5427 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5428
5429 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5430 v8::Local<v8::Object> global = env->Global();
5431 global->Set(v8_str("trouble"), fun->GetFunction());
5432
5433 Script::Compile(v8_str("function trouble_callee() {"
5434 " var x = null;"
5435 " return x.foo;"
5436 "};"
5437 "function trouble_caller() {"
5438 " trouble();"
5439 "};"))->Run();
5440 Local<Value> trouble = global->Get(v8_str("trouble"));
5441 CHECK(trouble->IsFunction());
5442 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5443 CHECK(trouble_callee->IsFunction());
5444 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5445 CHECK(trouble_caller->IsFunction());
5446 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5447 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00005448 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5449}
5450
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005451static const char* script_resource_name = "ExceptionInNativeScript.js";
5452static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5453 v8::Handle<Value>) {
5454 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5455 CHECK(!name_val.IsEmpty() && name_val->IsString());
5456 v8::String::AsciiValue name(message->GetScriptResourceName());
5457 CHECK_EQ(script_resource_name, *name);
5458 CHECK_EQ(3, message->GetLineNumber());
5459 v8::String::AsciiValue source_line(message->GetSourceLine());
5460 CHECK_EQ(" new o.foo();", *source_line);
5461}
5462
5463TEST(ExceptionInNativeScript) {
5464 v8::HandleScope scope;
5465 LocalContext env;
5466 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5467
5468 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5469 v8::Local<v8::Object> global = env->Global();
5470 global->Set(v8_str("trouble"), fun->GetFunction());
5471
5472 Script::Compile(v8_str("function trouble() {\n"
5473 " var o = {};\n"
5474 " new o.foo();\n"
5475 "};"), v8::String::New(script_resource_name))->Run();
5476 Local<Value> trouble = global->Get(v8_str("trouble"));
5477 CHECK(trouble->IsFunction());
5478 Function::Cast(*trouble)->Call(global, 0, NULL);
5479 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5480}
5481
ager@chromium.org8bb60582008-12-11 12:02:20 +00005482
5483TEST(CompilationErrorUsingTryCatchHandler) {
5484 v8::HandleScope scope;
5485 LocalContext env;
5486 v8::TryCatch try_catch;
5487 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5488 CHECK_NE(NULL, *try_catch.Exception());
5489 CHECK(try_catch.HasCaught());
5490}
5491
5492
5493TEST(TryCatchFinallyUsingTryCatchHandler) {
5494 v8::HandleScope scope;
5495 LocalContext env;
5496 v8::TryCatch try_catch;
5497 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5498 CHECK(!try_catch.HasCaught());
5499 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5500 CHECK(try_catch.HasCaught());
5501 try_catch.Reset();
5502 Script::Compile(v8_str("(function() {"
5503 "try { throw ''; } finally { return; }"
5504 "})()"))->Run();
5505 CHECK(!try_catch.HasCaught());
5506 Script::Compile(v8_str("(function()"
5507 " { try { throw ''; } finally { throw 0; }"
5508 "})()"))->Run();
5509 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005510}
5511
5512
5513// SecurityHandler can't be run twice
5514TEST(SecurityHandler) {
5515 v8::HandleScope scope0;
5516 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5517 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5518 IndexedSecurityTestCallback);
5519 // Create an environment
5520 v8::Persistent<Context> context0 =
5521 Context::New(NULL, global_template);
5522 context0->Enter();
5523
5524 v8::Handle<v8::Object> global0 = context0->Global();
5525 v8::Handle<Script> script0 = v8_compile("foo = 111");
5526 script0->Run();
5527 global0->Set(v8_str("0"), v8_num(999));
5528 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5529 CHECK_EQ(111, foo0->Int32Value());
5530 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5531 CHECK_EQ(999, z0->Int32Value());
5532
5533 // Create another environment, should fail security checks.
5534 v8::HandleScope scope1;
5535
5536 v8::Persistent<Context> context1 =
5537 Context::New(NULL, global_template);
5538 context1->Enter();
5539
5540 v8::Handle<v8::Object> global1 = context1->Global();
5541 global1->Set(v8_str("othercontext"), global0);
5542 // This set will fail the security check.
5543 v8::Handle<Script> script1 =
5544 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5545 script1->Run();
5546 // This read will pass the security check.
5547 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5548 CHECK_EQ(111, foo1->Int32Value());
5549 // This read will pass the security check.
5550 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5551 CHECK_EQ(999, z1->Int32Value());
5552
5553 // Create another environment, should pass security checks.
5554 { g_security_callback_result = true; // allow security handler to pass.
5555 v8::HandleScope scope2;
5556 LocalContext context2;
5557 v8::Handle<v8::Object> global2 = context2->Global();
5558 global2->Set(v8_str("othercontext"), global0);
5559 v8::Handle<Script> script2 =
5560 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5561 script2->Run();
5562 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5563 CHECK_EQ(333, foo2->Int32Value());
5564 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5565 CHECK_EQ(888, z2->Int32Value());
5566 }
5567
5568 context1->Exit();
5569 context1.Dispose();
5570
5571 context0->Exit();
5572 context0.Dispose();
5573}
5574
5575
5576THREADED_TEST(SecurityChecks) {
5577 v8::HandleScope handle_scope;
5578 LocalContext env1;
5579 v8::Persistent<Context> env2 = Context::New();
5580
5581 Local<Value> foo = v8_str("foo");
5582 Local<Value> bar = v8_str("bar");
5583
5584 // Set to the same domain.
5585 env1->SetSecurityToken(foo);
5586
5587 // Create a function in env1.
5588 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5589 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5590 CHECK(spy->IsFunction());
5591
5592 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005593 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005594 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5595 CHECK(spy2->IsFunction());
5596
5597 // Switch to env2 in the same domain and invoke spy on env2.
5598 {
5599 env2->SetSecurityToken(foo);
5600 // Enter env2
5601 Context::Scope scope_env2(env2);
5602 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
5603 CHECK(result->IsFunction());
5604 }
5605
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005606 {
5607 env2->SetSecurityToken(bar);
5608 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005609
5610 // Call cross_domain_call, it should throw an exception
5611 v8::TryCatch try_catch;
5612 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
5613 CHECK(try_catch.HasCaught());
5614 }
5615
5616 env2.Dispose();
5617}
5618
5619
5620// Regression test case for issue 1183439.
5621THREADED_TEST(SecurityChecksForPrototypeChain) {
5622 v8::HandleScope scope;
5623 LocalContext current;
5624 v8::Persistent<Context> other = Context::New();
5625
5626 // Change context to be able to get to the Object function in the
5627 // other context without hitting the security checks.
5628 v8::Local<Value> other_object;
5629 { Context::Scope scope(other);
5630 other_object = other->Global()->Get(v8_str("Object"));
5631 other->Global()->Set(v8_num(42), v8_num(87));
5632 }
5633
5634 current->Global()->Set(v8_str("other"), other->Global());
5635 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
5636
5637 // Make sure the security check fails here and we get an undefined
5638 // result instead of getting the Object function. Repeat in a loop
5639 // to make sure to exercise the IC code.
5640 v8::Local<Script> access_other0 = v8_compile("other.Object");
5641 v8::Local<Script> access_other1 = v8_compile("other[42]");
5642 for (int i = 0; i < 5; i++) {
5643 CHECK(!access_other0->Run()->Equals(other_object));
5644 CHECK(access_other0->Run()->IsUndefined());
5645 CHECK(!access_other1->Run()->Equals(v8_num(87)));
5646 CHECK(access_other1->Run()->IsUndefined());
5647 }
5648
5649 // Create an object that has 'other' in its prototype chain and make
5650 // sure we cannot access the Object function indirectly through
5651 // that. Repeat in a loop to make sure to exercise the IC code.
5652 v8_compile("function F() { };"
5653 "F.prototype = other;"
5654 "var f = new F();")->Run();
5655 v8::Local<Script> access_f0 = v8_compile("f.Object");
5656 v8::Local<Script> access_f1 = v8_compile("f[42]");
5657 for (int j = 0; j < 5; j++) {
5658 CHECK(!access_f0->Run()->Equals(other_object));
5659 CHECK(access_f0->Run()->IsUndefined());
5660 CHECK(!access_f1->Run()->Equals(v8_num(87)));
5661 CHECK(access_f1->Run()->IsUndefined());
5662 }
5663
5664 // Now it gets hairy: Set the prototype for the other global object
5665 // to be the current global object. The prototype chain for 'f' now
5666 // goes through 'other' but ends up in the current global object.
5667 { Context::Scope scope(other);
5668 other->Global()->Set(v8_str("__proto__"), current->Global());
5669 }
5670 // Set a named and an index property on the current global
5671 // object. To force the lookup to go through the other global object,
5672 // the properties must not exist in the other global object.
5673 current->Global()->Set(v8_str("foo"), v8_num(100));
5674 current->Global()->Set(v8_num(99), v8_num(101));
5675 // Try to read the properties from f and make sure that the access
5676 // gets stopped by the security checks on the other global object.
5677 Local<Script> access_f2 = v8_compile("f.foo");
5678 Local<Script> access_f3 = v8_compile("f[99]");
5679 for (int k = 0; k < 5; k++) {
5680 CHECK(!access_f2->Run()->Equals(v8_num(100)));
5681 CHECK(access_f2->Run()->IsUndefined());
5682 CHECK(!access_f3->Run()->Equals(v8_num(101)));
5683 CHECK(access_f3->Run()->IsUndefined());
5684 }
5685 other.Dispose();
5686}
5687
5688
5689THREADED_TEST(CrossDomainDelete) {
5690 v8::HandleScope handle_scope;
5691 LocalContext env1;
5692 v8::Persistent<Context> env2 = Context::New();
5693
5694 Local<Value> foo = v8_str("foo");
5695 Local<Value> bar = v8_str("bar");
5696
5697 // Set to the same domain.
5698 env1->SetSecurityToken(foo);
5699 env2->SetSecurityToken(foo);
5700
5701 env1->Global()->Set(v8_str("prop"), v8_num(3));
5702 env2->Global()->Set(v8_str("env1"), env1->Global());
5703
5704 // Change env2 to a different domain and delete env1.prop.
5705 env2->SetSecurityToken(bar);
5706 {
5707 Context::Scope scope_env2(env2);
5708 Local<Value> result =
5709 Script::Compile(v8_str("delete env1.prop"))->Run();
5710 CHECK(result->IsFalse());
5711 }
5712
5713 // Check that env1.prop still exists.
5714 Local<Value> v = env1->Global()->Get(v8_str("prop"));
5715 CHECK(v->IsNumber());
5716 CHECK_EQ(3, v->Int32Value());
5717
5718 env2.Dispose();
5719}
5720
5721
ager@chromium.org870a0b62008-11-04 11:43:05 +00005722THREADED_TEST(CrossDomainIsPropertyEnumerable) {
5723 v8::HandleScope handle_scope;
5724 LocalContext env1;
5725 v8::Persistent<Context> env2 = Context::New();
5726
5727 Local<Value> foo = v8_str("foo");
5728 Local<Value> bar = v8_str("bar");
5729
5730 // Set to the same domain.
5731 env1->SetSecurityToken(foo);
5732 env2->SetSecurityToken(foo);
5733
5734 env1->Global()->Set(v8_str("prop"), v8_num(3));
5735 env2->Global()->Set(v8_str("env1"), env1->Global());
5736
5737 // env1.prop is enumerable in env2.
5738 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
5739 {
5740 Context::Scope scope_env2(env2);
5741 Local<Value> result = Script::Compile(test)->Run();
5742 CHECK(result->IsTrue());
5743 }
5744
5745 // Change env2 to a different domain and test again.
5746 env2->SetSecurityToken(bar);
5747 {
5748 Context::Scope scope_env2(env2);
5749 Local<Value> result = Script::Compile(test)->Run();
5750 CHECK(result->IsFalse());
5751 }
5752
5753 env2.Dispose();
5754}
5755
5756
ager@chromium.org236ad962008-09-25 09:45:57 +00005757THREADED_TEST(CrossDomainForIn) {
5758 v8::HandleScope handle_scope;
5759 LocalContext env1;
5760 v8::Persistent<Context> env2 = Context::New();
5761
5762 Local<Value> foo = v8_str("foo");
5763 Local<Value> bar = v8_str("bar");
5764
5765 // Set to the same domain.
5766 env1->SetSecurityToken(foo);
5767 env2->SetSecurityToken(foo);
5768
5769 env1->Global()->Set(v8_str("prop"), v8_num(3));
5770 env2->Global()->Set(v8_str("env1"), env1->Global());
5771
5772 // Change env2 to a different domain and set env1's global object
5773 // as the __proto__ of an object in env2 and enumerate properties
5774 // in for-in. It shouldn't enumerate properties on env1's global
5775 // object.
5776 env2->SetSecurityToken(bar);
5777 {
5778 Context::Scope scope_env2(env2);
5779 Local<Value> result =
5780 CompileRun("(function(){var obj = {'__proto__':env1};"
5781 "for (var p in obj)"
5782 " if (p == 'prop') return false;"
5783 "return true;})()");
5784 CHECK(result->IsTrue());
5785 }
5786 env2.Dispose();
5787}
5788
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005789
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005790TEST(ContextDetachGlobal) {
5791 v8::HandleScope handle_scope;
5792 LocalContext env1;
5793 v8::Persistent<Context> env2 = Context::New();
5794
5795 Local<v8::Object> global1 = env1->Global();
5796
5797 Local<Value> foo = v8_str("foo");
5798
5799 // Set to the same domain.
5800 env1->SetSecurityToken(foo);
5801 env2->SetSecurityToken(foo);
5802
5803 // Enter env2
5804 env2->Enter();
5805
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005806 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005807 Local<v8::Object> global2 = env2->Global();
5808 global2->Set(v8_str("prop"), v8::Integer::New(1));
5809 CompileRun("function getProp() {return prop;}");
5810
5811 env1->Global()->Set(v8_str("getProp"),
5812 global2->Get(v8_str("getProp")));
5813
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005814 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005815 env2->Exit();
5816 env2->DetachGlobal();
5817 // env2 has a new global object.
5818 CHECK(!env2->Global()->Equals(global2));
5819
5820 v8::Persistent<Context> env3 =
5821 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5822 env3->SetSecurityToken(v8_str("bar"));
5823 env3->Enter();
5824
5825 Local<v8::Object> global3 = env3->Global();
5826 CHECK_EQ(global2, global3);
5827 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5828 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5829 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5830 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5831 env3->Exit();
5832
5833 // Call getProp in env1, and it should return the value 1
5834 {
5835 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5836 CHECK(get_prop->IsFunction());
5837 v8::TryCatch try_catch;
5838 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5839 CHECK(!try_catch.HasCaught());
5840 CHECK_EQ(1, r->Int32Value());
5841 }
5842
5843 // Check that env3 is not accessible from env1
5844 {
5845 Local<Value> r = global3->Get(v8_str("prop2"));
5846 CHECK(r->IsUndefined());
5847 }
5848
5849 env2.Dispose();
5850 env3.Dispose();
5851}
5852
5853
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005854TEST(DetachAndReattachGlobal) {
5855 v8::HandleScope scope;
5856 LocalContext env1;
5857
5858 // Create second environment.
5859 v8::Persistent<Context> env2 = Context::New();
5860
5861 Local<Value> foo = v8_str("foo");
5862
5863 // Set same security token for env1 and env2.
5864 env1->SetSecurityToken(foo);
5865 env2->SetSecurityToken(foo);
5866
5867 // Create a property on the global object in env2.
5868 {
5869 v8::Context::Scope scope(env2);
5870 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5871 }
5872
5873 // Create a reference to env2 global from env1 global.
5874 env1->Global()->Set(v8_str("other"), env2->Global());
5875
5876 // Check that we have access to other.p in env2 from env1.
5877 Local<Value> result = CompileRun("other.p");
5878 CHECK(result->IsInt32());
5879 CHECK_EQ(42, result->Int32Value());
5880
5881 // Hold on to global from env2 and detach global from env2.
5882 Local<v8::Object> global2 = env2->Global();
5883 env2->DetachGlobal();
5884
5885 // Check that the global has been detached. No other.p property can
5886 // be found.
5887 result = CompileRun("other.p");
5888 CHECK(result->IsUndefined());
5889
5890 // Reuse global2 for env3.
5891 v8::Persistent<Context> env3 =
5892 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5893 CHECK_EQ(global2, env3->Global());
5894
5895 // Start by using the same security token for env3 as for env1 and env2.
5896 env3->SetSecurityToken(foo);
5897
5898 // Create a property on the global object in env3.
5899 {
5900 v8::Context::Scope scope(env3);
5901 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5902 }
5903
5904 // Check that other.p is now the property in env3 and that we have access.
5905 result = CompileRun("other.p");
5906 CHECK(result->IsInt32());
5907 CHECK_EQ(24, result->Int32Value());
5908
5909 // Change security token for env3 to something different from env1 and env2.
5910 env3->SetSecurityToken(v8_str("bar"));
5911
5912 // Check that we do not have access to other.p in env1. |other| is now
5913 // the global object for env3 which has a different security token,
5914 // so access should be blocked.
5915 result = CompileRun("other.p");
5916 CHECK(result->IsUndefined());
5917
5918 // Detach the global for env3 and reattach it to env2.
5919 env3->DetachGlobal();
5920 env2->ReattachGlobal(global2);
5921
5922 // Check that we have access to other.p again in env1. |other| is now
5923 // the global object for env2 which has the same security token as env1.
5924 result = CompileRun("other.p");
5925 CHECK(result->IsInt32());
5926 CHECK_EQ(42, result->Int32Value());
5927
5928 env2.Dispose();
5929 env3.Dispose();
5930}
5931
5932
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005933static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005934static bool NamedAccessBlocker(Local<v8::Object> global,
5935 Local<Value> name,
5936 v8::AccessType type,
5937 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005938 return Context::GetCurrent()->Global()->Equals(global) ||
5939 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005940}
5941
5942
5943static bool IndexedAccessBlocker(Local<v8::Object> global,
5944 uint32_t key,
5945 v8::AccessType type,
5946 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005947 return Context::GetCurrent()->Global()->Equals(global) ||
5948 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005949}
5950
5951
5952static int g_echo_value = -1;
5953static v8::Handle<Value> EchoGetter(Local<String> name,
5954 const AccessorInfo& info) {
5955 return v8_num(g_echo_value);
5956}
5957
5958
5959static void EchoSetter(Local<String> name,
5960 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005961 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005962 if (value->IsNumber())
5963 g_echo_value = value->Int32Value();
5964}
5965
5966
5967static v8::Handle<Value> UnreachableGetter(Local<String> name,
5968 const AccessorInfo& info) {
5969 CHECK(false); // This function should not be called..
5970 return v8::Undefined();
5971}
5972
5973
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005974static void UnreachableSetter(Local<String>, Local<Value>,
5975 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005976 CHECK(false); // This function should nto be called.
5977}
5978
5979
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005980TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005981 v8::HandleScope handle_scope;
5982 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5983
5984 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5985 IndexedAccessBlocker);
5986
5987 // Add an accessor accessible by cross-domain JS code.
5988 global_template->SetAccessor(
5989 v8_str("accessible_prop"),
5990 EchoGetter, EchoSetter,
5991 v8::Handle<Value>(),
5992 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5993
5994 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005995 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005996 UnreachableGetter, UnreachableSetter,
5997 v8::Handle<Value>(),
5998 v8::DEFAULT);
5999
6000 // Create an environment
6001 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6002 context0->Enter();
6003
6004 v8::Handle<v8::Object> global0 = context0->Global();
6005
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006006 // Define a property with JS getter and setter.
6007 CompileRun(
6008 "function getter() { return 'getter'; };\n"
6009 "function setter() { return 'setter'; }\n"
6010 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6011
6012 Local<Value> getter = global0->Get(v8_str("getter"));
6013 Local<Value> setter = global0->Get(v8_str("setter"));
6014
6015 // And define normal element.
6016 global0->Set(239, v8_str("239"));
6017
6018 // Define an element with JS getter and setter.
6019 CompileRun(
6020 "function el_getter() { return 'el_getter'; };\n"
6021 "function el_setter() { return 'el_setter'; };\n"
6022 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6023
6024 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6025 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6026
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006027 v8::HandleScope scope1;
6028
6029 v8::Persistent<Context> context1 = Context::New();
6030 context1->Enter();
6031
6032 v8::Handle<v8::Object> global1 = context1->Global();
6033 global1->Set(v8_str("other"), global0);
6034
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006035 // Access blocked property.
6036 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006037
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006038 ExpectUndefined("other.blocked_prop");
6039 ExpectUndefined(
6040 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6041 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006042
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006043 // Enable ACCESS_HAS
6044 allowed_access_type[v8::ACCESS_HAS] = true;
6045 ExpectUndefined("other.blocked_prop");
6046 // ... and now we can get the descriptor...
6047 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006048 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006049 // ... and enumerate the property.
6050 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6051 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006052
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006053 // Access blocked element.
6054 CompileRun("other[239] = 1");
6055
6056 ExpectUndefined("other[239]");
6057 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6058 ExpectFalse("propertyIsEnumerable.call(other, '239')");
6059
6060 // Enable ACCESS_HAS
6061 allowed_access_type[v8::ACCESS_HAS] = true;
6062 ExpectUndefined("other[239]");
6063 // ... and now we can get the descriptor...
6064 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6065 // ... and enumerate the property.
6066 ExpectTrue("propertyIsEnumerable.call(other, '239')");
6067 allowed_access_type[v8::ACCESS_HAS] = false;
6068
6069 // Access a property with JS accessor.
6070 CompileRun("other.js_accessor_p = 2");
6071
6072 ExpectUndefined("other.js_accessor_p");
6073 ExpectUndefined(
6074 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6075
6076 // Enable ACCESS_HAS.
6077 allowed_access_type[v8::ACCESS_HAS] = true;
6078 ExpectUndefined("other.js_accessor_p");
6079 ExpectUndefined(
6080 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6081 ExpectUndefined(
6082 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6083 ExpectUndefined(
6084 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6085 allowed_access_type[v8::ACCESS_HAS] = false;
6086
6087 // Enable both ACCESS_HAS and ACCESS_GET.
6088 allowed_access_type[v8::ACCESS_HAS] = true;
6089 allowed_access_type[v8::ACCESS_GET] = true;
6090
6091 ExpectString("other.js_accessor_p", "getter");
6092 ExpectObject(
6093 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6094 ExpectUndefined(
6095 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6096 ExpectUndefined(
6097 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6098
6099 allowed_access_type[v8::ACCESS_GET] = false;
6100 allowed_access_type[v8::ACCESS_HAS] = false;
6101
6102 // Enable both ACCESS_HAS and ACCESS_SET.
6103 allowed_access_type[v8::ACCESS_HAS] = true;
6104 allowed_access_type[v8::ACCESS_SET] = true;
6105
6106 ExpectUndefined("other.js_accessor_p");
6107 ExpectUndefined(
6108 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6109 ExpectObject(
6110 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6111 ExpectUndefined(
6112 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6113
6114 allowed_access_type[v8::ACCESS_SET] = false;
6115 allowed_access_type[v8::ACCESS_HAS] = false;
6116
6117 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6118 allowed_access_type[v8::ACCESS_HAS] = true;
6119 allowed_access_type[v8::ACCESS_GET] = true;
6120 allowed_access_type[v8::ACCESS_SET] = true;
6121
6122 ExpectString("other.js_accessor_p", "getter");
6123 ExpectObject(
6124 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6125 ExpectObject(
6126 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6127 ExpectUndefined(
6128 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6129
6130 allowed_access_type[v8::ACCESS_SET] = false;
6131 allowed_access_type[v8::ACCESS_GET] = false;
6132 allowed_access_type[v8::ACCESS_HAS] = false;
6133
6134 // Access an element with JS accessor.
6135 CompileRun("other[42] = 2");
6136
6137 ExpectUndefined("other[42]");
6138 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6139
6140 // Enable ACCESS_HAS.
6141 allowed_access_type[v8::ACCESS_HAS] = true;
6142 ExpectUndefined("other[42]");
6143 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6144 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6145 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6146 allowed_access_type[v8::ACCESS_HAS] = false;
6147
6148 // Enable both ACCESS_HAS and ACCESS_GET.
6149 allowed_access_type[v8::ACCESS_HAS] = true;
6150 allowed_access_type[v8::ACCESS_GET] = true;
6151
6152 ExpectString("other[42]", "el_getter");
6153 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6154 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6155 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6156
6157 allowed_access_type[v8::ACCESS_GET] = false;
6158 allowed_access_type[v8::ACCESS_HAS] = false;
6159
6160 // Enable both ACCESS_HAS and ACCESS_SET.
6161 allowed_access_type[v8::ACCESS_HAS] = true;
6162 allowed_access_type[v8::ACCESS_SET] = true;
6163
6164 ExpectUndefined("other[42]");
6165 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6166 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6167 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6168
6169 allowed_access_type[v8::ACCESS_SET] = false;
6170 allowed_access_type[v8::ACCESS_HAS] = false;
6171
6172 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6173 allowed_access_type[v8::ACCESS_HAS] = true;
6174 allowed_access_type[v8::ACCESS_GET] = true;
6175 allowed_access_type[v8::ACCESS_SET] = true;
6176
6177 ExpectString("other[42]", "el_getter");
6178 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6179 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6180 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6181
6182 allowed_access_type[v8::ACCESS_SET] = false;
6183 allowed_access_type[v8::ACCESS_GET] = false;
6184 allowed_access_type[v8::ACCESS_HAS] = false;
6185
6186 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006188 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006189 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006190 CHECK(value->IsNumber());
6191 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006192 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006193
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006194 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006195 CHECK(value->IsNumber());
6196 CHECK_EQ(3, value->Int32Value());
6197
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006198 value = CompileRun(
6199 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6200 CHECK(value->IsNumber());
6201 CHECK_EQ(3, value->Int32Value());
6202
6203 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00006204 CHECK(value->IsTrue());
6205
6206 // Enumeration doesn't enumerate accessors from inaccessible objects in
6207 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006208 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00006209 CompileRun("(function(){var obj = {'__proto__':other};"
6210 "for (var p in obj)"
6211 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
6212 " return false;"
6213 " }"
6214 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00006215 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006216
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006217 context1->Exit();
6218 context0->Exit();
6219 context1.Dispose();
6220 context0.Dispose();
6221}
6222
6223
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006224TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00006225 v8::HandleScope handle_scope;
6226 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6227
6228 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6229 IndexedAccessBlocker);
6230
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006231 // Add accessible accessor.
6232 global_template->SetAccessor(
6233 v8_str("accessible_prop"),
6234 EchoGetter, EchoSetter,
6235 v8::Handle<Value>(),
6236 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6237
6238
ricow@chromium.org65001782011-02-15 13:36:41 +00006239 // Add an accessor that is not accessible by cross-domain JS code.
6240 global_template->SetAccessor(v8_str("blocked_prop"),
6241 UnreachableGetter, UnreachableSetter,
6242 v8::Handle<Value>(),
6243 v8::DEFAULT);
6244
6245 // Create an environment
6246 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6247 context0->Enter();
6248
6249 v8::Handle<v8::Object> global0 = context0->Global();
6250
6251 v8::Persistent<Context> context1 = Context::New();
6252 context1->Enter();
6253 v8::Handle<v8::Object> global1 = context1->Global();
6254 global1->Set(v8_str("other"), global0);
6255
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006256 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00006257 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006258
6259 ExpectUndefined("other.blocked_prop");
6260
6261 // Regression test for issue 1027.
6262 CompileRun("Object.defineProperty(\n"
6263 " other, 'blocked_prop', {configurable: false})");
6264 ExpectUndefined("other.blocked_prop");
6265 ExpectUndefined(
6266 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6267
6268 // Regression test for issue 1171.
6269 ExpectTrue("Object.isExtensible(other)");
6270 CompileRun("Object.preventExtensions(other)");
6271 ExpectTrue("Object.isExtensible(other)");
6272
6273 // Object.seal and Object.freeze.
6274 CompileRun("Object.freeze(other)");
6275 ExpectTrue("Object.isExtensible(other)");
6276
6277 CompileRun("Object.seal(other)");
6278 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00006279
6280 // Regression test for issue 1250.
6281 // Make sure that we can set the accessible accessors value using normal
6282 // assignment.
6283 CompileRun("other.accessible_prop = 42");
6284 CHECK_EQ(42, g_echo_value);
6285
6286 v8::Handle<Value> value;
6287 // We follow Safari in ignoring assignments to host object accessors.
6288 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6289 value = CompileRun("other.accessible_prop == 42");
6290 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00006291}
6292
6293
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006294static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6295 Local<Value> name,
6296 v8::AccessType type,
6297 Local<Value> data) {
6298 return false;
6299}
6300
6301
6302static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6303 uint32_t key,
6304 v8::AccessType type,
6305 Local<Value> data) {
6306 return false;
6307}
6308
6309
6310THREADED_TEST(AccessControlGetOwnPropertyNames) {
6311 v8::HandleScope handle_scope;
6312 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6313
6314 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6315 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6316 GetOwnPropertyNamesIndexedBlocker);
6317
6318 // Create an environment
6319 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6320 context0->Enter();
6321
6322 v8::Handle<v8::Object> global0 = context0->Global();
6323
6324 v8::HandleScope scope1;
6325
6326 v8::Persistent<Context> context1 = Context::New();
6327 context1->Enter();
6328
6329 v8::Handle<v8::Object> global1 = context1->Global();
6330 global1->Set(v8_str("other"), global0);
6331 global1->Set(v8_str("object"), obj_template->NewInstance());
6332
6333 v8::Handle<Value> value;
6334
6335 // Attempt to get the property names of the other global object and
6336 // of an object that requires access checks. Accessing the other
6337 // global object should be blocked by access checks on the global
6338 // proxy object. Accessing the object that requires access checks
6339 // is blocked by the access checks on the object itself.
6340 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6341 CHECK(value->IsTrue());
6342
6343 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6344 CHECK(value->IsTrue());
6345
6346 context1->Exit();
6347 context0->Exit();
6348 context1.Dispose();
6349 context0.Dispose();
6350}
6351
6352
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006353static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6354 v8::Handle<v8::Array> result = v8::Array::New(1);
6355 result->Set(0, v8_str("x"));
6356 return result;
6357}
6358
6359
6360THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6361 v8::HandleScope handle_scope;
6362 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6363
6364 obj_template->Set(v8_str("x"), v8::Integer::New(42));
6365 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6366 NamedPropertyEnumerator);
6367
6368 LocalContext context;
6369 v8::Handle<v8::Object> global = context->Global();
6370 global->Set(v8_str("object"), obj_template->NewInstance());
6371
6372 v8::Handle<Value> value =
6373 CompileRun("Object.getOwnPropertyNames(object).join(',')");
6374 CHECK_EQ(v8_str("x"), value);
6375}
6376
6377
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006378static v8::Handle<Value> ConstTenGetter(Local<String> name,
6379 const AccessorInfo& info) {
6380 return v8_num(10);
6381}
6382
6383
6384THREADED_TEST(CrossDomainAccessors) {
6385 v8::HandleScope handle_scope;
6386
6387 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6388
6389 v8::Handle<v8::ObjectTemplate> global_template =
6390 func_template->InstanceTemplate();
6391
6392 v8::Handle<v8::ObjectTemplate> proto_template =
6393 func_template->PrototypeTemplate();
6394
6395 // Add an accessor to proto that's accessible by cross-domain JS code.
6396 proto_template->SetAccessor(v8_str("accessible"),
6397 ConstTenGetter, 0,
6398 v8::Handle<Value>(),
6399 v8::ALL_CAN_READ);
6400
6401 // Add an accessor that is not accessible by cross-domain JS code.
6402 global_template->SetAccessor(v8_str("unreachable"),
6403 UnreachableGetter, 0,
6404 v8::Handle<Value>(),
6405 v8::DEFAULT);
6406
6407 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6408 context0->Enter();
6409
6410 Local<v8::Object> global = context0->Global();
6411 // Add a normal property that shadows 'accessible'
6412 global->Set(v8_str("accessible"), v8_num(11));
6413
6414 // Enter a new context.
6415 v8::HandleScope scope1;
6416 v8::Persistent<Context> context1 = Context::New();
6417 context1->Enter();
6418
6419 v8::Handle<v8::Object> global1 = context1->Global();
6420 global1->Set(v8_str("other"), global);
6421
6422 // Should return 10, instead of 11
6423 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6424 CHECK(value->IsNumber());
6425 CHECK_EQ(10, value->Int32Value());
6426
6427 value = v8_compile("other.unreachable")->Run();
6428 CHECK(value->IsUndefined());
6429
6430 context1->Exit();
6431 context0->Exit();
6432 context1.Dispose();
6433 context0.Dispose();
6434}
6435
6436
6437static int named_access_count = 0;
6438static int indexed_access_count = 0;
6439
6440static bool NamedAccessCounter(Local<v8::Object> global,
6441 Local<Value> name,
6442 v8::AccessType type,
6443 Local<Value> data) {
6444 named_access_count++;
6445 return true;
6446}
6447
6448
6449static bool IndexedAccessCounter(Local<v8::Object> global,
6450 uint32_t key,
6451 v8::AccessType type,
6452 Local<Value> data) {
6453 indexed_access_count++;
6454 return true;
6455}
6456
6457
6458// This one is too easily disturbed by other tests.
6459TEST(AccessControlIC) {
6460 named_access_count = 0;
6461 indexed_access_count = 0;
6462
6463 v8::HandleScope handle_scope;
6464
6465 // Create an environment.
6466 v8::Persistent<Context> context0 = Context::New();
6467 context0->Enter();
6468
6469 // Create an object that requires access-check functions to be
6470 // called for cross-domain access.
6471 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6472 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6473 IndexedAccessCounter);
6474 Local<v8::Object> object = object_template->NewInstance();
6475
6476 v8::HandleScope scope1;
6477
6478 // Create another environment.
6479 v8::Persistent<Context> context1 = Context::New();
6480 context1->Enter();
6481
6482 // Make easy access to the object from the other environment.
6483 v8::Handle<v8::Object> global1 = context1->Global();
6484 global1->Set(v8_str("obj"), object);
6485
6486 v8::Handle<Value> value;
6487
6488 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006489 CompileRun("function testProp(obj) {"
6490 " for (var i = 0; i < 10; i++) obj.prop = 1;"
6491 " for (var j = 0; j < 10; j++) obj.prop;"
6492 " return obj.prop"
6493 "}");
6494 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006495 CHECK(value->IsNumber());
6496 CHECK_EQ(1, value->Int32Value());
6497 CHECK_EQ(21, named_access_count);
6498
6499 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006500 CompileRun("var p = 'prop';"
6501 "function testKeyed(obj) {"
6502 " for (var i = 0; i < 10; i++) obj[p] = 1;"
6503 " for (var j = 0; j < 10; j++) obj[p];"
6504 " return obj[p];"
6505 "}");
6506 // Use obj which requires access checks. No inline caching is used
6507 // in that case.
6508 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006509 CHECK(value->IsNumber());
6510 CHECK_EQ(1, value->Int32Value());
6511 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006512 // Force the inline caches into generic state and try again.
6513 CompileRun("testKeyed({ a: 0 })");
6514 CompileRun("testKeyed({ b: 0 })");
6515 value = CompileRun("testKeyed(obj)");
6516 CHECK(value->IsNumber());
6517 CHECK_EQ(1, value->Int32Value());
6518 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006519
6520 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00006521 CompileRun("function testIndexed(obj) {"
6522 " for (var i = 0; i < 10; i++) obj[0] = 1;"
6523 " for (var j = 0; j < 10; j++) obj[0];"
6524 " return obj[0]"
6525 "}");
6526 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006527 CHECK(value->IsNumber());
6528 CHECK_EQ(1, value->Int32Value());
6529 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006530 // Force the inline caches into generic state.
6531 CompileRun("testIndexed(new Array(1))");
6532 // Test that the indexed access check is called.
6533 value = CompileRun("testIndexed(obj)");
6534 CHECK(value->IsNumber());
6535 CHECK_EQ(1, value->Int32Value());
6536 CHECK_EQ(42, indexed_access_count);
6537
6538 // Check that the named access check is called when invoking
6539 // functions on an object that requires access checks.
6540 CompileRun("obj.f = function() {}");
6541 CompileRun("function testCallNormal(obj) {"
6542 " for (var i = 0; i < 10; i++) obj.f();"
6543 "}");
6544 CompileRun("testCallNormal(obj)");
6545 CHECK_EQ(74, named_access_count);
6546
6547 // Force obj into slow case.
6548 value = CompileRun("delete obj.prop");
6549 CHECK(value->BooleanValue());
6550 // Force inline caches into dictionary probing mode.
6551 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6552 // Test that the named access check is called.
6553 value = CompileRun("testProp(obj);");
6554 CHECK(value->IsNumber());
6555 CHECK_EQ(1, value->Int32Value());
6556 CHECK_EQ(96, named_access_count);
6557
6558 // Force the call inline cache into dictionary probing mode.
6559 CompileRun("o.f = function() {}; testCallNormal(o)");
6560 // Test that the named access check is still called for each
6561 // invocation of the function.
6562 value = CompileRun("testCallNormal(obj)");
6563 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006564
6565 context1->Exit();
6566 context0->Exit();
6567 context1.Dispose();
6568 context0.Dispose();
6569}
6570
6571
6572static bool NamedAccessFlatten(Local<v8::Object> global,
6573 Local<Value> name,
6574 v8::AccessType type,
6575 Local<Value> data) {
6576 char buf[100];
6577 int len;
6578
6579 CHECK(name->IsString());
6580
6581 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006582 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006583 CHECK_EQ(4, len);
6584
6585 uint16_t buf2[100];
6586
6587 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006588 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006589 CHECK_EQ(4, len);
6590
6591 return true;
6592}
6593
6594
6595static bool IndexedAccessFlatten(Local<v8::Object> global,
6596 uint32_t key,
6597 v8::AccessType type,
6598 Local<Value> data) {
6599 return true;
6600}
6601
6602
6603// Regression test. In access checks, operations that may cause
6604// garbage collection are not allowed. It used to be the case that
6605// using the Write operation on a string could cause a garbage
6606// collection due to flattening of the string. This is no longer the
6607// case.
6608THREADED_TEST(AccessControlFlatten) {
6609 named_access_count = 0;
6610 indexed_access_count = 0;
6611
6612 v8::HandleScope handle_scope;
6613
6614 // Create an environment.
6615 v8::Persistent<Context> context0 = Context::New();
6616 context0->Enter();
6617
6618 // Create an object that requires access-check functions to be
6619 // called for cross-domain access.
6620 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6621 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
6622 IndexedAccessFlatten);
6623 Local<v8::Object> object = object_template->NewInstance();
6624
6625 v8::HandleScope scope1;
6626
6627 // Create another environment.
6628 v8::Persistent<Context> context1 = Context::New();
6629 context1->Enter();
6630
6631 // Make easy access to the object from the other environment.
6632 v8::Handle<v8::Object> global1 = context1->Global();
6633 global1->Set(v8_str("obj"), object);
6634
6635 v8::Handle<Value> value;
6636
6637 value = v8_compile("var p = 'as' + 'df';")->Run();
6638 value = v8_compile("obj[p];")->Run();
6639
6640 context1->Exit();
6641 context0->Exit();
6642 context1.Dispose();
6643 context0.Dispose();
6644}
6645
6646
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647static v8::Handle<Value> AccessControlNamedGetter(
6648 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006649 return v8::Integer::New(42);
6650}
6651
6652
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006653static v8::Handle<Value> AccessControlNamedSetter(
6654 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006655 return value;
6656}
6657
6658
6659static v8::Handle<Value> AccessControlIndexedGetter(
6660 uint32_t index,
6661 const AccessorInfo& info) {
6662 return v8_num(42);
6663}
6664
6665
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006666static v8::Handle<Value> AccessControlIndexedSetter(
6667 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006668 return value;
6669}
6670
6671
6672THREADED_TEST(AccessControlInterceptorIC) {
6673 named_access_count = 0;
6674 indexed_access_count = 0;
6675
6676 v8::HandleScope handle_scope;
6677
6678 // Create an environment.
6679 v8::Persistent<Context> context0 = Context::New();
6680 context0->Enter();
6681
6682 // Create an object that requires access-check functions to be
6683 // called for cross-domain access. The object also has interceptors
6684 // interceptor.
6685 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6686 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6687 IndexedAccessCounter);
6688 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
6689 AccessControlNamedSetter);
6690 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
6691 AccessControlIndexedSetter);
6692 Local<v8::Object> object = object_template->NewInstance();
6693
6694 v8::HandleScope scope1;
6695
6696 // Create another environment.
6697 v8::Persistent<Context> context1 = Context::New();
6698 context1->Enter();
6699
6700 // Make easy access to the object from the other environment.
6701 v8::Handle<v8::Object> global1 = context1->Global();
6702 global1->Set(v8_str("obj"), object);
6703
6704 v8::Handle<Value> value;
6705
6706 // Check that the named access-control function is called every time
6707 // eventhough there is an interceptor on the object.
6708 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
6709 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
6710 "obj.x")->Run();
6711 CHECK(value->IsNumber());
6712 CHECK_EQ(42, value->Int32Value());
6713 CHECK_EQ(21, named_access_count);
6714
6715 value = v8_compile("var p = 'x';")->Run();
6716 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
6717 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
6718 "obj[p]")->Run();
6719 CHECK(value->IsNumber());
6720 CHECK_EQ(42, value->Int32Value());
6721 CHECK_EQ(42, named_access_count);
6722
6723 // Check that the indexed access-control function is called every
6724 // time eventhough there is an interceptor on the object.
6725 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
6726 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
6727 "obj[0]")->Run();
6728 CHECK(value->IsNumber());
6729 CHECK_EQ(42, value->Int32Value());
6730 CHECK_EQ(21, indexed_access_count);
6731
6732 context1->Exit();
6733 context0->Exit();
6734 context1.Dispose();
6735 context0.Dispose();
6736}
6737
6738
6739THREADED_TEST(Version) {
6740 v8::V8::GetVersion();
6741}
6742
6743
6744static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
6745 ApiTestFuzzer::Fuzz();
6746 return v8_num(12);
6747}
6748
6749
6750THREADED_TEST(InstanceProperties) {
6751 v8::HandleScope handle_scope;
6752 LocalContext context;
6753
6754 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6755 Local<ObjectTemplate> instance = t->InstanceTemplate();
6756
6757 instance->Set(v8_str("x"), v8_num(42));
6758 instance->Set(v8_str("f"),
6759 v8::FunctionTemplate::New(InstanceFunctionCallback));
6760
6761 Local<Value> o = t->GetFunction()->NewInstance();
6762
6763 context->Global()->Set(v8_str("i"), o);
6764 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
6765 CHECK_EQ(42, value->Int32Value());
6766
6767 value = Script::Compile(v8_str("i.f()"))->Run();
6768 CHECK_EQ(12, value->Int32Value());
6769}
6770
6771
6772static v8::Handle<Value>
6773GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
6774 ApiTestFuzzer::Fuzz();
6775 return v8::Handle<Value>();
6776}
6777
6778
6779THREADED_TEST(GlobalObjectInstanceProperties) {
6780 v8::HandleScope handle_scope;
6781
6782 Local<Value> global_object;
6783
6784 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6785 t->InstanceTemplate()->SetNamedPropertyHandler(
6786 GlobalObjectInstancePropertiesGet);
6787 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6788 instance_template->Set(v8_str("x"), v8_num(42));
6789 instance_template->Set(v8_str("f"),
6790 v8::FunctionTemplate::New(InstanceFunctionCallback));
6791
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006792 // The script to check how Crankshaft compiles missing global function
6793 // invocations. function g is not defined and should throw on call.
6794 const char* script =
6795 "function wrapper(call) {"
6796 " var x = 0, y = 1;"
6797 " for (var i = 0; i < 1000; i++) {"
6798 " x += i * 100;"
6799 " y += i * 100;"
6800 " }"
6801 " if (call) g();"
6802 "}"
6803 "for (var i = 0; i < 17; i++) wrapper(false);"
6804 "var thrown = 0;"
6805 "try { wrapper(true); } catch (e) { thrown = 1; };"
6806 "thrown";
6807
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006808 {
6809 LocalContext env(NULL, instance_template);
6810 // Hold on to the global object so it can be used again in another
6811 // environment initialization.
6812 global_object = env->Global();
6813
6814 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6815 CHECK_EQ(42, value->Int32Value());
6816 value = Script::Compile(v8_str("f()"))->Run();
6817 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006818 value = Script::Compile(v8_str(script))->Run();
6819 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006820 }
6821
6822 {
6823 // Create new environment reusing the global object.
6824 LocalContext env(NULL, instance_template, global_object);
6825 Local<Value> value = Script::Compile(v8_str("x"))->Run();
6826 CHECK_EQ(42, value->Int32Value());
6827 value = Script::Compile(v8_str("f()"))->Run();
6828 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006829 value = Script::Compile(v8_str(script))->Run();
6830 CHECK_EQ(1, value->Int32Value());
6831 }
6832}
6833
6834
6835THREADED_TEST(CallKnownGlobalReceiver) {
6836 v8::HandleScope handle_scope;
6837
6838 Local<Value> global_object;
6839
6840 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6841 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6842
6843 // The script to check that we leave global object not
6844 // global object proxy on stack when we deoptimize from inside
6845 // arguments evaluation.
6846 // To provoke error we need to both force deoptimization
6847 // from arguments evaluation and to force CallIC to take
6848 // CallIC_Miss code path that can't cope with global proxy.
6849 const char* script =
6850 "function bar(x, y) { try { } finally { } }"
6851 "function baz(x) { try { } finally { } }"
6852 "function bom(x) { try { } finally { } }"
6853 "function foo(x) { bar([x], bom(2)); }"
6854 "for (var i = 0; i < 10000; i++) foo(1);"
6855 "foo";
6856
6857 Local<Value> foo;
6858 {
6859 LocalContext env(NULL, instance_template);
6860 // Hold on to the global object so it can be used again in another
6861 // environment initialization.
6862 global_object = env->Global();
6863 foo = Script::Compile(v8_str(script))->Run();
6864 }
6865
6866 {
6867 // Create new environment reusing the global object.
6868 LocalContext env(NULL, instance_template, global_object);
6869 env->Global()->Set(v8_str("foo"), foo);
6870 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006871 }
6872}
6873
6874
6875static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
6876 ApiTestFuzzer::Fuzz();
6877 return v8_num(42);
6878}
6879
6880
6881static int shadow_y;
6882static int shadow_y_setter_call_count;
6883static int shadow_y_getter_call_count;
6884
6885
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006886static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006887 shadow_y_setter_call_count++;
6888 shadow_y = 42;
6889}
6890
6891
6892static v8::Handle<Value> ShadowYGetter(Local<String> name,
6893 const AccessorInfo& info) {
6894 ApiTestFuzzer::Fuzz();
6895 shadow_y_getter_call_count++;
6896 return v8_num(shadow_y);
6897}
6898
6899
6900static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
6901 const AccessorInfo& info) {
6902 return v8::Handle<Value>();
6903}
6904
6905
6906static v8::Handle<Value> ShadowNamedGet(Local<String> key,
6907 const AccessorInfo&) {
6908 return v8::Handle<Value>();
6909}
6910
6911
6912THREADED_TEST(ShadowObject) {
6913 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
6914 v8::HandleScope handle_scope;
6915
6916 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
6917 LocalContext context(NULL, global_template);
6918
6919 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6920 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
6921 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
6922 Local<ObjectTemplate> proto = t->PrototypeTemplate();
6923 Local<ObjectTemplate> instance = t->InstanceTemplate();
6924
6925 // Only allow calls of f on instances of t.
6926 Local<v8::Signature> signature = v8::Signature::New(t);
6927 proto->Set(v8_str("f"),
6928 v8::FunctionTemplate::New(ShadowFunctionCallback,
6929 Local<Value>(),
6930 signature));
6931 proto->Set(v8_str("x"), v8_num(12));
6932
6933 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
6934
6935 Local<Value> o = t->GetFunction()->NewInstance();
6936 context->Global()->Set(v8_str("__proto__"), o);
6937
6938 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006939 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006940 CHECK(value->IsBoolean());
6941 CHECK(!value->BooleanValue());
6942
6943 value = Script::Compile(v8_str("x"))->Run();
6944 CHECK_EQ(12, value->Int32Value());
6945
6946 value = Script::Compile(v8_str("f()"))->Run();
6947 CHECK_EQ(42, value->Int32Value());
6948
6949 Script::Compile(v8_str("y = 42"))->Run();
6950 CHECK_EQ(1, shadow_y_setter_call_count);
6951 value = Script::Compile(v8_str("y"))->Run();
6952 CHECK_EQ(1, shadow_y_getter_call_count);
6953 CHECK_EQ(42, value->Int32Value());
6954}
6955
6956
6957THREADED_TEST(HiddenPrototype) {
6958 v8::HandleScope handle_scope;
6959 LocalContext context;
6960
6961 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6962 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6963 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6964 t1->SetHiddenPrototype(true);
6965 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6966 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6967 t2->SetHiddenPrototype(true);
6968 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6969 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6970 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6971
6972 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6973 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6974 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6975 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6976
6977 // Setting the prototype on an object skips hidden prototypes.
6978 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6979 o0->Set(v8_str("__proto__"), o1);
6980 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6981 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6982 o0->Set(v8_str("__proto__"), o2);
6983 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6984 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6985 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6986 o0->Set(v8_str("__proto__"), o3);
6987 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6988 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6989 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6990 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6991
6992 // Getting the prototype of o0 should get the first visible one
6993 // which is o3. Therefore, z should not be defined on the prototype
6994 // object.
6995 Local<Value> proto = o0->Get(v8_str("__proto__"));
6996 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006997 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006998}
6999
7000
ager@chromium.org5c838252010-02-19 08:53:10 +00007001THREADED_TEST(SetPrototype) {
7002 v8::HandleScope handle_scope;
7003 LocalContext context;
7004
7005 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7006 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7007 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7008 t1->SetHiddenPrototype(true);
7009 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7010 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7011 t2->SetHiddenPrototype(true);
7012 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7013 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7014 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7015
7016 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7017 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7018 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7019 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7020
7021 // Setting the prototype on an object does not skip hidden prototypes.
7022 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7023 CHECK(o0->SetPrototype(o1));
7024 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7025 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7026 CHECK(o1->SetPrototype(o2));
7027 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7028 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7029 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7030 CHECK(o2->SetPrototype(o3));
7031 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7032 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7033 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7034 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7035
7036 // Getting the prototype of o0 should get the first visible one
7037 // which is o3. Therefore, z should not be defined on the prototype
7038 // object.
7039 Local<Value> proto = o0->Get(v8_str("__proto__"));
7040 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007041 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007042
7043 // However, Object::GetPrototype ignores hidden prototype.
7044 Local<Value> proto0 = o0->GetPrototype();
7045 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007046 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00007047
7048 Local<Value> proto1 = o1->GetPrototype();
7049 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007050 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00007051
7052 Local<Value> proto2 = o2->GetPrototype();
7053 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007054 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00007055}
7056
7057
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007058THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00007059 v8::HandleScope handle_scope;
7060 LocalContext context;
7061
7062 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007063 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7064 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00007065 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007066 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007067 CHECK(CompileRun(
7068 "(function() {"
7069 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007070 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007071 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007072 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7073 CHECK_EQ(42,
7074 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007075
7076 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007077 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00007078 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007079 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00007080 CHECK(CompileRun(
7081 "(function() {"
7082 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007083 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00007084 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00007085 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00007086}
7087
7088
ager@chromium.org5c838252010-02-19 08:53:10 +00007089THREADED_TEST(SetPrototypeThrows) {
7090 v8::HandleScope handle_scope;
7091 LocalContext context;
7092
7093 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7094
7095 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7096 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7097
7098 CHECK(o0->SetPrototype(o1));
7099 // If setting the prototype leads to the cycle, SetPrototype should
7100 // return false and keep VM in sane state.
7101 v8::TryCatch try_catch;
7102 CHECK(!o1->SetPrototype(o0));
7103 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007104 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00007105
7106 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7107}
7108
7109
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007110THREADED_TEST(GetterSetterExceptions) {
7111 v8::HandleScope handle_scope;
7112 LocalContext context;
7113 CompileRun(
7114 "function Foo() { };"
7115 "function Throw() { throw 5; };"
7116 "var x = { };"
7117 "x.__defineSetter__('set', Throw);"
7118 "x.__defineGetter__('get', Throw);");
7119 Local<v8::Object> x =
7120 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7121 v8::TryCatch try_catch;
7122 x->Set(v8_str("set"), v8::Integer::New(8));
7123 x->Get(v8_str("get"));
7124 x->Set(v8_str("set"), v8::Integer::New(8));
7125 x->Get(v8_str("get"));
7126 x->Set(v8_str("set"), v8::Integer::New(8));
7127 x->Get(v8_str("get"));
7128 x->Set(v8_str("set"), v8::Integer::New(8));
7129 x->Get(v8_str("get"));
7130}
7131
7132
7133THREADED_TEST(Constructor) {
7134 v8::HandleScope handle_scope;
7135 LocalContext context;
7136 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7137 templ->SetClassName(v8_str("Fun"));
7138 Local<Function> cons = templ->GetFunction();
7139 context->Global()->Set(v8_str("Fun"), cons);
7140 Local<v8::Object> inst = cons->NewInstance();
7141 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
7142 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7143 CHECK(value->BooleanValue());
7144}
7145
lrn@chromium.org1c092762011-05-09 09:42:16 +00007146
7147static Handle<Value> ConstructorCallback(const Arguments& args) {
7148 ApiTestFuzzer::Fuzz();
7149 Local<Object> This;
7150
7151 if (args.IsConstructCall()) {
7152 Local<Object> Holder = args.Holder();
7153 This = Object::New();
7154 Local<Value> proto = Holder->GetPrototype();
7155 if (proto->IsObject()) {
7156 This->SetPrototype(proto);
7157 }
7158 } else {
7159 This = args.This();
7160 }
7161
7162 This->Set(v8_str("a"), args[0]);
7163 return This;
7164}
7165
7166
7167static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7168 ApiTestFuzzer::Fuzz();
7169 return args[0];
7170}
7171
7172
7173THREADED_TEST(ConstructorForObject) {
7174 v8::HandleScope handle_scope;
7175 LocalContext context;
7176
7177 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7178 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7179 Local<Object> instance = instance_template->NewInstance();
7180 context->Global()->Set(v8_str("obj"), instance);
7181 v8::TryCatch try_catch;
7182 Local<Value> value;
7183 CHECK(!try_catch.HasCaught());
7184
7185 // Call the Object's constructor with a 32-bit signed integer.
7186 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7187 CHECK(!try_catch.HasCaught());
7188 CHECK(value->IsInt32());
7189 CHECK_EQ(28, value->Int32Value());
7190
7191 Local<Value> args1[] = { v8_num(28) };
7192 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7193 CHECK(value_obj1->IsObject());
7194 Local<Object> object1 = Local<Object>::Cast(value_obj1);
7195 value = object1->Get(v8_str("a"));
7196 CHECK(value->IsInt32());
7197 CHECK(!try_catch.HasCaught());
7198 CHECK_EQ(28, value->Int32Value());
7199
7200 // Call the Object's constructor with a String.
7201 value = CompileRun(
7202 "(function() { var o = new obj('tipli'); return o.a; })()");
7203 CHECK(!try_catch.HasCaught());
7204 CHECK(value->IsString());
7205 String::AsciiValue string_value1(value->ToString());
7206 CHECK_EQ("tipli", *string_value1);
7207
7208 Local<Value> args2[] = { v8_str("tipli") };
7209 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7210 CHECK(value_obj2->IsObject());
7211 Local<Object> object2 = Local<Object>::Cast(value_obj2);
7212 value = object2->Get(v8_str("a"));
7213 CHECK(!try_catch.HasCaught());
7214 CHECK(value->IsString());
7215 String::AsciiValue string_value2(value->ToString());
7216 CHECK_EQ("tipli", *string_value2);
7217
7218 // Call the Object's constructor with a Boolean.
7219 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7220 CHECK(!try_catch.HasCaught());
7221 CHECK(value->IsBoolean());
7222 CHECK_EQ(true, value->BooleanValue());
7223
7224 Handle<Value> args3[] = { v8::Boolean::New(true) };
7225 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7226 CHECK(value_obj3->IsObject());
7227 Local<Object> object3 = Local<Object>::Cast(value_obj3);
7228 value = object3->Get(v8_str("a"));
7229 CHECK(!try_catch.HasCaught());
7230 CHECK(value->IsBoolean());
7231 CHECK_EQ(true, value->BooleanValue());
7232
7233 // Call the Object's constructor with undefined.
7234 Handle<Value> args4[] = { v8::Undefined() };
7235 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7236 CHECK(value_obj4->IsObject());
7237 Local<Object> object4 = Local<Object>::Cast(value_obj4);
7238 value = object4->Get(v8_str("a"));
7239 CHECK(!try_catch.HasCaught());
7240 CHECK(value->IsUndefined());
7241
7242 // Call the Object's constructor with null.
7243 Handle<Value> args5[] = { v8::Null() };
7244 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7245 CHECK(value_obj5->IsObject());
7246 Local<Object> object5 = Local<Object>::Cast(value_obj5);
7247 value = object5->Get(v8_str("a"));
7248 CHECK(!try_catch.HasCaught());
7249 CHECK(value->IsNull());
7250 }
7251
7252 // Check exception handling when there is no constructor set for the Object.
7253 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7254 Local<Object> instance = instance_template->NewInstance();
7255 context->Global()->Set(v8_str("obj2"), instance);
7256 v8::TryCatch try_catch;
7257 Local<Value> value;
7258 CHECK(!try_catch.HasCaught());
7259
7260 value = CompileRun("new obj2(28)");
7261 CHECK(try_catch.HasCaught());
7262 String::AsciiValue exception_value1(try_catch.Exception());
7263 CHECK_EQ("TypeError: object is not a function", *exception_value1);
7264 try_catch.Reset();
7265
7266 Local<Value> args[] = { v8_num(29) };
7267 value = instance->CallAsConstructor(1, args);
7268 CHECK(try_catch.HasCaught());
7269 String::AsciiValue exception_value2(try_catch.Exception());
7270 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7271 try_catch.Reset();
7272 }
7273
7274 // Check the case when constructor throws exception.
7275 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7276 instance_template->SetCallAsFunctionHandler(ThrowValue);
7277 Local<Object> instance = instance_template->NewInstance();
7278 context->Global()->Set(v8_str("obj3"), instance);
7279 v8::TryCatch try_catch;
7280 Local<Value> value;
7281 CHECK(!try_catch.HasCaught());
7282
7283 value = CompileRun("new obj3(22)");
7284 CHECK(try_catch.HasCaught());
7285 String::AsciiValue exception_value1(try_catch.Exception());
7286 CHECK_EQ("22", *exception_value1);
7287 try_catch.Reset();
7288
7289 Local<Value> args[] = { v8_num(23) };
7290 value = instance->CallAsConstructor(1, args);
7291 CHECK(try_catch.HasCaught());
7292 String::AsciiValue exception_value2(try_catch.Exception());
7293 CHECK_EQ("23", *exception_value2);
7294 try_catch.Reset();
7295 }
7296
7297 // Check whether constructor returns with an object or non-object.
7298 { Local<FunctionTemplate> function_template =
7299 FunctionTemplate::New(FakeConstructorCallback);
7300 Local<Function> function = function_template->GetFunction();
7301 Local<Object> instance1 = function;
7302 context->Global()->Set(v8_str("obj4"), instance1);
7303 v8::TryCatch try_catch;
7304 Local<Value> value;
7305 CHECK(!try_catch.HasCaught());
7306
7307 CHECK(instance1->IsObject());
7308 CHECK(instance1->IsFunction());
7309
7310 value = CompileRun("new obj4(28)");
7311 CHECK(!try_catch.HasCaught());
7312 CHECK(value->IsObject());
7313
7314 Local<Value> args1[] = { v8_num(28) };
7315 value = instance1->CallAsConstructor(1, args1);
7316 CHECK(!try_catch.HasCaught());
7317 CHECK(value->IsObject());
7318
7319 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7320 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7321 Local<Object> instance2 = instance_template->NewInstance();
7322 context->Global()->Set(v8_str("obj5"), instance2);
7323 CHECK(!try_catch.HasCaught());
7324
7325 CHECK(instance2->IsObject());
7326 CHECK(!instance2->IsFunction());
7327
7328 value = CompileRun("new obj5(28)");
7329 CHECK(!try_catch.HasCaught());
7330 CHECK(!value->IsObject());
7331
7332 Local<Value> args2[] = { v8_num(28) };
7333 value = instance2->CallAsConstructor(1, args2);
7334 CHECK(!try_catch.HasCaught());
7335 CHECK(!value->IsObject());
7336 }
7337}
7338
7339
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007340THREADED_TEST(FunctionDescriptorException) {
7341 v8::HandleScope handle_scope;
7342 LocalContext context;
7343 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7344 templ->SetClassName(v8_str("Fun"));
7345 Local<Function> cons = templ->GetFunction();
7346 context->Global()->Set(v8_str("Fun"), cons);
7347 Local<Value> value = CompileRun(
7348 "function test() {"
7349 " try {"
7350 " (new Fun()).blah()"
7351 " } catch (e) {"
7352 " var str = String(e);"
7353 " if (str.indexOf('TypeError') == -1) return 1;"
7354 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00007355 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007356 " return 0;"
7357 " }"
7358 " return 4;"
7359 "}"
7360 "test();");
7361 CHECK_EQ(0, value->Int32Value());
7362}
7363
7364
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007365THREADED_TEST(EvalAliasedDynamic) {
7366 v8::HandleScope scope;
7367 LocalContext current;
7368
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007369 // Tests where aliased eval can only be resolved dynamically.
7370 Local<Script> script =
7371 Script::Compile(v8_str("function f(x) { "
7372 " var foo = 2;"
7373 " with (x) { return eval('foo'); }"
7374 "}"
7375 "foo = 0;"
7376 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007377 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007378 "var x = new Object();"
7379 "x.eval = function(x) { return 1; };"
7380 "result3 = f(x);"));
7381 script->Run();
7382 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7383 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7384 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7385
7386 v8::TryCatch try_catch;
7387 script =
7388 Script::Compile(v8_str("function f(x) { "
7389 " var bar = 2;"
7390 " with (x) { return eval('bar'); }"
7391 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007392 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007393 script->Run();
7394 CHECK(try_catch.HasCaught());
7395 try_catch.Reset();
7396}
7397
7398
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007399THREADED_TEST(CrossEval) {
7400 v8::HandleScope scope;
7401 LocalContext other;
7402 LocalContext current;
7403
7404 Local<String> token = v8_str("<security token>");
7405 other->SetSecurityToken(token);
7406 current->SetSecurityToken(token);
7407
7408 // Setup reference from current to other.
7409 current->Global()->Set(v8_str("other"), other->Global());
7410
7411 // Check that new variables are introduced in other context.
7412 Local<Script> script =
7413 Script::Compile(v8_str("other.eval('var foo = 1234')"));
7414 script->Run();
7415 Local<Value> foo = other->Global()->Get(v8_str("foo"));
7416 CHECK_EQ(1234, foo->Int32Value());
7417 CHECK(!current->Global()->Has(v8_str("foo")));
7418
7419 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007420 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007421 script =
7422 Script::Compile(v8_str("other.eval('na = 1234')"));
7423 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007424 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7425 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007426
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007427 // Check that global variables in current context are not visible in other
7428 // context.
7429 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007430 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007431 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007432 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007433 CHECK(try_catch.HasCaught());
7434 try_catch.Reset();
7435
7436 // Check that local variables in current context are not visible in other
7437 // context.
7438 script =
7439 Script::Compile(v8_str("(function() { "
7440 " var baz = 87;"
7441 " return other.eval('baz');"
7442 "})();"));
7443 result = script->Run();
7444 CHECK(try_catch.HasCaught());
7445 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007446
7447 // Check that global variables in the other environment are visible
7448 // when evaluting code.
7449 other->Global()->Set(v8_str("bis"), v8_num(1234));
7450 script = Script::Compile(v8_str("other.eval('bis')"));
7451 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007452 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007453
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007454 // Check that the 'this' pointer points to the global object evaluating
7455 // code.
7456 other->Global()->Set(v8_str("t"), other->Global());
7457 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007458 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007459 CHECK(result->IsTrue());
7460 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007461
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007462 // Check that variables introduced in with-statement are not visible in
7463 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007464 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007465 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007466 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007467 CHECK(try_catch.HasCaught());
7468 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007469
7470 // Check that you cannot use 'eval.call' with another object than the
7471 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00007472 script =
7473 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7474 result = script->Run();
7475 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007476}
7477
7478
ager@chromium.orge2902be2009-06-08 12:21:35 +00007479// Test that calling eval in a context which has been detached from
7480// its global throws an exception. This behavior is consistent with
7481// other JavaScript implementations.
7482THREADED_TEST(EvalInDetachedGlobal) {
7483 v8::HandleScope scope;
7484
7485 v8::Persistent<Context> context0 = Context::New();
7486 v8::Persistent<Context> context1 = Context::New();
7487
7488 // Setup function in context0 that uses eval from context0.
7489 context0->Enter();
7490 v8::Handle<v8::Value> fun =
7491 CompileRun("var x = 42;"
7492 "(function() {"
7493 " var e = eval;"
7494 " return function(s) { return e(s); }"
7495 "})()");
7496 context0->Exit();
7497
7498 // Put the function into context1 and call it before and after
7499 // detaching the global. Before detaching, the call succeeds and
7500 // after detaching and exception is thrown.
7501 context1->Enter();
7502 context1->Global()->Set(v8_str("fun"), fun);
7503 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7504 CHECK_EQ(42, x_value->Int32Value());
7505 context0->DetachGlobal();
7506 v8::TryCatch catcher;
7507 x_value = CompileRun("fun('x')");
7508 CHECK(x_value.IsEmpty());
7509 CHECK(catcher.HasCaught());
7510 context1->Exit();
7511
7512 context1.Dispose();
7513 context0.Dispose();
7514}
7515
7516
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007517THREADED_TEST(CrossLazyLoad) {
7518 v8::HandleScope scope;
7519 LocalContext other;
7520 LocalContext current;
7521
7522 Local<String> token = v8_str("<security token>");
7523 other->SetSecurityToken(token);
7524 current->SetSecurityToken(token);
7525
7526 // Setup reference from current to other.
7527 current->Global()->Set(v8_str("other"), other->Global());
7528
7529 // Trigger lazy loading in other context.
7530 Local<Script> script =
7531 Script::Compile(v8_str("other.eval('new Date(42)')"));
7532 Local<Value> value = script->Run();
7533 CHECK_EQ(42.0, value->NumberValue());
7534}
7535
7536
7537static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7538 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007539 if (args.IsConstructCall()) {
7540 if (args[0]->IsInt32()) {
7541 return v8_num(-args[0]->Int32Value());
7542 }
7543 }
7544
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007545 return args[0];
7546}
7547
7548
7549// Test that a call handler can be set for objects which will allow
7550// non-function objects created through the API to be called as
7551// functions.
7552THREADED_TEST(CallAsFunction) {
7553 v8::HandleScope scope;
7554 LocalContext context;
7555
lrn@chromium.org1c092762011-05-09 09:42:16 +00007556 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7557 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7558 instance_template->SetCallAsFunctionHandler(call_as_function);
7559 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7560 context->Global()->Set(v8_str("obj"), instance);
7561 v8::TryCatch try_catch;
7562 Local<Value> value;
7563 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007564
lrn@chromium.org1c092762011-05-09 09:42:16 +00007565 value = CompileRun("obj(42)");
7566 CHECK(!try_catch.HasCaught());
7567 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007568
lrn@chromium.org1c092762011-05-09 09:42:16 +00007569 value = CompileRun("(function(o){return o(49)})(obj)");
7570 CHECK(!try_catch.HasCaught());
7571 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007572
lrn@chromium.org1c092762011-05-09 09:42:16 +00007573 // test special case of call as function
7574 value = CompileRun("[obj]['0'](45)");
7575 CHECK(!try_catch.HasCaught());
7576 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007577
lrn@chromium.org1c092762011-05-09 09:42:16 +00007578 value = CompileRun("obj.call = Function.prototype.call;"
7579 "obj.call(null, 87)");
7580 CHECK(!try_catch.HasCaught());
7581 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007582
lrn@chromium.org1c092762011-05-09 09:42:16 +00007583 // Regression tests for bug #1116356: Calling call through call/apply
7584 // must work for non-function receivers.
7585 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7586 value = CompileRun(apply_99);
7587 CHECK(!try_catch.HasCaught());
7588 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007589
lrn@chromium.org1c092762011-05-09 09:42:16 +00007590 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7591 value = CompileRun(call_17);
7592 CHECK(!try_catch.HasCaught());
7593 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00007594
lrn@chromium.org1c092762011-05-09 09:42:16 +00007595 // Check that the call-as-function handler can be called through
7596 // new.
7597 value = CompileRun("new obj(43)");
7598 CHECK(!try_catch.HasCaught());
7599 CHECK_EQ(-43, value->Int32Value());
7600
7601 // Check that the call-as-function handler can be called through
7602 // the API.
7603 v8::Handle<Value> args[] = { v8_num(28) };
7604 value = instance->CallAsFunction(instance, 1, args);
7605 CHECK(!try_catch.HasCaught());
7606 CHECK_EQ(28, value->Int32Value());
7607 }
7608
7609 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7610 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7611 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7612 context->Global()->Set(v8_str("obj2"), instance);
7613 v8::TryCatch try_catch;
7614 Local<Value> value;
7615 CHECK(!try_catch.HasCaught());
7616
7617 // Call an object without call-as-function handler through the JS
7618 value = CompileRun("obj2(28)");
7619 CHECK(value.IsEmpty());
7620 CHECK(try_catch.HasCaught());
7621 String::AsciiValue exception_value1(try_catch.Exception());
7622 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
7623 *exception_value1);
7624 try_catch.Reset();
7625
7626 // Call an object without call-as-function handler through the API
7627 value = CompileRun("obj2(28)");
7628 v8::Handle<Value> args[] = { v8_num(28) };
7629 value = instance->CallAsFunction(instance, 1, args);
7630 CHECK(value.IsEmpty());
7631 CHECK(try_catch.HasCaught());
7632 String::AsciiValue exception_value2(try_catch.Exception());
7633 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
7634 try_catch.Reset();
7635 }
7636
7637 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7638 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7639 instance_template->SetCallAsFunctionHandler(ThrowValue);
7640 Local<v8::Object> instance = t->GetFunction()->NewInstance();
7641 context->Global()->Set(v8_str("obj3"), instance);
7642 v8::TryCatch try_catch;
7643 Local<Value> value;
7644 CHECK(!try_catch.HasCaught());
7645
7646 // Catch the exception which is thrown by call-as-function handler
7647 value = CompileRun("obj3(22)");
7648 CHECK(try_catch.HasCaught());
7649 String::AsciiValue exception_value1(try_catch.Exception());
7650 CHECK_EQ("22", *exception_value1);
7651 try_catch.Reset();
7652
7653 v8::Handle<Value> args[] = { v8_num(23) };
7654 value = instance->CallAsFunction(instance, 1, args);
7655 CHECK(try_catch.HasCaught());
7656 String::AsciiValue exception_value2(try_catch.Exception());
7657 CHECK_EQ("23", *exception_value2);
7658 try_catch.Reset();
7659 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007660}
7661
7662
karlklose@chromium.org83a47282011-05-11 11:54:09 +00007663// Check whether a non-function object is callable.
7664THREADED_TEST(CallableObject) {
7665 v8::HandleScope scope;
7666 LocalContext context;
7667
7668 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7669 instance_template->SetCallAsFunctionHandler(call_as_function);
7670 Local<Object> instance = instance_template->NewInstance();
7671 v8::TryCatch try_catch;
7672
7673 CHECK(instance->IsCallable());
7674 CHECK(!try_catch.HasCaught());
7675 }
7676
7677 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7678 Local<Object> instance = instance_template->NewInstance();
7679 v8::TryCatch try_catch;
7680
7681 CHECK(!instance->IsCallable());
7682 CHECK(!try_catch.HasCaught());
7683 }
7684
7685 { Local<FunctionTemplate> function_template =
7686 FunctionTemplate::New(call_as_function);
7687 Local<Function> function = function_template->GetFunction();
7688 Local<Object> instance = function;
7689 v8::TryCatch try_catch;
7690
7691 CHECK(instance->IsCallable());
7692 CHECK(!try_catch.HasCaught());
7693 }
7694
7695 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
7696 Local<Function> function = function_template->GetFunction();
7697 Local<Object> instance = function;
7698 v8::TryCatch try_catch;
7699
7700 CHECK(instance->IsCallable());
7701 CHECK(!try_catch.HasCaught());
7702 }
7703}
7704
7705
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007706static int CountHandles() {
7707 return v8::HandleScope::NumberOfHandles();
7708}
7709
7710
7711static int Recurse(int depth, int iterations) {
7712 v8::HandleScope scope;
7713 if (depth == 0) return CountHandles();
7714 for (int i = 0; i < iterations; i++) {
7715 Local<v8::Number> n = v8::Integer::New(42);
7716 }
7717 return Recurse(depth - 1, iterations);
7718}
7719
7720
7721THREADED_TEST(HandleIteration) {
7722 static const int kIterations = 500;
7723 static const int kNesting = 200;
7724 CHECK_EQ(0, CountHandles());
7725 {
7726 v8::HandleScope scope1;
7727 CHECK_EQ(0, CountHandles());
7728 for (int i = 0; i < kIterations; i++) {
7729 Local<v8::Number> n = v8::Integer::New(42);
7730 CHECK_EQ(i + 1, CountHandles());
7731 }
7732
7733 CHECK_EQ(kIterations, CountHandles());
7734 {
7735 v8::HandleScope scope2;
7736 for (int j = 0; j < kIterations; j++) {
7737 Local<v8::Number> n = v8::Integer::New(42);
7738 CHECK_EQ(j + 1 + kIterations, CountHandles());
7739 }
7740 }
7741 CHECK_EQ(kIterations, CountHandles());
7742 }
7743 CHECK_EQ(0, CountHandles());
7744 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
7745}
7746
7747
7748static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
7749 Local<String> name,
7750 const AccessorInfo& info) {
7751 ApiTestFuzzer::Fuzz();
7752 return v8::Handle<Value>();
7753}
7754
7755
7756THREADED_TEST(InterceptorHasOwnProperty) {
7757 v8::HandleScope scope;
7758 LocalContext context;
7759 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7760 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7761 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
7762 Local<Function> function = fun_templ->GetFunction();
7763 context->Global()->Set(v8_str("constructor"), function);
7764 v8::Handle<Value> value = CompileRun(
7765 "var o = new constructor();"
7766 "o.hasOwnProperty('ostehaps');");
7767 CHECK_EQ(false, value->BooleanValue());
7768 value = CompileRun(
7769 "o.ostehaps = 42;"
7770 "o.hasOwnProperty('ostehaps');");
7771 CHECK_EQ(true, value->BooleanValue());
7772 value = CompileRun(
7773 "var p = new constructor();"
7774 "p.hasOwnProperty('ostehaps');");
7775 CHECK_EQ(false, value->BooleanValue());
7776}
7777
7778
ager@chromium.org9085a012009-05-11 19:22:57 +00007779static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
7780 Local<String> name,
7781 const AccessorInfo& info) {
7782 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 HEAP->CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00007784 return v8::Handle<Value>();
7785}
7786
7787
7788THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
7789 v8::HandleScope scope;
7790 LocalContext context;
7791 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7792 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
7793 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
7794 Local<Function> function = fun_templ->GetFunction();
7795 context->Global()->Set(v8_str("constructor"), function);
7796 // Let's first make some stuff so we can be sure to get a good GC.
7797 CompileRun(
7798 "function makestr(size) {"
7799 " switch (size) {"
7800 " case 1: return 'f';"
7801 " case 2: return 'fo';"
7802 " case 3: return 'foo';"
7803 " }"
7804 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
7805 "}"
7806 "var x = makestr(12345);"
7807 "x = makestr(31415);"
7808 "x = makestr(23456);");
7809 v8::Handle<Value> value = CompileRun(
7810 "var o = new constructor();"
7811 "o.__proto__ = new String(x);"
7812 "o.hasOwnProperty('ostehaps');");
7813 CHECK_EQ(false, value->BooleanValue());
7814}
7815
7816
ager@chromium.orge2902be2009-06-08 12:21:35 +00007817typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
7818 const AccessorInfo& info);
7819
7820
7821static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
7822 const char* source,
7823 int expected) {
7824 v8::HandleScope scope;
7825 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007826 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00007827 LocalContext context;
7828 context->Global()->Set(v8_str("o"), templ->NewInstance());
7829 v8::Handle<Value> value = CompileRun(source);
7830 CHECK_EQ(expected, value->Int32Value());
7831}
7832
7833
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007834static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
7835 const AccessorInfo& info) {
7836 ApiTestFuzzer::Fuzz();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007837 CHECK_EQ(v8_str("data"), info.Data());
7838 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007839 return v8::Integer::New(42);
7840}
7841
7842
7843// This test should hit the load IC for the interceptor case.
7844THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00007845 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007846 "var result = 0;"
7847 "for (var i = 0; i < 1000; i++) {"
7848 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00007849 "}",
7850 42);
7851}
7852
7853
7854// Below go several tests which verify that JITing for various
7855// configurations of interceptor and explicit fields works fine
7856// (those cases are special cased to get better performance).
7857
7858static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
7859 const AccessorInfo& info) {
7860 ApiTestFuzzer::Fuzz();
7861 return v8_str("x")->Equals(name)
7862 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
7863}
7864
7865
7866THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
7867 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7868 "var result = 0;"
7869 "o.y = 239;"
7870 "for (var i = 0; i < 1000; i++) {"
7871 " result = o.y;"
7872 "}",
7873 239);
7874}
7875
7876
7877THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
7878 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7879 "var result = 0;"
7880 "o.__proto__ = { 'y': 239 };"
7881 "for (var i = 0; i < 1000; i++) {"
7882 " result = o.y + o.x;"
7883 "}",
7884 239 + 42);
7885}
7886
7887
7888THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
7889 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7890 "var result = 0;"
7891 "o.__proto__.y = 239;"
7892 "for (var i = 0; i < 1000; i++) {"
7893 " result = o.y + o.x;"
7894 "}",
7895 239 + 42);
7896}
7897
7898
7899THREADED_TEST(InterceptorLoadICUndefined) {
7900 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7901 "var result = 0;"
7902 "for (var i = 0; i < 1000; i++) {"
7903 " result = (o.y == undefined) ? 239 : 42;"
7904 "}",
7905 239);
7906}
7907
7908
7909THREADED_TEST(InterceptorLoadICWithOverride) {
7910 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7911 "fst = new Object(); fst.__proto__ = o;"
7912 "snd = new Object(); snd.__proto__ = fst;"
7913 "var result1 = 0;"
7914 "for (var i = 0; i < 1000; i++) {"
7915 " result1 = snd.x;"
7916 "}"
7917 "fst.x = 239;"
7918 "var result = 0;"
7919 "for (var i = 0; i < 1000; i++) {"
7920 " result = snd.x;"
7921 "}"
7922 "result + result1",
7923 239 + 42);
7924}
7925
7926
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007927// Test the case when we stored field into
7928// a stub, but interceptor produced value on its own.
7929THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
7930 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7931 "proto = new Object();"
7932 "o.__proto__ = proto;"
7933 "proto.x = 239;"
7934 "for (var i = 0; i < 1000; i++) {"
7935 " o.x;"
7936 // Now it should be ICed and keep a reference to x defined on proto
7937 "}"
7938 "var result = 0;"
7939 "for (var i = 0; i < 1000; i++) {"
7940 " result += o.x;"
7941 "}"
7942 "result;",
7943 42 * 1000);
7944}
7945
7946
7947// Test the case when we stored field into
7948// a stub, but it got invalidated later on.
7949THREADED_TEST(InterceptorLoadICInvalidatedField) {
7950 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
7951 "proto1 = new Object();"
7952 "proto2 = new Object();"
7953 "o.__proto__ = proto1;"
7954 "proto1.__proto__ = proto2;"
7955 "proto2.y = 239;"
7956 "for (var i = 0; i < 1000; i++) {"
7957 " o.y;"
7958 // Now it should be ICed and keep a reference to y defined on proto2
7959 "}"
7960 "proto1.y = 42;"
7961 "var result = 0;"
7962 "for (var i = 0; i < 1000; i++) {"
7963 " result += o.y;"
7964 "}"
7965 "result;",
7966 42 * 1000);
7967}
7968
7969
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00007970static int interceptor_load_not_handled_calls = 0;
7971static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
7972 const AccessorInfo& info) {
7973 ++interceptor_load_not_handled_calls;
7974 return v8::Handle<v8::Value>();
7975}
7976
7977
7978// Test how post-interceptor lookups are done in the non-cacheable
7979// case: the interceptor should not be invoked during this lookup.
7980THREADED_TEST(InterceptorLoadICPostInterceptor) {
7981 interceptor_load_not_handled_calls = 0;
7982 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
7983 "receiver = new Object();"
7984 "receiver.__proto__ = o;"
7985 "proto = new Object();"
7986 "/* Make proto a slow-case object. */"
7987 "for (var i = 0; i < 1000; i++) {"
7988 " proto[\"xxxxxxxx\" + i] = [];"
7989 "}"
7990 "proto.x = 17;"
7991 "o.__proto__ = proto;"
7992 "var result = 0;"
7993 "for (var i = 0; i < 1000; i++) {"
7994 " result += receiver.x;"
7995 "}"
7996 "result;",
7997 17 * 1000);
7998 CHECK_EQ(1000, interceptor_load_not_handled_calls);
7999}
8000
8001
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008002// Test the case when we stored field into
8003// a stub, but it got invalidated later on due to override on
8004// global object which is between interceptor and fields' holders.
8005THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8006 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8007 "o.__proto__ = this;" // set a global to be a proto of o.
8008 "this.__proto__.y = 239;"
8009 "for (var i = 0; i < 10; i++) {"
8010 " if (o.y != 239) throw 'oops: ' + o.y;"
8011 // Now it should be ICed and keep a reference to y defined on field_holder.
8012 "}"
8013 "this.y = 42;" // Assign on a global.
8014 "var result = 0;"
8015 "for (var i = 0; i < 10; i++) {"
8016 " result += o.y;"
8017 "}"
8018 "result;",
8019 42 * 10);
8020}
8021
8022
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008023static void SetOnThis(Local<String> name,
8024 Local<Value> value,
8025 const AccessorInfo& info) {
8026 info.This()->ForceSet(name, value);
8027}
8028
8029
8030THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8031 v8::HandleScope scope;
8032 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8033 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8034 templ->SetAccessor(v8_str("y"), Return239);
8035 LocalContext context;
8036 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008037
8038 // Check the case when receiver and interceptor's holder
8039 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008040 v8::Handle<Value> value = CompileRun(
8041 "var result = 0;"
8042 "for (var i = 0; i < 7; i++) {"
8043 " result = o.y;"
8044 "}");
8045 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008046
8047 // Check the case when interceptor's holder is in proto chain
8048 // of receiver.
8049 value = CompileRun(
8050 "r = { __proto__: o };"
8051 "var result = 0;"
8052 "for (var i = 0; i < 7; i++) {"
8053 " result = r.y;"
8054 "}");
8055 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008056}
8057
8058
8059THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8060 v8::HandleScope scope;
8061 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8062 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8063 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8064 templ_p->SetAccessor(v8_str("y"), Return239);
8065
8066 LocalContext context;
8067 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8068 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8069
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008070 // Check the case when receiver and interceptor's holder
8071 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008072 v8::Handle<Value> value = CompileRun(
8073 "o.__proto__ = p;"
8074 "var result = 0;"
8075 "for (var i = 0; i < 7; i++) {"
8076 " result = o.x + o.y;"
8077 "}");
8078 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008079
8080 // Check the case when interceptor's holder is in proto chain
8081 // of receiver.
8082 value = CompileRun(
8083 "r = { __proto__: o };"
8084 "var result = 0;"
8085 "for (var i = 0; i < 7; i++) {"
8086 " result = r.x + r.y;"
8087 "}");
8088 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008089}
8090
8091
8092THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8093 v8::HandleScope scope;
8094 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8095 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8096 templ->SetAccessor(v8_str("y"), Return239);
8097
8098 LocalContext context;
8099 context->Global()->Set(v8_str("o"), templ->NewInstance());
8100
8101 v8::Handle<Value> value = CompileRun(
8102 "fst = new Object(); fst.__proto__ = o;"
8103 "snd = new Object(); snd.__proto__ = fst;"
8104 "var result1 = 0;"
8105 "for (var i = 0; i < 7; i++) {"
8106 " result1 = snd.x;"
8107 "}"
8108 "fst.x = 239;"
8109 "var result = 0;"
8110 "for (var i = 0; i < 7; i++) {"
8111 " result = snd.x;"
8112 "}"
8113 "result + result1");
8114 CHECK_EQ(239 + 42, value->Int32Value());
8115}
8116
8117
8118// Test the case when we stored callback into
8119// a stub, but interceptor produced value on its own.
8120THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8121 v8::HandleScope scope;
8122 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8123 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8124 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8125 templ_p->SetAccessor(v8_str("y"), Return239);
8126
8127 LocalContext context;
8128 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8129 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8130
8131 v8::Handle<Value> value = CompileRun(
8132 "o.__proto__ = p;"
8133 "for (var i = 0; i < 7; i++) {"
8134 " o.x;"
8135 // Now it should be ICed and keep a reference to x defined on p
8136 "}"
8137 "var result = 0;"
8138 "for (var i = 0; i < 7; i++) {"
8139 " result += o.x;"
8140 "}"
8141 "result");
8142 CHECK_EQ(42 * 7, value->Int32Value());
8143}
8144
8145
8146// Test the case when we stored callback into
8147// a stub, but it got invalidated later on.
8148THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8149 v8::HandleScope scope;
8150 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8151 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8152 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8153 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8154
8155 LocalContext context;
8156 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8157 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8158
8159 v8::Handle<Value> value = CompileRun(
8160 "inbetween = new Object();"
8161 "o.__proto__ = inbetween;"
8162 "inbetween.__proto__ = p;"
8163 "for (var i = 0; i < 10; i++) {"
8164 " o.y;"
8165 // Now it should be ICed and keep a reference to y defined on p
8166 "}"
8167 "inbetween.y = 42;"
8168 "var result = 0;"
8169 "for (var i = 0; i < 10; i++) {"
8170 " result += o.y;"
8171 "}"
8172 "result");
8173 CHECK_EQ(42 * 10, value->Int32Value());
8174}
8175
8176
8177// Test the case when we stored callback into
8178// a stub, but it got invalidated later on due to override on
8179// global object which is between interceptor and callbacks' holders.
8180THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8181 v8::HandleScope scope;
8182 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8183 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8184 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8185 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8186
8187 LocalContext context;
8188 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8189 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8190
8191 v8::Handle<Value> value = CompileRun(
8192 "o.__proto__ = this;"
8193 "this.__proto__ = p;"
8194 "for (var i = 0; i < 10; i++) {"
8195 " if (o.y != 239) throw 'oops: ' + o.y;"
8196 // Now it should be ICed and keep a reference to y defined on p
8197 "}"
8198 "this.y = 42;"
8199 "var result = 0;"
8200 "for (var i = 0; i < 10; i++) {"
8201 " result += o.y;"
8202 "}"
8203 "result");
8204 CHECK_EQ(42 * 10, value->Int32Value());
8205}
8206
8207
ager@chromium.orge2902be2009-06-08 12:21:35 +00008208static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8209 const AccessorInfo& info) {
8210 ApiTestFuzzer::Fuzz();
8211 CHECK(v8_str("x")->Equals(name));
8212 return v8::Integer::New(0);
8213}
8214
8215
8216THREADED_TEST(InterceptorReturningZero) {
8217 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8218 "o.x == undefined ? 1 : 0",
8219 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008220}
8221
8222
8223static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008224 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008225 CHECK(v8_str("x")->Equals(key));
8226 CHECK_EQ(42, value->Int32Value());
8227 return value;
8228}
8229
8230
8231// This test should hit the store IC for the interceptor case.
8232THREADED_TEST(InterceptorStoreIC) {
8233 v8::HandleScope scope;
8234 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8235 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008236 InterceptorStoreICSetter,
8237 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008238 LocalContext context;
8239 context->Global()->Set(v8_str("o"), templ->NewInstance());
8240 v8::Handle<Value> value = CompileRun(
8241 "for (var i = 0; i < 1000; i++) {"
8242 " o.x = 42;"
8243 "}");
8244}
8245
8246
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008247THREADED_TEST(InterceptorStoreICWithNoSetter) {
8248 v8::HandleScope scope;
8249 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8250 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8251 LocalContext context;
8252 context->Global()->Set(v8_str("o"), templ->NewInstance());
8253 v8::Handle<Value> value = CompileRun(
8254 "for (var i = 0; i < 1000; i++) {"
8255 " o.y = 239;"
8256 "}"
8257 "42 + o.y");
8258 CHECK_EQ(239 + 42, value->Int32Value());
8259}
8260
8261
8262
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008263
8264v8::Handle<Value> call_ic_function;
8265v8::Handle<Value> call_ic_function2;
8266v8::Handle<Value> call_ic_function3;
8267
8268static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8269 const AccessorInfo& info) {
8270 ApiTestFuzzer::Fuzz();
8271 CHECK(v8_str("x")->Equals(name));
8272 return call_ic_function;
8273}
8274
8275
8276// This test should hit the call IC for the interceptor case.
8277THREADED_TEST(InterceptorCallIC) {
8278 v8::HandleScope scope;
8279 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8280 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8281 LocalContext context;
8282 context->Global()->Set(v8_str("o"), templ->NewInstance());
8283 call_ic_function =
8284 v8_compile("function f(x) { return x + 1; }; f")->Run();
8285 v8::Handle<Value> value = CompileRun(
8286 "var result = 0;"
8287 "for (var i = 0; i < 1000; i++) {"
8288 " result = o.x(41);"
8289 "}");
8290 CHECK_EQ(42, value->Int32Value());
8291}
8292
kasperl@chromium.orge959c182009-07-27 08:59:04 +00008293
8294// This test checks that if interceptor doesn't provide
8295// a value, we can fetch regular value.
8296THREADED_TEST(InterceptorCallICSeesOthers) {
8297 v8::HandleScope scope;
8298 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8299 templ->SetNamedPropertyHandler(NoBlockGetterX);
8300 LocalContext context;
8301 context->Global()->Set(v8_str("o"), templ->NewInstance());
8302 v8::Handle<Value> value = CompileRun(
8303 "o.x = function f(x) { return x + 1; };"
8304 "var result = 0;"
8305 "for (var i = 0; i < 7; i++) {"
8306 " result = o.x(41);"
8307 "}");
8308 CHECK_EQ(42, value->Int32Value());
8309}
8310
8311
8312static v8::Handle<Value> call_ic_function4;
8313static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8314 const AccessorInfo& info) {
8315 ApiTestFuzzer::Fuzz();
8316 CHECK(v8_str("x")->Equals(name));
8317 return call_ic_function4;
8318}
8319
8320
8321// This test checks that if interceptor provides a function,
8322// even if we cached shadowed variant, interceptor's function
8323// is invoked
8324THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8325 v8::HandleScope scope;
8326 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8327 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8328 LocalContext context;
8329 context->Global()->Set(v8_str("o"), templ->NewInstance());
8330 call_ic_function4 =
8331 v8_compile("function f(x) { return x - 1; }; f")->Run();
8332 v8::Handle<Value> value = CompileRun(
8333 "o.__proto__.x = function(x) { return x + 1; };"
8334 "var result = 0;"
8335 "for (var i = 0; i < 1000; i++) {"
8336 " result = o.x(42);"
8337 "}");
8338 CHECK_EQ(41, value->Int32Value());
8339}
8340
8341
8342// Test the case when we stored cacheable lookup into
8343// a stub, but it got invalidated later on
8344THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8345 v8::HandleScope scope;
8346 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8347 templ->SetNamedPropertyHandler(NoBlockGetterX);
8348 LocalContext context;
8349 context->Global()->Set(v8_str("o"), templ->NewInstance());
8350 v8::Handle<Value> value = CompileRun(
8351 "proto1 = new Object();"
8352 "proto2 = new Object();"
8353 "o.__proto__ = proto1;"
8354 "proto1.__proto__ = proto2;"
8355 "proto2.y = function(x) { return x + 1; };"
8356 // Invoke it many times to compile a stub
8357 "for (var i = 0; i < 7; i++) {"
8358 " o.y(42);"
8359 "}"
8360 "proto1.y = function(x) { return x - 1; };"
8361 "var result = 0;"
8362 "for (var i = 0; i < 7; i++) {"
8363 " result += o.y(42);"
8364 "}");
8365 CHECK_EQ(41 * 7, value->Int32Value());
8366}
8367
8368
8369static v8::Handle<Value> call_ic_function5;
8370static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8371 const AccessorInfo& info) {
8372 ApiTestFuzzer::Fuzz();
8373 if (v8_str("x")->Equals(name))
8374 return call_ic_function5;
8375 else
8376 return Local<Value>();
8377}
8378
8379
8380// This test checks that if interceptor doesn't provide a function,
8381// cached constant function is used
8382THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8383 v8::HandleScope scope;
8384 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8385 templ->SetNamedPropertyHandler(NoBlockGetterX);
8386 LocalContext context;
8387 context->Global()->Set(v8_str("o"), templ->NewInstance());
8388 v8::Handle<Value> value = CompileRun(
8389 "function inc(x) { return x + 1; };"
8390 "inc(1);"
8391 "o.x = inc;"
8392 "var result = 0;"
8393 "for (var i = 0; i < 1000; i++) {"
8394 " result = o.x(42);"
8395 "}");
8396 CHECK_EQ(43, value->Int32Value());
8397}
8398
8399
8400// This test checks that if interceptor provides a function,
8401// even if we cached constant function, interceptor's function
8402// is invoked
8403THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8404 v8::HandleScope scope;
8405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8406 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8407 LocalContext context;
8408 context->Global()->Set(v8_str("o"), templ->NewInstance());
8409 call_ic_function5 =
8410 v8_compile("function f(x) { return x - 1; }; f")->Run();
8411 v8::Handle<Value> value = CompileRun(
8412 "function inc(x) { return x + 1; };"
8413 "inc(1);"
8414 "o.x = inc;"
8415 "var result = 0;"
8416 "for (var i = 0; i < 1000; i++) {"
8417 " result = o.x(42);"
8418 "}");
8419 CHECK_EQ(41, value->Int32Value());
8420}
8421
8422
8423// Test the case when we stored constant function into
8424// a stub, but it got invalidated later on
8425THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8426 v8::HandleScope scope;
8427 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8428 templ->SetNamedPropertyHandler(NoBlockGetterX);
8429 LocalContext context;
8430 context->Global()->Set(v8_str("o"), templ->NewInstance());
8431 v8::Handle<Value> value = CompileRun(
8432 "function inc(x) { return x + 1; };"
8433 "inc(1);"
8434 "proto1 = new Object();"
8435 "proto2 = new Object();"
8436 "o.__proto__ = proto1;"
8437 "proto1.__proto__ = proto2;"
8438 "proto2.y = inc;"
8439 // Invoke it many times to compile a stub
8440 "for (var i = 0; i < 7; i++) {"
8441 " o.y(42);"
8442 "}"
8443 "proto1.y = function(x) { return x - 1; };"
8444 "var result = 0;"
8445 "for (var i = 0; i < 7; i++) {"
8446 " result += o.y(42);"
8447 "}");
8448 CHECK_EQ(41 * 7, value->Int32Value());
8449}
8450
8451
8452// Test the case when we stored constant function into
8453// a stub, but it got invalidated later on due to override on
8454// global object which is between interceptor and constant function' holders.
8455THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8456 v8::HandleScope scope;
8457 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8458 templ->SetNamedPropertyHandler(NoBlockGetterX);
8459 LocalContext context;
8460 context->Global()->Set(v8_str("o"), templ->NewInstance());
8461 v8::Handle<Value> value = CompileRun(
8462 "function inc(x) { return x + 1; };"
8463 "inc(1);"
8464 "o.__proto__ = this;"
8465 "this.__proto__.y = inc;"
8466 // Invoke it many times to compile a stub
8467 "for (var i = 0; i < 7; i++) {"
8468 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8469 "}"
8470 "this.y = function(x) { return x - 1; };"
8471 "var result = 0;"
8472 "for (var i = 0; i < 7; i++) {"
8473 " result += o.y(42);"
8474 "}");
8475 CHECK_EQ(41 * 7, value->Int32Value());
8476}
8477
8478
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008479// Test the case when actual function to call sits on global object.
8480THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8481 v8::HandleScope scope;
8482 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8483 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8484
8485 LocalContext context;
8486 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8487
8488 v8::Handle<Value> value = CompileRun(
8489 "try {"
8490 " o.__proto__ = this;"
8491 " for (var i = 0; i < 10; i++) {"
8492 " var v = o.parseFloat('239');"
8493 " if (v != 239) throw v;"
8494 // Now it should be ICed and keep a reference to parseFloat.
8495 " }"
8496 " var result = 0;"
8497 " for (var i = 0; i < 10; i++) {"
8498 " result += o.parseFloat('239');"
8499 " }"
8500 " result"
8501 "} catch(e) {"
8502 " e"
8503 "};");
8504 CHECK_EQ(239 * 10, value->Int32Value());
8505}
8506
ager@chromium.org5c838252010-02-19 08:53:10 +00008507static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8508 const AccessorInfo& info) {
8509 ApiTestFuzzer::Fuzz();
8510 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8511 ++(*call_count);
8512 if ((*call_count) % 20 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 HEAP->CollectAllGarbage(true);
ager@chromium.org5c838252010-02-19 08:53:10 +00008514 }
8515 return v8::Handle<Value>();
8516}
8517
8518static v8::Handle<Value> FastApiCallback_TrivialSignature(
8519 const v8::Arguments& args) {
8520 ApiTestFuzzer::Fuzz();
8521 CHECK_EQ(args.This(), args.Holder());
8522 CHECK(args.Data()->Equals(v8_str("method_data")));
8523 return v8::Integer::New(args[0]->Int32Value() + 1);
8524}
8525
8526static v8::Handle<Value> FastApiCallback_SimpleSignature(
8527 const v8::Arguments& args) {
8528 ApiTestFuzzer::Fuzz();
8529 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8530 CHECK(args.Data()->Equals(v8_str("method_data")));
8531 // Note, we're using HasRealNamedProperty instead of Has to avoid
8532 // invoking the interceptor again.
8533 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8534 return v8::Integer::New(args[0]->Int32Value() + 1);
8535}
8536
8537// Helper to maximize the odds of object moving.
8538static void GenerateSomeGarbage() {
8539 CompileRun(
8540 "var garbage;"
8541 "for (var i = 0; i < 1000; i++) {"
8542 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8543 "}"
8544 "garbage = undefined;");
8545}
8546
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008547
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008548v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8549 static int count = 0;
8550 if (count++ % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008551 HEAP-> CollectAllGarbage(true); // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008552 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
8553 }
8554 return v8::Handle<v8::Value>();
8555}
8556
8557
8558THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8559 v8::HandleScope scope;
8560 LocalContext context;
8561 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8562 nativeobject_templ->Set("callback",
8563 v8::FunctionTemplate::New(DirectApiCallback));
8564 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8565 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8566 // call the api function multiple times to ensure direct call stub creation.
8567 CompileRun(
8568 "function f() {"
8569 " for (var i = 1; i <= 30; i++) {"
8570 " nativeobject.callback();"
8571 " }"
8572 "}"
8573 "f();");
8574}
8575
8576
8577v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8578 return v8::ThrowException(v8_str("g"));
8579}
8580
8581
8582THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8583 v8::HandleScope scope;
8584 LocalContext context;
8585 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8586 nativeobject_templ->Set("callback",
8587 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8588 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8589 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8590 // call the api function multiple times to ensure direct call stub creation.
8591 v8::Handle<Value> result = CompileRun(
8592 "var result = '';"
8593 "function f() {"
8594 " for (var i = 1; i <= 5; i++) {"
8595 " try { nativeobject.callback(); } catch (e) { result += e; }"
8596 " }"
8597 "}"
8598 "f(); result;");
8599 CHECK_EQ(v8_str("ggggg"), result);
8600}
8601
8602
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008603v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
8604 const v8::AccessorInfo& info) {
8605 if (++p_getter_count % 3 == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 HEAP->CollectAllGarbage(true);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008607 GenerateSomeGarbage();
8608 }
8609 return v8::Handle<v8::Value>();
8610}
8611
8612
8613THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
8614 v8::HandleScope scope;
8615 LocalContext context;
8616 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8617 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
8618 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8619 p_getter_count = 0;
8620 CompileRun(
8621 "function f() {"
8622 " for (var i = 0; i < 30; i++) o1.p1;"
8623 "}"
8624 "f();");
8625 CHECK_EQ(30, p_getter_count);
8626}
8627
8628
8629v8::Handle<v8::Value> ThrowingDirectGetterCallback(
8630 Local<String> name, const v8::AccessorInfo& info) {
8631 return v8::ThrowException(v8_str("g"));
8632}
8633
8634
8635THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
8636 v8::HandleScope scope;
8637 LocalContext context;
8638 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
8639 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
8640 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8641 v8::Handle<Value> result = CompileRun(
8642 "var result = '';"
8643 "for (var i = 0; i < 5; i++) {"
8644 " try { o1.p1; } catch (e) { result += e; }"
8645 "}"
8646 "result;");
8647 CHECK_EQ(v8_str("ggggg"), result);
8648}
8649
8650
ager@chromium.org5c838252010-02-19 08:53:10 +00008651THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
8652 int interceptor_call_count = 0;
8653 v8::HandleScope scope;
8654 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8655 v8::Handle<v8::FunctionTemplate> method_templ =
8656 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8657 v8_str("method_data"),
8658 v8::Handle<v8::Signature>());
8659 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8660 proto_templ->Set(v8_str("method"), method_templ);
8661 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8662 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8663 NULL, NULL, NULL, NULL,
8664 v8::External::Wrap(&interceptor_call_count));
8665 LocalContext context;
8666 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8667 GenerateSomeGarbage();
8668 context->Global()->Set(v8_str("o"), fun->NewInstance());
8669 v8::Handle<Value> value = CompileRun(
8670 "var result = 0;"
8671 "for (var i = 0; i < 100; i++) {"
8672 " result = o.method(41);"
8673 "}");
8674 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8675 CHECK_EQ(100, interceptor_call_count);
8676}
8677
8678THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
8679 int interceptor_call_count = 0;
8680 v8::HandleScope scope;
8681 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8682 v8::Handle<v8::FunctionTemplate> method_templ =
8683 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8684 v8_str("method_data"),
8685 v8::Signature::New(fun_templ));
8686 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8687 proto_templ->Set(v8_str("method"), method_templ);
8688 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8689 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8690 NULL, NULL, NULL, NULL,
8691 v8::External::Wrap(&interceptor_call_count));
8692 LocalContext context;
8693 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8694 GenerateSomeGarbage();
8695 context->Global()->Set(v8_str("o"), fun->NewInstance());
8696 v8::Handle<Value> value = CompileRun(
8697 "o.foo = 17;"
8698 "var receiver = {};"
8699 "receiver.__proto__ = o;"
8700 "var result = 0;"
8701 "for (var i = 0; i < 100; i++) {"
8702 " result = receiver.method(41);"
8703 "}");
8704 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8705 CHECK_EQ(100, interceptor_call_count);
8706}
8707
8708THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
8709 int interceptor_call_count = 0;
8710 v8::HandleScope scope;
8711 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8712 v8::Handle<v8::FunctionTemplate> method_templ =
8713 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8714 v8_str("method_data"),
8715 v8::Signature::New(fun_templ));
8716 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8717 proto_templ->Set(v8_str("method"), method_templ);
8718 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8719 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8720 NULL, NULL, NULL, NULL,
8721 v8::External::Wrap(&interceptor_call_count));
8722 LocalContext context;
8723 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8724 GenerateSomeGarbage();
8725 context->Global()->Set(v8_str("o"), fun->NewInstance());
8726 v8::Handle<Value> value = CompileRun(
8727 "o.foo = 17;"
8728 "var receiver = {};"
8729 "receiver.__proto__ = o;"
8730 "var result = 0;"
8731 "var saved_result = 0;"
8732 "for (var i = 0; i < 100; i++) {"
8733 " result = receiver.method(41);"
8734 " if (i == 50) {"
8735 " saved_result = result;"
8736 " receiver = {method: function(x) { return x - 1 }};"
8737 " }"
8738 "}");
8739 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8740 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8741 CHECK_GE(interceptor_call_count, 50);
8742}
8743
8744THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
8745 int interceptor_call_count = 0;
8746 v8::HandleScope scope;
8747 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8748 v8::Handle<v8::FunctionTemplate> method_templ =
8749 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8750 v8_str("method_data"),
8751 v8::Signature::New(fun_templ));
8752 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8753 proto_templ->Set(v8_str("method"), method_templ);
8754 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8755 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8756 NULL, NULL, NULL, NULL,
8757 v8::External::Wrap(&interceptor_call_count));
8758 LocalContext context;
8759 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8760 GenerateSomeGarbage();
8761 context->Global()->Set(v8_str("o"), fun->NewInstance());
8762 v8::Handle<Value> value = CompileRun(
8763 "o.foo = 17;"
8764 "var receiver = {};"
8765 "receiver.__proto__ = o;"
8766 "var result = 0;"
8767 "var saved_result = 0;"
8768 "for (var i = 0; i < 100; i++) {"
8769 " result = receiver.method(41);"
8770 " if (i == 50) {"
8771 " saved_result = result;"
8772 " o.method = function(x) { return x - 1 };"
8773 " }"
8774 "}");
8775 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8776 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8777 CHECK_GE(interceptor_call_count, 50);
8778}
8779
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008780THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
8781 int interceptor_call_count = 0;
8782 v8::HandleScope scope;
8783 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8784 v8::Handle<v8::FunctionTemplate> method_templ =
8785 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8786 v8_str("method_data"),
8787 v8::Signature::New(fun_templ));
8788 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8789 proto_templ->Set(v8_str("method"), method_templ);
8790 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8791 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8792 NULL, NULL, NULL, NULL,
8793 v8::External::Wrap(&interceptor_call_count));
8794 LocalContext context;
8795 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8796 GenerateSomeGarbage();
8797 context->Global()->Set(v8_str("o"), fun->NewInstance());
8798 v8::TryCatch try_catch;
8799 v8::Handle<Value> value = CompileRun(
8800 "o.foo = 17;"
8801 "var receiver = {};"
8802 "receiver.__proto__ = o;"
8803 "var result = 0;"
8804 "var saved_result = 0;"
8805 "for (var i = 0; i < 100; i++) {"
8806 " result = receiver.method(41);"
8807 " if (i == 50) {"
8808 " saved_result = result;"
8809 " receiver = 333;"
8810 " }"
8811 "}");
8812 CHECK(try_catch.HasCaught());
8813 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8814 try_catch.Exception()->ToString());
8815 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8816 CHECK_GE(interceptor_call_count, 50);
8817}
8818
ager@chromium.org5c838252010-02-19 08:53:10 +00008819THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
8820 int interceptor_call_count = 0;
8821 v8::HandleScope scope;
8822 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8823 v8::Handle<v8::FunctionTemplate> method_templ =
8824 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8825 v8_str("method_data"),
8826 v8::Signature::New(fun_templ));
8827 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8828 proto_templ->Set(v8_str("method"), method_templ);
8829 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8830 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
8831 NULL, NULL, NULL, NULL,
8832 v8::External::Wrap(&interceptor_call_count));
8833 LocalContext context;
8834 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8835 GenerateSomeGarbage();
8836 context->Global()->Set(v8_str("o"), fun->NewInstance());
8837 v8::TryCatch try_catch;
8838 v8::Handle<Value> value = CompileRun(
8839 "o.foo = 17;"
8840 "var receiver = {};"
8841 "receiver.__proto__ = o;"
8842 "var result = 0;"
8843 "var saved_result = 0;"
8844 "for (var i = 0; i < 100; i++) {"
8845 " result = receiver.method(41);"
8846 " if (i == 50) {"
8847 " saved_result = result;"
8848 " receiver = {method: receiver.method};"
8849 " }"
8850 "}");
8851 CHECK(try_catch.HasCaught());
8852 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
8853 try_catch.Exception()->ToString());
8854 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8855 CHECK_GE(interceptor_call_count, 50);
8856}
8857
8858THREADED_TEST(CallICFastApi_TrivialSignature) {
8859 v8::HandleScope scope;
8860 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8861 v8::Handle<v8::FunctionTemplate> method_templ =
8862 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
8863 v8_str("method_data"),
8864 v8::Handle<v8::Signature>());
8865 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8866 proto_templ->Set(v8_str("method"), method_templ);
8867 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8868 LocalContext context;
8869 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8870 GenerateSomeGarbage();
8871 context->Global()->Set(v8_str("o"), fun->NewInstance());
8872 v8::Handle<Value> value = CompileRun(
8873 "var result = 0;"
8874 "for (var i = 0; i < 100; i++) {"
8875 " result = o.method(41);"
8876 "}");
8877
8878 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8879}
8880
8881THREADED_TEST(CallICFastApi_SimpleSignature) {
8882 v8::HandleScope scope;
8883 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8884 v8::Handle<v8::FunctionTemplate> method_templ =
8885 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8886 v8_str("method_data"),
8887 v8::Signature::New(fun_templ));
8888 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8889 proto_templ->Set(v8_str("method"), method_templ);
8890 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8891 LocalContext context;
8892 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8893 GenerateSomeGarbage();
8894 context->Global()->Set(v8_str("o"), fun->NewInstance());
8895 v8::Handle<Value> value = CompileRun(
8896 "o.foo = 17;"
8897 "var receiver = {};"
8898 "receiver.__proto__ = o;"
8899 "var result = 0;"
8900 "for (var i = 0; i < 100; i++) {"
8901 " result = receiver.method(41);"
8902 "}");
8903
8904 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
8905}
8906
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008907THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008908 v8::HandleScope scope;
8909 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8910 v8::Handle<v8::FunctionTemplate> method_templ =
8911 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8912 v8_str("method_data"),
8913 v8::Signature::New(fun_templ));
8914 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8915 proto_templ->Set(v8_str("method"), method_templ);
8916 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8917 LocalContext context;
8918 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8919 GenerateSomeGarbage();
8920 context->Global()->Set(v8_str("o"), fun->NewInstance());
8921 v8::Handle<Value> value = CompileRun(
8922 "o.foo = 17;"
8923 "var receiver = {};"
8924 "receiver.__proto__ = o;"
8925 "var result = 0;"
8926 "var saved_result = 0;"
8927 "for (var i = 0; i < 100; i++) {"
8928 " result = receiver.method(41);"
8929 " if (i == 50) {"
8930 " saved_result = result;"
8931 " receiver = {method: function(x) { return x - 1 }};"
8932 " }"
8933 "}");
8934 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
8935 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8936}
8937
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00008938THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
8939 v8::HandleScope scope;
8940 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8941 v8::Handle<v8::FunctionTemplate> method_templ =
8942 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
8943 v8_str("method_data"),
8944 v8::Signature::New(fun_templ));
8945 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
8946 proto_templ->Set(v8_str("method"), method_templ);
8947 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
8948 LocalContext context;
8949 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
8950 GenerateSomeGarbage();
8951 context->Global()->Set(v8_str("o"), fun->NewInstance());
8952 v8::TryCatch try_catch;
8953 v8::Handle<Value> value = CompileRun(
8954 "o.foo = 17;"
8955 "var receiver = {};"
8956 "receiver.__proto__ = o;"
8957 "var result = 0;"
8958 "var saved_result = 0;"
8959 "for (var i = 0; i < 100; i++) {"
8960 " result = receiver.method(41);"
8961 " if (i == 50) {"
8962 " saved_result = result;"
8963 " receiver = 333;"
8964 " }"
8965 "}");
8966 CHECK(try_catch.HasCaught());
8967 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
8968 try_catch.Exception()->ToString());
8969 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
8970}
8971
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008972
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008973v8::Handle<Value> keyed_call_ic_function;
8974
8975static v8::Handle<Value> InterceptorKeyedCallICGetter(
8976 Local<String> name, const AccessorInfo& info) {
8977 ApiTestFuzzer::Fuzz();
8978 if (v8_str("x")->Equals(name)) {
8979 return keyed_call_ic_function;
8980 }
8981 return v8::Handle<Value>();
8982}
8983
8984
8985// Test the case when we stored cacheable lookup into
8986// a stub, but the function name changed (to another cacheable function).
8987THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
8988 v8::HandleScope scope;
8989 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8990 templ->SetNamedPropertyHandler(NoBlockGetterX);
8991 LocalContext context;
8992 context->Global()->Set(v8_str("o"), templ->NewInstance());
8993 v8::Handle<Value> value = CompileRun(
8994 "proto = new Object();"
8995 "proto.y = function(x) { return x + 1; };"
8996 "proto.z = function(x) { return x - 1; };"
8997 "o.__proto__ = proto;"
8998 "var result = 0;"
8999 "var method = 'y';"
9000 "for (var i = 0; i < 10; i++) {"
9001 " if (i == 5) { method = 'z'; };"
9002 " result += o[method](41);"
9003 "}");
9004 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9005}
9006
9007
9008// Test the case when we stored cacheable lookup into
9009// a stub, but the function name changed (and the new function is present
9010// both before and after the interceptor in the prototype chain).
9011THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9012 v8::HandleScope scope;
9013 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9014 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9015 LocalContext context;
9016 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9017 keyed_call_ic_function =
9018 v8_compile("function f(x) { return x - 1; }; f")->Run();
9019 v8::Handle<Value> value = CompileRun(
9020 "o = new Object();"
9021 "proto2 = new Object();"
9022 "o.y = function(x) { return x + 1; };"
9023 "proto2.y = function(x) { return x + 2; };"
9024 "o.__proto__ = proto1;"
9025 "proto1.__proto__ = proto2;"
9026 "var result = 0;"
9027 "var method = 'x';"
9028 "for (var i = 0; i < 10; i++) {"
9029 " if (i == 5) { method = 'y'; };"
9030 " result += o[method](41);"
9031 "}");
9032 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9033}
9034
9035
9036// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9037// on the global object.
9038THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9039 v8::HandleScope scope;
9040 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9041 templ->SetNamedPropertyHandler(NoBlockGetterX);
9042 LocalContext context;
9043 context->Global()->Set(v8_str("o"), templ->NewInstance());
9044 v8::Handle<Value> value = CompileRun(
9045 "function inc(x) { return x + 1; };"
9046 "inc(1);"
9047 "function dec(x) { return x - 1; };"
9048 "dec(1);"
9049 "o.__proto__ = this;"
9050 "this.__proto__.x = inc;"
9051 "this.__proto__.y = dec;"
9052 "var result = 0;"
9053 "var method = 'x';"
9054 "for (var i = 0; i < 10; i++) {"
9055 " if (i == 5) { method = 'y'; };"
9056 " result += o[method](41);"
9057 "}");
9058 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9059}
9060
9061
9062// Test the case when actual function to call sits on global object.
9063THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9064 v8::HandleScope scope;
9065 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9066 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9067 LocalContext context;
9068 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9069
9070 v8::Handle<Value> value = CompileRun(
9071 "function len(x) { return x.length; };"
9072 "o.__proto__ = this;"
9073 "var m = 'parseFloat';"
9074 "var result = 0;"
9075 "for (var i = 0; i < 10; i++) {"
9076 " if (i == 5) {"
9077 " m = 'len';"
9078 " saved_result = result;"
9079 " };"
9080 " result = o[m]('239');"
9081 "}");
9082 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9083 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9084}
9085
9086// Test the map transition before the interceptor.
9087THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9088 v8::HandleScope scope;
9089 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9090 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9091 LocalContext context;
9092 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9093
9094 v8::Handle<Value> value = CompileRun(
9095 "var o = new Object();"
9096 "o.__proto__ = proto;"
9097 "o.method = function(x) { return x + 1; };"
9098 "var m = 'method';"
9099 "var result = 0;"
9100 "for (var i = 0; i < 10; i++) {"
9101 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
9102 " result += o[m](41);"
9103 "}");
9104 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9105}
9106
9107
9108// Test the map transition after the interceptor.
9109THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9110 v8::HandleScope scope;
9111 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9112 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9113 LocalContext context;
9114 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9115
9116 v8::Handle<Value> value = CompileRun(
9117 "var proto = new Object();"
9118 "o.__proto__ = proto;"
9119 "proto.method = function(x) { return x + 1; };"
9120 "var m = 'method';"
9121 "var result = 0;"
9122 "for (var i = 0; i < 10; i++) {"
9123 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9124 " result += o[m](41);"
9125 "}");
9126 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9127}
9128
9129
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009130static int interceptor_call_count = 0;
9131
9132static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9133 const AccessorInfo& info) {
9134 ApiTestFuzzer::Fuzz();
9135 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9136 return call_ic_function2;
9137 }
9138 return v8::Handle<Value>();
9139}
9140
9141
9142// This test should hit load and call ICs for the interceptor case.
9143// Once in a while, the interceptor will reply that a property was not
9144// found in which case we should get a reference error.
9145THREADED_TEST(InterceptorICReferenceErrors) {
9146 v8::HandleScope scope;
9147 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9148 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9149 LocalContext context(0, templ, v8::Handle<Value>());
9150 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9151 v8::Handle<Value> value = CompileRun(
9152 "function f() {"
9153 " for (var i = 0; i < 1000; i++) {"
9154 " try { x; } catch(e) { return true; }"
9155 " }"
9156 " return false;"
9157 "};"
9158 "f();");
9159 CHECK_EQ(true, value->BooleanValue());
9160 interceptor_call_count = 0;
9161 value = CompileRun(
9162 "function g() {"
9163 " for (var i = 0; i < 1000; i++) {"
9164 " try { x(42); } catch(e) { return true; }"
9165 " }"
9166 " return false;"
9167 "};"
9168 "g();");
9169 CHECK_EQ(true, value->BooleanValue());
9170}
9171
9172
9173static int interceptor_ic_exception_get_count = 0;
9174
9175static v8::Handle<Value> InterceptorICExceptionGetter(
9176 Local<String> name,
9177 const AccessorInfo& info) {
9178 ApiTestFuzzer::Fuzz();
9179 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9180 return call_ic_function3;
9181 }
9182 if (interceptor_ic_exception_get_count == 20) {
9183 return v8::ThrowException(v8_num(42));
9184 }
9185 // Do not handle get for properties other than x.
9186 return v8::Handle<Value>();
9187}
9188
9189// Test interceptor load/call IC where the interceptor throws an
9190// exception once in a while.
9191THREADED_TEST(InterceptorICGetterExceptions) {
9192 interceptor_ic_exception_get_count = 0;
9193 v8::HandleScope scope;
9194 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9195 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9196 LocalContext context(0, templ, v8::Handle<Value>());
9197 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9198 v8::Handle<Value> value = CompileRun(
9199 "function f() {"
9200 " for (var i = 0; i < 100; i++) {"
9201 " try { x; } catch(e) { return true; }"
9202 " }"
9203 " return false;"
9204 "};"
9205 "f();");
9206 CHECK_EQ(true, value->BooleanValue());
9207 interceptor_ic_exception_get_count = 0;
9208 value = CompileRun(
9209 "function f() {"
9210 " for (var i = 0; i < 100; i++) {"
9211 " try { x(42); } catch(e) { return true; }"
9212 " }"
9213 " return false;"
9214 "};"
9215 "f();");
9216 CHECK_EQ(true, value->BooleanValue());
9217}
9218
9219
9220static int interceptor_ic_exception_set_count = 0;
9221
9222static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009223 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009224 ApiTestFuzzer::Fuzz();
9225 if (++interceptor_ic_exception_set_count > 20) {
9226 return v8::ThrowException(v8_num(42));
9227 }
9228 // Do not actually handle setting.
9229 return v8::Handle<Value>();
9230}
9231
9232// Test interceptor store IC where the interceptor throws an exception
9233// once in a while.
9234THREADED_TEST(InterceptorICSetterExceptions) {
9235 interceptor_ic_exception_set_count = 0;
9236 v8::HandleScope scope;
9237 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9238 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9239 LocalContext context(0, templ, v8::Handle<Value>());
9240 v8::Handle<Value> value = CompileRun(
9241 "function f() {"
9242 " for (var i = 0; i < 100; i++) {"
9243 " try { x = 42; } catch(e) { return true; }"
9244 " }"
9245 " return false;"
9246 "};"
9247 "f();");
9248 CHECK_EQ(true, value->BooleanValue());
9249}
9250
9251
9252// Test that we ignore null interceptors.
9253THREADED_TEST(NullNamedInterceptor) {
9254 v8::HandleScope scope;
9255 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9256 templ->SetNamedPropertyHandler(0);
9257 LocalContext context;
9258 templ->Set("x", v8_num(42));
9259 v8::Handle<v8::Object> obj = templ->NewInstance();
9260 context->Global()->Set(v8_str("obj"), obj);
9261 v8::Handle<Value> value = CompileRun("obj.x");
9262 CHECK(value->IsInt32());
9263 CHECK_EQ(42, value->Int32Value());
9264}
9265
9266
9267// Test that we ignore null interceptors.
9268THREADED_TEST(NullIndexedInterceptor) {
9269 v8::HandleScope scope;
9270 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9271 templ->SetIndexedPropertyHandler(0);
9272 LocalContext context;
9273 templ->Set("42", v8_num(42));
9274 v8::Handle<v8::Object> obj = templ->NewInstance();
9275 context->Global()->Set(v8_str("obj"), obj);
9276 v8::Handle<Value> value = CompileRun("obj[42]");
9277 CHECK(value->IsInt32());
9278 CHECK_EQ(42, value->Int32Value());
9279}
9280
9281
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009282THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9283 v8::HandleScope scope;
9284 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9285 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9286 LocalContext env;
9287 env->Global()->Set(v8_str("obj"),
9288 templ->GetFunction()->NewInstance());
9289 ExpectTrue("obj.x === 42");
9290 ExpectTrue("!obj.propertyIsEnumerable('x')");
9291}
9292
9293
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009294static Handle<Value> ThrowingGetter(Local<String> name,
9295 const AccessorInfo& info) {
9296 ApiTestFuzzer::Fuzz();
9297 ThrowException(Handle<Value>());
9298 return Undefined();
9299}
9300
9301
9302THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9303 HandleScope scope;
9304 LocalContext context;
9305
9306 Local<FunctionTemplate> templ = FunctionTemplate::New();
9307 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9308 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9309
9310 Local<Object> instance = templ->GetFunction()->NewInstance();
9311
9312 Local<Object> another = Object::New();
9313 another->SetPrototype(instance);
9314
9315 Local<Object> with_js_getter = CompileRun(
9316 "o = {};\n"
9317 "o.__defineGetter__('f', function() { throw undefined; });\n"
9318 "o\n").As<Object>();
9319 CHECK(!with_js_getter.IsEmpty());
9320
9321 TryCatch try_catch;
9322
9323 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9324 CHECK(try_catch.HasCaught());
9325 try_catch.Reset();
9326 CHECK(result.IsEmpty());
9327
9328 result = another->GetRealNamedProperty(v8_str("f"));
9329 CHECK(try_catch.HasCaught());
9330 try_catch.Reset();
9331 CHECK(result.IsEmpty());
9332
9333 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9334 CHECK(try_catch.HasCaught());
9335 try_catch.Reset();
9336 CHECK(result.IsEmpty());
9337
9338 result = another->Get(v8_str("f"));
9339 CHECK(try_catch.HasCaught());
9340 try_catch.Reset();
9341 CHECK(result.IsEmpty());
9342
9343 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9344 CHECK(try_catch.HasCaught());
9345 try_catch.Reset();
9346 CHECK(result.IsEmpty());
9347
9348 result = with_js_getter->Get(v8_str("f"));
9349 CHECK(try_catch.HasCaught());
9350 try_catch.Reset();
9351 CHECK(result.IsEmpty());
9352}
9353
9354
9355static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9356 TryCatch try_catch;
9357 // Verboseness is important: it triggers message delivery which can call into
9358 // external code.
9359 try_catch.SetVerbose(true);
9360 CompileRun("throw 'from JS';");
9361 CHECK(try_catch.HasCaught());
9362 CHECK(!i::Isolate::Current()->has_pending_exception());
9363 CHECK(!i::Isolate::Current()->has_scheduled_exception());
9364 return Undefined();
9365}
9366
9367
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009368static int call_depth;
9369
9370
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009371static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9372 TryCatch try_catch;
9373}
9374
9375
9376static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009377 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009378}
9379
9380
9381static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009382 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009383}
9384
9385
9386static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9387 Handle<String> errorMessageString = message->Get();
9388 CHECK(!errorMessageString.IsEmpty());
9389 message->GetStackTrace();
9390 message->GetScriptResourceName();
9391}
9392
9393THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9394 HandleScope scope;
9395 LocalContext context;
9396
9397 Local<Function> func =
9398 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9399 context->Global()->Set(v8_str("func"), func);
9400
9401 MessageCallback callbacks[] =
9402 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9403 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9404 MessageCallback callback = callbacks[i];
9405 if (callback != NULL) {
9406 V8::AddMessageListener(callback);
9407 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00009408 // Some small number to control number of times message handler should
9409 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009410 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009411 ExpectFalse(
9412 "var thrown = false;\n"
9413 "try { func(); } catch(e) { thrown = true; }\n"
9414 "thrown\n");
9415 if (callback != NULL) {
9416 V8::RemoveMessageListeners(callback);
9417 }
9418 }
9419}
9420
9421
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009422static v8::Handle<Value> ParentGetter(Local<String> name,
9423 const AccessorInfo& info) {
9424 ApiTestFuzzer::Fuzz();
9425 return v8_num(1);
9426}
9427
9428
9429static v8::Handle<Value> ChildGetter(Local<String> name,
9430 const AccessorInfo& info) {
9431 ApiTestFuzzer::Fuzz();
9432 return v8_num(42);
9433}
9434
9435
9436THREADED_TEST(Overriding) {
9437 v8::HandleScope scope;
9438 LocalContext context;
9439
9440 // Parent template.
9441 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9442 Local<ObjectTemplate> parent_instance_templ =
9443 parent_templ->InstanceTemplate();
9444 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9445
9446 // Template that inherits from the parent template.
9447 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9448 Local<ObjectTemplate> child_instance_templ =
9449 child_templ->InstanceTemplate();
9450 child_templ->Inherit(parent_templ);
9451 // Override 'f'. The child version of 'f' should get called for child
9452 // instances.
9453 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9454 // Add 'g' twice. The 'g' added last should get called for instances.
9455 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9456 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9457
9458 // Add 'h' as an accessor to the proto template with ReadOnly attributes
9459 // so 'h' can be shadowed on the instance object.
9460 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9461 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9462 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9463
9464 // Add 'i' as an accessor to the instance template with ReadOnly attributes
9465 // but the attribute does not have effect because it is duplicated with
9466 // NULL setter.
9467 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9468 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9469
9470
9471
9472 // Instantiate the child template.
9473 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9474
9475 // Check that the child function overrides the parent one.
9476 context->Global()->Set(v8_str("o"), instance);
9477 Local<Value> value = v8_compile("o.f")->Run();
9478 // Check that the 'g' that was added last is hit.
9479 CHECK_EQ(42, value->Int32Value());
9480 value = v8_compile("o.g")->Run();
9481 CHECK_EQ(42, value->Int32Value());
9482
9483 // Check 'h' can be shadowed.
9484 value = v8_compile("o.h = 3; o.h")->Run();
9485 CHECK_EQ(3, value->Int32Value());
9486
9487 // Check 'i' is cannot be shadowed or changed.
9488 value = v8_compile("o.i = 3; o.i")->Run();
9489 CHECK_EQ(42, value->Int32Value());
9490}
9491
9492
9493static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9494 ApiTestFuzzer::Fuzz();
9495 if (args.IsConstructCall()) {
9496 return v8::Boolean::New(true);
9497 }
9498 return v8::Boolean::New(false);
9499}
9500
9501
9502THREADED_TEST(IsConstructCall) {
9503 v8::HandleScope scope;
9504
9505 // Function template with call handler.
9506 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9507 templ->SetCallHandler(IsConstructHandler);
9508
9509 LocalContext context;
9510
9511 context->Global()->Set(v8_str("f"), templ->GetFunction());
9512 Local<Value> value = v8_compile("f()")->Run();
9513 CHECK(!value->BooleanValue());
9514 value = v8_compile("new f()")->Run();
9515 CHECK(value->BooleanValue());
9516}
9517
9518
9519THREADED_TEST(ObjectProtoToString) {
9520 v8::HandleScope scope;
9521 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9522 templ->SetClassName(v8_str("MyClass"));
9523
9524 LocalContext context;
9525
9526 Local<String> customized_tostring = v8_str("customized toString");
9527
9528 // Replace Object.prototype.toString
9529 v8_compile("Object.prototype.toString = function() {"
9530 " return 'customized toString';"
9531 "}")->Run();
9532
9533 // Normal ToString call should call replaced Object.prototype.toString
9534 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9535 Local<String> value = instance->ToString();
9536 CHECK(value->IsString() && value->Equals(customized_tostring));
9537
9538 // ObjectProtoToString should not call replace toString function.
9539 value = instance->ObjectProtoToString();
9540 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9541
9542 // Check global
9543 value = context->Global()->ObjectProtoToString();
9544 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9545
9546 // Check ordinary object
9547 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009548 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009549 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9550}
9551
9552
ager@chromium.orgbeb25712010-11-29 08:02:25 +00009553THREADED_TEST(ObjectGetConstructorName) {
9554 v8::HandleScope scope;
9555 LocalContext context;
9556 v8_compile("function Parent() {};"
9557 "function Child() {};"
9558 "Child.prototype = new Parent();"
9559 "var outer = { inner: function() { } };"
9560 "var p = new Parent();"
9561 "var c = new Child();"
9562 "var x = new outer.inner();")->Run();
9563
9564 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9565 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9566 v8_str("Parent")));
9567
9568 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9569 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9570 v8_str("Child")));
9571
9572 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9573 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9574 v8_str("outer.inner")));
9575}
9576
9577
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009578bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009579i::Semaphore* ApiTestFuzzer::all_tests_done_=
9580 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009581int ApiTestFuzzer::active_tests_;
9582int ApiTestFuzzer::tests_being_run_;
9583int ApiTestFuzzer::current_;
9584
9585
9586// We are in a callback and want to switch to another thread (if we
9587// are currently running the thread fuzzing test).
9588void ApiTestFuzzer::Fuzz() {
9589 if (!fuzzing_) return;
9590 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9591 test->ContextSwitch();
9592}
9593
9594
9595// Let the next thread go. Since it is also waiting on the V8 lock it may
9596// not start immediately.
9597bool ApiTestFuzzer::NextThread() {
9598 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009599 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009600 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009601 if (kLogThreading)
9602 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009603 return false;
9604 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009605 if (kLogThreading) {
9606 printf("Switch from %s to %s\n",
9607 test_name,
9608 RegisterThreadedTest::nth(test_position)->name());
9609 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009610 current_ = test_position;
9611 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
9612 return true;
9613}
9614
9615
9616void ApiTestFuzzer::Run() {
9617 // When it is our turn...
9618 gate_->Wait();
9619 {
9620 // ... get the V8 lock and start running the test.
9621 v8::Locker locker;
9622 CallTest();
9623 }
9624 // This test finished.
9625 active_ = false;
9626 active_tests_--;
9627 // If it was the last then signal that fact.
9628 if (active_tests_ == 0) {
9629 all_tests_done_->Signal();
9630 } else {
9631 // Otherwise select a new test and start that.
9632 NextThread();
9633 }
9634}
9635
9636
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009637static unsigned linear_congruential_generator;
9638
9639
9640void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009641 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009642 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +00009643 int count = RegisterThreadedTest::count();
9644 int start = count * part / (LAST_PART + 1);
9645 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
9646 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009647 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009648 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009649 }
9650 for (int i = 0; i < active_tests_; i++) {
9651 RegisterThreadedTest::nth(i)->fuzzer_->Start();
9652 }
9653}
9654
9655
9656static void CallTestNumber(int test_number) {
9657 (RegisterThreadedTest::nth(test_number)->callback())();
9658}
9659
9660
9661void ApiTestFuzzer::RunAllTests() {
9662 // Set off the first test.
9663 current_ = -1;
9664 NextThread();
9665 // Wait till they are all done.
9666 all_tests_done_->Wait();
9667}
9668
9669
9670int ApiTestFuzzer::GetNextTestNumber() {
9671 int next_test;
9672 do {
9673 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
9674 linear_congruential_generator *= 1664525u;
9675 linear_congruential_generator += 1013904223u;
9676 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
9677 return next_test;
9678}
9679
9680
9681void ApiTestFuzzer::ContextSwitch() {
9682 // If the new thread is the same as the current thread there is nothing to do.
9683 if (NextThread()) {
9684 // Now it can start.
9685 v8::Unlocker unlocker;
9686 // Wait till someone starts us again.
9687 gate_->Wait();
9688 // And we're off.
9689 }
9690}
9691
9692
9693void ApiTestFuzzer::TearDown() {
9694 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00009695 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
9696 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
9697 if (fuzzer != NULL) fuzzer->Join();
9698 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009699}
9700
9701
9702// Lets not be needlessly self-referential.
9703TEST(Threading) {
9704 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
9705 ApiTestFuzzer::RunAllTests();
9706 ApiTestFuzzer::TearDown();
9707}
9708
9709TEST(Threading2) {
9710 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
9711 ApiTestFuzzer::RunAllTests();
9712 ApiTestFuzzer::TearDown();
9713}
9714
lrn@chromium.org1c092762011-05-09 09:42:16 +00009715TEST(Threading3) {
9716 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
9717 ApiTestFuzzer::RunAllTests();
9718 ApiTestFuzzer::TearDown();
9719}
9720
9721TEST(Threading4) {
9722 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
9723 ApiTestFuzzer::RunAllTests();
9724 ApiTestFuzzer::TearDown();
9725}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009726
9727void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009728 if (kLogThreading)
9729 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009730 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009731 if (kLogThreading)
9732 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009733}
9734
9735
9736static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009737 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009738 ApiTestFuzzer::Fuzz();
9739 v8::Unlocker unlocker;
9740 const char* code = "throw 7;";
9741 {
9742 v8::Locker nested_locker;
9743 v8::HandleScope scope;
9744 v8::Handle<Value> exception;
9745 { v8::TryCatch try_catch;
9746 v8::Handle<Value> value = CompileRun(code);
9747 CHECK(value.IsEmpty());
9748 CHECK(try_catch.HasCaught());
9749 // Make sure to wrap the exception in a new handle because
9750 // the handle returned from the TryCatch is destroyed
9751 // when the TryCatch is destroyed.
9752 exception = Local<Value>::New(try_catch.Exception());
9753 }
9754 return v8::ThrowException(exception);
9755 }
9756}
9757
9758
9759static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009760 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009761 ApiTestFuzzer::Fuzz();
9762 v8::Unlocker unlocker;
9763 const char* code = "throw 7;";
9764 {
9765 v8::Locker nested_locker;
9766 v8::HandleScope scope;
9767 v8::Handle<Value> value = CompileRun(code);
9768 CHECK(value.IsEmpty());
9769 return v8_str("foo");
9770 }
9771}
9772
9773
9774// These are locking tests that don't need to be run again
9775// as part of the locking aggregation tests.
9776TEST(NestedLockers) {
9777 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009778 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009779 v8::HandleScope scope;
9780 LocalContext env;
9781 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
9782 Local<Function> fun = fun_templ->GetFunction();
9783 env->Global()->Set(v8_str("throw_in_js"), fun);
9784 Local<Script> script = v8_compile("(function () {"
9785 " try {"
9786 " throw_in_js();"
9787 " return 42;"
9788 " } catch (e) {"
9789 " return e * 13;"
9790 " }"
9791 "})();");
9792 CHECK_EQ(91, script->Run()->Int32Value());
9793}
9794
9795
9796// These are locking tests that don't need to be run again
9797// as part of the locking aggregation tests.
9798TEST(NestedLockersNoTryCatch) {
9799 v8::Locker locker;
9800 v8::HandleScope scope;
9801 LocalContext env;
9802 Local<v8::FunctionTemplate> fun_templ =
9803 v8::FunctionTemplate::New(ThrowInJSNoCatch);
9804 Local<Function> fun = fun_templ->GetFunction();
9805 env->Global()->Set(v8_str("throw_in_js"), fun);
9806 Local<Script> script = v8_compile("(function () {"
9807 " try {"
9808 " throw_in_js();"
9809 " return 42;"
9810 " } catch (e) {"
9811 " return e * 13;"
9812 " }"
9813 "})();");
9814 CHECK_EQ(91, script->Run()->Int32Value());
9815}
9816
9817
9818THREADED_TEST(RecursiveLocking) {
9819 v8::Locker locker;
9820 {
9821 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009822 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009823 }
9824}
9825
9826
9827static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
9828 ApiTestFuzzer::Fuzz();
9829 v8::Unlocker unlocker;
9830 return v8::Undefined();
9831}
9832
9833
9834THREADED_TEST(LockUnlockLock) {
9835 {
9836 v8::Locker locker;
9837 v8::HandleScope scope;
9838 LocalContext env;
9839 Local<v8::FunctionTemplate> fun_templ =
9840 v8::FunctionTemplate::New(UnlockForAMoment);
9841 Local<Function> fun = fun_templ->GetFunction();
9842 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9843 Local<Script> script = v8_compile("(function () {"
9844 " unlock_for_a_moment();"
9845 " return 42;"
9846 "})();");
9847 CHECK_EQ(42, script->Run()->Int32Value());
9848 }
9849 {
9850 v8::Locker locker;
9851 v8::HandleScope scope;
9852 LocalContext env;
9853 Local<v8::FunctionTemplate> fun_templ =
9854 v8::FunctionTemplate::New(UnlockForAMoment);
9855 Local<Function> fun = fun_templ->GetFunction();
9856 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
9857 Local<Script> script = v8_compile("(function () {"
9858 " unlock_for_a_moment();"
9859 " return 42;"
9860 "})();");
9861 CHECK_EQ(42, script->Run()->Int32Value());
9862 }
9863}
9864
9865
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009866static int GetGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009867 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009868 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009869 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
9870 if (object->IsJSGlobalObject()) count++;
9871 return count;
9872}
9873
9874
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009875static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009876 // We need to collect all garbage twice to be sure that everything
9877 // has been collected. This is because inline caches are cleared in
9878 // the first garbage collection but some of the maps have already
9879 // been marked at that point. Therefore some of the maps are not
9880 // collected until the second garbage collection.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009881 HEAP->global_context_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 HEAP->CollectAllGarbage(false);
9883 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009884 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009885#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009886 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009887#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009888 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009889}
9890
9891
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009892TEST(DontLeakGlobalObjects) {
9893 // Regression test for issues 1139850 and 1174891.
9894
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009895 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009896
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009897 for (int i = 0; i < 5; i++) {
9898 { v8::HandleScope scope;
9899 LocalContext context;
9900 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009901 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009902
9903 { v8::HandleScope scope;
9904 LocalContext context;
9905 v8_compile("Date")->Run();
9906 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009907 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009908
9909 { v8::HandleScope scope;
9910 LocalContext context;
9911 v8_compile("/aaa/")->Run();
9912 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009913 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009914
9915 { v8::HandleScope scope;
9916 const char* extension_list[] = { "v8/gc" };
9917 v8::ExtensionConfiguration extensions(1, extension_list);
9918 LocalContext context(&extensions);
9919 v8_compile("gc();")->Run();
9920 }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00009921 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009922 }
9923}
9924
9925
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009926v8::Persistent<v8::Object> some_object;
9927v8::Persistent<v8::Object> bad_handle;
9928
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009929void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009930 v8::HandleScope scope;
9931 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009932 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009933}
9934
9935
9936THREADED_TEST(NewPersistentHandleFromWeakCallback) {
9937 LocalContext context;
9938
9939 v8::Persistent<v8::Object> handle1, handle2;
9940 {
9941 v8::HandleScope scope;
9942 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
9943 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9944 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9945 }
9946 // Note: order is implementation dependent alas: currently
9947 // global handle nodes are processed by PostGarbageCollectionProcessing
9948 // in reverse allocation order, so if second allocated handle is deleted,
9949 // weak callback of the first handle would be able to 'reallocate' it.
9950 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
9951 handle2.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009953}
9954
9955
9956v8::Persistent<v8::Object> to_be_disposed;
9957
9958void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
9959 to_be_disposed.Dispose();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960 HEAP->CollectAllGarbage(false);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009961 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009962}
9963
9964
9965THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
9966 LocalContext context;
9967
9968 v8::Persistent<v8::Object> handle1, handle2;
9969 {
9970 v8::HandleScope scope;
9971 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9972 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9973 }
9974 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
9975 to_be_disposed = handle2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 HEAP->CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00009977}
9978
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009979void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
9980 handle.Dispose();
9981}
9982
9983void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
9984 v8::HandleScope scope;
9985 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00009986 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009987}
9988
9989
9990THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
9991 LocalContext context;
9992
9993 v8::Persistent<v8::Object> handle1, handle2, handle3;
9994 {
9995 v8::HandleScope scope;
9996 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
9997 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
9998 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
9999 }
10000 handle2.MakeWeak(NULL, DisposingCallback);
10001 handle3.MakeWeak(NULL, HandleCreatingCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 HEAP->CollectAllGarbage(false);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010003}
10004
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000010005
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010006THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010007 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010008
10009 const int nof = 2;
10010 const char* sources[nof] = {
10011 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10012 "Object()"
10013 };
10014
10015 for (int i = 0; i < nof; i++) {
10016 const char* source = sources[i];
10017 { v8::HandleScope scope;
10018 LocalContext context;
10019 CompileRun(source);
10020 }
10021 { v8::HandleScope scope;
10022 LocalContext context;
10023 CompileRun(source);
10024 }
10025 }
10026}
10027
10028
10029static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10030 v8::HandleScope inner;
10031 env->Enter();
10032 v8::Handle<Value> three = v8_num(3);
10033 v8::Handle<Value> value = inner.Close(three);
10034 env->Exit();
10035 return value;
10036}
10037
10038
10039THREADED_TEST(NestedHandleScopeAndContexts) {
10040 v8::HandleScope outer;
10041 v8::Persistent<Context> env = Context::New();
10042 env->Enter();
10043 v8::Handle<Value> value = NestedScope(env);
10044 v8::Handle<String> str = value->ToString();
10045 env->Exit();
10046 env.Dispose();
10047}
10048
10049
10050THREADED_TEST(ExternalAllocatedMemory) {
10051 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +000010052 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010053 const int kSize = 1024*1024;
10054 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10055 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10056}
10057
10058
10059THREADED_TEST(DisposeEnteredContext) {
10060 v8::HandleScope scope;
10061 LocalContext outer;
10062 { v8::Persistent<v8::Context> inner = v8::Context::New();
10063 inner->Enter();
10064 inner.Dispose();
10065 inner.Clear();
10066 inner->Exit();
10067 }
10068}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010069
10070
10071// Regression test for issue 54, object templates with internal fields
10072// but no accessors or interceptors did not get their internal field
10073// count set on instances.
10074THREADED_TEST(Regress54) {
10075 v8::HandleScope outer;
10076 LocalContext context;
10077 static v8::Persistent<v8::ObjectTemplate> templ;
10078 if (templ.IsEmpty()) {
10079 v8::HandleScope inner;
10080 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10081 local->SetInternalFieldCount(1);
10082 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10083 }
10084 v8::Handle<v8::Object> result = templ->NewInstance();
10085 CHECK_EQ(1, result->InternalFieldCount());
10086}
10087
10088
10089// If part of the threaded tests, this test makes ThreadingTest fail
10090// on mac.
10091TEST(CatchStackOverflow) {
10092 v8::HandleScope scope;
10093 LocalContext context;
10094 v8::TryCatch try_catch;
10095 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10096 "function f() {"
10097 " return f();"
10098 "}"
10099 ""
10100 "f();"));
10101 v8::Handle<v8::Value> result = script->Run();
10102 CHECK(result.IsEmpty());
10103}
10104
10105
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010106static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10107 const char* resource_name,
10108 int line_offset) {
10109 v8::HandleScope scope;
10110 v8::TryCatch try_catch;
10111 v8::Handle<v8::Value> result = script->Run();
10112 CHECK(result.IsEmpty());
10113 CHECK(try_catch.HasCaught());
10114 v8::Handle<v8::Message> message = try_catch.Message();
10115 CHECK(!message.IsEmpty());
10116 CHECK_EQ(10 + line_offset, message->GetLineNumber());
10117 CHECK_EQ(91, message->GetStartPosition());
10118 CHECK_EQ(92, message->GetEndPosition());
10119 CHECK_EQ(2, message->GetStartColumn());
10120 CHECK_EQ(3, message->GetEndColumn());
10121 v8::String::AsciiValue line(message->GetSourceLine());
10122 CHECK_EQ(" throw 'nirk';", *line);
10123 v8::String::AsciiValue name(message->GetScriptResourceName());
10124 CHECK_EQ(resource_name, *name);
10125}
10126
10127
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010128THREADED_TEST(TryCatchSourceInfo) {
10129 v8::HandleScope scope;
10130 LocalContext context;
10131 v8::Handle<v8::String> source = v8::String::New(
10132 "function Foo() {\n"
10133 " return Bar();\n"
10134 "}\n"
10135 "\n"
10136 "function Bar() {\n"
10137 " return Baz();\n"
10138 "}\n"
10139 "\n"
10140 "function Baz() {\n"
10141 " throw 'nirk';\n"
10142 "}\n"
10143 "\n"
10144 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010145
10146 const char* resource_name;
10147 v8::Handle<v8::Script> script;
10148 resource_name = "test.js";
10149 script = v8::Script::Compile(source, v8::String::New(resource_name));
10150 CheckTryCatchSourceInfo(script, resource_name, 0);
10151
10152 resource_name = "test1.js";
10153 v8::ScriptOrigin origin1(v8::String::New(resource_name));
10154 script = v8::Script::Compile(source, &origin1);
10155 CheckTryCatchSourceInfo(script, resource_name, 0);
10156
10157 resource_name = "test2.js";
10158 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10159 script = v8::Script::Compile(source, &origin2);
10160 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010161}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010162
10163
10164THREADED_TEST(CompilationCache) {
10165 v8::HandleScope scope;
10166 LocalContext context;
10167 v8::Handle<v8::String> source0 = v8::String::New("1234");
10168 v8::Handle<v8::String> source1 = v8::String::New("1234");
10169 v8::Handle<v8::Script> script0 =
10170 v8::Script::Compile(source0, v8::String::New("test.js"));
10171 v8::Handle<v8::Script> script1 =
10172 v8::Script::Compile(source1, v8::String::New("test.js"));
10173 v8::Handle<v8::Script> script2 =
10174 v8::Script::Compile(source0); // different origin
10175 CHECK_EQ(1234, script0->Run()->Int32Value());
10176 CHECK_EQ(1234, script1->Run()->Int32Value());
10177 CHECK_EQ(1234, script2->Run()->Int32Value());
10178}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000010179
10180
10181static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10182 ApiTestFuzzer::Fuzz();
10183 return v8_num(42);
10184}
10185
10186
10187THREADED_TEST(CallbackFunctionName) {
10188 v8::HandleScope scope;
10189 LocalContext context;
10190 Local<ObjectTemplate> t = ObjectTemplate::New();
10191 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10192 context->Global()->Set(v8_str("obj"), t->NewInstance());
10193 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10194 CHECK(value->IsString());
10195 v8::String::AsciiValue name(value);
10196 CHECK_EQ("asdf", *name);
10197}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010198
10199
10200THREADED_TEST(DateAccess) {
10201 v8::HandleScope scope;
10202 LocalContext context;
10203 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10204 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010205 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010206}
10207
10208
10209void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010210 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010211 v8::Handle<v8::Array> props = obj->GetPropertyNames();
10212 CHECK_EQ(elmc, props->Length());
10213 for (int i = 0; i < elmc; i++) {
10214 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10215 CHECK_EQ(elmv[i], *elm);
10216 }
10217}
10218
10219
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010220void CheckOwnProperties(v8::Handle<v8::Value> val,
10221 int elmc,
10222 const char* elmv[]) {
10223 v8::Handle<v8::Object> obj = val.As<v8::Object>();
10224 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10225 CHECK_EQ(elmc, props->Length());
10226 for (int i = 0; i < elmc; i++) {
10227 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10228 CHECK_EQ(elmv[i], *elm);
10229 }
10230}
10231
10232
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010233THREADED_TEST(PropertyEnumeration) {
10234 v8::HandleScope scope;
10235 LocalContext context;
10236 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10237 "var result = [];"
10238 "result[0] = {};"
10239 "result[1] = {a: 1, b: 2};"
10240 "result[2] = [1, 2, 3];"
10241 "var proto = {x: 1, y: 2, z: 3};"
10242 "var x = { __proto__: proto, w: 0, z: 1 };"
10243 "result[3] = x;"
10244 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010245 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010246 CHECK_EQ(4, elms->Length());
10247 int elmc0 = 0;
10248 const char** elmv0 = NULL;
10249 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010250 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010251 int elmc1 = 2;
10252 const char* elmv1[] = {"a", "b"};
10253 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010254 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010255 int elmc2 = 3;
10256 const char* elmv2[] = {"0", "1", "2"};
10257 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010258 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010259 int elmc3 = 4;
10260 const char* elmv3[] = {"w", "z", "x", "y"};
10261 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010262 int elmc4 = 2;
10263 const char* elmv4[] = {"w", "z"};
10264 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010265}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010267THREADED_TEST(PropertyEnumeration2) {
10268 v8::HandleScope scope;
10269 LocalContext context;
10270 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10271 "var result = [];"
10272 "result[0] = {};"
10273 "result[1] = {a: 1, b: 2};"
10274 "result[2] = [1, 2, 3];"
10275 "var proto = {x: 1, y: 2, z: 3};"
10276 "var x = { __proto__: proto, w: 0, z: 1 };"
10277 "result[3] = x;"
10278 "result;"))->Run();
10279 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10280 CHECK_EQ(4, elms->Length());
10281 int elmc0 = 0;
10282 const char** elmv0 = NULL;
10283 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10284
10285 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10286 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10287 CHECK_EQ(0, props->Length());
10288 for (uint32_t i = 0; i < props->Length(); i++) {
10289 printf("p[%d]\n", i);
10290 }
10291}
ager@chromium.org870a0b62008-11-04 11:43:05 +000010292
ager@chromium.org870a0b62008-11-04 11:43:05 +000010293static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10294 Local<Value> name,
10295 v8::AccessType type,
10296 Local<Value> data) {
10297 return type != v8::ACCESS_SET;
10298}
10299
10300
10301static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10302 uint32_t key,
10303 v8::AccessType type,
10304 Local<Value> data) {
10305 return type != v8::ACCESS_SET;
10306}
10307
10308
10309THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10310 v8::HandleScope scope;
10311 LocalContext context;
10312 Local<ObjectTemplate> templ = ObjectTemplate::New();
10313 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10314 IndexedSetAccessBlocker);
10315 templ->Set(v8_str("x"), v8::True());
10316 Local<v8::Object> instance = templ->NewInstance();
10317 context->Global()->Set(v8_str("obj"), instance);
10318 Local<Value> value = CompileRun("obj.x");
10319 CHECK(value->BooleanValue());
10320}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010321
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010322
ager@chromium.org32912102009-01-16 10:38:43 +000010323static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10324 Local<Value> name,
10325 v8::AccessType type,
10326 Local<Value> data) {
10327 return false;
10328}
10329
10330
10331static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10332 uint32_t key,
10333 v8::AccessType type,
10334 Local<Value> data) {
10335 return false;
10336}
10337
10338
10339
10340THREADED_TEST(AccessChecksReenabledCorrectly) {
10341 v8::HandleScope scope;
10342 LocalContext context;
10343 Local<ObjectTemplate> templ = ObjectTemplate::New();
10344 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10345 IndexedGetAccessBlocker);
10346 templ->Set(v8_str("a"), v8_str("a"));
10347 // Add more than 8 (see kMaxFastProperties) properties
10348 // so that the constructor will force copying map.
10349 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010350 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000010351 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010352 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000010353 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010354 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000010355 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010356 buf[2] = k;
10357 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000010358 templ->Set(v8_str(buf), v8::Number::New(k));
10359 }
10360 }
10361 }
10362
10363 Local<v8::Object> instance_1 = templ->NewInstance();
10364 context->Global()->Set(v8_str("obj_1"), instance_1);
10365
10366 Local<Value> value_1 = CompileRun("obj_1.a");
10367 CHECK(value_1->IsUndefined());
10368
10369 Local<v8::Object> instance_2 = templ->NewInstance();
10370 context->Global()->Set(v8_str("obj_2"), instance_2);
10371
10372 Local<Value> value_2 = CompileRun("obj_2.a");
10373 CHECK(value_2->IsUndefined());
10374}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010375
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010376
ager@chromium.org8bb60582008-12-11 12:02:20 +000010377// This tests that access check information remains on the global
10378// object template when creating contexts.
10379THREADED_TEST(AccessControlRepeatedContextCreation) {
10380 v8::HandleScope handle_scope;
10381 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10382 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10383 IndexedSetAccessBlocker);
10384 i::Handle<i::ObjectTemplateInfo> internal_template =
10385 v8::Utils::OpenHandle(*global_template);
10386 CHECK(!internal_template->constructor()->IsUndefined());
10387 i::Handle<i::FunctionTemplateInfo> constructor(
10388 i::FunctionTemplateInfo::cast(internal_template->constructor()));
10389 CHECK(!constructor->access_check_info()->IsUndefined());
10390 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
10391 CHECK(!constructor->access_check_info()->IsUndefined());
10392}
10393
10394
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010395THREADED_TEST(TurnOnAccessCheck) {
10396 v8::HandleScope handle_scope;
10397
10398 // Create an environment with access check to the global object disabled by
10399 // default.
10400 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10401 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10402 IndexedGetAccessBlocker,
10403 v8::Handle<v8::Value>(),
10404 false);
10405 v8::Persistent<Context> context = Context::New(NULL, global_template);
10406 Context::Scope context_scope(context);
10407
10408 // Set up a property and a number of functions.
10409 context->Global()->Set(v8_str("a"), v8_num(1));
10410 CompileRun("function f1() {return a;}"
10411 "function f2() {return a;}"
10412 "function g1() {return h();}"
10413 "function g2() {return h();}"
10414 "function h() {return 1;}");
10415 Local<Function> f1 =
10416 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10417 Local<Function> f2 =
10418 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10419 Local<Function> g1 =
10420 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10421 Local<Function> g2 =
10422 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10423 Local<Function> h =
10424 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10425
10426 // Get the global object.
10427 v8::Handle<v8::Object> global = context->Global();
10428
10429 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10430 // uses the runtime system to retreive property a whereas f2 uses global load
10431 // inline cache.
10432 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10433 for (int i = 0; i < 4; i++) {
10434 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10435 }
10436
10437 // Same for g1 and g2.
10438 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10439 for (int i = 0; i < 4; i++) {
10440 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10441 }
10442
10443 // Detach the global and turn on access check.
10444 context->DetachGlobal();
10445 context->Global()->TurnOnAccessCheck();
10446
10447 // Failing access check to property get results in undefined.
10448 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10449 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10450
10451 // Failing access check to function call results in exception.
10452 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10453 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10454
10455 // No failing access check when just returning a constant.
10456 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10457}
10458
10459
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010460v8::Handle<v8::String> a;
10461v8::Handle<v8::String> h;
10462
10463static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10464 Local<Value> name,
10465 v8::AccessType type,
10466 Local<Value> data) {
10467 return !(name->Equals(a) || name->Equals(h));
10468}
10469
10470
10471THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10472 v8::HandleScope handle_scope;
10473
10474 // Create an environment with access check to the global object disabled by
10475 // default. When the registered access checker will block access to properties
10476 // a and h
10477 a = v8_str("a");
10478 h = v8_str("h");
10479 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10480 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10481 IndexedGetAccessBlocker,
10482 v8::Handle<v8::Value>(),
10483 false);
10484 v8::Persistent<Context> context = Context::New(NULL, global_template);
10485 Context::Scope context_scope(context);
10486
10487 // Set up a property and a number of functions.
10488 context->Global()->Set(v8_str("a"), v8_num(1));
10489 static const char* source = "function f1() {return a;}"
10490 "function f2() {return a;}"
10491 "function g1() {return h();}"
10492 "function g2() {return h();}"
10493 "function h() {return 1;}";
10494
10495 CompileRun(source);
10496 Local<Function> f1;
10497 Local<Function> f2;
10498 Local<Function> g1;
10499 Local<Function> g2;
10500 Local<Function> h;
10501 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10502 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10503 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10504 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10505 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10506
10507 // Get the global object.
10508 v8::Handle<v8::Object> global = context->Global();
10509
10510 // Call f1 one time and f2 a number of times. This will ensure that f1 still
10511 // uses the runtime system to retreive property a whereas f2 uses global load
10512 // inline cache.
10513 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10514 for (int i = 0; i < 4; i++) {
10515 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10516 }
10517
10518 // Same for g1 and g2.
10519 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10520 for (int i = 0; i < 4; i++) {
10521 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10522 }
10523
10524 // Detach the global and turn on access check now blocking access to property
10525 // a and function h.
10526 context->DetachGlobal();
10527 context->Global()->TurnOnAccessCheck();
10528
10529 // Failing access check to property get results in undefined.
10530 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10531 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10532
10533 // Failing access check to function call results in exception.
10534 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10535 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10536
10537 // No failing access check when just returning a constant.
10538 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10539
10540 // Now compile the source again. And get the newly compiled functions, except
10541 // for h for which access is blocked.
10542 CompileRun(source);
10543 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10544 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10545 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10546 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10547 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10548
10549 // Failing access check to property get results in undefined.
10550 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10551 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10552
10553 // Failing access check to function call results in exception.
10554 CHECK(g1->Call(global, 0, NULL).IsEmpty());
10555 CHECK(g2->Call(global, 0, NULL).IsEmpty());
10556}
10557
10558
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010559// This test verifies that pre-compilation (aka preparsing) can be called
10560// without initializing the whole VM. Thus we cannot run this test in a
10561// multi-threaded setup.
10562TEST(PreCompile) {
10563 // TODO(155): This test would break without the initialization of V8. This is
10564 // a workaround for now to make this test not fail.
10565 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010566 const char* script = "function foo(a) { return a+1; }";
10567 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010568 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010569 CHECK_NE(sd->Length(), 0);
10570 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010571 CHECK(!sd->HasError());
10572 delete sd;
10573}
10574
10575
10576TEST(PreCompileWithError) {
10577 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010578 const char* script = "function foo(a) { return 1 * * 2; }";
10579 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010580 v8::ScriptData::PreCompile(script, i::StrLength(script));
10581 CHECK(sd->HasError());
10582 delete sd;
10583}
10584
10585
10586TEST(Regress31661) {
10587 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010588 const char* script = " The Definintive Guide";
10589 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010590 v8::ScriptData::PreCompile(script, i::StrLength(script));
10591 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010592 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010593}
10594
10595
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000010596// Tests that ScriptData can be serialized and deserialized.
10597TEST(PreCompileSerialization) {
10598 v8::V8::Initialize();
10599 const char* script = "function foo(a) { return a+1; }";
10600 v8::ScriptData* sd =
10601 v8::ScriptData::PreCompile(script, i::StrLength(script));
10602
10603 // Serialize.
10604 int serialized_data_length = sd->Length();
10605 char* serialized_data = i::NewArray<char>(serialized_data_length);
10606 memcpy(serialized_data, sd->Data(), serialized_data_length);
10607
10608 // Deserialize.
10609 v8::ScriptData* deserialized_sd =
10610 v8::ScriptData::New(serialized_data, serialized_data_length);
10611
10612 // Verify that the original is the same as the deserialized.
10613 CHECK_EQ(sd->Length(), deserialized_sd->Length());
10614 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
10615 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
10616
10617 delete sd;
10618 delete deserialized_sd;
10619}
10620
10621
10622// Attempts to deserialize bad data.
10623TEST(PreCompileDeserializationError) {
10624 v8::V8::Initialize();
10625 const char* data = "DONT CARE";
10626 int invalid_size = 3;
10627 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
10628
10629 CHECK_EQ(0, sd->Length());
10630
10631 delete sd;
10632}
10633
10634
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010635// Attempts to deserialize bad data.
10636TEST(PreCompileInvalidPreparseDataError) {
10637 v8::V8::Initialize();
10638 v8::HandleScope scope;
10639 LocalContext context;
10640
10641 const char* script = "function foo(){ return 5;}\n"
10642 "function bar(){ return 6 + 7;} foo();";
10643 v8::ScriptData* sd =
10644 v8::ScriptData::PreCompile(script, i::StrLength(script));
10645 CHECK(!sd->HasError());
10646 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010647 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000010648 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010649 const int kFunctionEntryStartOffset = 0;
10650 const int kFunctionEntryEndOffset = 1;
10651 unsigned* sd_data =
10652 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010653
10654 // Overwrite function bar's end position with 0.
10655 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
10656 v8::TryCatch try_catch;
10657
10658 Local<String> source = String::New(script);
10659 Local<Script> compiled_script = Script::New(source, NULL, sd);
10660 CHECK(try_catch.HasCaught());
10661 String::AsciiValue exception_value(try_catch.Message()->Get());
10662 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
10663 *exception_value);
10664
10665 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010666
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010667 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010668 // will not be found when searching for it by position and we should fall
10669 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000010670 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
10671 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010672 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
10673 200;
10674 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010675 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000010676
10677 delete sd;
10678}
10679
10680
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010681// Verifies that the Handle<String> and const char* versions of the API produce
10682// the same results (at least for one trivial case).
10683TEST(PreCompileAPIVariationsAreSame) {
10684 v8::V8::Initialize();
10685 v8::HandleScope scope;
10686
10687 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010688
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010689 v8::ScriptData* sd_from_cstring =
10690 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
10691
10692 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010693 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010694 v8::String::NewExternal(resource));
10695
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010696 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
10697 v8::String::New(cstring));
10698
10699 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010700 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010701 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010702 sd_from_cstring->Length()));
10703
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010704 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
10705 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
10706 sd_from_string->Data(),
10707 sd_from_cstring->Length()));
10708
10709
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010710 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010711 delete sd_from_external_string;
10712 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010713}
10714
10715
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010716// This tests that we do not allow dictionary load/call inline caches
10717// to use functions that have not yet been compiled. The potential
10718// problem of loading a function that has not yet been compiled can
10719// arise because we share code between contexts via the compilation
10720// cache.
10721THREADED_TEST(DictionaryICLoadedFunction) {
10722 v8::HandleScope scope;
10723 // Test LoadIC.
10724 for (int i = 0; i < 2; i++) {
10725 LocalContext context;
10726 context->Global()->Set(v8_str("tmp"), v8::True());
10727 context->Global()->Delete(v8_str("tmp"));
10728 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
10729 }
10730 // Test CallIC.
10731 for (int i = 0; i < 2; i++) {
10732 LocalContext context;
10733 context->Global()->Set(v8_str("tmp"), v8::True());
10734 context->Global()->Delete(v8_str("tmp"));
10735 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
10736 }
10737}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010738
10739
10740// Test that cross-context new calls use the context of the callee to
10741// create the new JavaScript object.
10742THREADED_TEST(CrossContextNew) {
10743 v8::HandleScope scope;
10744 v8::Persistent<Context> context0 = Context::New();
10745 v8::Persistent<Context> context1 = Context::New();
10746
10747 // Allow cross-domain access.
10748 Local<String> token = v8_str("<security token>");
10749 context0->SetSecurityToken(token);
10750 context1->SetSecurityToken(token);
10751
10752 // Set an 'x' property on the Object prototype and define a
10753 // constructor function in context0.
10754 context0->Enter();
10755 CompileRun("Object.prototype.x = 42; function C() {};");
10756 context0->Exit();
10757
10758 // Call the constructor function from context0 and check that the
10759 // result has the 'x' property.
10760 context1->Enter();
10761 context1->Global()->Set(v8_str("other"), context0->Global());
10762 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
10763 CHECK(value->IsInt32());
10764 CHECK_EQ(42, value->Int32Value());
10765 context1->Exit();
10766
10767 // Dispose the contexts to allow them to be garbage collected.
10768 context0.Dispose();
10769 context1.Dispose();
10770}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010771
10772
10773class RegExpInterruptTest {
10774 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010775 RegExpInterruptTest() : block_(NULL) {}
10776 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010777 void RunTest() {
10778 block_ = i::OS::CreateSemaphore(0);
10779 gc_count_ = 0;
10780 gc_during_regexp_ = 0;
10781 regexp_success_ = false;
10782 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010783 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010784 gc_thread.Start();
10785 v8::Locker::StartPreemption(1);
10786
10787 LongRunningRegExp();
10788 {
10789 v8::Unlocker unlock;
10790 gc_thread.Join();
10791 }
10792 v8::Locker::StopPreemption();
10793 CHECK(regexp_success_);
10794 CHECK(gc_success_);
10795 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010796
ager@chromium.org381abbb2009-02-25 13:23:22 +000010797 private:
10798 // Number of garbage collections required.
10799 static const int kRequiredGCs = 5;
10800
10801 class GCThread : public i::Thread {
10802 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010803 explicit GCThread(RegExpInterruptTest* test)
10804 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000010805 virtual void Run() {
10806 test_->CollectGarbage();
10807 }
10808 private:
10809 RegExpInterruptTest* test_;
10810 };
10811
10812 void CollectGarbage() {
10813 block_->Wait();
10814 while (gc_during_regexp_ < kRequiredGCs) {
10815 {
10816 v8::Locker lock;
10817 // TODO(lrn): Perhaps create some garbage before collecting.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010819 gc_count_++;
10820 }
10821 i::OS::Sleep(1);
10822 }
10823 gc_success_ = true;
10824 }
10825
10826 void LongRunningRegExp() {
10827 block_->Signal(); // Enable garbage collection thread on next preemption.
10828 int rounds = 0;
10829 while (gc_during_regexp_ < kRequiredGCs) {
10830 int gc_before = gc_count_;
10831 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010832 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010833 const char* c_source =
10834 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10835 ".exec('aaaaaaaaaaaaaaab') === null";
10836 Local<String> source = String::New(c_source);
10837 Local<Script> script = Script::Compile(source);
10838 Local<Value> result = script->Run();
10839 if (!result->BooleanValue()) {
10840 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
10841 return;
10842 }
10843 }
10844 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010845 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000010846 const char* c_source =
10847 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
10848 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
10849 Local<String> source = String::New(c_source);
10850 Local<Script> script = Script::Compile(source);
10851 Local<Value> result = script->Run();
10852 if (!result->BooleanValue()) {
10853 gc_during_regexp_ = kRequiredGCs;
10854 return;
10855 }
10856 }
10857 int gc_after = gc_count_;
10858 gc_during_regexp_ += gc_after - gc_before;
10859 rounds++;
10860 i::OS::Sleep(1);
10861 }
10862 regexp_success_ = true;
10863 }
10864
10865 i::Semaphore* block_;
10866 int gc_count_;
10867 int gc_during_regexp_;
10868 bool regexp_success_;
10869 bool gc_success_;
10870};
10871
10872
10873// Test that a regular expression execution can be interrupted and
10874// survive a garbage collection.
10875TEST(RegExpInterruption) {
10876 v8::Locker lock;
10877 v8::V8::Initialize();
10878 v8::HandleScope scope;
10879 Local<Context> local_env;
10880 {
10881 LocalContext env;
10882 local_env = env.local();
10883 }
10884
10885 // Local context should still be live.
10886 CHECK(!local_env.IsEmpty());
10887 local_env->Enter();
10888
10889 // Should complete without problems.
10890 RegExpInterruptTest().RunTest();
10891
10892 local_env->Exit();
10893}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010894
10895
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010896class ApplyInterruptTest {
10897 public:
10898 ApplyInterruptTest() : block_(NULL) {}
10899 ~ApplyInterruptTest() { delete block_; }
10900 void RunTest() {
10901 block_ = i::OS::CreateSemaphore(0);
10902 gc_count_ = 0;
10903 gc_during_apply_ = 0;
10904 apply_success_ = false;
10905 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010906 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010907 gc_thread.Start();
10908 v8::Locker::StartPreemption(1);
10909
10910 LongRunningApply();
10911 {
10912 v8::Unlocker unlock;
10913 gc_thread.Join();
10914 }
10915 v8::Locker::StopPreemption();
10916 CHECK(apply_success_);
10917 CHECK(gc_success_);
10918 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010919
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010920 private:
10921 // Number of garbage collections required.
10922 static const int kRequiredGCs = 2;
10923
10924 class GCThread : public i::Thread {
10925 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010926 explicit GCThread(ApplyInterruptTest* test)
10927 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010928 virtual void Run() {
10929 test_->CollectGarbage();
10930 }
10931 private:
10932 ApplyInterruptTest* test_;
10933 };
10934
10935 void CollectGarbage() {
10936 block_->Wait();
10937 while (gc_during_apply_ < kRequiredGCs) {
10938 {
10939 v8::Locker lock;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 HEAP->CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010941 gc_count_++;
10942 }
10943 i::OS::Sleep(1);
10944 }
10945 gc_success_ = true;
10946 }
10947
10948 void LongRunningApply() {
10949 block_->Signal();
10950 int rounds = 0;
10951 while (gc_during_apply_ < kRequiredGCs) {
10952 int gc_before = gc_count_;
10953 {
10954 const char* c_source =
10955 "function do_very_little(bar) {"
10956 " this.foo = bar;"
10957 "}"
10958 "for (var i = 0; i < 100000; i++) {"
10959 " do_very_little.apply(this, ['bar']);"
10960 "}";
10961 Local<String> source = String::New(c_source);
10962 Local<Script> script = Script::Compile(source);
10963 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000010964 // Check that no exception was thrown.
10965 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010966 }
10967 int gc_after = gc_count_;
10968 gc_during_apply_ += gc_after - gc_before;
10969 rounds++;
10970 }
10971 apply_success_ = true;
10972 }
10973
10974 i::Semaphore* block_;
10975 int gc_count_;
10976 int gc_during_apply_;
10977 bool apply_success_;
10978 bool gc_success_;
10979};
10980
10981
10982// Test that nothing bad happens if we get a preemption just when we were
10983// about to do an apply().
10984TEST(ApplyInterruption) {
10985 v8::Locker lock;
10986 v8::V8::Initialize();
10987 v8::HandleScope scope;
10988 Local<Context> local_env;
10989 {
10990 LocalContext env;
10991 local_env = env.local();
10992 }
10993
10994 // Local context should still be live.
10995 CHECK(!local_env.IsEmpty());
10996 local_env->Enter();
10997
10998 // Should complete without problems.
10999 ApplyInterruptTest().RunTest();
11000
11001 local_env->Exit();
11002}
11003
11004
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011005// Verify that we can clone an object
11006TEST(ObjectClone) {
11007 v8::HandleScope scope;
11008 LocalContext env;
11009
11010 const char* sample =
11011 "var rv = {};" \
11012 "rv.alpha = 'hello';" \
11013 "rv.beta = 123;" \
11014 "rv;";
11015
11016 // Create an object, verify basics.
11017 Local<Value> val = CompileRun(sample);
11018 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011019 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000011020 obj->Set(v8_str("gamma"), v8_str("cloneme"));
11021
11022 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11023 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11024 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11025
11026 // Clone it.
11027 Local<v8::Object> clone = obj->Clone();
11028 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11029 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11030 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11031
11032 // Set a property on the clone, verify each object.
11033 clone->Set(v8_str("beta"), v8::Integer::New(456));
11034 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11035 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11036}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011037
11038
ager@chromium.org5ec48922009-05-05 07:25:34 +000011039class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11040 public:
11041 explicit AsciiVectorResource(i::Vector<const char> vector)
11042 : data_(vector) {}
11043 virtual ~AsciiVectorResource() {}
11044 virtual size_t length() const { return data_.length(); }
11045 virtual const char* data() const { return data_.start(); }
11046 private:
11047 i::Vector<const char> data_;
11048};
11049
11050
11051class UC16VectorResource : public v8::String::ExternalStringResource {
11052 public:
11053 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11054 : data_(vector) {}
11055 virtual ~UC16VectorResource() {}
11056 virtual size_t length() const { return data_.length(); }
11057 virtual const i::uc16* data() const { return data_.start(); }
11058 private:
11059 i::Vector<const i::uc16> data_;
11060};
11061
11062
11063static void MorphAString(i::String* string,
11064 AsciiVectorResource* ascii_resource,
11065 UC16VectorResource* uc16_resource) {
11066 CHECK(i::StringShape(string).IsExternal());
11067 if (string->IsAsciiRepresentation()) {
11068 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011069 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011070 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011071 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011072 i::ExternalTwoByteString* morphed =
11073 i::ExternalTwoByteString::cast(string);
11074 morphed->set_resource(uc16_resource);
11075 } else {
11076 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011077 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011078 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011079 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011080 i::ExternalAsciiString* morphed =
11081 i::ExternalAsciiString::cast(string);
11082 morphed->set_resource(ascii_resource);
11083 }
11084}
11085
11086
11087// Test that we can still flatten a string if the components it is built up
11088// from have been turned into 16 bit strings in the mean time.
11089THREADED_TEST(MorphCompositeStringTest) {
11090 const char* c_string = "Now is the time for all good men"
11091 " to come to the aid of the party";
11092 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11093 {
11094 v8::HandleScope scope;
11095 LocalContext env;
11096 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011097 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011098 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011099 i::Vector<const uint16_t>(two_byte_string,
11100 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011101
11102 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011104 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000011106
11107 env->Global()->Set(v8_str("lhs"), lhs);
11108 env->Global()->Set(v8_str("rhs"), rhs);
11109
11110 CompileRun(
11111 "var cons = lhs + rhs;"
11112 "var slice = lhs.substring(1, lhs.length - 1);"
11113 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11114
11115 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11116 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11117
11118 // Now do some stuff to make sure the strings are flattened, etc.
11119 CompileRun(
11120 "/[^a-z]/.test(cons);"
11121 "/[^a-z]/.test(slice);"
11122 "/[^a-z]/.test(slice_on_cons);");
11123 const char* expected_cons =
11124 "Now is the time for all good men to come to the aid of the party"
11125 "Now is the time for all good men to come to the aid of the party";
11126 const char* expected_slice =
11127 "ow is the time for all good men to come to the aid of the part";
11128 const char* expected_slice_on_cons =
11129 "ow is the time for all good men to come to the aid of the party"
11130 "Now is the time for all good men to come to the aid of the part";
11131 CHECK_EQ(String::New(expected_cons),
11132 env->Global()->Get(v8_str("cons")));
11133 CHECK_EQ(String::New(expected_slice),
11134 env->Global()->Get(v8_str("slice")));
11135 CHECK_EQ(String::New(expected_slice_on_cons),
11136 env->Global()->Get(v8_str("slice_on_cons")));
11137 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011138 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011139}
11140
11141
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011142TEST(CompileExternalTwoByteSource) {
11143 v8::HandleScope scope;
11144 LocalContext context;
11145
11146 // This is a very short list of sources, which currently is to check for a
11147 // regression caused by r2703.
11148 const char* ascii_sources[] = {
11149 "0.5",
11150 "-0.5", // This mainly testes PushBack in the Scanner.
11151 "--0.5", // This mainly testes PushBack in the Scanner.
11152 NULL
11153 };
11154
11155 // Compile the sources as external two byte strings.
11156 for (int i = 0; ascii_sources[i] != NULL; i++) {
11157 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11158 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011159 i::Vector<const uint16_t>(two_byte_string,
11160 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011161 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11162 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011163 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011164 }
11165}
11166
11167
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011168class RegExpStringModificationTest {
11169 public:
11170 RegExpStringModificationTest()
11171 : block_(i::OS::CreateSemaphore(0)),
11172 morphs_(0),
11173 morphs_during_regexp_(0),
11174 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11175 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11176 ~RegExpStringModificationTest() { delete block_; }
11177 void RunTest() {
11178 regexp_success_ = false;
11179 morph_success_ = false;
11180
11181 // Initialize the contents of two_byte_content_ to be a uc16 representation
11182 // of "aaaaaaaaaaaaaab".
11183 for (int i = 0; i < 14; i++) {
11184 two_byte_content_[i] = 'a';
11185 }
11186 two_byte_content_[14] = 'b';
11187
11188 // Create the input string for the regexp - the one we are going to change
11189 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011190 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011191
11192 // Inject the input as a global variable.
11193 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11195 i::Isolate::Current()->global_context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011196 *input_name,
11197 *input_,
11198 NONE,
11199 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011200
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011201 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011202 morph_thread.Start();
11203 v8::Locker::StartPreemption(1);
11204 LongRunningRegExp();
11205 {
11206 v8::Unlocker unlock;
11207 morph_thread.Join();
11208 }
11209 v8::Locker::StopPreemption();
11210 CHECK(regexp_success_);
11211 CHECK(morph_success_);
11212 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011213
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011214 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011215 // Number of string modifications required.
11216 static const int kRequiredModifications = 5;
11217 static const int kMaxModifications = 100;
11218
11219 class MorphThread : public i::Thread {
11220 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011221 explicit MorphThread(RegExpStringModificationTest* test)
11222 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011223 virtual void Run() {
11224 test_->MorphString();
11225 }
11226 private:
11227 RegExpStringModificationTest* test_;
11228 };
11229
11230 void MorphString() {
11231 block_->Wait();
11232 while (morphs_during_regexp_ < kRequiredModifications &&
11233 morphs_ < kMaxModifications) {
11234 {
11235 v8::Locker lock;
11236 // Swap string between ascii and two-byte representation.
11237 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000011238 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011239 morphs_++;
11240 }
11241 i::OS::Sleep(1);
11242 }
11243 morph_success_ = true;
11244 }
11245
11246 void LongRunningRegExp() {
11247 block_->Signal(); // Enable morphing thread on next preemption.
11248 while (morphs_during_regexp_ < kRequiredModifications &&
11249 morphs_ < kMaxModifications) {
11250 int morphs_before = morphs_;
11251 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000011252 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011253 // Match 15-30 "a"'s against 14 and a "b".
11254 const char* c_source =
11255 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11256 ".exec(input) === null";
11257 Local<String> source = String::New(c_source);
11258 Local<Script> script = Script::Compile(source);
11259 Local<Value> result = script->Run();
11260 CHECK(result->IsTrue());
11261 }
11262 int morphs_after = morphs_;
11263 morphs_during_regexp_ += morphs_after - morphs_before;
11264 }
11265 regexp_success_ = true;
11266 }
11267
11268 i::uc16 two_byte_content_[15];
11269 i::Semaphore* block_;
11270 int morphs_;
11271 int morphs_during_regexp_;
11272 bool regexp_success_;
11273 bool morph_success_;
11274 i::Handle<i::String> input_;
11275 AsciiVectorResource ascii_resource_;
11276 UC16VectorResource uc16_resource_;
11277};
11278
11279
11280// Test that a regular expression execution can be interrupted and
11281// the string changed without failing.
11282TEST(RegExpStringModification) {
11283 v8::Locker lock;
11284 v8::V8::Initialize();
11285 v8::HandleScope scope;
11286 Local<Context> local_env;
11287 {
11288 LocalContext env;
11289 local_env = env.local();
11290 }
11291
11292 // Local context should still be live.
11293 CHECK(!local_env.IsEmpty());
11294 local_env->Enter();
11295
11296 // Should complete without problems.
11297 RegExpStringModificationTest().RunTest();
11298
11299 local_env->Exit();
11300}
11301
11302
11303// Test that we can set a property on the global object even if there
11304// is a read-only property in the prototype chain.
11305TEST(ReadOnlyPropertyInGlobalProto) {
11306 v8::HandleScope scope;
11307 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11308 LocalContext context(0, templ);
11309 v8::Handle<v8::Object> global = context->Global();
11310 v8::Handle<v8::Object> global_proto =
11311 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11312 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11313 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11314 // Check without 'eval' or 'with'.
11315 v8::Handle<v8::Value> res =
11316 CompileRun("function f() { x = 42; return x; }; f()");
11317 // Check with 'eval'.
11318 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11319 CHECK_EQ(v8::Integer::New(42), res);
11320 // Check with 'with'.
11321 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11322 CHECK_EQ(v8::Integer::New(42), res);
11323}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011324
11325static int force_set_set_count = 0;
11326static int force_set_get_count = 0;
11327bool pass_on_get = false;
11328
11329static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11330 const v8::AccessorInfo& info) {
11331 force_set_get_count++;
11332 if (pass_on_get) {
11333 return v8::Handle<v8::Value>();
11334 } else {
11335 return v8::Int32::New(3);
11336 }
11337}
11338
11339static void ForceSetSetter(v8::Local<v8::String> name,
11340 v8::Local<v8::Value> value,
11341 const v8::AccessorInfo& info) {
11342 force_set_set_count++;
11343}
11344
11345static v8::Handle<v8::Value> ForceSetInterceptSetter(
11346 v8::Local<v8::String> name,
11347 v8::Local<v8::Value> value,
11348 const v8::AccessorInfo& info) {
11349 force_set_set_count++;
11350 return v8::Undefined();
11351}
11352
11353TEST(ForceSet) {
11354 force_set_get_count = 0;
11355 force_set_set_count = 0;
11356 pass_on_get = false;
11357
11358 v8::HandleScope scope;
11359 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11360 v8::Handle<v8::String> access_property = v8::String::New("a");
11361 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11362 LocalContext context(NULL, templ);
11363 v8::Handle<v8::Object> global = context->Global();
11364
11365 // Ordinary properties
11366 v8::Handle<v8::String> simple_property = v8::String::New("p");
11367 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11368 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11369 // This should fail because the property is read-only
11370 global->Set(simple_property, v8::Int32::New(5));
11371 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11372 // This should succeed even though the property is read-only
11373 global->ForceSet(simple_property, v8::Int32::New(6));
11374 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11375
11376 // Accessors
11377 CHECK_EQ(0, force_set_set_count);
11378 CHECK_EQ(0, force_set_get_count);
11379 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11380 // CHECK_EQ the property shouldn't override it, just call the setter
11381 // which in this case does nothing.
11382 global->Set(access_property, v8::Int32::New(7));
11383 CHECK_EQ(3, global->Get(access_property)->Int32Value());
11384 CHECK_EQ(1, force_set_set_count);
11385 CHECK_EQ(2, force_set_get_count);
11386 // Forcing the property to be set should override the accessor without
11387 // calling it
11388 global->ForceSet(access_property, v8::Int32::New(8));
11389 CHECK_EQ(8, global->Get(access_property)->Int32Value());
11390 CHECK_EQ(1, force_set_set_count);
11391 CHECK_EQ(2, force_set_get_count);
11392}
11393
11394TEST(ForceSetWithInterceptor) {
11395 force_set_get_count = 0;
11396 force_set_set_count = 0;
11397 pass_on_get = false;
11398
11399 v8::HandleScope scope;
11400 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11401 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11402 LocalContext context(NULL, templ);
11403 v8::Handle<v8::Object> global = context->Global();
11404
11405 v8::Handle<v8::String> some_property = v8::String::New("a");
11406 CHECK_EQ(0, force_set_set_count);
11407 CHECK_EQ(0, force_set_get_count);
11408 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11409 // Setting the property shouldn't override it, just call the setter
11410 // which in this case does nothing.
11411 global->Set(some_property, v8::Int32::New(7));
11412 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11413 CHECK_EQ(1, force_set_set_count);
11414 CHECK_EQ(2, force_set_get_count);
11415 // Getting the property when the interceptor returns an empty handle
11416 // should yield undefined, since the property isn't present on the
11417 // object itself yet.
11418 pass_on_get = true;
11419 CHECK(global->Get(some_property)->IsUndefined());
11420 CHECK_EQ(1, force_set_set_count);
11421 CHECK_EQ(3, force_set_get_count);
11422 // Forcing the property to be set should cause the value to be
11423 // set locally without calling the interceptor.
11424 global->ForceSet(some_property, v8::Int32::New(8));
11425 CHECK_EQ(8, global->Get(some_property)->Int32Value());
11426 CHECK_EQ(1, force_set_set_count);
11427 CHECK_EQ(4, force_set_get_count);
11428 // Reenabling the interceptor should cause it to take precedence over
11429 // the property
11430 pass_on_get = false;
11431 CHECK_EQ(3, global->Get(some_property)->Int32Value());
11432 CHECK_EQ(1, force_set_set_count);
11433 CHECK_EQ(5, force_set_get_count);
11434 // The interceptor should also work for other properties
11435 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11436 CHECK_EQ(1, force_set_set_count);
11437 CHECK_EQ(6, force_set_get_count);
11438}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011439
11440
ager@chromium.orge2902be2009-06-08 12:21:35 +000011441THREADED_TEST(ForceDelete) {
11442 v8::HandleScope scope;
11443 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11444 LocalContext context(NULL, templ);
11445 v8::Handle<v8::Object> global = context->Global();
11446
11447 // Ordinary properties
11448 v8::Handle<v8::String> simple_property = v8::String::New("p");
11449 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11450 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11451 // This should fail because the property is dont-delete.
11452 CHECK(!global->Delete(simple_property));
11453 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11454 // This should succeed even though the property is dont-delete.
11455 CHECK(global->ForceDelete(simple_property));
11456 CHECK(global->Get(simple_property)->IsUndefined());
11457}
11458
11459
11460static int force_delete_interceptor_count = 0;
11461static bool pass_on_delete = false;
11462
11463
11464static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11465 v8::Local<v8::String> name,
11466 const v8::AccessorInfo& info) {
11467 force_delete_interceptor_count++;
11468 if (pass_on_delete) {
11469 return v8::Handle<v8::Boolean>();
11470 } else {
11471 return v8::True();
11472 }
11473}
11474
11475
11476THREADED_TEST(ForceDeleteWithInterceptor) {
11477 force_delete_interceptor_count = 0;
11478 pass_on_delete = false;
11479
11480 v8::HandleScope scope;
11481 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11482 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11483 LocalContext context(NULL, templ);
11484 v8::Handle<v8::Object> global = context->Global();
11485
11486 v8::Handle<v8::String> some_property = v8::String::New("a");
11487 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11488
11489 // Deleting a property should get intercepted and nothing should
11490 // happen.
11491 CHECK_EQ(0, force_delete_interceptor_count);
11492 CHECK(global->Delete(some_property));
11493 CHECK_EQ(1, force_delete_interceptor_count);
11494 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11495 // Deleting the property when the interceptor returns an empty
11496 // handle should not delete the property since it is DontDelete.
11497 pass_on_delete = true;
11498 CHECK(!global->Delete(some_property));
11499 CHECK_EQ(2, force_delete_interceptor_count);
11500 CHECK_EQ(42, global->Get(some_property)->Int32Value());
11501 // Forcing the property to be deleted should delete the value
11502 // without calling the interceptor.
11503 CHECK(global->ForceDelete(some_property));
11504 CHECK(global->Get(some_property)->IsUndefined());
11505 CHECK_EQ(2, force_delete_interceptor_count);
11506}
11507
11508
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011509// Make sure that forcing a delete invalidates any IC stubs, so we
11510// don't read the hole value.
11511THREADED_TEST(ForceDeleteIC) {
11512 v8::HandleScope scope;
11513 LocalContext context;
11514 // Create a DontDelete variable on the global object.
11515 CompileRun("this.__proto__ = { foo: 'horse' };"
11516 "var foo = 'fish';"
11517 "function f() { return foo.length; }");
11518 // Initialize the IC for foo in f.
11519 CompileRun("for (var i = 0; i < 4; i++) f();");
11520 // Make sure the value of foo is correct before the deletion.
11521 CHECK_EQ(4, CompileRun("f()")->Int32Value());
11522 // Force the deletion of foo.
11523 CHECK(context->Global()->ForceDelete(v8_str("foo")));
11524 // Make sure the value for foo is read from the prototype, and that
11525 // we don't get in trouble with reading the deleted cell value
11526 // sentinel.
11527 CHECK_EQ(5, CompileRun("f()")->Int32Value());
11528}
11529
11530
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000011531v8::Persistent<Context> calling_context0;
11532v8::Persistent<Context> calling_context1;
11533v8::Persistent<Context> calling_context2;
11534
11535
11536// Check that the call to the callback is initiated in
11537// calling_context2, the directly calling context is calling_context1
11538// and the callback itself is in calling_context0.
11539static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11540 ApiTestFuzzer::Fuzz();
11541 CHECK(Context::GetCurrent() == calling_context0);
11542 CHECK(Context::GetCalling() == calling_context1);
11543 CHECK(Context::GetEntered() == calling_context2);
11544 return v8::Integer::New(42);
11545}
11546
11547
11548THREADED_TEST(GetCallingContext) {
11549 v8::HandleScope scope;
11550
11551 calling_context0 = Context::New();
11552 calling_context1 = Context::New();
11553 calling_context2 = Context::New();
11554
11555 // Allow cross-domain access.
11556 Local<String> token = v8_str("<security token>");
11557 calling_context0->SetSecurityToken(token);
11558 calling_context1->SetSecurityToken(token);
11559 calling_context2->SetSecurityToken(token);
11560
11561 // Create an object with a C++ callback in context0.
11562 calling_context0->Enter();
11563 Local<v8::FunctionTemplate> callback_templ =
11564 v8::FunctionTemplate::New(GetCallingContextCallback);
11565 calling_context0->Global()->Set(v8_str("callback"),
11566 callback_templ->GetFunction());
11567 calling_context0->Exit();
11568
11569 // Expose context0 in context1 and setup a function that calls the
11570 // callback function.
11571 calling_context1->Enter();
11572 calling_context1->Global()->Set(v8_str("context0"),
11573 calling_context0->Global());
11574 CompileRun("function f() { context0.callback() }");
11575 calling_context1->Exit();
11576
11577 // Expose context1 in context2 and call the callback function in
11578 // context0 indirectly through f in context1.
11579 calling_context2->Enter();
11580 calling_context2->Global()->Set(v8_str("context1"),
11581 calling_context1->Global());
11582 CompileRun("context1.f()");
11583 calling_context2->Exit();
11584
11585 // Dispose the contexts to allow them to be garbage collected.
11586 calling_context0.Dispose();
11587 calling_context1.Dispose();
11588 calling_context2.Dispose();
11589 calling_context0.Clear();
11590 calling_context1.Clear();
11591 calling_context2.Clear();
11592}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011593
11594
11595// Check that a variable declaration with no explicit initialization
11596// value does not shadow an existing property in the prototype chain.
11597//
11598// This is consistent with Firefox and Safari.
11599//
11600// See http://crbug.com/12548.
11601THREADED_TEST(InitGlobalVarInProtoChain) {
11602 v8::HandleScope scope;
11603 LocalContext context;
11604 // Introduce a variable in the prototype chain.
11605 CompileRun("__proto__.x = 42");
11606 v8::Handle<v8::Value> result = CompileRun("var x; x");
11607 CHECK(!result->IsUndefined());
11608 CHECK_EQ(42, result->Int32Value());
11609}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000011610
11611
11612// Regression test for issue 398.
11613// If a function is added to an object, creating a constant function
11614// field, and the result is cloned, replacing the constant function on the
11615// original should not affect the clone.
11616// See http://code.google.com/p/v8/issues/detail?id=398
11617THREADED_TEST(ReplaceConstantFunction) {
11618 v8::HandleScope scope;
11619 LocalContext context;
11620 v8::Handle<v8::Object> obj = v8::Object::New();
11621 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
11622 v8::Handle<v8::String> foo_string = v8::String::New("foo");
11623 obj->Set(foo_string, func_templ->GetFunction());
11624 v8::Handle<v8::Object> obj_clone = obj->Clone();
11625 obj_clone->Set(foo_string, v8::String::New("Hello"));
11626 CHECK(!obj->Get(foo_string)->IsUndefined());
11627}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000011628
11629
11630// Regression test for http://crbug.com/16276.
11631THREADED_TEST(Regress16276) {
11632 v8::HandleScope scope;
11633 LocalContext context;
11634 // Force the IC in f to be a dictionary load IC.
11635 CompileRun("function f(obj) { return obj.x; }\n"
11636 "var obj = { x: { foo: 42 }, y: 87 };\n"
11637 "var x = obj.x;\n"
11638 "delete obj.y;\n"
11639 "for (var i = 0; i < 5; i++) f(obj);");
11640 // Detach the global object to make 'this' refer directly to the
11641 // global object (not the proxy), and make sure that the dictionary
11642 // load IC doesn't mess up loading directly from the global object.
11643 context->DetachGlobal();
11644 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
11645}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011646
11647
11648THREADED_TEST(PixelArray) {
11649 v8::HandleScope scope;
11650 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011651 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011652 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011653 i::Handle<i::ExternalPixelArray> pixels =
11654 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 FACTORY->NewExternalArray(kElementCount,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011656 v8::kExternalPixelArray,
11657 pixel_data));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011659 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011660 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011663 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011664 CHECK_EQ(i % 256, pixels->get(i));
11665 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011666 }
11667
11668 v8::Handle<v8::Object> obj = v8::Object::New();
11669 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
11670 // Set the elements to be the pixels.
11671 // jsobj->set_elements(*pixels);
11672 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011673 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011674 obj->Set(v8_str("field"), v8::Int32::New(1503));
11675 context->Global()->Set(v8_str("pixels"), obj);
11676 v8::Handle<v8::Value> result = CompileRun("pixels.field");
11677 CHECK_EQ(1503, result->Int32Value());
11678 result = CompileRun("pixels[1]");
11679 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011680
11681 result = CompileRun("var sum = 0;"
11682 "for (var i = 0; i < 8; i++) {"
11683 " sum += pixels[i] = pixels[i] = -i;"
11684 "}"
11685 "sum;");
11686 CHECK_EQ(-28, result->Int32Value());
11687
11688 result = CompileRun("var sum = 0;"
11689 "for (var i = 0; i < 8; i++) {"
11690 " sum += pixels[i] = pixels[i] = 0;"
11691 "}"
11692 "sum;");
11693 CHECK_EQ(0, result->Int32Value());
11694
11695 result = CompileRun("var sum = 0;"
11696 "for (var i = 0; i < 8; i++) {"
11697 " sum += pixels[i] = pixels[i] = 255;"
11698 "}"
11699 "sum;");
11700 CHECK_EQ(8 * 255, result->Int32Value());
11701
11702 result = CompileRun("var sum = 0;"
11703 "for (var i = 0; i < 8; i++) {"
11704 " sum += pixels[i] = pixels[i] = 256 + i;"
11705 "}"
11706 "sum;");
11707 CHECK_EQ(2076, result->Int32Value());
11708
11709 result = CompileRun("var sum = 0;"
11710 "for (var i = 0; i < 8; i++) {"
11711 " sum += pixels[i] = pixels[i] = i;"
11712 "}"
11713 "sum;");
11714 CHECK_EQ(28, result->Int32Value());
11715
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011716 result = CompileRun("var sum = 0;"
11717 "for (var i = 0; i < 8; i++) {"
11718 " sum += pixels[i];"
11719 "}"
11720 "sum;");
11721 CHECK_EQ(28, result->Int32Value());
11722
11723 i::Handle<i::Smi> value(i::Smi::FromInt(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011724 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011725 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011726 *value.location() = i::Smi::FromInt(256);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011727 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011728 CHECK_EQ(255,
11729 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011730 *value.location() = i::Smi::FromInt(-1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011731 i::SetElement(jsobj, 1, value, i::kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011732 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011733
11734 result = CompileRun("for (var i = 0; i < 8; i++) {"
11735 " pixels[i] = (i * 65) - 109;"
11736 "}"
11737 "pixels[1] + pixels[6];");
11738 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011739 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11740 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11741 CHECK_EQ(21,
11742 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11743 CHECK_EQ(86,
11744 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11745 CHECK_EQ(151,
11746 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11747 CHECK_EQ(216,
11748 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11749 CHECK_EQ(255,
11750 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11751 CHECK_EQ(255,
11752 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011753 result = CompileRun("var sum = 0;"
11754 "for (var i = 0; i < 8; i++) {"
11755 " sum += pixels[i];"
11756 "}"
11757 "sum;");
11758 CHECK_EQ(984, result->Int32Value());
11759
11760 result = CompileRun("for (var i = 0; i < 8; i++) {"
11761 " pixels[i] = (i * 1.1);"
11762 "}"
11763 "pixels[1] + pixels[6];");
11764 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011765 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
11766 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
11767 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
11768 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
11769 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
11770 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
11771 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
11772 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011773
11774 result = CompileRun("for (var i = 0; i < 8; i++) {"
11775 " pixels[7] = undefined;"
11776 "}"
11777 "pixels[7];");
11778 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011779 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011780
11781 result = CompileRun("for (var i = 0; i < 8; i++) {"
11782 " pixels[6] = '2.3';"
11783 "}"
11784 "pixels[6];");
11785 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011786 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011787
11788 result = CompileRun("for (var i = 0; i < 8; i++) {"
11789 " pixels[5] = NaN;"
11790 "}"
11791 "pixels[5];");
11792 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011793 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011794
11795 result = CompileRun("for (var i = 0; i < 8; i++) {"
11796 " pixels[8] = Infinity;"
11797 "}"
11798 "pixels[8];");
11799 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011800 CHECK_EQ(255,
11801 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011802
11803 result = CompileRun("for (var i = 0; i < 8; i++) {"
11804 " pixels[9] = -Infinity;"
11805 "}"
11806 "pixels[9];");
11807 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011808 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011809
11810 result = CompileRun("pixels[3] = 33;"
11811 "delete pixels[3];"
11812 "pixels[3];");
11813 CHECK_EQ(33, result->Int32Value());
11814
11815 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
11816 "pixels[2] = 12; pixels[3] = 13;"
11817 "pixels.__defineGetter__('2',"
11818 "function() { return 120; });"
11819 "pixels[2];");
11820 CHECK_EQ(12, result->Int32Value());
11821
11822 result = CompileRun("var js_array = new Array(40);"
11823 "js_array[0] = 77;"
11824 "js_array;");
11825 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11826
11827 result = CompileRun("pixels[1] = 23;"
11828 "pixels.__proto__ = [];"
11829 "js_array.__proto__ = pixels;"
11830 "js_array.concat(pixels);");
11831 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
11832 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
11833
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000011834 result = CompileRun("pixels[1] = 23;");
11835 CHECK_EQ(23, result->Int32Value());
11836
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011837 // Test for index greater than 255. Regression test for:
11838 // http://code.google.com/p/chromium/issues/detail?id=26337.
11839 result = CompileRun("pixels[256] = 255;");
11840 CHECK_EQ(255, result->Int32Value());
11841 result = CompileRun("var i = 0;"
11842 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
11843 "i");
11844 CHECK_EQ(255, result->Int32Value());
11845
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011846 // Make sure that pixel array ICs recognize when a non-pixel array
11847 // is passed to it.
11848 result = CompileRun("function pa_load(p) {"
11849 " var sum = 0;"
11850 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11851 " return sum;"
11852 "}"
11853 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11854 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11855 "just_ints = new Object();"
11856 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11857 "for (var i = 0; i < 10; ++i) {"
11858 " result = pa_load(just_ints);"
11859 "}"
11860 "result");
11861 CHECK_EQ(32640, result->Int32Value());
11862
11863 // Make sure that pixel array ICs recognize out-of-bound accesses.
11864 result = CompileRun("function pa_load(p, start) {"
11865 " var sum = 0;"
11866 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11867 " return sum;"
11868 "}"
11869 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11870 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11871 "for (var i = 0; i < 10; ++i) {"
11872 " result = pa_load(pixels,-10);"
11873 "}"
11874 "result");
11875 CHECK_EQ(0, result->Int32Value());
11876
11877 // Make sure that generic ICs properly handles a pixel array.
11878 result = CompileRun("function pa_load(p) {"
11879 " var sum = 0;"
11880 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11881 " return sum;"
11882 "}"
11883 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11884 "just_ints = new Object();"
11885 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11886 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11887 "for (var i = 0; i < 10; ++i) {"
11888 " result = pa_load(pixels);"
11889 "}"
11890 "result");
11891 CHECK_EQ(32640, result->Int32Value());
11892
11893 // Make sure that generic load ICs recognize out-of-bound accesses in
11894 // pixel arrays.
11895 result = CompileRun("function pa_load(p, start) {"
11896 " var sum = 0;"
11897 " for (var j = start; j < 256; j++) { sum += p[j]; }"
11898 " return sum;"
11899 "}"
11900 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11901 "just_ints = new Object();"
11902 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11903 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
11904 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
11905 "for (var i = 0; i < 10; ++i) {"
11906 " result = pa_load(pixels,-10);"
11907 "}"
11908 "result");
11909 CHECK_EQ(0, result->Int32Value());
11910
11911 // Make sure that generic ICs properly handles other types than pixel
11912 // arrays (that the inlined fast pixel array test leaves the right information
11913 // in the right registers).
11914 result = CompileRun("function pa_load(p) {"
11915 " var sum = 0;"
11916 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
11917 " return sum;"
11918 "}"
11919 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
11920 "just_ints = new Object();"
11921 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11922 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
11923 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
11924 "sparse_array = new Object();"
11925 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
11926 "sparse_array[1000000] = 3;"
11927 "for (var i = 0; i < 10; ++i) {"
11928 " result = pa_load(sparse_array);"
11929 "}"
11930 "result");
11931 CHECK_EQ(32640, result->Int32Value());
11932
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011933 // Make sure that pixel array store ICs clamp values correctly.
11934 result = CompileRun("function pa_store(p) {"
11935 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11936 "}"
11937 "pa_store(pixels);"
11938 "var sum = 0;"
11939 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11940 "sum");
11941 CHECK_EQ(48896, result->Int32Value());
11942
11943 // Make sure that pixel array stores correctly handle accesses outside
11944 // of the pixel array..
11945 result = CompileRun("function pa_store(p,start) {"
11946 " for (var j = 0; j < 256; j++) {"
11947 " p[j+start] = j * 2;"
11948 " }"
11949 "}"
11950 "pa_store(pixels,0);"
11951 "pa_store(pixels,-128);"
11952 "var sum = 0;"
11953 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11954 "sum");
11955 CHECK_EQ(65280, result->Int32Value());
11956
11957 // Make sure that the generic store stub correctly handle accesses outside
11958 // of the pixel array..
11959 result = CompileRun("function pa_store(p,start) {"
11960 " for (var j = 0; j < 256; j++) {"
11961 " p[j+start] = j * 2;"
11962 " }"
11963 "}"
11964 "pa_store(pixels,0);"
11965 "just_ints = new Object();"
11966 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
11967 "pa_store(just_ints, 0);"
11968 "pa_store(pixels,-128);"
11969 "var sum = 0;"
11970 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11971 "sum");
11972 CHECK_EQ(65280, result->Int32Value());
11973
11974 // Make sure that the generic keyed store stub clamps pixel array values
11975 // correctly.
11976 result = CompileRun("function pa_store(p) {"
11977 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
11978 "}"
11979 "pa_store(pixels);"
11980 "just_ints = new Object();"
11981 "pa_store(just_ints);"
11982 "pa_store(pixels);"
11983 "var sum = 0;"
11984 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
11985 "sum");
11986 CHECK_EQ(48896, result->Int32Value());
11987
11988 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011989 result = CompileRun("function pa_load(p) {"
11990 " var sum = 0;"
11991 " for (var i=0; i<256; ++i) {"
11992 " sum += p[i];"
11993 " }"
11994 " return sum; "
11995 "}"
11996 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011997 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011998 " result = pa_load(pixels);"
11999 "}"
12000 "result");
12001 CHECK_EQ(32640, result->Int32Value());
12002
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012003 // Make sure that pixel array stores are optimized by crankshaft.
12004 result = CompileRun("function pa_init(p) {"
12005 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12006 "}"
12007 "function pa_load(p) {"
12008 " var sum = 0;"
12009 " for (var i=0; i<256; ++i) {"
12010 " sum += p[i];"
12011 " }"
12012 " return sum; "
12013 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012014 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012015 " pa_init(pixels);"
12016 "}"
12017 "result = pa_load(pixels);"
12018 "result");
12019 CHECK_EQ(32640, result->Int32Value());
12020
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012021 free(pixel_data);
12022}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012023
ager@chromium.org96c75b52009-08-26 09:13:16 +000012024
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012025THREADED_TEST(PixelArrayInfo) {
12026 v8::HandleScope scope;
12027 LocalContext context;
12028 for (int size = 0; size < 100; size += 10) {
12029 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12030 v8::Handle<v8::Object> obj = v8::Object::New();
12031 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12032 CHECK(obj->HasIndexedPropertiesInPixelData());
12033 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12034 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12035 free(pixel_data);
12036 }
12037}
12038
12039
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012040static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12041 uint32_t index,
12042 const AccessorInfo& info) {
12043 ApiTestFuzzer::Fuzz();
12044 return v8::Handle<Value>();
12045}
12046
12047
12048static v8::Handle<Value> NotHandledIndexedPropertySetter(
12049 uint32_t index,
12050 Local<Value> value,
12051 const AccessorInfo& info) {
12052 ApiTestFuzzer::Fuzz();
12053 return v8::Handle<Value>();
12054}
12055
12056
12057THREADED_TEST(PixelArrayWithInterceptor) {
12058 v8::HandleScope scope;
12059 LocalContext context;
12060 const int kElementCount = 260;
12061 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012062 i::Handle<i::ExternalPixelArray> pixels =
12063 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012064 FACTORY->NewExternalArray(kElementCount,
12065 v8::kExternalPixelArray,
12066 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000012067 for (int i = 0; i < kElementCount; i++) {
12068 pixels->set(i, i % 256);
12069 }
12070 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12071 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12072 NotHandledIndexedPropertySetter);
12073 v8::Handle<v8::Object> obj = templ->NewInstance();
12074 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12075 context->Global()->Set(v8_str("pixels"), obj);
12076 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12077 CHECK_EQ(1, result->Int32Value());
12078 result = CompileRun("var sum = 0;"
12079 "for (var i = 0; i < 8; i++) {"
12080 " sum += pixels[i] = pixels[i] = -i;"
12081 "}"
12082 "sum;");
12083 CHECK_EQ(-28, result->Int32Value());
12084 result = CompileRun("pixels.hasOwnProperty('1')");
12085 CHECK(result->BooleanValue());
12086 free(pixel_data);
12087}
12088
12089
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012090static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12091 switch (array_type) {
12092 case v8::kExternalByteArray:
12093 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012094 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012095 return 1;
12096 break;
12097 case v8::kExternalShortArray:
12098 case v8::kExternalUnsignedShortArray:
12099 return 2;
12100 break;
12101 case v8::kExternalIntArray:
12102 case v8::kExternalUnsignedIntArray:
12103 case v8::kExternalFloatArray:
12104 return 4;
12105 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012106 case v8::kExternalDoubleArray:
12107 return 8;
12108 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012109 default:
12110 UNREACHABLE();
12111 return -1;
12112 }
12113 UNREACHABLE();
12114 return -1;
12115}
12116
12117
ager@chromium.org3811b432009-10-28 14:53:37 +000012118template <class ExternalArrayClass, class ElementType>
12119static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12120 int64_t low,
12121 int64_t high) {
12122 v8::HandleScope scope;
12123 LocalContext context;
12124 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012125 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000012126 ElementType* array_data =
12127 static_cast<ElementType*>(malloc(kElementCount * element_size));
12128 i::Handle<ExternalArrayClass> array =
12129 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12131 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012132 for (int i = 0; i < kElementCount; i++) {
12133 array->set(i, static_cast<ElementType>(i));
12134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012135 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012136 for (int i = 0; i < kElementCount; i++) {
12137 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
12138 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12139 }
12140
12141 v8::Handle<v8::Object> obj = v8::Object::New();
12142 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12143 // Set the elements to be the external array.
12144 obj->SetIndexedPropertiesToExternalArrayData(array_data,
12145 array_type,
12146 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012147 CHECK_EQ(
12148 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012149 obj->Set(v8_str("field"), v8::Int32::New(1503));
12150 context->Global()->Set(v8_str("ext_array"), obj);
12151 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12152 CHECK_EQ(1503, result->Int32Value());
12153 result = CompileRun("ext_array[1]");
12154 CHECK_EQ(1, result->Int32Value());
12155
12156 // Check pass through of assigned smis
12157 result = CompileRun("var sum = 0;"
12158 "for (var i = 0; i < 8; i++) {"
12159 " sum += ext_array[i] = ext_array[i] = -i;"
12160 "}"
12161 "sum;");
12162 CHECK_EQ(-28, result->Int32Value());
12163
12164 // Check assigned smis
12165 result = CompileRun("for (var i = 0; i < 8; i++) {"
12166 " ext_array[i] = i;"
12167 "}"
12168 "var sum = 0;"
12169 "for (var i = 0; i < 8; i++) {"
12170 " sum += ext_array[i];"
12171 "}"
12172 "sum;");
12173 CHECK_EQ(28, result->Int32Value());
12174
12175 // Check assigned smis in reverse order
12176 result = CompileRun("for (var i = 8; --i >= 0; ) {"
12177 " ext_array[i] = i;"
12178 "}"
12179 "var sum = 0;"
12180 "for (var i = 0; i < 8; i++) {"
12181 " sum += ext_array[i];"
12182 "}"
12183 "sum;");
12184 CHECK_EQ(28, result->Int32Value());
12185
12186 // Check pass through of assigned HeapNumbers
12187 result = CompileRun("var sum = 0;"
12188 "for (var i = 0; i < 16; i+=2) {"
12189 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12190 "}"
12191 "sum;");
12192 CHECK_EQ(-28, result->Int32Value());
12193
12194 // Check assigned HeapNumbers
12195 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12196 " ext_array[i] = (i * 0.5);"
12197 "}"
12198 "var sum = 0;"
12199 "for (var i = 0; i < 16; i+=2) {"
12200 " sum += ext_array[i];"
12201 "}"
12202 "sum;");
12203 CHECK_EQ(28, result->Int32Value());
12204
12205 // Check assigned HeapNumbers in reverse order
12206 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12207 " ext_array[i] = (i * 0.5);"
12208 "}"
12209 "var sum = 0;"
12210 "for (var i = 0; i < 16; i+=2) {"
12211 " sum += ext_array[i];"
12212 "}"
12213 "sum;");
12214 CHECK_EQ(28, result->Int32Value());
12215
12216 i::ScopedVector<char> test_buf(1024);
12217
12218 // Check legal boundary conditions.
12219 // The repeated loads and stores ensure the ICs are exercised.
12220 const char* boundary_program =
12221 "var res = 0;"
12222 "for (var i = 0; i < 16; i++) {"
12223 " ext_array[i] = %lld;"
12224 " if (i > 8) {"
12225 " res = ext_array[i];"
12226 " }"
12227 "}"
12228 "res;";
12229 i::OS::SNPrintF(test_buf,
12230 boundary_program,
12231 low);
12232 result = CompileRun(test_buf.start());
12233 CHECK_EQ(low, result->IntegerValue());
12234
12235 i::OS::SNPrintF(test_buf,
12236 boundary_program,
12237 high);
12238 result = CompileRun(test_buf.start());
12239 CHECK_EQ(high, result->IntegerValue());
12240
12241 // Check misprediction of type in IC.
12242 result = CompileRun("var tmp_array = ext_array;"
12243 "var sum = 0;"
12244 "for (var i = 0; i < 8; i++) {"
12245 " tmp_array[i] = i;"
12246 " sum += tmp_array[i];"
12247 " if (i == 4) {"
12248 " tmp_array = {};"
12249 " }"
12250 "}"
12251 "sum;");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 HEAP->CollectAllGarbage(false); // Force GC to trigger verification.
ager@chromium.org3811b432009-10-28 14:53:37 +000012253 CHECK_EQ(28, result->Int32Value());
12254
12255 // Make sure out-of-range loads do not throw.
12256 i::OS::SNPrintF(test_buf,
12257 "var caught_exception = false;"
12258 "try {"
12259 " ext_array[%d];"
12260 "} catch (e) {"
12261 " caught_exception = true;"
12262 "}"
12263 "caught_exception;",
12264 kElementCount);
12265 result = CompileRun(test_buf.start());
12266 CHECK_EQ(false, result->BooleanValue());
12267
12268 // Make sure out-of-range stores do not throw.
12269 i::OS::SNPrintF(test_buf,
12270 "var caught_exception = false;"
12271 "try {"
12272 " ext_array[%d] = 1;"
12273 "} catch (e) {"
12274 " caught_exception = true;"
12275 "}"
12276 "caught_exception;",
12277 kElementCount);
12278 result = CompileRun(test_buf.start());
12279 CHECK_EQ(false, result->BooleanValue());
12280
12281 // Check other boundary conditions, values and operations.
12282 result = CompileRun("for (var i = 0; i < 8; i++) {"
12283 " ext_array[7] = undefined;"
12284 "}"
12285 "ext_array[7];");
12286 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012287 CHECK_EQ(
12288 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012289
12290 result = CompileRun("for (var i = 0; i < 8; i++) {"
12291 " ext_array[6] = '2.3';"
12292 "}"
12293 "ext_array[6];");
12294 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012295 CHECK_EQ(
12296 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000012297
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012298 if (array_type != v8::kExternalFloatArray &&
12299 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012300 // Though the specification doesn't state it, be explicit about
12301 // converting NaNs and +/-Infinity to zero.
12302 result = CompileRun("for (var i = 0; i < 8; i++) {"
12303 " ext_array[i] = 5;"
12304 "}"
12305 "for (var i = 0; i < 8; i++) {"
12306 " ext_array[i] = NaN;"
12307 "}"
12308 "ext_array[5];");
12309 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012310 CHECK_EQ(0,
12311 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012312
12313 result = CompileRun("for (var i = 0; i < 8; i++) {"
12314 " ext_array[i] = 5;"
12315 "}"
12316 "for (var i = 0; i < 8; i++) {"
12317 " ext_array[i] = Infinity;"
12318 "}"
12319 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012320 int expected_value =
12321 (array_type == v8::kExternalPixelArray) ? 255 : 0;
12322 CHECK_EQ(expected_value, result->Int32Value());
12323 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012324 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000012325
12326 result = CompileRun("for (var i = 0; i < 8; i++) {"
12327 " ext_array[i] = 5;"
12328 "}"
12329 "for (var i = 0; i < 8; i++) {"
12330 " ext_array[i] = -Infinity;"
12331 "}"
12332 "ext_array[5];");
12333 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012334 CHECK_EQ(0,
12335 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012336
12337 // Check truncation behavior of integral arrays.
12338 const char* unsigned_data =
12339 "var source_data = [0.6, 10.6];"
12340 "var expected_results = [0, 10];";
12341 const char* signed_data =
12342 "var source_data = [0.6, 10.6, -0.6, -10.6];"
12343 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012344 const char* pixel_data =
12345 "var source_data = [0.6, 10.6];"
12346 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012347 bool is_unsigned =
12348 (array_type == v8::kExternalUnsignedByteArray ||
12349 array_type == v8::kExternalUnsignedShortArray ||
12350 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012351 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012352
12353 i::OS::SNPrintF(test_buf,
12354 "%s"
12355 "var all_passed = true;"
12356 "for (var i = 0; i < source_data.length; i++) {"
12357 " for (var j = 0; j < 8; j++) {"
12358 " ext_array[j] = source_data[i];"
12359 " }"
12360 " all_passed = all_passed &&"
12361 " (ext_array[5] == expected_results[i]);"
12362 "}"
12363 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012364 (is_unsigned ?
12365 unsigned_data :
12366 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000012367 result = CompileRun(test_buf.start());
12368 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000012369 }
12370
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000012371 for (int i = 0; i < kElementCount; i++) {
12372 array->set(i, static_cast<ElementType>(i));
12373 }
12374 // Test complex assignments
12375 result = CompileRun("function ee_op_test_complex_func(sum) {"
12376 " for (var i = 0; i < 40; ++i) {"
12377 " sum += (ext_array[i] += 1);"
12378 " sum += (ext_array[i] -= 1);"
12379 " } "
12380 " return sum;"
12381 "}"
12382 "sum=0;"
12383 "for (var i=0;i<10000;++i) {"
12384 " sum=ee_op_test_complex_func(sum);"
12385 "}"
12386 "sum;");
12387 CHECK_EQ(16000000, result->Int32Value());
12388
12389 // Test count operations
12390 result = CompileRun("function ee_op_test_count_func(sum) {"
12391 " for (var i = 0; i < 40; ++i) {"
12392 " sum += (++ext_array[i]);"
12393 " sum += (--ext_array[i]);"
12394 " } "
12395 " return sum;"
12396 "}"
12397 "sum=0;"
12398 "for (var i=0;i<10000;++i) {"
12399 " sum=ee_op_test_count_func(sum);"
12400 "}"
12401 "sum;");
12402 CHECK_EQ(16000000, result->Int32Value());
12403
ager@chromium.org3811b432009-10-28 14:53:37 +000012404 result = CompileRun("ext_array[3] = 33;"
12405 "delete ext_array[3];"
12406 "ext_array[3];");
12407 CHECK_EQ(33, result->Int32Value());
12408
12409 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12410 "ext_array[2] = 12; ext_array[3] = 13;"
12411 "ext_array.__defineGetter__('2',"
12412 "function() { return 120; });"
12413 "ext_array[2];");
12414 CHECK_EQ(12, result->Int32Value());
12415
12416 result = CompileRun("var js_array = new Array(40);"
12417 "js_array[0] = 77;"
12418 "js_array;");
12419 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12420
12421 result = CompileRun("ext_array[1] = 23;"
12422 "ext_array.__proto__ = [];"
12423 "js_array.__proto__ = ext_array;"
12424 "js_array.concat(ext_array);");
12425 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12426 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12427
12428 result = CompileRun("ext_array[1] = 23;");
12429 CHECK_EQ(23, result->Int32Value());
12430
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012431 // Test more complex manipulations which cause eax to contain values
12432 // that won't be completely overwritten by loads from the arrays.
12433 // This catches bugs in the instructions used for the KeyedLoadIC
12434 // for byte and word types.
12435 {
12436 const int kXSize = 300;
12437 const int kYSize = 300;
12438 const int kLargeElementCount = kXSize * kYSize * 4;
12439 ElementType* large_array_data =
12440 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12441 i::Handle<ExternalArrayClass> large_array =
12442 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012443 FACTORY->NewExternalArray(kLargeElementCount,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012444 array_type,
12445 array_data));
12446 v8::Handle<v8::Object> large_obj = v8::Object::New();
12447 // Set the elements to be the external array.
12448 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12449 array_type,
12450 kLargeElementCount);
12451 context->Global()->Set(v8_str("large_array"), large_obj);
12452 // Initialize contents of a few rows.
12453 for (int x = 0; x < 300; x++) {
12454 int row = 0;
12455 int offset = row * 300 * 4;
12456 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12457 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12458 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12459 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12460 row = 150;
12461 offset = row * 300 * 4;
12462 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12463 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12464 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12465 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12466 row = 298;
12467 offset = row * 300 * 4;
12468 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12469 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12470 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12471 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12472 }
12473 // The goal of the code below is to make "offset" large enough
12474 // that the computation of the index (which goes into eax) has
12475 // high bits set which will not be overwritten by a byte or short
12476 // load.
12477 result = CompileRun("var failed = false;"
12478 "var offset = 0;"
12479 "for (var i = 0; i < 300; i++) {"
12480 " if (large_array[4 * i] != 127 ||"
12481 " large_array[4 * i + 1] != 0 ||"
12482 " large_array[4 * i + 2] != 0 ||"
12483 " large_array[4 * i + 3] != 127) {"
12484 " failed = true;"
12485 " }"
12486 "}"
12487 "offset = 150 * 300 * 4;"
12488 "for (var i = 0; i < 300; i++) {"
12489 " if (large_array[offset + 4 * i] != 127 ||"
12490 " large_array[offset + 4 * i + 1] != 0 ||"
12491 " large_array[offset + 4 * i + 2] != 0 ||"
12492 " large_array[offset + 4 * i + 3] != 127) {"
12493 " failed = true;"
12494 " }"
12495 "}"
12496 "offset = 298 * 300 * 4;"
12497 "for (var i = 0; i < 300; i++) {"
12498 " if (large_array[offset + 4 * i] != 127 ||"
12499 " large_array[offset + 4 * i + 1] != 0 ||"
12500 " large_array[offset + 4 * i + 2] != 0 ||"
12501 " large_array[offset + 4 * i + 3] != 127) {"
12502 " failed = true;"
12503 " }"
12504 "}"
12505 "!failed;");
12506 CHECK_EQ(true, result->BooleanValue());
12507 free(large_array_data);
12508 }
12509
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012510 // The "" property descriptor is overloaded to store information about
12511 // the external array. Ensure that setting and accessing the "" property
12512 // works (it should overwrite the information cached about the external
12513 // array in the DescriptorArray) in various situations.
12514 result = CompileRun("ext_array[''] = 23; ext_array['']");
12515 CHECK_EQ(23, result->Int32Value());
12516
12517 // Property "" set after the external array is associated with the object.
12518 {
12519 v8::Handle<v8::Object> obj2 = v8::Object::New();
12520 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12521 obj2->Set(v8_str(""), v8::Int32::New(1503));
12522 // Set the elements to be the external array.
12523 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12524 array_type,
12525 kElementCount);
12526 context->Global()->Set(v8_str("ext_array"), obj2);
12527 result = CompileRun("ext_array['']");
12528 CHECK_EQ(1503, result->Int32Value());
12529 }
12530
12531 // Property "" set after the external array is associated with the object.
12532 {
12533 v8::Handle<v8::Object> obj2 = v8::Object::New();
12534 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12535 // Set the elements to be the external array.
12536 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12537 array_type,
12538 kElementCount);
12539 obj2->Set(v8_str(""), v8::Int32::New(1503));
12540 context->Global()->Set(v8_str("ext_array"), obj2);
12541 result = CompileRun("ext_array['']");
12542 CHECK_EQ(1503, result->Int32Value());
12543 }
12544
12545 // Should reuse the map from previous test.
12546 {
12547 v8::Handle<v8::Object> obj2 = v8::Object::New();
12548 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12549 // Set the elements to be the external array. Should re-use the map
12550 // from previous test.
12551 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12552 array_type,
12553 kElementCount);
12554 context->Global()->Set(v8_str("ext_array"), obj2);
12555 result = CompileRun("ext_array['']");
12556 }
12557
12558 // Property "" is a constant function that shouldn't not be interfered with
12559 // when an external array is set.
12560 {
12561 v8::Handle<v8::Object> obj2 = v8::Object::New();
12562 // Start
12563 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12564
12565 // Add a constant function to an object.
12566 context->Global()->Set(v8_str("ext_array"), obj2);
12567 result = CompileRun("ext_array[''] = function() {return 1503;};"
12568 "ext_array['']();");
12569
12570 // Add an external array transition to the same map that
12571 // has the constant transition.
12572 v8::Handle<v8::Object> obj3 = v8::Object::New();
12573 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12574 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12575 array_type,
12576 kElementCount);
12577 context->Global()->Set(v8_str("ext_array"), obj3);
12578 }
12579
12580 // If a external array transition is in the map, it should get clobbered
12581 // by a constant function.
12582 {
12583 // Add an external array transition.
12584 v8::Handle<v8::Object> obj3 = v8::Object::New();
12585 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12586 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12587 array_type,
12588 kElementCount);
12589
12590 // Add a constant function to the same map that just got an external array
12591 // transition.
12592 v8::Handle<v8::Object> obj2 = v8::Object::New();
12593 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
12594 context->Global()->Set(v8_str("ext_array"), obj2);
12595 result = CompileRun("ext_array[''] = function() {return 1503;};"
12596 "ext_array['']();");
12597 }
12598
ager@chromium.org3811b432009-10-28 14:53:37 +000012599 free(array_data);
12600}
12601
12602
12603THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012604 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012605 v8::kExternalByteArray,
12606 -128,
12607 127);
12608}
12609
12610
12611THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012612 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012613 v8::kExternalUnsignedByteArray,
12614 0,
12615 255);
12616}
12617
12618
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012619THREADED_TEST(ExternalPixelArray) {
12620 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
12621 v8::kExternalPixelArray,
12622 0,
12623 255);
12624}
12625
12626
ager@chromium.org3811b432009-10-28 14:53:37 +000012627THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012628 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012629 v8::kExternalShortArray,
12630 -32768,
12631 32767);
12632}
12633
12634
12635THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012636 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012637 v8::kExternalUnsignedShortArray,
12638 0,
12639 65535);
12640}
12641
12642
12643THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012644 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012645 v8::kExternalIntArray,
12646 INT_MIN, // -2147483648
12647 INT_MAX); // 2147483647
12648}
12649
12650
12651THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012652 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012653 v8::kExternalUnsignedIntArray,
12654 0,
12655 UINT_MAX); // 4294967295
12656}
12657
12658
12659THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000012660 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000012661 v8::kExternalFloatArray,
12662 -500,
12663 500);
12664}
12665
12666
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012667THREADED_TEST(ExternalDoubleArray) {
12668 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
12669 v8::kExternalDoubleArray,
12670 -500,
12671 500);
12672}
12673
12674
ager@chromium.org3811b432009-10-28 14:53:37 +000012675THREADED_TEST(ExternalArrays) {
12676 TestExternalByteArray();
12677 TestExternalUnsignedByteArray();
12678 TestExternalShortArray();
12679 TestExternalUnsignedShortArray();
12680 TestExternalIntArray();
12681 TestExternalUnsignedIntArray();
12682 TestExternalFloatArray();
12683}
12684
12685
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012686void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
12687 v8::HandleScope scope;
12688 LocalContext context;
12689 for (int size = 0; size < 100; size += 10) {
12690 int element_size = ExternalArrayElementSize(array_type);
12691 void* external_data = malloc(size * element_size);
12692 v8::Handle<v8::Object> obj = v8::Object::New();
12693 obj->SetIndexedPropertiesToExternalArrayData(
12694 external_data, array_type, size);
12695 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
12696 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
12697 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
12698 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
12699 free(external_data);
12700 }
12701}
12702
12703
12704THREADED_TEST(ExternalArrayInfo) {
12705 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
12706 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
12707 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
12708 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
12709 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
12710 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
12711 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012712 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012713 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000012714}
12715
12716
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012717THREADED_TEST(ScriptContextDependence) {
12718 v8::HandleScope scope;
12719 LocalContext c1;
12720 const char *source = "foo";
12721 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
12722 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
12723 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
12724 CHECK_EQ(dep->Run()->Int32Value(), 100);
12725 CHECK_EQ(indep->Run()->Int32Value(), 100);
12726 LocalContext c2;
12727 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
12728 CHECK_EQ(dep->Run()->Int32Value(), 100);
12729 CHECK_EQ(indep->Run()->Int32Value(), 101);
12730}
12731
ager@chromium.org96c75b52009-08-26 09:13:16 +000012732
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000012733THREADED_TEST(StackTrace) {
12734 v8::HandleScope scope;
12735 LocalContext context;
12736 v8::TryCatch try_catch;
12737 const char *source = "function foo() { FAIL.FAIL; }; foo();";
12738 v8::Handle<v8::String> src = v8::String::New(source);
12739 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
12740 v8::Script::New(src, origin)->Run();
12741 CHECK(try_catch.HasCaught());
12742 v8::String::Utf8Value stack(try_catch.StackTrace());
12743 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
12744}
ager@chromium.org96c75b52009-08-26 09:13:16 +000012745
12746
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012747// Checks that a StackFrame has certain expected values.
12748void checkStackFrame(const char* expected_script_name,
12749 const char* expected_func_name, int expected_line_number,
12750 int expected_column, bool is_eval, bool is_constructor,
12751 v8::Handle<v8::StackFrame> frame) {
12752 v8::HandleScope scope;
12753 v8::String::Utf8Value func_name(frame->GetFunctionName());
12754 v8::String::Utf8Value script_name(frame->GetScriptName());
12755 if (*script_name == NULL) {
12756 // The situation where there is no associated script, like for evals.
12757 CHECK(expected_script_name == NULL);
12758 } else {
12759 CHECK(strstr(*script_name, expected_script_name) != NULL);
12760 }
12761 CHECK(strstr(*func_name, expected_func_name) != NULL);
12762 CHECK_EQ(expected_line_number, frame->GetLineNumber());
12763 CHECK_EQ(expected_column, frame->GetColumn());
12764 CHECK_EQ(is_eval, frame->IsEval());
12765 CHECK_EQ(is_constructor, frame->IsConstructor());
12766}
12767
12768
12769v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
12770 v8::HandleScope scope;
12771 const char* origin = "capture-stack-trace-test";
12772 const int kOverviewTest = 1;
12773 const int kDetailedTest = 2;
12774
12775 ASSERT(args.Length() == 1);
12776
12777 int testGroup = args[0]->Int32Value();
12778 if (testGroup == kOverviewTest) {
12779 v8::Handle<v8::StackTrace> stackTrace =
12780 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
12781 CHECK_EQ(4, stackTrace->GetFrameCount());
12782 checkStackFrame(origin, "bar", 2, 10, false, false,
12783 stackTrace->GetFrame(0));
12784 checkStackFrame(origin, "foo", 6, 3, false, false,
12785 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012786 // This is the source string inside the eval which has the call to foo.
12787 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012788 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012789 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012790 checkStackFrame(origin, "", 8, 7, false, false,
12791 stackTrace->GetFrame(3));
12792
12793 CHECK(stackTrace->AsArray()->IsArray());
12794 } else if (testGroup == kDetailedTest) {
12795 v8::Handle<v8::StackTrace> stackTrace =
12796 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12797 CHECK_EQ(4, stackTrace->GetFrameCount());
12798 checkStackFrame(origin, "bat", 4, 22, false, false,
12799 stackTrace->GetFrame(0));
12800 checkStackFrame(origin, "baz", 8, 3, false, true,
12801 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012802#ifdef ENABLE_DEBUGGER_SUPPORT
12803 bool is_eval = true;
12804#else // ENABLE_DEBUGGER_SUPPORT
12805 bool is_eval = false;
12806#endif // ENABLE_DEBUGGER_SUPPORT
12807
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012808 // This is the source string inside the eval which has the call to baz.
12809 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012810 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000012811 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012812 checkStackFrame(origin, "", 10, 1, false, false,
12813 stackTrace->GetFrame(3));
12814
12815 CHECK(stackTrace->AsArray()->IsArray());
12816 }
12817 return v8::Undefined();
12818}
12819
12820
12821// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012822// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
12823// THREADED_TEST(CaptureStackTrace) {
12824TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000012825 v8::HandleScope scope;
12826 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
12827 Local<ObjectTemplate> templ = ObjectTemplate::New();
12828 templ->Set(v8_str("AnalyzeStackInNativeCode"),
12829 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
12830 LocalContext context(0, templ);
12831
12832 // Test getting OVERVIEW information. Should ignore information that is not
12833 // script name, function name, line number, and column offset.
12834 const char *overview_source =
12835 "function bar() {\n"
12836 " var y; AnalyzeStackInNativeCode(1);\n"
12837 "}\n"
12838 "function foo() {\n"
12839 "\n"
12840 " bar();\n"
12841 "}\n"
12842 "var x;eval('new foo();');";
12843 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
12844 v8::Handle<Value> overview_result =
12845 v8::Script::New(overview_src, origin)->Run();
12846 ASSERT(!overview_result.IsEmpty());
12847 ASSERT(overview_result->IsObject());
12848
12849 // Test getting DETAILED information.
12850 const char *detailed_source =
12851 "function bat() {AnalyzeStackInNativeCode(2);\n"
12852 "}\n"
12853 "\n"
12854 "function baz() {\n"
12855 " bat();\n"
12856 "}\n"
12857 "eval('new baz();');";
12858 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
12859 // Make the script using a non-zero line and column offset.
12860 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
12861 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
12862 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
12863 v8::Handle<v8::Script> detailed_script(
12864 v8::Script::New(detailed_src, &detailed_origin));
12865 v8::Handle<Value> detailed_result = detailed_script->Run();
12866 ASSERT(!detailed_result.IsEmpty());
12867 ASSERT(detailed_result->IsObject());
12868}
12869
12870
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012871static void StackTraceForUncaughtExceptionListener(
12872 v8::Handle<v8::Message> message,
12873 v8::Handle<Value>) {
12874 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
12875 CHECK_EQ(2, stack_trace->GetFrameCount());
12876 checkStackFrame("origin", "foo", 2, 3, false, false,
12877 stack_trace->GetFrame(0));
12878 checkStackFrame("origin", "bar", 5, 3, false, false,
12879 stack_trace->GetFrame(1));
12880}
12881
12882TEST(CaptureStackTraceForUncaughtException) {
12883 report_count = 0;
12884 v8::HandleScope scope;
12885 LocalContext env;
12886 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
12887 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
12888
12889 Script::Compile(v8_str("function foo() {\n"
12890 " throw 1;\n"
12891 "};\n"
12892 "function bar() {\n"
12893 " foo();\n"
12894 "};"),
12895 v8_str("origin"))->Run();
12896 v8::Local<v8::Object> global = env->Global();
12897 Local<Value> trouble = global->Get(v8_str("bar"));
12898 CHECK(trouble->IsFunction());
12899 Function::Cast(*trouble)->Call(global, 0, NULL);
12900 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12901 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
12902}
12903
12904
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000012905TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
12906 v8::HandleScope scope;
12907 LocalContext env;
12908 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
12909 1024,
12910 v8::StackTrace::kDetailed);
12911
12912 CompileRun(
12913 "var setters = ['column', 'lineNumber', 'scriptName',\n"
12914 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
12915 " 'isConstructor'];\n"
12916 "for (var i = 0; i < setters.length; i++) {\n"
12917 " var prop = setters[i];\n"
12918 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
12919 "}\n");
12920 CompileRun("throw 'exception';");
12921 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
12922}
12923
12924
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000012925v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
12926 v8::HandleScope scope;
12927 v8::Handle<v8::StackTrace> stackTrace =
12928 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
12929 CHECK_EQ(5, stackTrace->GetFrameCount());
12930 v8::Handle<v8::String> url = v8_str("eval_url");
12931 for (int i = 0; i < 3; i++) {
12932 v8::Handle<v8::String> name =
12933 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
12934 CHECK(!name.IsEmpty());
12935 CHECK_EQ(url, name);
12936 }
12937 return v8::Undefined();
12938}
12939
12940
12941TEST(SourceURLInStackTrace) {
12942 v8::HandleScope scope;
12943 Local<ObjectTemplate> templ = ObjectTemplate::New();
12944 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
12945 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
12946 LocalContext context(0, templ);
12947
12948 const char *source =
12949 "function outer() {\n"
12950 "function bar() {\n"
12951 " AnalyzeStackOfEvalWithSourceURL();\n"
12952 "}\n"
12953 "function foo() {\n"
12954 "\n"
12955 " bar();\n"
12956 "}\n"
12957 "foo();\n"
12958 "}\n"
12959 "eval('(' + outer +')()//@ sourceURL=eval_url');";
12960 CHECK(CompileRun(source)->IsUndefined());
12961}
12962
12963
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012964// Test that idle notification can be handled and eventually returns true.
ager@chromium.org96c75b52009-08-26 09:13:16 +000012965THREADED_TEST(IdleNotification) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012966 bool rv = false;
12967 for (int i = 0; i < 100; i++) {
12968 rv = v8::V8::IdleNotification();
12969 if (rv)
12970 break;
12971 }
12972 CHECK(rv == true);
12973}
12974
12975
12976static uint32_t* stack_limit;
12977
12978static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012979 stack_limit = reinterpret_cast<uint32_t*>(
12980 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012981 return v8::Undefined();
12982}
12983
12984
12985// Uses the address of a local variable to determine the stack top now.
12986// Given a size, returns an address that is that far from the current
12987// top of stack.
12988static uint32_t* ComputeStackLimit(uint32_t size) {
12989 uint32_t* answer = &size - (size / sizeof(size));
12990 // If the size is very large and the stack is very near the bottom of
12991 // memory then the calculation above may wrap around and give an address
12992 // that is above the (downwards-growing) stack. In that case we return
12993 // a very low address.
12994 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
12995 return answer;
12996}
12997
12998
12999TEST(SetResourceConstraints) {
13000 static const int K = 1024;
13001 uint32_t* set_limit = ComputeStackLimit(128 * K);
13002
13003 // Set stack limit.
13004 v8::ResourceConstraints constraints;
13005 constraints.set_stack_limit(set_limit);
13006 CHECK(v8::SetResourceConstraints(&constraints));
13007
13008 // Execute a script.
13009 v8::HandleScope scope;
13010 LocalContext env;
13011 Local<v8::FunctionTemplate> fun_templ =
13012 v8::FunctionTemplate::New(GetStackLimitCallback);
13013 Local<Function> fun = fun_templ->GetFunction();
13014 env->Global()->Set(v8_str("get_stack_limit"), fun);
13015 CompileRun("get_stack_limit();");
13016
13017 CHECK(stack_limit == set_limit);
13018}
13019
13020
13021TEST(SetResourceConstraintsInThread) {
13022 uint32_t* set_limit;
13023 {
13024 v8::Locker locker;
13025 static const int K = 1024;
13026 set_limit = ComputeStackLimit(128 * K);
13027
13028 // Set stack limit.
13029 v8::ResourceConstraints constraints;
13030 constraints.set_stack_limit(set_limit);
13031 CHECK(v8::SetResourceConstraints(&constraints));
13032
13033 // Execute a script.
13034 v8::HandleScope scope;
13035 LocalContext env;
13036 Local<v8::FunctionTemplate> fun_templ =
13037 v8::FunctionTemplate::New(GetStackLimitCallback);
13038 Local<Function> fun = fun_templ->GetFunction();
13039 env->Global()->Set(v8_str("get_stack_limit"), fun);
13040 CompileRun("get_stack_limit();");
13041
13042 CHECK(stack_limit == set_limit);
13043 }
13044 {
13045 v8::Locker locker;
13046 CHECK(stack_limit == set_limit);
13047 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000013048}
ager@chromium.org3811b432009-10-28 14:53:37 +000013049
13050
13051THREADED_TEST(GetHeapStatistics) {
13052 v8::HandleScope scope;
13053 LocalContext c1;
13054 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013055 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13056 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013057 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013058 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13059 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000013060}
13061
13062
13063static double DoubleFromBits(uint64_t value) {
13064 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013065 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013066 return target;
13067}
13068
13069
13070static uint64_t DoubleToBits(double value) {
13071 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000013072 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000013073 return target;
13074}
13075
13076
13077static double DoubleToDateTime(double input) {
13078 double date_limit = 864e13;
13079 if (IsNaN(input) || input < -date_limit || input > date_limit) {
13080 return i::OS::nan_value();
13081 }
13082 return (input < 0) ? -(floor(-input)) : floor(input);
13083}
13084
13085// We don't have a consistent way to write 64-bit constants syntactically, so we
13086// split them into two 32-bit constants and combine them programmatically.
13087static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13088 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13089}
13090
13091
13092THREADED_TEST(QuietSignalingNaNs) {
13093 v8::HandleScope scope;
13094 LocalContext context;
13095 v8::TryCatch try_catch;
13096
13097 // Special double values.
13098 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13099 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13100 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13101 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13102 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13103 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13104 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13105
13106 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13107 // on either side of the epoch.
13108 double date_limit = 864e13;
13109
13110 double test_values[] = {
13111 snan,
13112 qnan,
13113 infinity,
13114 max_normal,
13115 date_limit + 1,
13116 date_limit,
13117 min_normal,
13118 max_denormal,
13119 min_denormal,
13120 0,
13121 -0,
13122 -min_denormal,
13123 -max_denormal,
13124 -min_normal,
13125 -date_limit,
13126 -date_limit - 1,
13127 -max_normal,
13128 -infinity,
13129 -qnan,
13130 -snan
13131 };
13132 int num_test_values = 20;
13133
13134 for (int i = 0; i < num_test_values; i++) {
13135 double test_value = test_values[i];
13136
13137 // Check that Number::New preserves non-NaNs and quiets SNaNs.
13138 v8::Handle<v8::Value> number = v8::Number::New(test_value);
13139 double stored_number = number->NumberValue();
13140 if (!IsNaN(test_value)) {
13141 CHECK_EQ(test_value, stored_number);
13142 } else {
13143 uint64_t stored_bits = DoubleToBits(stored_number);
13144 // Check if quiet nan (bits 51..62 all set).
13145 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13146 }
13147
13148 // Check that Date::New preserves non-NaNs in the date range and
13149 // quiets SNaNs.
13150 v8::Handle<v8::Value> date = v8::Date::New(test_value);
13151 double expected_stored_date = DoubleToDateTime(test_value);
13152 double stored_date = date->NumberValue();
13153 if (!IsNaN(expected_stored_date)) {
13154 CHECK_EQ(expected_stored_date, stored_date);
13155 } else {
13156 uint64_t stored_bits = DoubleToBits(stored_date);
13157 // Check if quiet nan (bits 51..62 all set).
13158 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13159 }
13160 }
13161}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000013162
13163
13164static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13165 v8::HandleScope scope;
13166 v8::TryCatch tc;
13167 v8::Handle<v8::String> str = args[0]->ToString();
13168 if (tc.HasCaught())
13169 return tc.ReThrow();
13170 return v8::Undefined();
13171}
13172
13173
13174// Test that an exception can be propagated down through a spaghetti
13175// stack using ReThrow.
13176THREADED_TEST(SpaghettiStackReThrow) {
13177 v8::HandleScope scope;
13178 LocalContext context;
13179 context->Global()->Set(
13180 v8::String::New("s"),
13181 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13182 v8::TryCatch try_catch;
13183 CompileRun(
13184 "var i = 0;"
13185 "var o = {"
13186 " toString: function () {"
13187 " if (i == 10) {"
13188 " throw 'Hey!';"
13189 " } else {"
13190 " i++;"
13191 " return s(o);"
13192 " }"
13193 " }"
13194 "};"
13195 "s(o);");
13196 CHECK(try_catch.HasCaught());
13197 v8::String::Utf8Value value(try_catch.Exception());
13198 CHECK_EQ(0, strcmp(*value, "Hey!"));
13199}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013200
13201
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013202TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013203 v8::V8::Initialize();
13204
13205 v8::HandleScope scope;
13206 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000013207 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013208 int gc_count;
13209
ager@chromium.org60121232009-12-03 11:25:37 +000013210 // Create a context used to keep the code from aging in the compilation
13211 // cache.
13212 other_context = Context::New();
13213
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013214 // Context-dependent context data creates reference from the compilation
13215 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013216 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013217 context = Context::New();
13218 {
13219 v8::HandleScope scope;
13220
13221 context->Enter();
13222 Local<v8::String> obj = v8::String::New("");
13223 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000013224 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013225 context->Exit();
13226 }
13227 context.Dispose();
13228 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013229 other_context->Enter();
13230 CompileRun(source_simple);
13231 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013232 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013233 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013234 }
ager@chromium.org60121232009-12-03 11:25:37 +000013235 CHECK_GE(2, gc_count);
13236 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013237
13238 // Eval in a function creates reference from the compilation cache to the
13239 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013240 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013241 context = Context::New();
13242 {
13243 v8::HandleScope scope;
13244
13245 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000013246 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013247 context->Exit();
13248 }
13249 context.Dispose();
13250 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013251 other_context->Enter();
13252 CompileRun(source_eval);
13253 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013254 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013255 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013256 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013257 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000013258 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013259
13260 // Looking up the line number for an exception creates reference from the
13261 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000013262 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013263 context = Context::New();
13264 {
13265 v8::HandleScope scope;
13266
13267 context->Enter();
13268 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000013269 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013270 CHECK(try_catch.HasCaught());
13271 v8::Handle<v8::Message> message = try_catch.Message();
13272 CHECK(!message.IsEmpty());
13273 CHECK_EQ(1, message->GetLineNumber());
13274 context->Exit();
13275 }
13276 context.Dispose();
13277 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000013278 other_context->Enter();
13279 CompileRun(source_exception);
13280 other_context->Exit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013281 HEAP->CollectAllGarbage(false);
ager@chromium.org60121232009-12-03 11:25:37 +000013282 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013283 }
ager@chromium.org60121232009-12-03 11:25:37 +000013284 CHECK_GE(2, gc_count);
13285 CHECK_EQ(1, GetGlobalObjectsCount());
13286
13287 other_context.Dispose();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000013288}
ager@chromium.org5c838252010-02-19 08:53:10 +000013289
13290
13291THREADED_TEST(ScriptOrigin) {
13292 v8::HandleScope scope;
13293 LocalContext env;
13294 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13295 v8::Handle<v8::String> script = v8::String::New(
13296 "function f() {}\n\nfunction g() {}");
13297 v8::Script::Compile(script, &origin)->Run();
13298 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13299 env->Global()->Get(v8::String::New("f")));
13300 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13301 env->Global()->Get(v8::String::New("g")));
13302
13303 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13304 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13305 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13306
13307 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13308 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13309 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13310}
13311
13312
13313THREADED_TEST(ScriptLineNumber) {
13314 v8::HandleScope scope;
13315 LocalContext env;
13316 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13317 v8::Handle<v8::String> script = v8::String::New(
13318 "function f() {}\n\nfunction g() {}");
13319 v8::Script::Compile(script, &origin)->Run();
13320 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13321 env->Global()->Get(v8::String::New("f")));
13322 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13323 env->Global()->Get(v8::String::New("g")));
13324 CHECK_EQ(0, f->GetScriptLineNumber());
13325 CHECK_EQ(2, g->GetScriptLineNumber());
13326}
13327
13328
13329static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13330 const AccessorInfo& info) {
13331 return v8_num(42);
13332}
13333
13334
13335static void SetterWhichSetsYOnThisTo23(Local<String> name,
13336 Local<Value> value,
13337 const AccessorInfo& info) {
13338 info.This()->Set(v8_str("y"), v8_num(23));
13339}
13340
13341
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013342TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013343 v8::HandleScope scope;
13344 Local<ObjectTemplate> templ = ObjectTemplate::New();
13345 templ->SetAccessor(v8_str("x"),
13346 GetterWhichReturns42,
13347 SetterWhichSetsYOnThisTo23);
13348 LocalContext context;
13349 context->Global()->Set(v8_str("P"), templ->NewInstance());
13350 CompileRun("function C1() {"
13351 " this.x = 23;"
13352 "};"
13353 "C1.prototype = P;"
13354 "function C2() {"
13355 " this.x = 23"
13356 "};"
13357 "C2.prototype = { };"
13358 "C2.prototype.__proto__ = P;");
13359
13360 v8::Local<v8::Script> script;
13361 script = v8::Script::Compile(v8_str("new C1();"));
13362 for (int i = 0; i < 10; i++) {
13363 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13364 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13365 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13366 }
13367
13368 script = v8::Script::Compile(v8_str("new C2();"));
13369 for (int i = 0; i < 10; i++) {
13370 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13371 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13372 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13373 }
13374}
13375
13376
13377static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13378 Local<String> name, const AccessorInfo& info) {
13379 return v8_num(42);
13380}
13381
13382
13383static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13384 Local<String> name, Local<Value> value, const AccessorInfo& info) {
13385 if (name->Equals(v8_str("x"))) {
13386 info.This()->Set(v8_str("y"), v8_num(23));
13387 }
13388 return v8::Handle<Value>();
13389}
13390
13391
13392THREADED_TEST(InterceptorOnConstructorPrototype) {
13393 v8::HandleScope scope;
13394 Local<ObjectTemplate> templ = ObjectTemplate::New();
13395 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13396 NamedPropertySetterWhichSetsYOnThisTo23);
13397 LocalContext context;
13398 context->Global()->Set(v8_str("P"), templ->NewInstance());
13399 CompileRun("function C1() {"
13400 " this.x = 23;"
13401 "};"
13402 "C1.prototype = P;"
13403 "function C2() {"
13404 " this.x = 23"
13405 "};"
13406 "C2.prototype = { };"
13407 "C2.prototype.__proto__ = P;");
13408
13409 v8::Local<v8::Script> script;
13410 script = v8::Script::Compile(v8_str("new C1();"));
13411 for (int i = 0; i < 10; i++) {
13412 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13413 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13414 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13415 }
13416
13417 script = v8::Script::Compile(v8_str("new C2();"));
13418 for (int i = 0; i < 10; i++) {
13419 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13420 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13421 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13422 }
13423}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013424
13425
13426TEST(Bug618) {
13427 const char* source = "function C1() {"
13428 " this.x = 23;"
13429 "};"
13430 "C1.prototype = P;";
13431
13432 v8::HandleScope scope;
13433 LocalContext context;
13434 v8::Local<v8::Script> script;
13435
13436 // Use a simple object as prototype.
13437 v8::Local<v8::Object> prototype = v8::Object::New();
13438 prototype->Set(v8_str("y"), v8_num(42));
13439 context->Global()->Set(v8_str("P"), prototype);
13440
13441 // This compile will add the code to the compilation cache.
13442 CompileRun(source);
13443
13444 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000013445 // Allow enough iterations for the inobject slack tracking logic
13446 // to finalize instance size and install the fast construct stub.
13447 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013448 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13449 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13450 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13451 }
13452
13453 // Use an API object with accessors as prototype.
13454 Local<ObjectTemplate> templ = ObjectTemplate::New();
13455 templ->SetAccessor(v8_str("x"),
13456 GetterWhichReturns42,
13457 SetterWhichSetsYOnThisTo23);
13458 context->Global()->Set(v8_str("P"), templ->NewInstance());
13459
13460 // This compile will get the code from the compilation cache.
13461 CompileRun(source);
13462
13463 script = v8::Script::Compile(v8_str("new C1();"));
13464 for (int i = 0; i < 10; i++) {
13465 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13466 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13467 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13468 }
13469}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013470
13471int prologue_call_count = 0;
13472int epilogue_call_count = 0;
13473int prologue_call_count_second = 0;
13474int epilogue_call_count_second = 0;
13475
13476void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13477 ++prologue_call_count;
13478}
13479
13480void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13481 ++epilogue_call_count;
13482}
13483
13484void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13485 ++prologue_call_count_second;
13486}
13487
13488void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13489 ++epilogue_call_count_second;
13490}
13491
13492TEST(GCCallbacks) {
13493 LocalContext context;
13494
13495 v8::V8::AddGCPrologueCallback(PrologueCallback);
13496 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13497 CHECK_EQ(0, prologue_call_count);
13498 CHECK_EQ(0, epilogue_call_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013499 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013500 CHECK_EQ(1, prologue_call_count);
13501 CHECK_EQ(1, epilogue_call_count);
13502 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13503 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013504 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013505 CHECK_EQ(2, prologue_call_count);
13506 CHECK_EQ(2, epilogue_call_count);
13507 CHECK_EQ(1, prologue_call_count_second);
13508 CHECK_EQ(1, epilogue_call_count_second);
13509 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13510 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013511 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013512 CHECK_EQ(2, prologue_call_count);
13513 CHECK_EQ(2, epilogue_call_count);
13514 CHECK_EQ(2, prologue_call_count_second);
13515 CHECK_EQ(2, epilogue_call_count_second);
13516 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13517 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013518 HEAP->CollectAllGarbage(false);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000013519 CHECK_EQ(2, prologue_call_count);
13520 CHECK_EQ(2, epilogue_call_count);
13521 CHECK_EQ(2, prologue_call_count_second);
13522 CHECK_EQ(2, epilogue_call_count_second);
13523}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013524
13525
13526THREADED_TEST(AddToJSFunctionResultCache) {
13527 i::FLAG_allow_natives_syntax = true;
13528 v8::HandleScope scope;
13529
13530 LocalContext context;
13531
13532 const char* code =
13533 "(function() {"
13534 " var key0 = 'a';"
13535 " var key1 = 'b';"
13536 " var r0 = %_GetFromCache(0, key0);"
13537 " var r1 = %_GetFromCache(0, key1);"
13538 " var r0_ = %_GetFromCache(0, key0);"
13539 " if (r0 !== r0_)"
13540 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13541 " var r1_ = %_GetFromCache(0, key1);"
13542 " if (r1 !== r1_)"
13543 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13544 " return 'PASSED';"
13545 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013546 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013547 ExpectString(code, "PASSED");
13548}
13549
13550
13551static const int k0CacheSize = 16;
13552
13553THREADED_TEST(FillJSFunctionResultCache) {
13554 i::FLAG_allow_natives_syntax = true;
13555 v8::HandleScope scope;
13556
13557 LocalContext context;
13558
13559 const char* code =
13560 "(function() {"
13561 " var k = 'a';"
13562 " var r = %_GetFromCache(0, k);"
13563 " for (var i = 0; i < 16; i++) {"
13564 " %_GetFromCache(0, 'a' + i);"
13565 " };"
13566 " if (r === %_GetFromCache(0, k))"
13567 " return 'FAILED: k0CacheSize is too small';"
13568 " return 'PASSED';"
13569 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013570 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013571 ExpectString(code, "PASSED");
13572}
13573
13574
13575THREADED_TEST(RoundRobinGetFromCache) {
13576 i::FLAG_allow_natives_syntax = true;
13577 v8::HandleScope scope;
13578
13579 LocalContext context;
13580
13581 const char* code =
13582 "(function() {"
13583 " var keys = [];"
13584 " for (var i = 0; i < 16; i++) keys.push(i);"
13585 " var values = [];"
13586 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13587 " for (var i = 0; i < 16; i++) {"
13588 " var v = %_GetFromCache(0, keys[i]);"
13589 " if (v !== values[i])"
13590 " return 'Wrong value for ' + "
13591 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13592 " };"
13593 " return 'PASSED';"
13594 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013595 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013596 ExpectString(code, "PASSED");
13597}
13598
13599
13600THREADED_TEST(ReverseGetFromCache) {
13601 i::FLAG_allow_natives_syntax = true;
13602 v8::HandleScope scope;
13603
13604 LocalContext context;
13605
13606 const char* code =
13607 "(function() {"
13608 " var keys = [];"
13609 " for (var i = 0; i < 16; i++) keys.push(i);"
13610 " var values = [];"
13611 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
13612 " for (var i = 15; i >= 16; i--) {"
13613 " var v = %_GetFromCache(0, keys[i]);"
13614 " if (v !== values[i])"
13615 " return 'Wrong value for ' + "
13616 " keys[i] + ': ' + v + ' vs. ' + values[i];"
13617 " };"
13618 " return 'PASSED';"
13619 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013620 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013621 ExpectString(code, "PASSED");
13622}
13623
13624
13625THREADED_TEST(TestEviction) {
13626 i::FLAG_allow_natives_syntax = true;
13627 v8::HandleScope scope;
13628
13629 LocalContext context;
13630
13631 const char* code =
13632 "(function() {"
13633 " for (var i = 0; i < 2*16; i++) {"
13634 " %_GetFromCache(0, 'a' + i);"
13635 " };"
13636 " return 'PASSED';"
13637 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013638 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000013639 ExpectString(code, "PASSED");
13640}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000013641
13642
13643THREADED_TEST(TwoByteStringInAsciiCons) {
13644 // See Chromium issue 47824.
13645 v8::HandleScope scope;
13646
13647 LocalContext context;
13648 const char* init_code =
13649 "var str1 = 'abelspendabel';"
13650 "var str2 = str1 + str1 + str1;"
13651 "str2;";
13652 Local<Value> result = CompileRun(init_code);
13653
13654 CHECK(result->IsString());
13655 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
13656 int length = string->length();
13657 CHECK(string->IsAsciiRepresentation());
13658
13659 FlattenString(string);
13660 i::Handle<i::String> flat_string = FlattenGetString(string);
13661
13662 CHECK(string->IsAsciiRepresentation());
13663 CHECK(flat_string->IsAsciiRepresentation());
13664
13665 // Create external resource.
13666 uint16_t* uc16_buffer = new uint16_t[length + 1];
13667
13668 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
13669 uc16_buffer[length] = 0;
13670
13671 TestResource resource(uc16_buffer);
13672
13673 flat_string->MakeExternal(&resource);
13674
13675 CHECK(flat_string->IsTwoByteRepresentation());
13676
13677 // At this point, we should have a Cons string which is flat and ASCII,
13678 // with a first half that is a two-byte string (although it only contains
13679 // ASCII characters). This is a valid sequence of steps, and it can happen
13680 // in real pages.
13681
13682 CHECK(string->IsAsciiRepresentation());
13683 i::ConsString* cons = i::ConsString::cast(*string);
13684 CHECK_EQ(0, cons->second()->length());
13685 CHECK(cons->first()->IsTwoByteRepresentation());
13686
13687 // Check that some string operations work.
13688
13689 // Atom RegExp.
13690 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
13691 CHECK_EQ(6, reresult->Int32Value());
13692
13693 // Nonatom RegExp.
13694 reresult = CompileRun("str2.match(/abe./g).length;");
13695 CHECK_EQ(6, reresult->Int32Value());
13696
13697 reresult = CompileRun("str2.search(/bel/g);");
13698 CHECK_EQ(1, reresult->Int32Value());
13699
13700 reresult = CompileRun("str2.search(/be./g);");
13701 CHECK_EQ(1, reresult->Int32Value());
13702
13703 ExpectTrue("/bel/g.test(str2);");
13704
13705 ExpectTrue("/be./g.test(str2);");
13706
13707 reresult = CompileRun("/bel/g.exec(str2);");
13708 CHECK(!reresult->IsNull());
13709
13710 reresult = CompileRun("/be./g.exec(str2);");
13711 CHECK(!reresult->IsNull());
13712
13713 ExpectString("str2.substring(2, 10);", "elspenda");
13714
13715 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
13716
13717 ExpectString("str2.charAt(2);", "e");
13718
13719 reresult = CompileRun("str2.charCodeAt(2);");
13720 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
13721}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013722
13723
13724// Failed access check callback that performs a GC on each invocation.
13725void FailedAccessCheckCallbackGC(Local<v8::Object> target,
13726 v8::AccessType type,
13727 Local<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013728 HEAP->CollectAllGarbage(true);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000013729}
13730
13731
13732TEST(GCInFailedAccessCheckCallback) {
13733 // Install a failed access check callback that performs a GC on each
13734 // invocation. Then force the callback to be called from va
13735
13736 v8::V8::Initialize();
13737 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
13738
13739 v8::HandleScope scope;
13740
13741 // Create an ObjectTemplate for global objects and install access
13742 // check callbacks that will block access.
13743 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13744 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13745 IndexedGetAccessBlocker,
13746 v8::Handle<v8::Value>(),
13747 false);
13748
13749 // Create a context and set an x property on it's global object.
13750 LocalContext context0(NULL, global_template);
13751 context0->Global()->Set(v8_str("x"), v8_num(42));
13752 v8::Handle<v8::Object> global0 = context0->Global();
13753
13754 // Create a context with a different security token so that the
13755 // failed access check callback will be called on each access.
13756 LocalContext context1(NULL, global_template);
13757 context1->Global()->Set(v8_str("other"), global0);
13758
13759 // Get property with failed access check.
13760 ExpectUndefined("other.x");
13761
13762 // Get element with failed access check.
13763 ExpectUndefined("other[0]");
13764
13765 // Set property with failed access check.
13766 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
13767 CHECK(result->IsObject());
13768
13769 // Set element with failed access check.
13770 result = CompileRun("other[0] = new Object()");
13771 CHECK(result->IsObject());
13772
13773 // Get property attribute with failed access check.
13774 ExpectFalse("\'x\' in other");
13775
13776 // Get property attribute for element with failed access check.
13777 ExpectFalse("0 in other");
13778
13779 // Delete property.
13780 ExpectFalse("delete other.x");
13781
13782 // Delete element.
13783 CHECK_EQ(false, global0->Delete(0));
13784
13785 // DefineAccessor.
13786 CHECK_EQ(false,
13787 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
13788
13789 // Define JavaScript accessor.
13790 ExpectUndefined("Object.prototype.__defineGetter__.call("
13791 " other, \'x\', function() { return 42; })");
13792
13793 // LookupAccessor.
13794 ExpectUndefined("Object.prototype.__lookupGetter__.call("
13795 " other, \'x\')");
13796
13797 // HasLocalElement.
13798 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
13799
13800 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
13801 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
13802 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
13803
13804 // Reset the failed access check callback so it does not influence
13805 // the other tests.
13806 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
13807}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000013808
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013809TEST(DefaultIsolateGetCurrent) {
13810 CHECK(v8::Isolate::GetCurrent() != NULL);
13811 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13812 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13813 printf("*** %s\n", "DefaultIsolateGetCurrent success");
13814}
13815
13816TEST(IsolateNewDispose) {
13817 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13818 v8::Isolate* isolate = v8::Isolate::New();
13819 CHECK(isolate != NULL);
13820 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13821 CHECK(current_isolate != isolate);
13822 CHECK(current_isolate == v8::Isolate::GetCurrent());
13823
13824 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13825 last_location = last_message = NULL;
13826 isolate->Dispose();
13827 CHECK_EQ(last_location, NULL);
13828 CHECK_EQ(last_message, NULL);
13829}
13830
13831TEST(IsolateEnterExitDefault) {
13832 v8::HandleScope scope;
13833 LocalContext context;
13834 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
13835 CHECK(current_isolate != NULL); // Default isolate.
13836 ExpectString("'hello'", "hello");
13837 current_isolate->Enter();
13838 ExpectString("'still working'", "still working");
13839 current_isolate->Exit();
13840 ExpectString("'still working 2'", "still working 2");
13841 current_isolate->Exit();
13842 // Default isolate is always, well, 'default current'.
13843 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
13844 // Still working since default isolate is auto-entering any thread
13845 // that has no isolate and attempts to execute V8 APIs.
13846 ExpectString("'still working 3'", "still working 3");
13847}
13848
13849TEST(DisposeDefaultIsolate) {
13850 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13851
13852 // Run some V8 code to trigger default isolate to become 'current'.
13853 v8::HandleScope scope;
13854 LocalContext context;
13855 ExpectString("'run some V8'", "run some V8");
13856
13857 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13858 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
13859 last_location = last_message = NULL;
13860 isolate->Dispose();
13861 // It is not possible to dispose default isolate via Isolate API.
13862 CHECK_NE(last_location, NULL);
13863 CHECK_NE(last_message, NULL);
13864}
13865
13866TEST(RunDefaultAndAnotherIsolate) {
13867 v8::HandleScope scope;
13868 LocalContext context;
13869
13870 // Enter new isolate.
13871 v8::Isolate* isolate = v8::Isolate::New();
13872 CHECK(isolate);
13873 isolate->Enter();
13874 { // Need this block because subsequent Exit() will deallocate Heap,
13875 // so we need all scope objects to be deconstructed when it happens.
13876 v8::HandleScope scope_new;
13877 LocalContext context_new;
13878
13879 // Run something in new isolate.
13880 CompileRun("var foo = 153;");
13881 ExpectTrue("function f() { return foo == 153; }; f()");
13882 }
13883 isolate->Exit();
13884
13885 // This runs automatically in default isolate.
13886 // Variables in another isolate should be not available.
13887 ExpectTrue("function f() {"
13888 " try {"
13889 " foo;"
13890 " return false;"
13891 " } catch(e) {"
13892 " return true;"
13893 " }"
13894 "};"
13895 "var bar = 371;"
13896 "f()");
13897
13898 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13899 last_location = last_message = NULL;
13900 isolate->Dispose();
13901 CHECK_EQ(last_location, NULL);
13902 CHECK_EQ(last_message, NULL);
13903
13904 // Check that default isolate still runs.
13905 ExpectTrue("function f() { return bar == 371; }; f()");
13906}
13907
13908TEST(DisposeIsolateWhenInUse) {
13909 v8::Isolate* isolate = v8::Isolate::New();
13910 CHECK(isolate);
13911 isolate->Enter();
13912 v8::HandleScope scope;
13913 LocalContext context;
13914 // Run something in this isolate.
13915 ExpectTrue("true");
13916 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
13917 last_location = last_message = NULL;
13918 // Still entered, should fail.
13919 isolate->Dispose();
13920 CHECK_NE(last_location, NULL);
13921 CHECK_NE(last_message, NULL);
13922}
13923
13924TEST(RunTwoIsolatesOnSingleThread) {
13925 // Run isolate 1.
13926 v8::Isolate* isolate1 = v8::Isolate::New();
13927 isolate1->Enter();
13928 v8::Persistent<v8::Context> context1 = v8::Context::New();
13929
13930 {
13931 v8::Context::Scope cscope(context1);
13932 v8::HandleScope scope;
13933 // Run something in new isolate.
13934 CompileRun("var foo = 'isolate 1';");
13935 ExpectString("function f() { return foo; }; f()", "isolate 1");
13936 }
13937
13938 // Run isolate 2.
13939 v8::Isolate* isolate2 = v8::Isolate::New();
13940 v8::Persistent<v8::Context> context2;
13941
13942 {
13943 v8::Isolate::Scope iscope(isolate2);
13944 context2 = v8::Context::New();
13945 v8::Context::Scope cscope(context2);
13946 v8::HandleScope scope;
13947
13948 // Run something in new isolate.
13949 CompileRun("var foo = 'isolate 2';");
13950 ExpectString("function f() { return foo; }; f()", "isolate 2");
13951 }
13952
13953 {
13954 v8::Context::Scope cscope(context1);
13955 v8::HandleScope scope;
13956 // Now again in isolate 1
13957 ExpectString("function f() { return foo; }; f()", "isolate 1");
13958 }
13959
13960 isolate1->Exit();
13961
13962 // Run some stuff in default isolate.
13963 v8::Persistent<v8::Context> context_default = v8::Context::New();
13964
13965 {
13966 v8::Context::Scope cscope(context_default);
13967 v8::HandleScope scope;
13968 // Variables in other isolates should be not available, verify there
13969 // is an exception.
13970 ExpectTrue("function f() {"
13971 " try {"
13972 " foo;"
13973 " return false;"
13974 " } catch(e) {"
13975 " return true;"
13976 " }"
13977 "};"
13978 "var isDefaultIsolate = true;"
13979 "f()");
13980 }
13981
13982 isolate1->Enter();
13983
13984 {
13985 v8::Isolate::Scope iscope(isolate2);
13986 v8::Context::Scope cscope(context2);
13987 v8::HandleScope scope;
13988 ExpectString("function f() { return foo; }; f()", "isolate 2");
13989 }
13990
13991 {
13992 v8::Context::Scope cscope(context1);
13993 v8::HandleScope scope;
13994 ExpectString("function f() { return foo; }; f()", "isolate 1");
13995 }
13996
13997 {
13998 v8::Isolate::Scope iscope(isolate2);
13999 context2.Dispose();
14000 }
14001
14002 context1.Dispose();
14003 isolate1->Exit();
14004
14005 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14006 last_location = last_message = NULL;
14007
14008 isolate1->Dispose();
14009 CHECK_EQ(last_location, NULL);
14010 CHECK_EQ(last_message, NULL);
14011
14012 isolate2->Dispose();
14013 CHECK_EQ(last_location, NULL);
14014 CHECK_EQ(last_message, NULL);
14015
14016 // Check that default isolate still runs.
14017 {
14018 v8::Context::Scope cscope(context_default);
14019 v8::HandleScope scope;
14020 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14021 }
14022}
14023
14024static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14025 v8::Isolate::Scope isolate_scope(isolate);
14026 v8::HandleScope scope;
14027 LocalContext context;
14028 i::ScopedVector<char> code(1024);
14029 i::OS::SNPrintF(code, "function fib(n) {"
14030 " if (n <= 2) return 1;"
14031 " return fib(n-1) + fib(n-2);"
14032 "}"
14033 "fib(%d)", limit);
14034 Local<Value> value = CompileRun(code.start());
14035 CHECK(value->IsNumber());
14036 return static_cast<int>(value->NumberValue());
14037}
14038
14039class IsolateThread : public v8::internal::Thread {
14040 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014041 IsolateThread(v8::Isolate* isolate, int fib_limit)
14042 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014043 isolate_(isolate),
14044 fib_limit_(fib_limit),
14045 result_(0) { }
14046
14047 void Run() {
14048 result_ = CalcFibonacci(isolate_, fib_limit_);
14049 }
14050
14051 int result() { return result_; }
14052
14053 private:
14054 v8::Isolate* isolate_;
14055 int fib_limit_;
14056 int result_;
14057};
14058
14059TEST(MultipleIsolatesOnIndividualThreads) {
14060 v8::Isolate* isolate1 = v8::Isolate::New();
14061 v8::Isolate* isolate2 = v8::Isolate::New();
14062
14063 IsolateThread thread1(isolate1, 21);
14064 IsolateThread thread2(isolate2, 12);
14065
14066 // Compute some fibonacci numbers on 3 threads in 3 isolates.
14067 thread1.Start();
14068 thread2.Start();
14069
14070 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14071 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14072
14073 thread1.Join();
14074 thread2.Join();
14075
14076 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14077 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14078 CHECK_EQ(result1, 10946);
14079 CHECK_EQ(result2, 144);
14080 CHECK_EQ(result1, thread1.result());
14081 CHECK_EQ(result2, thread2.result());
14082
14083 isolate1->Dispose();
14084 isolate2->Dispose();
14085}
14086
lrn@chromium.org1c092762011-05-09 09:42:16 +000014087TEST(IsolateDifferentContexts) {
14088 v8::Isolate* isolate = v8::Isolate::New();
14089 Persistent<v8::Context> context;
14090 {
14091 v8::Isolate::Scope isolate_scope(isolate);
14092 v8::HandleScope handle_scope;
14093 context = v8::Context::New();
14094 v8::Context::Scope context_scope(context);
14095 Local<Value> v = CompileRun("2");
14096 CHECK(v->IsNumber());
14097 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14098 }
14099 {
14100 v8::Isolate::Scope isolate_scope(isolate);
14101 v8::HandleScope handle_scope;
14102 context = v8::Context::New();
14103 v8::Context::Scope context_scope(context);
14104 Local<Value> v = CompileRun("22");
14105 CHECK(v->IsNumber());
14106 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14107 }
14108}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014109
14110class InitDefaultIsolateThread : public v8::internal::Thread {
14111 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014112 enum TestCase {
14113 IgnoreOOM,
14114 SetResourceConstraints,
14115 SetFatalHandler,
14116 SetCounterFunction,
14117 SetCreateHistogramFunction,
14118 SetAddHistogramSampleFunction
14119 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014120
14121 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014122 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014123 testCase_(testCase),
14124 result_(false) { }
14125
14126 void Run() {
14127 switch (testCase_) {
14128 case IgnoreOOM:
14129 v8::V8::IgnoreOutOfMemoryException();
14130 break;
14131
14132 case SetResourceConstraints: {
14133 static const int K = 1024;
14134 v8::ResourceConstraints constraints;
14135 constraints.set_max_young_space_size(256 * K);
14136 constraints.set_max_old_space_size(4 * K * K);
14137 v8::SetResourceConstraints(&constraints);
14138 break;
14139 }
14140
14141 case SetFatalHandler:
14142 v8::V8::SetFatalErrorHandler(NULL);
14143 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014144
14145 case SetCounterFunction:
14146 v8::V8::SetCounterFunction(NULL);
14147 break;
14148
14149 case SetCreateHistogramFunction:
14150 v8::V8::SetCreateHistogramFunction(NULL);
14151 break;
14152
14153 case SetAddHistogramSampleFunction:
14154 v8::V8::SetAddHistogramSampleFunction(NULL);
14155 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014156 }
14157 result_ = true;
14158 }
14159
14160 bool result() { return result_; }
14161
14162 private:
14163 TestCase testCase_;
14164 bool result_;
14165};
14166
14167
14168static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14169 InitDefaultIsolateThread thread(testCase);
14170 thread.Start();
14171 thread.Join();
14172 CHECK_EQ(thread.result(), true);
14173}
14174
14175TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14176 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14177}
14178
14179TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14180 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14181}
14182
14183TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14184 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14185}
14186
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000014187TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14188 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14189}
14190
14191TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14192 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14193}
14194
14195TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14196 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14197}
14198
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000014199
14200TEST(StringCheckMultipleContexts) {
14201 const char* code =
14202 "(function() { return \"a\".charAt(0); })()";
14203
14204 {
14205 // Run the code twice in the first context to initialize the call IC.
14206 v8::HandleScope scope;
14207 LocalContext context1;
14208 ExpectString(code, "a");
14209 ExpectString(code, "a");
14210 }
14211
14212 {
14213 // Change the String.prototype in the second context and check
14214 // that the right function gets called.
14215 v8::HandleScope scope;
14216 LocalContext context2;
14217 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14218 ExpectString(code, "not a");
14219 }
14220}
14221
14222
14223TEST(NumberCheckMultipleContexts) {
14224 const char* code =
14225 "(function() { return (42).toString(); })()";
14226
14227 {
14228 // Run the code twice in the first context to initialize the call IC.
14229 v8::HandleScope scope;
14230 LocalContext context1;
14231 ExpectString(code, "42");
14232 ExpectString(code, "42");
14233 }
14234
14235 {
14236 // Change the Number.prototype in the second context and check
14237 // that the right function gets called.
14238 v8::HandleScope scope;
14239 LocalContext context2;
14240 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14241 ExpectString(code, "not 42");
14242 }
14243}
14244
14245
14246TEST(BooleanCheckMultipleContexts) {
14247 const char* code =
14248 "(function() { return true.toString(); })()";
14249
14250 {
14251 // Run the code twice in the first context to initialize the call IC.
14252 v8::HandleScope scope;
14253 LocalContext context1;
14254 ExpectString(code, "true");
14255 ExpectString(code, "true");
14256 }
14257
14258 {
14259 // Change the Boolean.prototype in the second context and check
14260 // that the right function gets called.
14261 v8::HandleScope scope;
14262 LocalContext context2;
14263 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14264 ExpectString(code, "");
14265 }
14266}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014267
14268
14269TEST(DontDeleteCellLoadIC) {
14270 const char* function_code =
14271 "function readCell() { while (true) { return cell; } }";
14272
14273 {
14274 // Run the code twice in the first context to initialize the load
14275 // IC for a don't delete cell.
14276 v8::HandleScope scope;
14277 LocalContext context1;
14278 CompileRun("var cell = \"first\";");
14279 ExpectBoolean("delete cell", false);
14280 CompileRun(function_code);
14281 ExpectString("readCell()", "first");
14282 ExpectString("readCell()", "first");
14283 }
14284
14285 {
14286 // Use a deletable cell in the second context.
14287 v8::HandleScope scope;
14288 LocalContext context2;
14289 CompileRun("cell = \"second\";");
14290 CompileRun(function_code);
14291 ExpectString("readCell()", "second");
14292 ExpectBoolean("delete cell", true);
14293 ExpectString("(function() {"
14294 " try {"
14295 " return readCell();"
14296 " } catch(e) {"
14297 " return e.toString();"
14298 " }"
14299 "})()",
14300 "ReferenceError: cell is not defined");
14301 CompileRun("cell = \"new_second\";");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014302 HEAP->CollectAllGarbage(true);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014303 ExpectString("readCell()", "new_second");
14304 ExpectString("readCell()", "new_second");
14305 }
14306}
14307
14308
14309TEST(DontDeleteCellLoadICForceDelete) {
14310 const char* function_code =
14311 "function readCell() { while (true) { return cell; } }";
14312
14313 // Run the code twice to initialize the load IC for a don't delete
14314 // cell.
14315 v8::HandleScope scope;
14316 LocalContext context;
14317 CompileRun("var cell = \"value\";");
14318 ExpectBoolean("delete cell", false);
14319 CompileRun(function_code);
14320 ExpectString("readCell()", "value");
14321 ExpectString("readCell()", "value");
14322
14323 // Delete the cell using the API and check the inlined code works
14324 // correctly.
14325 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14326 ExpectString("(function() {"
14327 " try {"
14328 " return readCell();"
14329 " } catch(e) {"
14330 " return e.toString();"
14331 " }"
14332 "})()",
14333 "ReferenceError: cell is not defined");
14334}
14335
14336
14337TEST(DontDeleteCellLoadICAPI) {
14338 const char* function_code =
14339 "function readCell() { while (true) { return cell; } }";
14340
14341 // Run the code twice to initialize the load IC for a don't delete
14342 // cell created using the API.
14343 v8::HandleScope scope;
14344 LocalContext context;
14345 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14346 ExpectBoolean("delete cell", false);
14347 CompileRun(function_code);
14348 ExpectString("readCell()", "value");
14349 ExpectString("readCell()", "value");
14350
14351 // Delete the cell using the API and check the inlined code works
14352 // correctly.
14353 CHECK(context->Global()->ForceDelete(v8_str("cell")));
14354 ExpectString("(function() {"
14355 " try {"
14356 " return readCell();"
14357 " } catch(e) {"
14358 " return e.toString();"
14359 " }"
14360 "})()",
14361 "ReferenceError: cell is not defined");
14362}
14363
14364
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014365TEST(RegExp) {
14366 v8::HandleScope scope;
14367 LocalContext context;
14368
14369 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14370 CHECK(re->IsRegExp());
14371 CHECK(re->GetSource()->Equals(v8_str("foo")));
14372 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14373
14374 re = v8::RegExp::New(v8_str("bar"),
14375 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14376 v8::RegExp::kGlobal));
14377 CHECK(re->IsRegExp());
14378 CHECK(re->GetSource()->Equals(v8_str("bar")));
14379 CHECK_EQ(static_cast<int>(re->GetFlags()),
14380 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
14381
14382 re = v8::RegExp::New(v8_str("baz"),
14383 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14384 v8::RegExp::kMultiline));
14385 CHECK(re->IsRegExp());
14386 CHECK(re->GetSource()->Equals(v8_str("baz")));
14387 CHECK_EQ(static_cast<int>(re->GetFlags()),
14388 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14389
14390 re = CompileRun("/quux/").As<v8::RegExp>();
14391 CHECK(re->IsRegExp());
14392 CHECK(re->GetSource()->Equals(v8_str("quux")));
14393 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14394
14395 re = CompileRun("/quux/gm").As<v8::RegExp>();
14396 CHECK(re->IsRegExp());
14397 CHECK(re->GetSource()->Equals(v8_str("quux")));
14398 CHECK_EQ(static_cast<int>(re->GetFlags()),
14399 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
14400
14401 // Override the RegExp constructor and check the API constructor
14402 // still works.
14403 CompileRun("RegExp = function() {}");
14404
14405 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14406 CHECK(re->IsRegExp());
14407 CHECK(re->GetSource()->Equals(v8_str("foobar")));
14408 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
14409
14410 re = v8::RegExp::New(v8_str("foobarbaz"),
14411 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14412 v8::RegExp::kMultiline));
14413 CHECK(re->IsRegExp());
14414 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14415 CHECK_EQ(static_cast<int>(re->GetFlags()),
14416 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
14417
14418 context->Global()->Set(v8_str("re"), re);
14419 ExpectTrue("re.test('FoobarbaZ')");
14420
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014421 // RegExps are objects on which you can set properties.
14422 re->Set(v8_str("property"), v8::Integer::New(32));
14423 v8::Handle<v8::Value> value = CompileRun("re.property");
14424 ASSERT_EQ(32, value->Int32Value());
14425
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014426 v8::TryCatch try_catch;
14427 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14428 CHECK(re.IsEmpty());
14429 CHECK(try_catch.HasCaught());
14430 context->Global()->Set(v8_str("ex"), try_catch.Exception());
14431 ExpectTrue("ex instanceof SyntaxError");
14432}
14433
14434
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014435THREADED_TEST(Equals) {
14436 v8::HandleScope handleScope;
14437 LocalContext localContext;
14438
14439 v8::Handle<v8::Object> globalProxy = localContext->Global();
14440 v8::Handle<Value> global = globalProxy->GetPrototype();
14441
14442 CHECK(global->StrictEquals(global));
14443 CHECK(!global->StrictEquals(globalProxy));
14444 CHECK(!globalProxy->StrictEquals(global));
14445 CHECK(globalProxy->StrictEquals(globalProxy));
14446
14447 CHECK(global->Equals(global));
14448 CHECK(!global->Equals(globalProxy));
14449 CHECK(!globalProxy->Equals(global));
14450 CHECK(globalProxy->Equals(globalProxy));
14451}
14452
14453
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014454static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14455 const v8::AccessorInfo& info ) {
14456 return v8_str("42!");
14457}
14458
14459
14460static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14461 v8::Handle<v8::Array> result = v8::Array::New();
14462 result->Set(0, v8_str("universalAnswer"));
14463 return result;
14464}
14465
14466
14467TEST(NamedEnumeratorAndForIn) {
14468 v8::HandleScope handle_scope;
14469 LocalContext context;
14470 v8::Context::Scope context_scope(context.local());
14471
14472 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14473 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14474 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14475 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14476 "var result = []; for (var k in o) result.push(k); result"));
14477 CHECK_EQ(1, result->Length());
14478 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14479}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000014480
14481
14482TEST(DefinePropertyPostDetach) {
14483 v8::HandleScope scope;
14484 LocalContext context;
14485 v8::Handle<v8::Object> proxy = context->Global();
14486 v8::Handle<v8::Function> define_property =
14487 CompileRun("(function() {"
14488 " Object.defineProperty("
14489 " this,"
14490 " 1,"
14491 " { configurable: true, enumerable: true, value: 3 });"
14492 "})").As<Function>();
14493 context->DetachGlobal();
14494 define_property->Call(proxy, 0, NULL);
14495}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014496
14497
14498static void InstallContextId(v8::Handle<Context> context, int id) {
14499 Context::Scope scope(context);
14500 CompileRun("Object.prototype").As<Object>()->
14501 Set(v8_str("context_id"), v8::Integer::New(id));
14502}
14503
14504
14505static void CheckContextId(v8::Handle<Object> object, int expected) {
14506 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14507}
14508
14509
14510THREADED_TEST(CreationContext) {
14511 HandleScope handle_scope;
14512 Persistent<Context> context1 = Context::New();
14513 InstallContextId(context1, 1);
14514 Persistent<Context> context2 = Context::New();
14515 InstallContextId(context2, 2);
14516 Persistent<Context> context3 = Context::New();
14517 InstallContextId(context3, 3);
14518
14519 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14520
14521 Local<Object> object1;
14522 Local<Function> func1;
14523 {
14524 Context::Scope scope(context1);
14525 object1 = Object::New();
14526 func1 = tmpl->GetFunction();
14527 }
14528
14529 Local<Object> object2;
14530 Local<Function> func2;
14531 {
14532 Context::Scope scope(context2);
14533 object2 = Object::New();
14534 func2 = tmpl->GetFunction();
14535 }
14536
14537 Local<Object> instance1;
14538 Local<Object> instance2;
14539
14540 {
14541 Context::Scope scope(context3);
14542 instance1 = func1->NewInstance();
14543 instance2 = func2->NewInstance();
14544 }
14545
14546 CHECK(object1->CreationContext() == context1);
14547 CheckContextId(object1, 1);
14548 CHECK(func1->CreationContext() == context1);
14549 CheckContextId(func1, 1);
14550 CHECK(instance1->CreationContext() == context1);
14551 CheckContextId(instance1, 1);
14552 CHECK(object2->CreationContext() == context2);
14553 CheckContextId(object2, 2);
14554 CHECK(func2->CreationContext() == context2);
14555 CheckContextId(func2, 2);
14556 CHECK(instance2->CreationContext() == context2);
14557 CheckContextId(instance2, 2);
14558
14559 {
14560 Context::Scope scope(context1);
14561 CHECK(object1->CreationContext() == context1);
14562 CheckContextId(object1, 1);
14563 CHECK(func1->CreationContext() == context1);
14564 CheckContextId(func1, 1);
14565 CHECK(instance1->CreationContext() == context1);
14566 CheckContextId(instance1, 1);
14567 CHECK(object2->CreationContext() == context2);
14568 CheckContextId(object2, 2);
14569 CHECK(func2->CreationContext() == context2);
14570 CheckContextId(func2, 2);
14571 CHECK(instance2->CreationContext() == context2);
14572 CheckContextId(instance2, 2);
14573 }
14574
14575 {
14576 Context::Scope scope(context2);
14577 CHECK(object1->CreationContext() == context1);
14578 CheckContextId(object1, 1);
14579 CHECK(func1->CreationContext() == context1);
14580 CheckContextId(func1, 1);
14581 CHECK(instance1->CreationContext() == context1);
14582 CheckContextId(instance1, 1);
14583 CHECK(object2->CreationContext() == context2);
14584 CheckContextId(object2, 2);
14585 CHECK(func2->CreationContext() == context2);
14586 CheckContextId(func2, 2);
14587 CHECK(instance2->CreationContext() == context2);
14588 CheckContextId(instance2, 2);
14589 }
14590
14591 context1.Dispose();
14592 context2.Dispose();
14593 context3.Dispose();
14594}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000014595
14596
14597Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
14598 const AccessorInfo& info) {
14599 if (index == 42) return v8_str("yes");
14600 return Handle<v8::Integer>();
14601}
14602
14603
14604Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
14605 const AccessorInfo& info) {
14606 if (property->Equals(v8_str("foo"))) return v8_str("yes");
14607 return Handle<Value>();
14608}
14609
14610
14611Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
14612 uint32_t index, const AccessorInfo& info) {
14613 if (index == 42) return v8_num(1).As<v8::Integer>();
14614 return Handle<v8::Integer>();
14615}
14616
14617
14618Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
14619 Local<String> property, const AccessorInfo& info) {
14620 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
14621 return Handle<v8::Integer>();
14622}
14623
14624
14625Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
14626 Local<String> property, const AccessorInfo& info) {
14627 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
14628 return Handle<v8::Integer>();
14629}
14630
14631
14632Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
14633 const AccessorInfo& info) {
14634 return v8_str("yes");
14635}
14636
14637
14638TEST(HasOwnProperty) {
14639 v8::HandleScope scope;
14640 LocalContext env;
14641 { // Check normal properties and defined getters.
14642 Handle<Value> value = CompileRun(
14643 "function Foo() {"
14644 " this.foo = 11;"
14645 " this.__defineGetter__('baz', function() { return 1; });"
14646 "};"
14647 "function Bar() { "
14648 " this.bar = 13;"
14649 " this.__defineGetter__('bla', function() { return 2; });"
14650 "};"
14651 "Bar.prototype = new Foo();"
14652 "new Bar();");
14653 CHECK(value->IsObject());
14654 Handle<Object> object = value->ToObject();
14655 CHECK(object->Has(v8_str("foo")));
14656 CHECK(!object->HasOwnProperty(v8_str("foo")));
14657 CHECK(object->HasOwnProperty(v8_str("bar")));
14658 CHECK(object->Has(v8_str("baz")));
14659 CHECK(!object->HasOwnProperty(v8_str("baz")));
14660 CHECK(object->HasOwnProperty(v8_str("bla")));
14661 }
14662 { // Check named getter interceptors.
14663 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14664 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
14665 Handle<Object> instance = templ->NewInstance();
14666 CHECK(!instance->HasOwnProperty(v8_str("42")));
14667 CHECK(instance->HasOwnProperty(v8_str("foo")));
14668 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14669 }
14670 { // Check indexed getter interceptors.
14671 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14672 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
14673 Handle<Object> instance = templ->NewInstance();
14674 CHECK(instance->HasOwnProperty(v8_str("42")));
14675 CHECK(!instance->HasOwnProperty(v8_str("43")));
14676 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14677 }
14678 { // Check named query interceptors.
14679 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14680 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
14681 Handle<Object> instance = templ->NewInstance();
14682 CHECK(instance->HasOwnProperty(v8_str("foo")));
14683 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14684 }
14685 { // Check indexed query interceptors.
14686 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14687 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
14688 Handle<Object> instance = templ->NewInstance();
14689 CHECK(instance->HasOwnProperty(v8_str("42")));
14690 CHECK(!instance->HasOwnProperty(v8_str("41")));
14691 }
14692 { // Check callbacks.
14693 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14694 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
14695 Handle<Object> instance = templ->NewInstance();
14696 CHECK(instance->HasOwnProperty(v8_str("foo")));
14697 CHECK(!instance->HasOwnProperty(v8_str("bar")));
14698 }
14699 { // Check that query wins on disagreement.
14700 Handle<ObjectTemplate> templ = ObjectTemplate::New();
14701 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
14702 0,
14703 HasOwnPropertyNamedPropertyQuery2);
14704 Handle<Object> instance = templ->NewInstance();
14705 CHECK(!instance->HasOwnProperty(v8_str("foo")));
14706 CHECK(instance->HasOwnProperty(v8_str("bar")));
14707 }
14708}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014709
14710
14711void CheckCodeGenerationAllowed() {
14712 Handle<Value> result = CompileRun("eval('42')");
14713 CHECK_EQ(42, result->Int32Value());
14714 result = CompileRun("(function(e) { return e('42'); })(eval)");
14715 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014716 result = CompileRun("var f = new Function('return 42'); f()");
14717 CHECK_EQ(42, result->Int32Value());
14718}
14719
14720
14721void CheckCodeGenerationDisallowed() {
14722 TryCatch try_catch;
14723
14724 Handle<Value> result = CompileRun("eval('42')");
14725 CHECK(result.IsEmpty());
14726 CHECK(try_catch.HasCaught());
14727 try_catch.Reset();
14728
14729 result = CompileRun("(function(e) { return e('42'); })(eval)");
14730 CHECK(result.IsEmpty());
14731 CHECK(try_catch.HasCaught());
14732 try_catch.Reset();
14733
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014734 result = CompileRun("var f = new Function('return 42'); f()");
14735 CHECK(result.IsEmpty());
14736 CHECK(try_catch.HasCaught());
14737}
14738
14739
14740bool CodeGenerationAllowed(Local<Context> context) {
14741 ApiTestFuzzer::Fuzz();
14742 return true;
14743}
14744
14745
14746bool CodeGenerationDisallowed(Local<Context> context) {
14747 ApiTestFuzzer::Fuzz();
14748 return false;
14749}
14750
14751
14752THREADED_TEST(AllowCodeGenFromStrings) {
14753 v8::HandleScope scope;
14754 LocalContext context;
14755
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014756 // eval and the Function constructor allowed by default.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014757 CheckCodeGenerationAllowed();
14758
ager@chromium.orgea91cc52011-05-23 06:06:11 +000014759 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000014760 context->AllowCodeGenerationFromStrings(false);
14761 CheckCodeGenerationDisallowed();
14762
14763 // Allow again.
14764 context->AllowCodeGenerationFromStrings(true);
14765 CheckCodeGenerationAllowed();
14766
14767 // Disallow but setting a global callback that will allow the calls.
14768 context->AllowCodeGenerationFromStrings(false);
14769 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
14770 CheckCodeGenerationAllowed();
14771
14772 // Set a callback that disallows the code generation.
14773 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
14774 CheckCodeGenerationDisallowed();
14775}
lrn@chromium.org1c092762011-05-09 09:42:16 +000014776
14777
14778static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
14779 return v8::Undefined();
14780}
14781
14782
14783THREADED_TEST(CallAPIFunctionOnNonObject) {
14784 v8::HandleScope scope;
14785 LocalContext context;
14786 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
14787 Handle<Function> function = templ->GetFunction();
14788 context->Global()->Set(v8_str("f"), function);
14789 TryCatch try_catch;
14790 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000014791}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014792
14793
14794// Regression test for issue 1470.
14795THREADED_TEST(ReadOnlyIndexedProperties) {
14796 v8::HandleScope scope;
14797 Local<ObjectTemplate> templ = ObjectTemplate::New();
14798
14799 LocalContext context;
14800 Local<v8::Object> obj = templ->NewInstance();
14801 context->Global()->Set(v8_str("obj"), obj);
14802 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14803 obj->Set(v8_str("1"), v8_str("foobar"));
14804 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
14805 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
14806 obj->Set(v8_num(2), v8_str("foobar"));
14807 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
14808
14809 // Test non-smi case.
14810 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
14811 obj->Set(v8_str("2000000000"), v8_str("foobar"));
14812 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
14813}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014814
14815
14816THREADED_TEST(Regress1516) {
14817 v8::HandleScope scope;
14818
14819 LocalContext context;
14820 { v8::HandleScope temp_scope;
14821 CompileRun("({'a': 0})");
14822 }
14823
14824 int elements;
14825 { i::MapCache* map_cache =
14826 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
14827 elements = map_cache->NumberOfElements();
14828 CHECK_LE(1, elements);
14829 }
14830
14831 i::Isolate::Current()->heap()->CollectAllGarbage(true);
14832 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
14833 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
14834 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
14835 CHECK_GT(elements, map_cache->NumberOfElements());
14836 }
14837 }
14838}