blob: f9880bdaee4b75e2b1b9659a59d9e2bda4e95ca4 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000028// We want to test our deprecated API entries, too.
29#define V8_DISABLE_DEPRECATIONS 1
30
ager@chromium.org3811b432009-10-28 14:53:37 +000031#include <limits.h>
32
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000033#ifndef WIN32
34#include <signal.h> // kill
35#include <unistd.h> // getpid
36#endif // WIN32
37
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000038#include "v8.h"
39
40#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000041#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000042#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000043#include "execution.h"
verwaest@chromium.org753aee42012-07-17 16:15:42 +000044#include "objects.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#include "snapshot.h"
46#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000047#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000048#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000049#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000050#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000051
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000052static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000053
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000054static bool IsNaN(double x) {
55#ifdef WIN32
56 return _isnan(x);
57#else
58 return isnan(x);
59#endif
60}
61
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000063using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000064using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000065using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000066using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000067using ::v8::FunctionTemplate;
68using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000069using ::v8::HandleScope;
70using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000071using ::v8::Message;
72using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000073using ::v8::Object;
74using ::v8::ObjectTemplate;
75using ::v8::Persistent;
76using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000077using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000078using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000079using ::v8::TryCatch;
80using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000081using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000082using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000084
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000085static void ExpectString(const char* code, const char* expected) {
86 Local<Value> result = CompileRun(code);
87 CHECK(result->IsString());
88 String::AsciiValue ascii(result);
89 CHECK_EQ(expected, *ascii);
90}
91
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000092static void ExpectInt32(const char* code, int expected) {
93 Local<Value> result = CompileRun(code);
94 CHECK(result->IsInt32());
95 CHECK_EQ(expected, result->Int32Value());
96}
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000097
98static void ExpectBoolean(const char* code, bool expected) {
99 Local<Value> result = CompileRun(code);
100 CHECK(result->IsBoolean());
101 CHECK_EQ(expected, result->BooleanValue());
102}
103
104
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000105static void ExpectTrue(const char* code) {
106 ExpectBoolean(code, true);
107}
108
109
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000110static void ExpectFalse(const char* code) {
111 ExpectBoolean(code, false);
112}
113
114
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000115static void ExpectObject(const char* code, Local<Value> expected) {
116 Local<Value> result = CompileRun(code);
117 CHECK(result->Equals(expected));
118}
119
120
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000121static void ExpectUndefined(const char* code) {
122 Local<Value> result = CompileRun(code);
123 CHECK(result->IsUndefined());
124}
125
126
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000127static int signature_callback_count;
128static v8::Handle<Value> IncrementingSignatureCallback(
129 const v8::Arguments& args) {
130 ApiTestFuzzer::Fuzz();
131 signature_callback_count++;
132 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
133 for (int i = 0; i < args.Length(); i++)
134 result->Set(v8::Integer::New(i), args[i]);
135 return result;
136}
137
138
139static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
140 ApiTestFuzzer::Fuzz();
141 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
142 for (int i = 0; i < args.Length(); i++) {
143 result->Set(v8::Integer::New(i), args[i]);
144 }
145 return result;
146}
147
148
149THREADED_TEST(Handles) {
150 v8::HandleScope scope;
151 Local<Context> local_env;
152 {
153 LocalContext env;
154 local_env = env.local();
155 }
156
157 // Local context should still be live.
158 CHECK(!local_env.IsEmpty());
159 local_env->Enter();
160
161 v8::Handle<v8::Primitive> undef = v8::Undefined();
162 CHECK(!undef.IsEmpty());
163 CHECK(undef->IsUndefined());
164
165 const char* c_source = "1 + 2 + 3";
166 Local<String> source = String::New(c_source);
167 Local<Script> script = Script::Compile(source);
168 CHECK_EQ(6, script->Run()->Int32Value());
169
170 local_env->Exit();
171}
172
173
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000174THREADED_TEST(ReceiverSignature) {
175 v8::HandleScope scope;
176 LocalContext env;
177 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
178 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
179 fun->PrototypeTemplate()->Set(
180 v8_str("m"),
181 v8::FunctionTemplate::New(IncrementingSignatureCallback,
182 v8::Handle<Value>(),
183 sig));
184 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
185 signature_callback_count = 0;
186 CompileRun(
187 "var o = new Fun();"
188 "o.m();");
189 CHECK_EQ(1, signature_callback_count);
190 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
191 sub_fun->Inherit(fun);
192 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
193 CompileRun(
194 "var o = new SubFun();"
195 "o.m();");
196 CHECK_EQ(2, signature_callback_count);
197
198 v8::TryCatch try_catch;
199 CompileRun(
200 "var o = { };"
201 "o.m = Fun.prototype.m;"
202 "o.m();");
203 CHECK_EQ(2, signature_callback_count);
204 CHECK(try_catch.HasCaught());
205 try_catch.Reset();
206 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
207 sub_fun->Inherit(fun);
208 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
209 CompileRun(
210 "var o = new UnrelFun();"
211 "o.m = Fun.prototype.m;"
212 "o.m();");
213 CHECK_EQ(2, signature_callback_count);
214 CHECK(try_catch.HasCaught());
215}
216
217
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000218THREADED_TEST(ArgumentSignature) {
219 v8::HandleScope scope;
220 LocalContext env;
221 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
222 cons->SetClassName(v8_str("Cons"));
223 v8::Handle<v8::Signature> sig =
224 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
225 v8::Handle<v8::FunctionTemplate> fun =
226 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
227 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
228 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
229
230 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000231 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232
233 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000234 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235
236 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000237 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
239 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
240 cons1->SetClassName(v8_str("Cons1"));
241 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
242 cons2->SetClassName(v8_str("Cons2"));
243 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
244 cons3->SetClassName(v8_str("Cons3"));
245
246 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
247 v8::Handle<v8::Signature> wsig =
248 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
249 v8::Handle<v8::FunctionTemplate> fun2 =
250 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
251
252 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
253 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
254 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
255 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
256 v8::Handle<Value> value4 = CompileRun(
257 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
258 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000259 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000260
261 v8::Handle<Value> value5 = CompileRun(
262 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000263 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264
265 v8::Handle<Value> value6 = CompileRun(
266 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000267 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268
269 v8::Handle<Value> value7 = CompileRun(
270 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
271 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000272 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000273
274 v8::Handle<Value> value8 = CompileRun(
275 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000276 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277}
278
279
280THREADED_TEST(HulIgennem) {
281 v8::HandleScope scope;
282 LocalContext env;
283 v8::Handle<v8::Primitive> undef = v8::Undefined();
284 Local<String> undef_str = undef->ToString();
285 char* value = i::NewArray<char>(undef_str->Length() + 1);
286 undef_str->WriteAscii(value);
287 CHECK_EQ(0, strcmp(value, "undefined"));
288 i::DeleteArray(value);
289}
290
291
292THREADED_TEST(Access) {
293 v8::HandleScope scope;
294 LocalContext env;
295 Local<v8::Object> obj = v8::Object::New();
296 Local<Value> foo_before = obj->Get(v8_str("foo"));
297 CHECK(foo_before->IsUndefined());
298 Local<String> bar_str = v8_str("bar");
299 obj->Set(v8_str("foo"), bar_str);
300 Local<Value> foo_after = obj->Get(v8_str("foo"));
301 CHECK(!foo_after->IsUndefined());
302 CHECK(foo_after->IsString());
303 CHECK_EQ(bar_str, foo_after);
304}
305
306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000307THREADED_TEST(AccessElement) {
308 v8::HandleScope scope;
309 LocalContext env;
310 Local<v8::Object> obj = v8::Object::New();
311 Local<Value> before = obj->Get(1);
312 CHECK(before->IsUndefined());
313 Local<String> bar_str = v8_str("bar");
314 obj->Set(1, bar_str);
315 Local<Value> after = obj->Get(1);
316 CHECK(!after->IsUndefined());
317 CHECK(after->IsString());
318 CHECK_EQ(bar_str, after);
319
320 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
321 CHECK_EQ(v8_str("a"), value->Get(0));
322 CHECK_EQ(v8_str("b"), value->Get(1));
323}
324
325
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000326THREADED_TEST(Script) {
327 v8::HandleScope scope;
328 LocalContext env;
329 const char* c_source = "1 + 2 + 3";
330 Local<String> source = String::New(c_source);
331 Local<Script> script = Script::Compile(source);
332 CHECK_EQ(6, script->Run()->Int32Value());
333}
334
335
336static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000337 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000339 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340 return converted;
341}
342
343
344class TestResource: public String::ExternalStringResource {
345 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000346 explicit TestResource(uint16_t* data, int* counter = NULL)
347 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000348 while (data[length_]) ++length_;
349 }
350
351 ~TestResource() {
352 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000353 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354 }
355
356 const uint16_t* data() const {
357 return data_;
358 }
359
360 size_t length() const {
361 return length_;
362 }
363 private:
364 uint16_t* data_;
365 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000366 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367};
368
369
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000370class TestAsciiResource: public String::ExternalAsciiStringResource {
371 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000372 explicit TestAsciiResource(const char* data, int* counter = NULL)
373 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374
375 ~TestAsciiResource() {
376 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000377 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000378 }
379
380 const char* data() const {
381 return data_;
382 }
383
384 size_t length() const {
385 return length_;
386 }
387 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000388 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000389 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000390 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000391};
392
393
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000394THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000395 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396 const char* c_source = "1 + 2 * 3";
397 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
398 {
399 v8::HandleScope scope;
400 LocalContext env;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000401 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402 Local<String> source = String::NewExternal(resource);
403 Local<Script> script = Script::Compile(source);
404 Local<Value> value = script->Run();
405 CHECK(value->IsNumber());
406 CHECK_EQ(7, value->Int32Value());
407 CHECK(source->IsExternal());
408 CHECK_EQ(resource,
409 static_cast<TestResource*>(source->GetExternalStringResource()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000410 String::Encoding encoding = String::UNKNOWN_ENCODING;
411 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
412 source->GetExternalStringResourceBase(&encoding));
413 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000414 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000415 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 v8::internal::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000418 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000419 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000420}
421
422
423THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000424 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425 const char* c_source = "1 + 2 * 3";
426 {
427 v8::HandleScope scope;
428 LocalContext env;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000429 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
430 &dispose_count);
431 Local<String> source = String::NewExternal(resource);
432 CHECK(source->IsExternalAscii());
433 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
434 source->GetExternalAsciiStringResource());
435 String::Encoding encoding = String::UNKNOWN_ENCODING;
436 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
437 source->GetExternalStringResourceBase(&encoding));
438 CHECK_EQ(String::ASCII_ENCODING, encoding);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439 Local<Script> script = Script::Compile(source);
440 Local<Value> value = script->Run();
441 CHECK(value->IsNumber());
442 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000444 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000448 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000449}
450
451
ager@chromium.org6f10e412009-02-13 10:11:16 +0000452THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000453 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000454 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
455 {
456 v8::HandleScope scope;
457 LocalContext env;
458 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
461 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000462 CHECK_EQ(source->IsExternal(), false);
463 CHECK_EQ(source->IsExternalAscii(), false);
464 String::Encoding encoding = String::UNKNOWN_ENCODING;
465 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
466 CHECK_EQ(String::ASCII_ENCODING, encoding);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000467 bool success = source->MakeExternal(new TestResource(two_byte_source,
468 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000469 CHECK(success);
470 Local<Script> script = Script::Compile(source);
471 Local<Value> value = script->Run();
472 CHECK(value->IsNumber());
473 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000474 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000475 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000478 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000479 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000480}
481
482
483THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000484 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000485 const char* c_source = "1 + 2 * 3";
486 {
487 v8::HandleScope scope;
488 LocalContext env;
489 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
492 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000493 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000494 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000495 CHECK(success);
496 Local<Script> script = Script::Compile(source);
497 Local<Value> value = script->Run();
498 CHECK(value->IsNumber());
499 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000500 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000501 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000502 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000504 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000505 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000506}
507
508
ager@chromium.org5c838252010-02-19 08:53:10 +0000509TEST(MakingExternalStringConditions) {
510 v8::HandleScope scope;
511 LocalContext env;
512
513 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 HEAP->CollectGarbage(i::NEW_SPACE);
515 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000516
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000517 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000518 Local<String> small_string = String::New(two_byte_string);
519 i::DeleteArray(two_byte_string);
520
ager@chromium.org5c838252010-02-19 08:53:10 +0000521 // We should refuse to externalize newly created small string.
522 CHECK(!small_string->CanMakeExternal());
523 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
525 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000526 // Old space strings should be accepted.
527 CHECK(small_string->CanMakeExternal());
528
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000529 two_byte_string = AsciiToTwoByteString("small string 2");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000530 small_string = String::New(two_byte_string);
531 i::DeleteArray(two_byte_string);
532
ager@chromium.org5c838252010-02-19 08:53:10 +0000533 // We should refuse externalizing newly created small string.
534 CHECK(!small_string->CanMakeExternal());
535 for (int i = 0; i < 100; i++) {
536 String::Value value(small_string);
537 }
538 // Frequently used strings should be accepted.
539 CHECK(small_string->CanMakeExternal());
540
541 const int buf_size = 10 * 1024;
542 char* buf = i::NewArray<char>(buf_size);
543 memset(buf, 'a', buf_size);
544 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000545
546 two_byte_string = AsciiToTwoByteString(buf);
547 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000548 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000549 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000550 // Large strings should be immediately accepted.
551 CHECK(large_string->CanMakeExternal());
552}
553
554
555TEST(MakingExternalAsciiStringConditions) {
556 v8::HandleScope scope;
557 LocalContext env;
558
559 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 HEAP->CollectGarbage(i::NEW_SPACE);
561 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000562
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000563 Local<String> small_string = String::New("s1");
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 // We should refuse to externalize newly created small string.
565 CHECK(!small_string->CanMakeExternal());
566 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
568 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000569 // Old space strings should be accepted.
570 CHECK(small_string->CanMakeExternal());
571
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000572 small_string = String::New("small string 2");
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 // We should refuse externalizing newly created small string.
574 CHECK(!small_string->CanMakeExternal());
575 for (int i = 0; i < 100; i++) {
576 String::Value value(small_string);
577 }
578 // Frequently used strings should be accepted.
579 CHECK(small_string->CanMakeExternal());
580
581 const int buf_size = 10 * 1024;
582 char* buf = i::NewArray<char>(buf_size);
583 memset(buf, 'a', buf_size);
584 buf[buf_size - 1] = '\0';
585 Local<String> large_string = String::New(buf);
586 i::DeleteArray(buf);
587 // Large strings should be immediately accepted.
588 CHECK(large_string->CanMakeExternal());
589}
590
591
ager@chromium.org6f10e412009-02-13 10:11:16 +0000592THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000593 {
594 v8::HandleScope scope;
595 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
596 Local<String> string =
597 String::NewExternal(new TestResource(two_byte_string));
598 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
599 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
601 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
602 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000603 CHECK(isymbol->IsSymbol());
604 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000605 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
606 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000607}
608
609
610THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000611 {
612 v8::HandleScope scope;
613 const char* one_byte_string = "test string";
614 Local<String> string = String::NewExternal(
615 new TestAsciiResource(i::StrDup(one_byte_string)));
616 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
617 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
619 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
620 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000621 CHECK(isymbol->IsSymbol());
622 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000623 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
624 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000625}
626
627
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628THREADED_TEST(ScavengeExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000629 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000630 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 {
632 v8::HandleScope scope;
633 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
634 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000635 String::NewExternal(new TestResource(two_byte_string,
636 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000637 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 HEAP->CollectGarbage(i::NEW_SPACE);
639 in_new_space = HEAP->InNewSpace(*istring);
640 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000641 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000642 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000644 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645}
646
647
648THREADED_TEST(ScavengeExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000649 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000650 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 {
652 v8::HandleScope scope;
653 const char* one_byte_string = "test string";
654 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000655 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000656 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 HEAP->CollectGarbage(i::NEW_SPACE);
658 in_new_space = HEAP->InNewSpace(*istring);
659 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000660 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000663 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000664}
665
666
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000667class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
668 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000669 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000670 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000671 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000672
673 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000674 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000675 dispose_(dispose) { }
676
677 void Dispose() {
678 ++dispose_calls;
679 if (dispose_) delete this;
680 }
681 private:
682 bool dispose_;
683};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000684
685
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000686int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000687int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688
689
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000691 const char* c_source = "1 + 2 * 3";
692
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000693 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000694 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000695 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
696 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000697 {
698 v8::HandleScope scope;
699 LocalContext env;
700 Local<String> source = String::NewExternal(&res_stack);
701 Local<Script> script = Script::Compile(source);
702 Local<Value> value = script->Run();
703 CHECK(value->IsNumber());
704 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000705 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000706 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000707 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000708 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000710 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000711 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000712
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000713 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000714 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000715 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
716 TestAsciiResource* res_heap =
717 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000718 {
719 v8::HandleScope scope;
720 LocalContext env;
721 Local<String> source = String::NewExternal(res_heap);
722 Local<Script> script = Script::Compile(source);
723 Local<Value> value = script->Run();
724 CHECK(value->IsNumber());
725 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000727 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000728 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000729 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000731 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000732 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000733}
734
735
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000736THREADED_TEST(StringConcat) {
737 {
738 v8::HandleScope scope;
739 LocalContext env;
740 const char* one_byte_string_1 = "function a_times_t";
741 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
742 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
743 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
744 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
745 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
746 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
747 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000748
749 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
750 Local<String> right = String::New(two_byte_source);
751 i::DeleteArray(two_byte_source);
752
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000753 Local<String> source = String::Concat(left, right);
754 right = String::NewExternal(
755 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
756 source = String::Concat(source, right);
757 right = String::NewExternal(
758 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
759 source = String::Concat(source, right);
760 right = v8_str(one_byte_string_2);
761 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000762
763 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
764 right = String::New(two_byte_source);
765 i::DeleteArray(two_byte_source);
766
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000767 source = String::Concat(source, right);
768 right = String::NewExternal(
769 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
770 source = String::Concat(source, right);
771 Local<Script> script = Script::Compile(source);
772 Local<Value> value = script->Run();
773 CHECK(value->IsNumber());
774 CHECK_EQ(68, value->Int32Value());
775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000777 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
778 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000779}
780
781
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782THREADED_TEST(GlobalProperties) {
783 v8::HandleScope scope;
784 LocalContext env;
785 v8::Handle<v8::Object> global = env->Global();
786 global->Set(v8_str("pi"), v8_num(3.1415926));
787 Local<Value> pi = global->Get(v8_str("pi"));
788 CHECK_EQ(3.1415926, pi->NumberValue());
789}
790
791
792static v8::Handle<Value> handle_call(const v8::Arguments& args) {
793 ApiTestFuzzer::Fuzz();
794 return v8_num(102);
795}
796
797
798static v8::Handle<Value> construct_call(const v8::Arguments& args) {
799 ApiTestFuzzer::Fuzz();
800 args.This()->Set(v8_str("x"), v8_num(1));
801 args.This()->Set(v8_str("y"), v8_num(2));
802 return args.This();
803}
804
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000805static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
806 ApiTestFuzzer::Fuzz();
807 return v8_num(239);
808}
809
810
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000811THREADED_TEST(FunctionTemplate) {
812 v8::HandleScope scope;
813 LocalContext env;
814 {
815 Local<v8::FunctionTemplate> fun_templ =
816 v8::FunctionTemplate::New(handle_call);
817 Local<Function> fun = fun_templ->GetFunction();
818 env->Global()->Set(v8_str("obj"), fun);
819 Local<Script> script = v8_compile("obj()");
820 CHECK_EQ(102, script->Run()->Int32Value());
821 }
822 // Use SetCallHandler to initialize a function template, should work like the
823 // previous one.
824 {
825 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
826 fun_templ->SetCallHandler(handle_call);
827 Local<Function> fun = fun_templ->GetFunction();
828 env->Global()->Set(v8_str("obj"), fun);
829 Local<Script> script = v8_compile("obj()");
830 CHECK_EQ(102, script->Run()->Int32Value());
831 }
832 // Test constructor calls.
833 {
834 Local<v8::FunctionTemplate> fun_templ =
835 v8::FunctionTemplate::New(construct_call);
836 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000837 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000838 Local<Function> fun = fun_templ->GetFunction();
839 env->Global()->Set(v8_str("obj"), fun);
840 Local<Script> script = v8_compile("var s = new obj(); s.x");
841 CHECK_EQ(1, script->Run()->Int32Value());
842
843 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
844 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000845
846 result = v8_compile("(new obj()).m")->Run();
847 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000848 }
849}
850
851
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000852static void* expected_ptr;
853static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
854 void* ptr = v8::External::Unwrap(args.Data());
855 CHECK_EQ(expected_ptr, ptr);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000856 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000857}
858
859
860static void TestExternalPointerWrapping() {
861 v8::HandleScope scope;
862 LocalContext env;
863
864 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
865
866 v8::Handle<v8::Object> obj = v8::Object::New();
867 obj->Set(v8_str("func"),
868 v8::FunctionTemplate::New(callback, data)->GetFunction());
869 env->Global()->Set(v8_str("obj"), obj);
870
871 CHECK(CompileRun(
872 "function foo() {\n"
873 " for (var i = 0; i < 13; i++) obj.func();\n"
874 "}\n"
875 "foo(), true")->BooleanValue());
876}
877
878
879THREADED_TEST(ExternalWrap) {
880 // Check heap allocated object.
881 int* ptr = new int;
882 expected_ptr = ptr;
883 TestExternalPointerWrapping();
884 delete ptr;
885
886 // Check stack allocated object.
887 int foo;
888 expected_ptr = &foo;
889 TestExternalPointerWrapping();
890
891 // Check not aligned addresses.
892 const int n = 100;
893 char* s = new char[n];
894 for (int i = 0; i < n; i++) {
895 expected_ptr = s + i;
896 TestExternalPointerWrapping();
897 }
898
899 delete[] s;
900
901 // Check several invalid addresses.
902 expected_ptr = reinterpret_cast<void*>(1);
903 TestExternalPointerWrapping();
904
905 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
906 TestExternalPointerWrapping();
907
908 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
909 TestExternalPointerWrapping();
910
911#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000912 // Check a value with a leading 1 bit in x64 Smi encoding.
913 expected_ptr = reinterpret_cast<void*>(0x400000000);
914 TestExternalPointerWrapping();
915
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000916 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
917 TestExternalPointerWrapping();
918
919 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
920 TestExternalPointerWrapping();
921#endif
922}
923
924
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000925THREADED_TEST(FindInstanceInPrototypeChain) {
926 v8::HandleScope scope;
927 LocalContext env;
928
929 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
930 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
931 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
932 derived->Inherit(base);
933
934 Local<v8::Function> base_function = base->GetFunction();
935 Local<v8::Function> derived_function = derived->GetFunction();
936 Local<v8::Function> other_function = other->GetFunction();
937
938 Local<v8::Object> base_instance = base_function->NewInstance();
939 Local<v8::Object> derived_instance = derived_function->NewInstance();
940 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
941 Local<v8::Object> other_instance = other_function->NewInstance();
942 derived_instance2->Set(v8_str("__proto__"), derived_instance);
943 other_instance->Set(v8_str("__proto__"), derived_instance2);
944
945 // base_instance is only an instance of base.
946 CHECK_EQ(base_instance,
947 base_instance->FindInstanceInPrototypeChain(base));
948 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
949 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
950
951 // derived_instance is an instance of base and derived.
952 CHECK_EQ(derived_instance,
953 derived_instance->FindInstanceInPrototypeChain(base));
954 CHECK_EQ(derived_instance,
955 derived_instance->FindInstanceInPrototypeChain(derived));
956 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
957
958 // other_instance is an instance of other and its immediate
959 // prototype derived_instance2 is an instance of base and derived.
960 // Note, derived_instance is an instance of base and derived too,
961 // but it comes after derived_instance2 in the prototype chain of
962 // other_instance.
963 CHECK_EQ(derived_instance2,
964 other_instance->FindInstanceInPrototypeChain(base));
965 CHECK_EQ(derived_instance2,
966 other_instance->FindInstanceInPrototypeChain(derived));
967 CHECK_EQ(other_instance,
968 other_instance->FindInstanceInPrototypeChain(other));
969}
970
971
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000972THREADED_TEST(TinyInteger) {
973 v8::HandleScope scope;
974 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000975 v8::Isolate* isolate = v8::Isolate::GetCurrent();
976
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000977 int32_t value = 239;
978 Local<v8::Integer> value_obj = v8::Integer::New(value);
979 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000980
981 value_obj = v8::Integer::New(value, isolate);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000983}
984
985
986THREADED_TEST(BigSmiInteger) {
987 v8::HandleScope scope;
988 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000989 v8::Isolate* isolate = v8::Isolate::GetCurrent();
990
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000991 int32_t value = i::Smi::kMaxValue;
992 // We cannot add one to a Smi::kMaxValue without wrapping.
993 if (i::kSmiValueSize < 32) {
994 CHECK(i::Smi::IsValid(value));
995 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000996
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000997 Local<v8::Integer> value_obj = v8::Integer::New(value);
998 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000999
1000 value_obj = v8::Integer::New(value, isolate);
1001 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001002 }
1003}
1004
1005
1006THREADED_TEST(BigInteger) {
1007 v8::HandleScope scope;
1008 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001009 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1010
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001011 // We cannot add one to a Smi::kMaxValue without wrapping.
1012 if (i::kSmiValueSize < 32) {
1013 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1014 // The code will not be run in that case, due to the "if" guard.
1015 int32_t value =
1016 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1017 CHECK(value > i::Smi::kMaxValue);
1018 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001019
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001020 Local<v8::Integer> value_obj = v8::Integer::New(value);
1021 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001022
1023 value_obj = v8::Integer::New(value, isolate);
1024 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001025 }
1026}
1027
1028
1029THREADED_TEST(TinyUnsignedInteger) {
1030 v8::HandleScope scope;
1031 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001032 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1033
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001034 uint32_t value = 239;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001035
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001036 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1037 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001038
1039 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1040 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001041}
1042
1043
1044THREADED_TEST(BigUnsignedSmiInteger) {
1045 v8::HandleScope scope;
1046 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001047 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1048
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001049 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1050 CHECK(i::Smi::IsValid(value));
1051 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001052
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001053 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1054 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001055
1056 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1057 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001058}
1059
1060
1061THREADED_TEST(BigUnsignedInteger) {
1062 v8::HandleScope scope;
1063 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001064 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1065
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001066 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1067 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1068 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001069
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001070 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1071 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001072
1073 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1074 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001075}
1076
1077
1078THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1079 v8::HandleScope scope;
1080 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001081 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1082
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001083 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1084 uint32_t value = INT32_MAX_AS_UINT + 1;
1085 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001086
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001087 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1088 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001089
1090 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1091 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001092}
1093
1094
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001095THREADED_TEST(IsNativeError) {
1096 v8::HandleScope scope;
1097 LocalContext env;
1098 v8::Handle<Value> syntax_error = CompileRun(
1099 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1100 CHECK(syntax_error->IsNativeError());
1101 v8::Handle<Value> not_error = CompileRun("{a:42}");
1102 CHECK(!not_error->IsNativeError());
1103 v8::Handle<Value> not_object = CompileRun("42");
1104 CHECK(!not_object->IsNativeError());
1105}
1106
1107
1108THREADED_TEST(StringObject) {
1109 v8::HandleScope scope;
1110 LocalContext env;
1111 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1112 CHECK(boxed_string->IsStringObject());
1113 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1114 CHECK(!unboxed_string->IsStringObject());
1115 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1116 CHECK(!boxed_not_string->IsStringObject());
1117 v8::Handle<Value> not_object = CompileRun("0");
1118 CHECK(!not_object->IsStringObject());
1119 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1120 CHECK(!as_boxed.IsEmpty());
1121 Local<v8::String> the_string = as_boxed->StringValue();
1122 CHECK(!the_string.IsEmpty());
1123 ExpectObject("\"test\"", the_string);
1124 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1125 CHECK(new_boxed_string->IsStringObject());
1126 as_boxed = new_boxed_string.As<v8::StringObject>();
1127 the_string = as_boxed->StringValue();
1128 CHECK(!the_string.IsEmpty());
1129 ExpectObject("\"test\"", the_string);
1130}
1131
1132
1133THREADED_TEST(NumberObject) {
1134 v8::HandleScope scope;
1135 LocalContext env;
1136 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1137 CHECK(boxed_number->IsNumberObject());
1138 v8::Handle<Value> unboxed_number = CompileRun("42");
1139 CHECK(!unboxed_number->IsNumberObject());
1140 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1141 CHECK(!boxed_not_number->IsNumberObject());
1142 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1143 CHECK(!as_boxed.IsEmpty());
1144 double the_number = as_boxed->NumberValue();
1145 CHECK_EQ(42.0, the_number);
1146 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1147 CHECK(new_boxed_number->IsNumberObject());
1148 as_boxed = new_boxed_number.As<v8::NumberObject>();
1149 the_number = as_boxed->NumberValue();
1150 CHECK_EQ(43.0, the_number);
1151}
1152
1153
1154THREADED_TEST(BooleanObject) {
1155 v8::HandleScope scope;
1156 LocalContext env;
1157 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1158 CHECK(boxed_boolean->IsBooleanObject());
1159 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1160 CHECK(!unboxed_boolean->IsBooleanObject());
1161 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1162 CHECK(!boxed_not_boolean->IsBooleanObject());
1163 v8::Handle<v8::BooleanObject> as_boxed =
1164 boxed_boolean.As<v8::BooleanObject>();
1165 CHECK(!as_boxed.IsEmpty());
1166 bool the_boolean = as_boxed->BooleanValue();
1167 CHECK_EQ(true, the_boolean);
1168 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1169 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1170 CHECK(boxed_true->IsBooleanObject());
1171 CHECK(boxed_false->IsBooleanObject());
1172 as_boxed = boxed_true.As<v8::BooleanObject>();
1173 CHECK_EQ(true, as_boxed->BooleanValue());
1174 as_boxed = boxed_false.As<v8::BooleanObject>();
1175 CHECK_EQ(false, as_boxed->BooleanValue());
1176}
1177
1178
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001179THREADED_TEST(Number) {
1180 v8::HandleScope scope;
1181 LocalContext env;
1182 double PI = 3.1415926;
1183 Local<v8::Number> pi_obj = v8::Number::New(PI);
1184 CHECK_EQ(PI, pi_obj->NumberValue());
1185}
1186
1187
1188THREADED_TEST(ToNumber) {
1189 v8::HandleScope scope;
1190 LocalContext env;
1191 Local<String> str = v8_str("3.1415926");
1192 CHECK_EQ(3.1415926, str->NumberValue());
1193 v8::Handle<v8::Boolean> t = v8::True();
1194 CHECK_EQ(1.0, t->NumberValue());
1195 v8::Handle<v8::Boolean> f = v8::False();
1196 CHECK_EQ(0.0, f->NumberValue());
1197}
1198
1199
1200THREADED_TEST(Date) {
1201 v8::HandleScope scope;
1202 LocalContext env;
1203 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001204 Local<Value> date = v8::Date::New(PI);
1205 CHECK_EQ(3.0, date->NumberValue());
1206 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1207 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001208}
1209
1210
1211THREADED_TEST(Boolean) {
1212 v8::HandleScope scope;
1213 LocalContext env;
1214 v8::Handle<v8::Boolean> t = v8::True();
1215 CHECK(t->Value());
1216 v8::Handle<v8::Boolean> f = v8::False();
1217 CHECK(!f->Value());
1218 v8::Handle<v8::Primitive> u = v8::Undefined();
1219 CHECK(!u->BooleanValue());
1220 v8::Handle<v8::Primitive> n = v8::Null();
1221 CHECK(!n->BooleanValue());
1222 v8::Handle<String> str1 = v8_str("");
1223 CHECK(!str1->BooleanValue());
1224 v8::Handle<String> str2 = v8_str("x");
1225 CHECK(str2->BooleanValue());
1226 CHECK(!v8::Number::New(0)->BooleanValue());
1227 CHECK(v8::Number::New(-1)->BooleanValue());
1228 CHECK(v8::Number::New(1)->BooleanValue());
1229 CHECK(v8::Number::New(42)->BooleanValue());
1230 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1231}
1232
1233
1234static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1235 ApiTestFuzzer::Fuzz();
1236 return v8_num(13.4);
1237}
1238
1239
1240static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1241 ApiTestFuzzer::Fuzz();
1242 return v8_num(876);
1243}
1244
1245
1246THREADED_TEST(GlobalPrototype) {
1247 v8::HandleScope scope;
1248 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1249 func_templ->PrototypeTemplate()->Set(
1250 "dummy",
1251 v8::FunctionTemplate::New(DummyCallHandler));
1252 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1253 templ->Set("x", v8_num(200));
1254 templ->SetAccessor(v8_str("m"), GetM);
1255 LocalContext env(0, templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001256 v8::Handle<Script> script(v8_compile("dummy()"));
1257 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001258 CHECK_EQ(13.4, result->NumberValue());
1259 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1260 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1261}
1262
1263
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001264THREADED_TEST(ObjectTemplate) {
1265 v8::HandleScope scope;
1266 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1267 templ1->Set("x", v8_num(10));
1268 templ1->Set("y", v8_num(13));
1269 LocalContext env;
1270 Local<v8::Object> instance1 = templ1->NewInstance();
1271 env->Global()->Set(v8_str("p"), instance1);
1272 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1273 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1274 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1275 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1276 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1277 templ2->Set("a", v8_num(12));
1278 templ2->Set("b", templ1);
1279 Local<v8::Object> instance2 = templ2->NewInstance();
1280 env->Global()->Set(v8_str("q"), instance2);
1281 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1282 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1283 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1284 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1285}
1286
1287
1288static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1289 ApiTestFuzzer::Fuzz();
1290 return v8_num(17.2);
1291}
1292
1293
1294static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1295 ApiTestFuzzer::Fuzz();
1296 return v8_num(15.2);
1297}
1298
1299
1300THREADED_TEST(DescriptorInheritance) {
1301 v8::HandleScope scope;
1302 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1303 super->PrototypeTemplate()->Set("flabby",
1304 v8::FunctionTemplate::New(GetFlabby));
1305 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1306
1307 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1308
1309 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1310 base1->Inherit(super);
1311 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1312
1313 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1314 base2->Inherit(super);
1315 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1316
1317 LocalContext env;
1318
1319 env->Global()->Set(v8_str("s"), super->GetFunction());
1320 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1321 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1322
1323 // Checks right __proto__ chain.
1324 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1325 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1326
1327 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1328
1329 // Instance accessor should not be visible on function object or its prototype
1330 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1331 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1332 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1333
1334 env->Global()->Set(v8_str("obj"),
1335 base1->GetFunction()->NewInstance());
1336 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1337 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1338 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1339 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1340 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1341
1342 env->Global()->Set(v8_str("obj2"),
1343 base2->GetFunction()->NewInstance());
1344 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1345 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1346 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1347 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1348 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1349
1350 // base1 and base2 cannot cross reference to each's prototype
1351 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1352 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1353}
1354
1355
1356int echo_named_call_count;
1357
1358
1359static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1360 const AccessorInfo& info) {
1361 ApiTestFuzzer::Fuzz();
1362 CHECK_EQ(v8_str("data"), info.Data());
1363 echo_named_call_count++;
1364 return name;
1365}
1366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367// Helper functions for Interceptor/Accessor interaction tests
1368
1369Handle<Value> SimpleAccessorGetter(Local<String> name,
1370 const AccessorInfo& info) {
1371 Handle<Object> self = info.This();
1372 return self->Get(String::Concat(v8_str("accessor_"), name));
1373}
1374
1375void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1376 const AccessorInfo& info) {
1377 Handle<Object> self = info.This();
1378 self->Set(String::Concat(v8_str("accessor_"), name), value);
1379}
1380
1381Handle<Value> EmptyInterceptorGetter(Local<String> name,
1382 const AccessorInfo& info) {
1383 return Handle<Value>();
1384}
1385
1386Handle<Value> EmptyInterceptorSetter(Local<String> name,
1387 Local<Value> value,
1388 const AccessorInfo& info) {
1389 return Handle<Value>();
1390}
1391
1392Handle<Value> InterceptorGetter(Local<String> name,
1393 const AccessorInfo& info) {
1394 // Intercept names that start with 'interceptor_'.
1395 String::AsciiValue ascii(name);
1396 char* name_str = *ascii;
1397 char prefix[] = "interceptor_";
1398 int i;
1399 for (i = 0; name_str[i] && prefix[i]; ++i) {
1400 if (name_str[i] != prefix[i]) return Handle<Value>();
1401 }
1402 Handle<Object> self = info.This();
1403 return self->GetHiddenValue(v8_str(name_str + i));
1404}
1405
1406Handle<Value> InterceptorSetter(Local<String> name,
1407 Local<Value> value,
1408 const AccessorInfo& info) {
1409 // Intercept accesses that set certain integer values.
1410 if (value->IsInt32() && value->Int32Value() < 10000) {
1411 Handle<Object> self = info.This();
1412 self->SetHiddenValue(name, value);
1413 return value;
1414 }
1415 return Handle<Value>();
1416}
1417
1418void AddAccessor(Handle<FunctionTemplate> templ,
1419 Handle<String> name,
1420 v8::AccessorGetter getter,
1421 v8::AccessorSetter setter) {
1422 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1423}
1424
1425void AddInterceptor(Handle<FunctionTemplate> templ,
1426 v8::NamedPropertyGetter getter,
1427 v8::NamedPropertySetter setter) {
1428 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1429}
1430
1431THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1432 v8::HandleScope scope;
1433 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1434 Handle<FunctionTemplate> child = FunctionTemplate::New();
1435 child->Inherit(parent);
1436 AddAccessor(parent, v8_str("age"),
1437 SimpleAccessorGetter, SimpleAccessorSetter);
1438 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1439 LocalContext env;
1440 env->Global()->Set(v8_str("Child"), child->GetFunction());
1441 CompileRun("var child = new Child;"
1442 "child.age = 10;");
1443 ExpectBoolean("child.hasOwnProperty('age')", false);
1444 ExpectInt32("child.age", 10);
1445 ExpectInt32("child.accessor_age", 10);
1446}
1447
1448THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1449 v8::HandleScope scope;
1450 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1451 Handle<FunctionTemplate> child = FunctionTemplate::New();
1452 child->Inherit(parent);
1453 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1454 LocalContext env;
1455 env->Global()->Set(v8_str("Child"), child->GetFunction());
1456 CompileRun("var child = new Child;"
1457 "var parent = child.__proto__;"
1458 "Object.defineProperty(parent, 'age', "
1459 " {get: function(){ return this.accessor_age; }, "
1460 " set: function(v){ this.accessor_age = v; }, "
1461 " enumerable: true, configurable: true});"
1462 "child.age = 10;");
1463 ExpectBoolean("child.hasOwnProperty('age')", false);
1464 ExpectInt32("child.age", 10);
1465 ExpectInt32("child.accessor_age", 10);
1466}
1467
1468THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1469 v8::HandleScope scope;
1470 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1471 Handle<FunctionTemplate> child = FunctionTemplate::New();
1472 child->Inherit(parent);
1473 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1474 LocalContext env;
1475 env->Global()->Set(v8_str("Child"), child->GetFunction());
1476 CompileRun("var child = new Child;"
1477 "var parent = child.__proto__;"
1478 "parent.name = 'Alice';");
1479 ExpectBoolean("child.hasOwnProperty('name')", false);
1480 ExpectString("child.name", "Alice");
1481 CompileRun("child.name = 'Bob';");
1482 ExpectString("child.name", "Bob");
1483 ExpectBoolean("child.hasOwnProperty('name')", true);
1484 ExpectString("parent.name", "Alice");
1485}
1486
1487THREADED_TEST(SwitchFromInterceptorToAccessor) {
1488 v8::HandleScope scope;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001489 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1490 AddAccessor(templ, v8_str("age"),
1491 SimpleAccessorGetter, SimpleAccessorSetter);
1492 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1493 LocalContext env;
1494 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1495 CompileRun("var obj = new Obj;"
1496 "function setAge(i){ obj.age = i; };"
1497 "for(var i = 0; i <= 10000; i++) setAge(i);");
1498 // All i < 10000 go to the interceptor.
1499 ExpectInt32("obj.interceptor_age", 9999);
1500 // The last i goes to the accessor.
1501 ExpectInt32("obj.accessor_age", 10000);
1502}
1503
1504THREADED_TEST(SwitchFromAccessorToInterceptor) {
1505 v8::HandleScope scope;
1506 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1507 AddAccessor(templ, v8_str("age"),
1508 SimpleAccessorGetter, SimpleAccessorSetter);
1509 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1510 LocalContext env;
1511 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1512 CompileRun("var obj = new Obj;"
1513 "function setAge(i){ obj.age = i; };"
1514 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1515 // All i >= 10000 go to the accessor.
1516 ExpectInt32("obj.accessor_age", 10000);
1517 // The last i goes to the interceptor.
1518 ExpectInt32("obj.interceptor_age", 9999);
1519}
1520
1521THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1522 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1524 Handle<FunctionTemplate> child = FunctionTemplate::New();
1525 child->Inherit(parent);
1526 AddAccessor(parent, v8_str("age"),
1527 SimpleAccessorGetter, SimpleAccessorSetter);
1528 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1529 LocalContext env;
1530 env->Global()->Set(v8_str("Child"), child->GetFunction());
1531 CompileRun("var child = new Child;"
1532 "function setAge(i){ child.age = i; };"
1533 "for(var i = 0; i <= 10000; i++) setAge(i);");
1534 // All i < 10000 go to the interceptor.
1535 ExpectInt32("child.interceptor_age", 9999);
1536 // The last i goes to the accessor.
1537 ExpectInt32("child.accessor_age", 10000);
1538}
1539
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001540THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 v8::HandleScope scope;
1542 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1543 Handle<FunctionTemplate> child = FunctionTemplate::New();
1544 child->Inherit(parent);
1545 AddAccessor(parent, v8_str("age"),
1546 SimpleAccessorGetter, SimpleAccessorSetter);
1547 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1548 LocalContext env;
1549 env->Global()->Set(v8_str("Child"), child->GetFunction());
1550 CompileRun("var child = new Child;"
1551 "function setAge(i){ child.age = i; };"
1552 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1553 // All i >= 10000 go to the accessor.
1554 ExpectInt32("child.accessor_age", 10000);
1555 // The last i goes to the interceptor.
1556 ExpectInt32("child.interceptor_age", 9999);
1557}
1558
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001559THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1560 v8::HandleScope scope;
1561 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1562 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1563 LocalContext env;
1564 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1565 CompileRun("var obj = new Obj;"
1566 "function setter(i) { this.accessor_age = i; };"
1567 "function getter() { return this.accessor_age; };"
1568 "function setAge(i) { obj.age = i; };"
1569 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1570 "for(var i = 0; i <= 10000; i++) setAge(i);");
1571 // All i < 10000 go to the interceptor.
1572 ExpectInt32("obj.interceptor_age", 9999);
1573 // The last i goes to the JavaScript accessor.
1574 ExpectInt32("obj.accessor_age", 10000);
1575 // The installed JavaScript getter is still intact.
1576 // This last part is a regression test for issue 1651 and relies on the fact
1577 // that both interceptor and accessor are being installed on the same object.
1578 ExpectInt32("obj.age", 10000);
1579 ExpectBoolean("obj.hasOwnProperty('age')", true);
1580 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1581}
1582
1583THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1584 v8::HandleScope scope;
1585 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1586 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1587 LocalContext env;
1588 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1589 CompileRun("var obj = new Obj;"
1590 "function setter(i) { this.accessor_age = i; };"
1591 "function getter() { return this.accessor_age; };"
1592 "function setAge(i) { obj.age = i; };"
1593 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1594 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1595 // All i >= 10000 go to the accessor.
1596 ExpectInt32("obj.accessor_age", 10000);
1597 // The last i goes to the interceptor.
1598 ExpectInt32("obj.interceptor_age", 9999);
1599 // The installed JavaScript getter is still intact.
1600 // This last part is a regression test for issue 1651 and relies on the fact
1601 // that both interceptor and accessor are being installed on the same object.
1602 ExpectInt32("obj.age", 10000);
1603 ExpectBoolean("obj.hasOwnProperty('age')", true);
1604 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1605}
1606
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607THREADED_TEST(SwitchFromInterceptorToProperty) {
1608 v8::HandleScope scope;
1609 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1610 Handle<FunctionTemplate> child = FunctionTemplate::New();
1611 child->Inherit(parent);
1612 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1613 LocalContext env;
1614 env->Global()->Set(v8_str("Child"), child->GetFunction());
1615 CompileRun("var child = new Child;"
1616 "function setAge(i){ child.age = i; };"
1617 "for(var i = 0; i <= 10000; i++) setAge(i);");
1618 // All i < 10000 go to the interceptor.
1619 ExpectInt32("child.interceptor_age", 9999);
1620 // The last i goes to child's own property.
1621 ExpectInt32("child.age", 10000);
1622}
1623
1624THREADED_TEST(SwitchFromPropertyToInterceptor) {
1625 v8::HandleScope scope;
1626 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1627 Handle<FunctionTemplate> child = FunctionTemplate::New();
1628 child->Inherit(parent);
1629 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1630 LocalContext env;
1631 env->Global()->Set(v8_str("Child"), child->GetFunction());
1632 CompileRun("var child = new Child;"
1633 "function setAge(i){ child.age = i; };"
1634 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1635 // All i >= 10000 go to child's own property.
1636 ExpectInt32("child.age", 10000);
1637 // The last i goes to the interceptor.
1638 ExpectInt32("child.interceptor_age", 9999);
1639}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001640
1641THREADED_TEST(NamedPropertyHandlerGetter) {
1642 echo_named_call_count = 0;
1643 v8::HandleScope scope;
1644 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1645 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1646 0, 0, 0, 0,
1647 v8_str("data"));
1648 LocalContext env;
1649 env->Global()->Set(v8_str("obj"),
1650 templ->GetFunction()->NewInstance());
1651 CHECK_EQ(echo_named_call_count, 0);
1652 v8_compile("obj.x")->Run();
1653 CHECK_EQ(echo_named_call_count, 1);
1654 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1655 v8::Handle<Value> str = CompileRun(code);
1656 String::AsciiValue value(str);
1657 CHECK_EQ(*value, "oddlepoddle");
1658 // Check default behavior
1659 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1660 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1661 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1662}
1663
1664
1665int echo_indexed_call_count = 0;
1666
1667
1668static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1669 const AccessorInfo& info) {
1670 ApiTestFuzzer::Fuzz();
1671 CHECK_EQ(v8_num(637), info.Data());
1672 echo_indexed_call_count++;
1673 return v8_num(index);
1674}
1675
1676
1677THREADED_TEST(IndexedPropertyHandlerGetter) {
1678 v8::HandleScope scope;
1679 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1680 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1681 0, 0, 0, 0,
1682 v8_num(637));
1683 LocalContext env;
1684 env->Global()->Set(v8_str("obj"),
1685 templ->GetFunction()->NewInstance());
1686 Local<Script> script = v8_compile("obj[900]");
1687 CHECK_EQ(script->Run()->Int32Value(), 900);
1688}
1689
1690
1691v8::Handle<v8::Object> bottom;
1692
1693static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1694 uint32_t index,
1695 const AccessorInfo& info) {
1696 ApiTestFuzzer::Fuzz();
1697 CHECK(info.This()->Equals(bottom));
1698 return v8::Handle<Value>();
1699}
1700
1701static v8::Handle<Value> CheckThisNamedPropertyHandler(
1702 Local<String> name,
1703 const AccessorInfo& info) {
1704 ApiTestFuzzer::Fuzz();
1705 CHECK(info.This()->Equals(bottom));
1706 return v8::Handle<Value>();
1707}
1708
1709
1710v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1711 Local<Value> value,
1712 const AccessorInfo& info) {
1713 ApiTestFuzzer::Fuzz();
1714 CHECK(info.This()->Equals(bottom));
1715 return v8::Handle<Value>();
1716}
1717
1718
1719v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1720 Local<Value> value,
1721 const AccessorInfo& info) {
1722 ApiTestFuzzer::Fuzz();
1723 CHECK(info.This()->Equals(bottom));
1724 return v8::Handle<Value>();
1725}
1726
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001727v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001728 uint32_t index,
1729 const AccessorInfo& info) {
1730 ApiTestFuzzer::Fuzz();
1731 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001732 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001733}
1734
1735
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001736v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001737 const AccessorInfo& info) {
1738 ApiTestFuzzer::Fuzz();
1739 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001740 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001741}
1742
1743
1744v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1745 uint32_t index,
1746 const AccessorInfo& info) {
1747 ApiTestFuzzer::Fuzz();
1748 CHECK(info.This()->Equals(bottom));
1749 return v8::Handle<v8::Boolean>();
1750}
1751
1752
1753v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1754 Local<String> property,
1755 const AccessorInfo& info) {
1756 ApiTestFuzzer::Fuzz();
1757 CHECK(info.This()->Equals(bottom));
1758 return v8::Handle<v8::Boolean>();
1759}
1760
1761
1762v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1763 const AccessorInfo& info) {
1764 ApiTestFuzzer::Fuzz();
1765 CHECK(info.This()->Equals(bottom));
1766 return v8::Handle<v8::Array>();
1767}
1768
1769
1770v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1771 const AccessorInfo& info) {
1772 ApiTestFuzzer::Fuzz();
1773 CHECK(info.This()->Equals(bottom));
1774 return v8::Handle<v8::Array>();
1775}
1776
1777
1778THREADED_TEST(PropertyHandlerInPrototype) {
1779 v8::HandleScope scope;
1780 LocalContext env;
1781
1782 // Set up a prototype chain with three interceptors.
1783 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1784 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1785 CheckThisIndexedPropertyHandler,
1786 CheckThisIndexedPropertySetter,
1787 CheckThisIndexedPropertyQuery,
1788 CheckThisIndexedPropertyDeleter,
1789 CheckThisIndexedPropertyEnumerator);
1790
1791 templ->InstanceTemplate()->SetNamedPropertyHandler(
1792 CheckThisNamedPropertyHandler,
1793 CheckThisNamedPropertySetter,
1794 CheckThisNamedPropertyQuery,
1795 CheckThisNamedPropertyDeleter,
1796 CheckThisNamedPropertyEnumerator);
1797
1798 bottom = templ->GetFunction()->NewInstance();
1799 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1800 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1801
1802 bottom->Set(v8_str("__proto__"), middle);
1803 middle->Set(v8_str("__proto__"), top);
1804 env->Global()->Set(v8_str("obj"), bottom);
1805
1806 // Indexed and named get.
1807 Script::Compile(v8_str("obj[0]"))->Run();
1808 Script::Compile(v8_str("obj.x"))->Run();
1809
1810 // Indexed and named set.
1811 Script::Compile(v8_str("obj[1] = 42"))->Run();
1812 Script::Compile(v8_str("obj.y = 42"))->Run();
1813
1814 // Indexed and named query.
1815 Script::Compile(v8_str("0 in obj"))->Run();
1816 Script::Compile(v8_str("'x' in obj"))->Run();
1817
1818 // Indexed and named deleter.
1819 Script::Compile(v8_str("delete obj[0]"))->Run();
1820 Script::Compile(v8_str("delete obj.x"))->Run();
1821
1822 // Enumerators.
1823 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1824}
1825
1826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1828 const AccessorInfo& info) {
1829 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001830 if (v8_str("pre")->Equals(key)) {
1831 return v8_str("PrePropertyHandler: pre");
1832 }
1833 return v8::Handle<String>();
1834}
1835
1836
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001837static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1838 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001839 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001840 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001841 }
1842
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001843 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001844}
1845
1846
1847THREADED_TEST(PrePropertyHandler) {
1848 v8::HandleScope scope;
1849 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1850 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1851 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001852 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001853 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001854 Script::Compile(v8_str(
1855 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1856 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1857 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1858 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1859 CHECK_EQ(v8_str("Object: on"), result_on);
1860 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1861 CHECK(result_post.IsEmpty());
1862}
1863
1864
ager@chromium.org870a0b62008-11-04 11:43:05 +00001865THREADED_TEST(UndefinedIsNotEnumerable) {
1866 v8::HandleScope scope;
1867 LocalContext env;
1868 v8::Handle<Value> result = Script::Compile(v8_str(
1869 "this.propertyIsEnumerable(undefined)"))->Run();
1870 CHECK(result->IsFalse());
1871}
1872
1873
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001874v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001875static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001876
1877
1878static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1879 ApiTestFuzzer::Fuzz();
1880 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1881 if (depth == kTargetRecursionDepth) return v8::Undefined();
1882 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1883 return call_recursively_script->Run();
1884}
1885
1886
1887static v8::Handle<Value> CallFunctionRecursivelyCall(
1888 const v8::Arguments& args) {
1889 ApiTestFuzzer::Fuzz();
1890 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1891 if (depth == kTargetRecursionDepth) {
1892 printf("[depth = %d]\n", depth);
1893 return v8::Undefined();
1894 }
1895 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1896 v8::Handle<Value> function =
1897 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001898 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001899}
1900
1901
1902THREADED_TEST(DeepCrossLanguageRecursion) {
1903 v8::HandleScope scope;
1904 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1905 global->Set(v8_str("callScriptRecursively"),
1906 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1907 global->Set(v8_str("callFunctionRecursively"),
1908 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1909 LocalContext env(NULL, global);
1910
1911 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1912 call_recursively_script = v8_compile("callScriptRecursively()");
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001913 call_recursively_script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 call_recursively_script = v8::Handle<Script>();
1915
1916 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1917 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1918}
1919
1920
1921static v8::Handle<Value>
1922 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1923 ApiTestFuzzer::Fuzz();
1924 return v8::ThrowException(key);
1925}
1926
1927
1928static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1929 Local<Value>,
1930 const AccessorInfo&) {
1931 v8::ThrowException(key);
1932 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1933}
1934
1935
1936THREADED_TEST(CallbackExceptionRegression) {
1937 v8::HandleScope scope;
1938 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1939 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1940 ThrowingPropertyHandlerSet);
1941 LocalContext env;
1942 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1943 v8::Handle<Value> otto = Script::Compile(v8_str(
1944 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1945 CHECK_EQ(v8_str("otto"), otto);
1946 v8::Handle<Value> netto = Script::Compile(v8_str(
1947 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1948 CHECK_EQ(v8_str("netto"), netto);
1949}
1950
1951
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952THREADED_TEST(FunctionPrototype) {
1953 v8::HandleScope scope;
1954 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1955 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1956 LocalContext env;
1957 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1958 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1959 CHECK_EQ(script->Run()->Int32Value(), 321);
1960}
1961
1962
1963THREADED_TEST(InternalFields) {
1964 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001965 LocalContext env;
1966
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001967 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1968 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1969 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001970 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1971 CHECK_EQ(1, obj->InternalFieldCount());
1972 CHECK(obj->GetInternalField(0)->IsUndefined());
1973 obj->SetInternalField(0, v8_num(17));
1974 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1975}
1976
1977
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001978THREADED_TEST(GlobalObjectInternalFields) {
1979 v8::HandleScope scope;
1980 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1981 global_template->SetInternalFieldCount(1);
1982 LocalContext env(NULL, global_template);
1983 v8::Handle<v8::Object> global_proxy = env->Global();
1984 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1985 CHECK_EQ(1, global->InternalFieldCount());
1986 CHECK(global->GetInternalField(0)->IsUndefined());
1987 global->SetInternalField(0, v8_num(17));
1988 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1989}
1990
1991
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001992THREADED_TEST(InternalFieldsNativePointers) {
1993 v8::HandleScope scope;
1994 LocalContext env;
1995
1996 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1997 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1998 instance_templ->SetInternalFieldCount(1);
1999 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2000 CHECK_EQ(1, obj->InternalFieldCount());
2001 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2002
2003 char* data = new char[100];
2004
2005 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002006 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002007 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002008 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002009
2010 // Check reading and writing aligned pointers.
2011 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002012 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002013 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2014
2015 // Check reading and writing unaligned pointers.
2016 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002017 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002018 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2019
2020 delete[] data;
2021}
2022
2023
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002024THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2025 v8::HandleScope scope;
2026 LocalContext env;
2027
2028 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2029 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2030 instance_templ->SetInternalFieldCount(1);
2031 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2032 CHECK_EQ(1, obj->InternalFieldCount());
2033 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2034
2035 char* data = new char[100];
2036
2037 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002038 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002039 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002040 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002041
2042 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002043 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002044 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2045
2046 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002047 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002048 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2049
2050 obj->SetInternalField(0, v8::External::Wrap(aligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002051 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002052 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2053
2054 obj->SetInternalField(0, v8::External::Wrap(unaligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002055 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002056 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2057
2058 delete[] data;
2059}
2060
2061
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002062static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2063 void* value) {
2064 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2065 obj->SetPointerInInternalField(0, value);
2066 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2067 CHECK_EQ(value, obj->GetPointerFromInternalField(0));
2068}
2069
2070
2071THREADED_TEST(InternalFieldsAlignedPointers) {
2072 v8::HandleScope scope;
2073 LocalContext env;
2074
2075 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2076 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2077 instance_templ->SetInternalFieldCount(1);
2078 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2079 CHECK_EQ(1, obj->InternalFieldCount());
2080
2081 CheckAlignedPointerInInternalField(obj, NULL);
2082
2083 int* heap_allocated = new int[100];
2084 CheckAlignedPointerInInternalField(obj, heap_allocated);
2085 delete[] heap_allocated;
2086
2087 int stack_allocated[100];
2088 CheckAlignedPointerInInternalField(obj, stack_allocated);
2089
2090 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2091 CheckAlignedPointerInInternalField(obj, huge);
2092}
2093
2094
2095static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2096 int index,
2097 void* value) {
2098 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2099 (*env)->SetAlignedPointerInEmbedderData(index, value);
2100 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2101 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2102}
2103
2104
2105static void* AlignedTestPointer(int i) {
2106 return reinterpret_cast<void*>(i * 1234);
2107}
2108
2109
2110THREADED_TEST(EmbedderDataAlignedPointers) {
2111 v8::HandleScope scope;
2112 LocalContext env;
2113
2114 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2115
2116 int* heap_allocated = new int[100];
2117 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2118 delete[] heap_allocated;
2119
2120 int stack_allocated[100];
2121 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2122
2123 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2124 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2125
2126 // Test growing of the embedder data's backing store.
2127 for (int i = 0; i < 100; i++) {
2128 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2129 }
2130 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2131 for (int i = 0; i < 100; i++) {
2132 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2133 }
2134}
2135
2136
2137static void CheckEmbedderData(LocalContext* env,
2138 int index,
2139 v8::Handle<Value> data) {
2140 (*env)->SetEmbedderData(index, data);
2141 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2142}
2143
2144THREADED_TEST(EmbedderData) {
2145 v8::HandleScope scope;
2146 LocalContext env;
2147
2148 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2149 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2150 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2151 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2152}
2153
2154
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002155THREADED_TEST(IdentityHash) {
2156 v8::HandleScope scope;
2157 LocalContext env;
2158
2159 // Ensure that the test starts with an fresh heap to test whether the hash
2160 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002161 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002162 Local<v8::Object> obj = v8::Object::New();
2163 int hash = obj->GetIdentityHash();
2164 int hash1 = obj->GetIdentityHash();
2165 CHECK_EQ(hash, hash1);
2166 int hash2 = v8::Object::New()->GetIdentityHash();
2167 // Since the identity hash is essentially a random number two consecutive
2168 // objects should not be assigned the same hash code. If the test below fails
2169 // the random number generator should be evaluated.
2170 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002171 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002172 int hash3 = v8::Object::New()->GetIdentityHash();
2173 // Make sure that the identity hash is not based on the initial address of
2174 // the object alone. If the test below fails the random number generator
2175 // should be evaluated.
2176 CHECK_NE(hash, hash3);
2177 int hash4 = obj->GetIdentityHash();
2178 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002179
2180 // Check identity hashes behaviour in the presence of JS accessors.
2181 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2182 {
2183 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2184 Local<v8::Object> o1 = v8::Object::New();
2185 Local<v8::Object> o2 = v8::Object::New();
2186 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2187 }
2188 {
2189 CompileRun(
2190 "function cnst() { return 42; };\n"
2191 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2192 Local<v8::Object> o1 = v8::Object::New();
2193 Local<v8::Object> o2 = v8::Object::New();
2194 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2195 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002196}
2197
2198
2199THREADED_TEST(HiddenProperties) {
2200 v8::HandleScope scope;
2201 LocalContext env;
2202
2203 v8::Local<v8::Object> obj = v8::Object::New();
2204 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2205 v8::Local<v8::String> empty = v8_str("");
2206 v8::Local<v8::String> prop_name = v8_str("prop_name");
2207
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002208 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002209
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002210 // Make sure delete of a non-existent hidden value works
2211 CHECK(obj->DeleteHiddenValue(key));
2212
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002213 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2214 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2215 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2216 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2217
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002218 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002219
2220 // Make sure we do not find the hidden property.
2221 CHECK(!obj->Has(empty));
2222 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2223 CHECK(obj->Get(empty)->IsUndefined());
2224 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2225 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2227 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2228
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002229 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002230
2231 // Add another property and delete it afterwards to force the object in
2232 // slow case.
2233 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2234 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2235 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2236 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2237 CHECK(obj->Delete(prop_name));
2238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2239
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002240 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002241
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002242 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2243 CHECK(obj->GetHiddenValue(key).IsEmpty());
2244
2245 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002246 CHECK(obj->DeleteHiddenValue(key));
2247 CHECK(obj->GetHiddenValue(key).IsEmpty());
2248}
2249
2250
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002251THREADED_TEST(Regress97784) {
2252 // Regression test for crbug.com/97784
2253 // Messing with the Object.prototype should not have effect on
2254 // hidden properties.
2255 v8::HandleScope scope;
2256 LocalContext env;
2257
2258 v8::Local<v8::Object> obj = v8::Object::New();
2259 v8::Local<v8::String> key = v8_str("hidden");
2260
2261 CompileRun(
2262 "set_called = false;"
2263 "Object.defineProperty("
2264 " Object.prototype,"
2265 " 'hidden',"
2266 " {get: function() { return 45; },"
2267 " set: function() { set_called = true; }})");
2268
2269 CHECK(obj->GetHiddenValue(key).IsEmpty());
2270 // Make sure that the getter and setter from Object.prototype is not invoked.
2271 // If it did we would have full access to the hidden properties in
2272 // the accessor.
2273 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2274 ExpectFalse("set_called");
2275 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2276}
2277
2278
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002279static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002280static v8::Handle<Value> InterceptorForHiddenProperties(
2281 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002282 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002283 return v8::Handle<Value>();
2284}
2285
2286
2287THREADED_TEST(HiddenPropertiesWithInterceptors) {
2288 v8::HandleScope scope;
2289 LocalContext context;
2290
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002291 interceptor_for_hidden_properties_called = false;
2292
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002293 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2294
2295 // Associate an interceptor with an object and start setting hidden values.
2296 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2297 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2298 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2299 Local<v8::Function> function = fun_templ->GetFunction();
2300 Local<v8::Object> obj = function->NewInstance();
2301 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2302 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002303 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002304}
2305
2306
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002307THREADED_TEST(External) {
2308 v8::HandleScope scope;
2309 int x = 3;
2310 Local<v8::External> ext = v8::External::New(&x);
2311 LocalContext env;
2312 env->Global()->Set(v8_str("ext"), ext);
2313 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002314 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002315 int* ptr = static_cast<int*>(reext->Value());
2316 CHECK_EQ(x, 3);
2317 *ptr = 10;
2318 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002319
2320 // Make sure unaligned pointers are wrapped properly.
2321 char* data = i::StrDup("0123456789");
2322 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2323 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2324 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2325 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2326
2327 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2328 CHECK_EQ('0', *char_ptr);
2329 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2330 CHECK_EQ('1', *char_ptr);
2331 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2332 CHECK_EQ('2', *char_ptr);
2333 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2334 CHECK_EQ('3', *char_ptr);
2335 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002336}
2337
2338
2339THREADED_TEST(GlobalHandle) {
2340 v8::Persistent<String> global;
2341 {
2342 v8::HandleScope scope;
2343 Local<String> str = v8_str("str");
2344 global = v8::Persistent<String>::New(str);
2345 }
2346 CHECK_EQ(global->Length(), 3);
2347 global.Dispose();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002348
2349 {
2350 v8::HandleScope scope;
2351 Local<String> str = v8_str("str");
2352 global = v8::Persistent<String>::New(str);
2353 }
2354 CHECK_EQ(global->Length(), 3);
2355 global.Dispose(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002356}
2357
2358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359class WeakCallCounter {
2360 public:
2361 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2362 int id() { return id_; }
2363 void increment() { number_of_weak_calls_++; }
2364 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2365 private:
2366 int id_;
2367 int number_of_weak_calls_;
2368};
2369
2370
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002371static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2373 CHECK_EQ(1234, counter->id());
2374 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002375 handle.Dispose();
2376}
2377
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002378
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002379THREADED_TEST(ApiObjectGroups) {
2380 HandleScope scope;
2381 LocalContext env;
2382
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002383 Persistent<Object> g1s1;
2384 Persistent<Object> g1s2;
2385 Persistent<Object> g1c1;
2386 Persistent<Object> g2s1;
2387 Persistent<Object> g2s2;
2388 Persistent<Object> g2c1;
2389
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002390 WeakCallCounter counter(1234);
2391
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002392 {
2393 HandleScope scope;
2394 g1s1 = Persistent<Object>::New(Object::New());
2395 g1s2 = Persistent<Object>::New(Object::New());
2396 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002397 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2398 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2399 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002400
2401 g2s1 = Persistent<Object>::New(Object::New());
2402 g2s2 = Persistent<Object>::New(Object::New());
2403 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002404 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2405 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2406 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002407 }
2408
2409 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2410
2411 // Connect group 1 and 2, make a cycle.
2412 CHECK(g1s2->Set(0, g2s2));
2413 CHECK(g2s1->Set(0, g1s1));
2414
2415 {
2416 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2417 Persistent<Value> g1_children[] = { g1c1 };
2418 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2419 Persistent<Value> g2_children[] = { g2c1 };
2420 V8::AddObjectGroup(g1_objects, 2);
2421 V8::AddImplicitReferences(g1s1, g1_children, 1);
2422 V8::AddObjectGroup(g2_objects, 2);
2423 V8::AddImplicitReferences(g2s2, g2_children, 1);
2424 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002425 // Do a single full GC, ensure incremental marking is stopped.
2426 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002427
2428 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002429 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002430
2431 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002432 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002433 // But make children strong roots---all the objects (except for children)
2434 // should be collectable now.
2435 g1c1.ClearWeak();
2436 g2c1.ClearWeak();
2437
2438 // Groups are deleted, rebuild groups.
2439 {
2440 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2441 Persistent<Value> g1_children[] = { g1c1 };
2442 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2443 Persistent<Value> g2_children[] = { g2c1 };
2444 V8::AddObjectGroup(g1_objects, 2);
2445 V8::AddImplicitReferences(g1s1, g1_children, 1);
2446 V8::AddObjectGroup(g2_objects, 2);
2447 V8::AddImplicitReferences(g2s2, g2_children, 1);
2448 }
2449
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002450 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002451
2452 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002453 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002454
2455 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002456 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2457 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002458
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002459 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002460 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002461}
2462
2463
2464THREADED_TEST(ApiObjectGroupsCycle) {
2465 HandleScope scope;
2466 LocalContext env;
2467
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002468 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002469
2470 Persistent<Object> g1s1;
2471 Persistent<Object> g1s2;
2472 Persistent<Object> g2s1;
2473 Persistent<Object> g2s2;
2474 Persistent<Object> g3s1;
2475 Persistent<Object> g3s2;
2476
2477 {
2478 HandleScope scope;
2479 g1s1 = Persistent<Object>::New(Object::New());
2480 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002481 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2482 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002483
2484 g2s1 = Persistent<Object>::New(Object::New());
2485 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002486 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2487 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002488
2489 g3s1 = Persistent<Object>::New(Object::New());
2490 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002491 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2492 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002493 }
2494
2495 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2496
2497 // Connect groups. We're building the following cycle:
2498 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2499 // groups.
2500 {
2501 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2502 Persistent<Value> g1_children[] = { g2s1 };
2503 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2504 Persistent<Value> g2_children[] = { g3s1 };
2505 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2506 Persistent<Value> g3_children[] = { g1s1 };
2507 V8::AddObjectGroup(g1_objects, 2);
2508 V8::AddImplicitReferences(g1s1, g1_children, 1);
2509 V8::AddObjectGroup(g2_objects, 2);
2510 V8::AddImplicitReferences(g2s1, g2_children, 1);
2511 V8::AddObjectGroup(g3_objects, 2);
2512 V8::AddImplicitReferences(g3s1, g3_children, 1);
2513 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002514 // Do a single full GC
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002515 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002516
2517 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002518 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002519
2520 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002521 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002522
2523 // Groups are deleted, rebuild groups.
2524 {
2525 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2526 Persistent<Value> g1_children[] = { g2s1 };
2527 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2528 Persistent<Value> g2_children[] = { g3s1 };
2529 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2530 Persistent<Value> g3_children[] = { g1s1 };
2531 V8::AddObjectGroup(g1_objects, 2);
2532 V8::AddImplicitReferences(g1s1, g1_children, 1);
2533 V8::AddObjectGroup(g2_objects, 2);
2534 V8::AddImplicitReferences(g2s1, g2_children, 1);
2535 V8::AddObjectGroup(g3_objects, 2);
2536 V8::AddImplicitReferences(g3s1, g3_children, 1);
2537 }
2538
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002539 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002540
2541 // All objects should be gone. 7 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002542 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002543}
2544
2545
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002546// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
2547// on the buildbots, so was made non-threaded for the time being.
2548TEST(ApiObjectGroupsCycleForScavenger) {
2549 HandleScope scope;
2550 LocalContext env;
2551
2552 WeakCallCounter counter(1234);
2553
2554 Persistent<Object> g1s1;
2555 Persistent<Object> g1s2;
2556 Persistent<Object> g2s1;
2557 Persistent<Object> g2s2;
2558 Persistent<Object> g3s1;
2559 Persistent<Object> g3s2;
2560
2561 {
2562 HandleScope scope;
2563 g1s1 = Persistent<Object>::New(Object::New());
2564 g1s2 = Persistent<Object>::New(Object::New());
2565 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2566 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2567
2568 g2s1 = Persistent<Object>::New(Object::New());
2569 g2s2 = Persistent<Object>::New(Object::New());
2570 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2571 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2572
2573 g3s1 = Persistent<Object>::New(Object::New());
2574 g3s2 = Persistent<Object>::New(Object::New());
2575 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2576 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2577 }
2578
2579 // Make a root.
2580 Persistent<Object> root = Persistent<Object>::New(g1s1);
2581 root.MarkPartiallyDependent();
2582
2583 // Connect groups. We're building the following cycle:
2584 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2585 // groups.
2586 {
2587 g1s1.MarkPartiallyDependent();
2588 g1s2.MarkPartiallyDependent();
2589 g2s1.MarkPartiallyDependent();
2590 g2s2.MarkPartiallyDependent();
2591 g3s1.MarkPartiallyDependent();
2592 g3s2.MarkPartiallyDependent();
2593 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2594 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2595 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2596 V8::AddObjectGroup(g1_objects, 2);
2597 g1s1->Set(v8_str("x"), g2s1);
2598 V8::AddObjectGroup(g2_objects, 2);
2599 g2s1->Set(v8_str("x"), g3s1);
2600 V8::AddObjectGroup(g3_objects, 2);
2601 g3s1->Set(v8_str("x"), g1s1);
2602 }
2603
2604 HEAP->CollectGarbage(i::NEW_SPACE);
2605
2606 // All objects should be alive.
2607 CHECK_EQ(0, counter.NumberOfWeakCalls());
2608
2609 // Weaken the root.
2610 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2611 root.MarkPartiallyDependent();
2612
2613 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2614 // Groups are deleted, rebuild groups.
2615 {
2616 g1s1.MarkPartiallyDependent(isolate);
2617 g1s2.MarkPartiallyDependent(isolate);
2618 g2s1.MarkPartiallyDependent(isolate);
2619 g2s2.MarkPartiallyDependent(isolate);
2620 g3s1.MarkPartiallyDependent(isolate);
2621 g3s2.MarkPartiallyDependent(isolate);
2622 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2623 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2624 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2625 V8::AddObjectGroup(g1_objects, 2);
2626 g1s1->Set(v8_str("x"), g2s1);
2627 V8::AddObjectGroup(g2_objects, 2);
2628 g2s1->Set(v8_str("x"), g3s1);
2629 V8::AddObjectGroup(g3_objects, 2);
2630 g3s1->Set(v8_str("x"), g1s1);
2631 }
2632
2633 HEAP->CollectGarbage(i::NEW_SPACE);
2634
2635 // All objects should be gone. 7 global handles in total.
2636 CHECK_EQ(7, counter.NumberOfWeakCalls());
2637}
2638
2639
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002640THREADED_TEST(ScriptException) {
2641 v8::HandleScope scope;
2642 LocalContext env;
2643 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2644 v8::TryCatch try_catch;
2645 Local<Value> result = script->Run();
2646 CHECK(result.IsEmpty());
2647 CHECK(try_catch.HasCaught());
2648 String::AsciiValue exception_value(try_catch.Exception());
2649 CHECK_EQ(*exception_value, "panama!");
2650}
2651
2652
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002653TEST(TryCatchCustomException) {
2654 v8::HandleScope scope;
2655 LocalContext env;
2656 v8::TryCatch try_catch;
2657 CompileRun("function CustomError() { this.a = 'b'; }"
2658 "(function f() { throw new CustomError(); })();");
2659 CHECK(try_catch.HasCaught());
2660 CHECK(try_catch.Exception()->ToObject()->
2661 Get(v8_str("a"))->Equals(v8_str("b")));
2662}
2663
2664
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002665bool message_received;
2666
2667
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002668static void check_message_0(v8::Handle<v8::Message> message,
2669 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002670 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002671 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002672 message_received = true;
2673}
2674
2675
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002676THREADED_TEST(MessageHandler0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002677 message_received = false;
2678 v8::HandleScope scope;
2679 CHECK(!message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002680 v8::V8::AddMessageListener(check_message_0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002681 LocalContext context;
2682 v8::ScriptOrigin origin =
2683 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002684 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2685 &origin);
2686 script->SetData(v8_str("7.56"));
2687 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002688 CHECK(message_received);
2689 // clear out the message listener
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002690 v8::V8::RemoveMessageListeners(check_message_0);
2691}
2692
2693
2694static void check_message_1(v8::Handle<v8::Message> message,
2695 v8::Handle<Value> data) {
2696 CHECK(data->IsNumber());
2697 CHECK_EQ(1337, data->Int32Value());
2698 message_received = true;
2699}
2700
2701
2702TEST(MessageHandler1) {
2703 message_received = false;
2704 v8::HandleScope scope;
2705 CHECK(!message_received);
2706 v8::V8::AddMessageListener(check_message_1);
2707 LocalContext context;
2708 CompileRun("throw 1337;");
2709 CHECK(message_received);
2710 // clear out the message listener
2711 v8::V8::RemoveMessageListeners(check_message_1);
2712}
2713
2714
2715static void check_message_2(v8::Handle<v8::Message> message,
2716 v8::Handle<Value> data) {
2717 LocalContext context;
2718 CHECK(data->IsObject());
2719 v8::Local<v8::Value> hidden_property =
2720 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2721 CHECK(v8_str("hidden value")->Equals(hidden_property));
2722 message_received = true;
2723}
2724
2725
2726TEST(MessageHandler2) {
2727 message_received = false;
2728 v8::HandleScope scope;
2729 CHECK(!message_received);
2730 v8::V8::AddMessageListener(check_message_2);
2731 LocalContext context;
2732 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2733 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2734 v8_str("hidden value"));
2735 context->Global()->Set(v8_str("error"), error);
2736 CompileRun("throw error;");
2737 CHECK(message_received);
2738 // clear out the message listener
2739 v8::V8::RemoveMessageListeners(check_message_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002740}
2741
2742
2743THREADED_TEST(GetSetProperty) {
2744 v8::HandleScope scope;
2745 LocalContext context;
2746 context->Global()->Set(v8_str("foo"), v8_num(14));
2747 context->Global()->Set(v8_str("12"), v8_num(92));
2748 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2749 context->Global()->Set(v8_num(13), v8_num(56));
2750 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2751 CHECK_EQ(14, foo->Int32Value());
2752 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2753 CHECK_EQ(92, twelve->Int32Value());
2754 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2755 CHECK_EQ(32, sixteen->Int32Value());
2756 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2757 CHECK_EQ(56, thirteen->Int32Value());
2758 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2759 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2760 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2761 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2762 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2763 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2764 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2765 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2766 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2767}
2768
2769
2770THREADED_TEST(PropertyAttributes) {
2771 v8::HandleScope scope;
2772 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002773 // none
2774 Local<String> prop = v8_str("none");
2775 context->Global()->Set(prop, v8_num(7));
2776 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002777 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002778 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002779 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2780 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002781 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002782 Script::Compile(v8_str("read_only = 9"))->Run();
2783 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2784 context->Global()->Set(prop, v8_num(10));
2785 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2786 // dont-delete
2787 prop = v8_str("dont_delete");
2788 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2789 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2790 Script::Compile(v8_str("delete dont_delete"))->Run();
2791 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002792 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2793 // dont-enum
2794 prop = v8_str("dont_enum");
2795 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2796 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2797 // absent
2798 prop = v8_str("absent");
2799 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2800 Local<Value> fake_prop = v8_num(1);
2801 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2802 // exception
2803 TryCatch try_catch;
2804 Local<Value> exception =
2805 CompileRun("({ toString: function() { throw 'exception';} })");
2806 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2807 CHECK(try_catch.HasCaught());
2808 String::AsciiValue exception_value(try_catch.Exception());
2809 CHECK_EQ("exception", *exception_value);
2810 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002811}
2812
2813
2814THREADED_TEST(Array) {
2815 v8::HandleScope scope;
2816 LocalContext context;
2817 Local<v8::Array> array = v8::Array::New();
2818 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002819 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002820 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002821 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002822 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002823 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002824 CHECK_EQ(3, array->Length());
2825 CHECK(!array->Has(0));
2826 CHECK(!array->Has(1));
2827 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002828 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002829 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002830 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002831 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002832 CHECK_EQ(1, arr->Get(0)->Int32Value());
2833 CHECK_EQ(2, arr->Get(1)->Int32Value());
2834 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002835 array = v8::Array::New(27);
2836 CHECK_EQ(27, array->Length());
2837 array = v8::Array::New(-27);
2838 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002839}
2840
2841
2842v8::Handle<Value> HandleF(const v8::Arguments& args) {
2843 v8::HandleScope scope;
2844 ApiTestFuzzer::Fuzz();
2845 Local<v8::Array> result = v8::Array::New(args.Length());
2846 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002847 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002848 return scope.Close(result);
2849}
2850
2851
2852THREADED_TEST(Vector) {
2853 v8::HandleScope scope;
2854 Local<ObjectTemplate> global = ObjectTemplate::New();
2855 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2856 LocalContext context(0, global);
2857
2858 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002859 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002860 CHECK_EQ(0, a0->Length());
2861
2862 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002863 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002864 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002865 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002866
2867 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002868 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002869 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002870 CHECK_EQ(12, a2->Get(0)->Int32Value());
2871 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002872
2873 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002874 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002875 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002876 CHECK_EQ(14, a3->Get(0)->Int32Value());
2877 CHECK_EQ(15, a3->Get(1)->Int32Value());
2878 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002879
2880 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002881 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002882 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002883 CHECK_EQ(17, a4->Get(0)->Int32Value());
2884 CHECK_EQ(18, a4->Get(1)->Int32Value());
2885 CHECK_EQ(19, a4->Get(2)->Int32Value());
2886 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002887}
2888
2889
2890THREADED_TEST(FunctionCall) {
2891 v8::HandleScope scope;
2892 LocalContext context;
2893 CompileRun(
2894 "function Foo() {"
2895 " var result = [];"
2896 " for (var i = 0; i < arguments.length; i++) {"
2897 " result.push(arguments[i]);"
2898 " }"
2899 " return result;"
2900 "}");
2901 Local<Function> Foo =
2902 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2903
2904 v8::Handle<Value>* args0 = NULL;
2905 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2906 CHECK_EQ(0, a0->Length());
2907
2908 v8::Handle<Value> args1[] = { v8_num(1.1) };
2909 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2910 CHECK_EQ(1, a1->Length());
2911 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2912
2913 v8::Handle<Value> args2[] = { v8_num(2.2),
2914 v8_num(3.3) };
2915 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2916 CHECK_EQ(2, a2->Length());
2917 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2918 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2919
2920 v8::Handle<Value> args3[] = { v8_num(4.4),
2921 v8_num(5.5),
2922 v8_num(6.6) };
2923 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2924 CHECK_EQ(3, a3->Length());
2925 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2926 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2927 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2928
2929 v8::Handle<Value> args4[] = { v8_num(7.7),
2930 v8_num(8.8),
2931 v8_num(9.9),
2932 v8_num(10.11) };
2933 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2934 CHECK_EQ(4, a4->Length());
2935 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2936 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2937 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2938 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2939}
2940
2941
2942static const char* js_code_causing_out_of_memory =
2943 "var a = new Array(); while(true) a.push(a);";
2944
2945
2946// These tests run for a long time and prevent us from running tests
2947// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002948TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002949 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002950 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002951 // Set heap limits.
2952 static const int K = 1024;
2953 v8::ResourceConstraints constraints;
2954 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002955 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002956 v8::SetResourceConstraints(&constraints);
2957
2958 // Execute a script that causes out of memory.
2959 v8::HandleScope scope;
2960 LocalContext context;
2961 v8::V8::IgnoreOutOfMemoryException();
2962 Local<Script> script =
2963 Script::Compile(String::New(js_code_causing_out_of_memory));
2964 Local<Value> result = script->Run();
2965
2966 // Check for out of memory state.
2967 CHECK(result.IsEmpty());
2968 CHECK(context->HasOutOfMemoryException());
2969}
2970
2971
2972v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2973 ApiTestFuzzer::Fuzz();
2974
2975 v8::HandleScope scope;
2976 LocalContext context;
2977 Local<Script> script =
2978 Script::Compile(String::New(js_code_causing_out_of_memory));
2979 Local<Value> result = script->Run();
2980
2981 // Check for out of memory state.
2982 CHECK(result.IsEmpty());
2983 CHECK(context->HasOutOfMemoryException());
2984
2985 return result;
2986}
2987
2988
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002989TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002990 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002991 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002992 // Set heap limits.
2993 static const int K = 1024;
2994 v8::ResourceConstraints constraints;
2995 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002996 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002997 v8::SetResourceConstraints(&constraints);
2998
2999 v8::HandleScope scope;
3000 Local<ObjectTemplate> templ = ObjectTemplate::New();
3001 templ->Set(v8_str("ProvokeOutOfMemory"),
3002 v8::FunctionTemplate::New(ProvokeOutOfMemory));
3003 LocalContext context(0, templ);
3004 v8::V8::IgnoreOutOfMemoryException();
3005 Local<Value> result = CompileRun(
3006 "var thrown = false;"
3007 "try {"
3008 " ProvokeOutOfMemory();"
3009 "} catch (e) {"
3010 " thrown = true;"
3011 "}");
3012 // Check for out of memory state.
3013 CHECK(result.IsEmpty());
3014 CHECK(context->HasOutOfMemoryException());
3015}
3016
3017
3018TEST(HugeConsStringOutOfMemory) {
3019 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003020 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003021 // Set heap limits.
3022 static const int K = 1024;
3023 v8::ResourceConstraints constraints;
3024 constraints.set_max_young_space_size(256 * K);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003025 constraints.set_max_old_space_size(3 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003026 v8::SetResourceConstraints(&constraints);
3027
3028 // Execute a script that causes out of memory.
3029 v8::V8::IgnoreOutOfMemoryException();
3030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003031 v8::HandleScope scope;
3032 LocalContext context;
3033
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003034 // Build huge string. This should fail with out of memory exception.
3035 Local<Value> result = CompileRun(
3036 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003037 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003038
3039 // Check for out of memory state.
3040 CHECK(result.IsEmpty());
3041 CHECK(context->HasOutOfMemoryException());
3042}
3043
3044
3045THREADED_TEST(ConstructCall) {
3046 v8::HandleScope scope;
3047 LocalContext context;
3048 CompileRun(
3049 "function Foo() {"
3050 " var result = [];"
3051 " for (var i = 0; i < arguments.length; i++) {"
3052 " result.push(arguments[i]);"
3053 " }"
3054 " return result;"
3055 "}");
3056 Local<Function> Foo =
3057 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3058
3059 v8::Handle<Value>* args0 = NULL;
3060 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3061 CHECK_EQ(0, a0->Length());
3062
3063 v8::Handle<Value> args1[] = { v8_num(1.1) };
3064 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3065 CHECK_EQ(1, a1->Length());
3066 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3067
3068 v8::Handle<Value> args2[] = { v8_num(2.2),
3069 v8_num(3.3) };
3070 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3071 CHECK_EQ(2, a2->Length());
3072 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3073 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3074
3075 v8::Handle<Value> args3[] = { v8_num(4.4),
3076 v8_num(5.5),
3077 v8_num(6.6) };
3078 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3079 CHECK_EQ(3, a3->Length());
3080 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3081 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3082 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3083
3084 v8::Handle<Value> args4[] = { v8_num(7.7),
3085 v8_num(8.8),
3086 v8_num(9.9),
3087 v8_num(10.11) };
3088 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3089 CHECK_EQ(4, a4->Length());
3090 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3091 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3092 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3093 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3094}
3095
3096
3097static void CheckUncle(v8::TryCatch* try_catch) {
3098 CHECK(try_catch->HasCaught());
3099 String::AsciiValue str_value(try_catch->Exception());
3100 CHECK_EQ(*str_value, "uncle?");
3101 try_catch->Reset();
3102}
3103
3104
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003105THREADED_TEST(ConversionNumber) {
3106 v8::HandleScope scope;
3107 LocalContext env;
3108 // Very large number.
3109 CompileRun("var obj = Math.pow(2,32) * 1237;");
3110 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3111 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
3112 CHECK_EQ(0, obj->ToInt32()->Value());
3113 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
3114 // Large number.
3115 CompileRun("var obj = -1234567890123;");
3116 obj = env->Global()->Get(v8_str("obj"));
3117 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
3118 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
3119 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
3120 // Small positive integer.
3121 CompileRun("var obj = 42;");
3122 obj = env->Global()->Get(v8_str("obj"));
3123 CHECK_EQ(42.0, obj->ToNumber()->Value());
3124 CHECK_EQ(42, obj->ToInt32()->Value());
3125 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3126 // Negative integer.
3127 CompileRun("var obj = -37;");
3128 obj = env->Global()->Get(v8_str("obj"));
3129 CHECK_EQ(-37.0, obj->ToNumber()->Value());
3130 CHECK_EQ(-37, obj->ToInt32()->Value());
3131 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
3132 // Positive non-int32 integer.
3133 CompileRun("var obj = 0x81234567;");
3134 obj = env->Global()->Get(v8_str("obj"));
3135 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
3136 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
3137 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
3138 // Fraction.
3139 CompileRun("var obj = 42.3;");
3140 obj = env->Global()->Get(v8_str("obj"));
3141 CHECK_EQ(42.3, obj->ToNumber()->Value());
3142 CHECK_EQ(42, obj->ToInt32()->Value());
3143 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3144 // Large negative fraction.
3145 CompileRun("var obj = -5726623061.75;");
3146 obj = env->Global()->Get(v8_str("obj"));
3147 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
3148 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
3149 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
3150}
3151
3152
3153THREADED_TEST(isNumberType) {
3154 v8::HandleScope scope;
3155 LocalContext env;
3156 // Very large number.
3157 CompileRun("var obj = Math.pow(2,32) * 1237;");
3158 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3159 CHECK(!obj->IsInt32());
3160 CHECK(!obj->IsUint32());
3161 // Large negative number.
3162 CompileRun("var obj = -1234567890123;");
3163 obj = env->Global()->Get(v8_str("obj"));
3164 CHECK(!obj->IsInt32());
3165 CHECK(!obj->IsUint32());
3166 // Small positive integer.
3167 CompileRun("var obj = 42;");
3168 obj = env->Global()->Get(v8_str("obj"));
3169 CHECK(obj->IsInt32());
3170 CHECK(obj->IsUint32());
3171 // Negative integer.
3172 CompileRun("var obj = -37;");
3173 obj = env->Global()->Get(v8_str("obj"));
3174 CHECK(obj->IsInt32());
3175 CHECK(!obj->IsUint32());
3176 // Positive non-int32 integer.
3177 CompileRun("var obj = 0x81234567;");
3178 obj = env->Global()->Get(v8_str("obj"));
3179 CHECK(!obj->IsInt32());
3180 CHECK(obj->IsUint32());
3181 // Fraction.
3182 CompileRun("var obj = 42.3;");
3183 obj = env->Global()->Get(v8_str("obj"));
3184 CHECK(!obj->IsInt32());
3185 CHECK(!obj->IsUint32());
3186 // Large negative fraction.
3187 CompileRun("var obj = -5726623061.75;");
3188 obj = env->Global()->Get(v8_str("obj"));
3189 CHECK(!obj->IsInt32());
3190 CHECK(!obj->IsUint32());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003191 // Positive zero
3192 CompileRun("var obj = 0.0;");
3193 obj = env->Global()->Get(v8_str("obj"));
3194 CHECK(obj->IsInt32());
3195 CHECK(obj->IsUint32());
3196 // Positive zero
3197 CompileRun("var obj = -0.0;");
3198 obj = env->Global()->Get(v8_str("obj"));
3199 CHECK(!obj->IsInt32());
3200 CHECK(!obj->IsUint32());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003201}
3202
3203
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003204THREADED_TEST(ConversionException) {
3205 v8::HandleScope scope;
3206 LocalContext env;
3207 CompileRun(
3208 "function TestClass() { };"
3209 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3210 "var obj = new TestClass();");
3211 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3212
3213 v8::TryCatch try_catch;
3214
3215 Local<Value> to_string_result = obj->ToString();
3216 CHECK(to_string_result.IsEmpty());
3217 CheckUncle(&try_catch);
3218
3219 Local<Value> to_number_result = obj->ToNumber();
3220 CHECK(to_number_result.IsEmpty());
3221 CheckUncle(&try_catch);
3222
3223 Local<Value> to_integer_result = obj->ToInteger();
3224 CHECK(to_integer_result.IsEmpty());
3225 CheckUncle(&try_catch);
3226
3227 Local<Value> to_uint32_result = obj->ToUint32();
3228 CHECK(to_uint32_result.IsEmpty());
3229 CheckUncle(&try_catch);
3230
3231 Local<Value> to_int32_result = obj->ToInt32();
3232 CHECK(to_int32_result.IsEmpty());
3233 CheckUncle(&try_catch);
3234
3235 Local<Value> to_object_result = v8::Undefined()->ToObject();
3236 CHECK(to_object_result.IsEmpty());
3237 CHECK(try_catch.HasCaught());
3238 try_catch.Reset();
3239
3240 int32_t int32_value = obj->Int32Value();
3241 CHECK_EQ(0, int32_value);
3242 CheckUncle(&try_catch);
3243
3244 uint32_t uint32_value = obj->Uint32Value();
3245 CHECK_EQ(0, uint32_value);
3246 CheckUncle(&try_catch);
3247
3248 double number_value = obj->NumberValue();
3249 CHECK_NE(0, IsNaN(number_value));
3250 CheckUncle(&try_catch);
3251
3252 int64_t integer_value = obj->IntegerValue();
3253 CHECK_EQ(0.0, static_cast<double>(integer_value));
3254 CheckUncle(&try_catch);
3255}
3256
3257
3258v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3259 ApiTestFuzzer::Fuzz();
3260 return v8::ThrowException(v8_str("konto"));
3261}
3262
3263
ager@chromium.org8bb60582008-12-11 12:02:20 +00003264v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003265 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003266 v8::HandleScope scope;
3267 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003268 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3269 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003270 return v8::Boolean::New(try_catch.HasCaught());
3271}
3272
3273
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003274THREADED_TEST(APICatch) {
3275 v8::HandleScope scope;
3276 Local<ObjectTemplate> templ = ObjectTemplate::New();
3277 templ->Set(v8_str("ThrowFromC"),
3278 v8::FunctionTemplate::New(ThrowFromC));
3279 LocalContext context(0, templ);
3280 CompileRun(
3281 "var thrown = false;"
3282 "try {"
3283 " ThrowFromC();"
3284 "} catch (e) {"
3285 " thrown = true;"
3286 "}");
3287 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3288 CHECK(thrown->BooleanValue());
3289}
3290
3291
ager@chromium.org8bb60582008-12-11 12:02:20 +00003292THREADED_TEST(APIThrowTryCatch) {
3293 v8::HandleScope scope;
3294 Local<ObjectTemplate> templ = ObjectTemplate::New();
3295 templ->Set(v8_str("ThrowFromC"),
3296 v8::FunctionTemplate::New(ThrowFromC));
3297 LocalContext context(0, templ);
3298 v8::TryCatch try_catch;
3299 CompileRun("ThrowFromC();");
3300 CHECK(try_catch.HasCaught());
3301}
3302
3303
3304// Test that a try-finally block doesn't shadow a try-catch block
3305// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003306//
3307// BUG(271): Some of the exception propagation does not work on the
3308// ARM simulator because the simulator separates the C++ stack and the
3309// JS stack. This test therefore fails on the simulator. The test is
3310// not threaded to allow the threading tests to run on the simulator.
3311TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003312 v8::HandleScope scope;
3313 Local<ObjectTemplate> templ = ObjectTemplate::New();
3314 templ->Set(v8_str("CCatcher"),
3315 v8::FunctionTemplate::New(CCatcher));
3316 LocalContext context(0, templ);
3317 Local<Value> result = CompileRun("try {"
3318 " try {"
3319 " CCatcher('throw 7;');"
3320 " } finally {"
3321 " }"
3322 "} catch (e) {"
3323 "}");
3324 CHECK(result->IsTrue());
3325}
3326
3327
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003328static void check_reference_error_message(
3329 v8::Handle<v8::Message> message,
3330 v8::Handle<v8::Value> data) {
3331 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3332 CHECK(message->Get()->Equals(v8_str(reference_error)));
3333}
3334
3335
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003336static v8::Handle<Value> Fail(const v8::Arguments& args) {
3337 ApiTestFuzzer::Fuzz();
3338 CHECK(false);
3339 return v8::Undefined();
3340}
3341
3342
3343// Test that overwritten methods are not invoked on uncaught exception
3344// formatting. However, they are invoked when performing normal error
3345// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003346TEST(APIThrowMessageOverwrittenToString) {
3347 v8::HandleScope scope;
3348 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003349 Local<ObjectTemplate> templ = ObjectTemplate::New();
3350 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3351 LocalContext context(NULL, templ);
3352 CompileRun("asdf;");
3353 CompileRun("var limit = {};"
3354 "limit.valueOf = fail;"
3355 "Error.stackTraceLimit = limit;");
3356 CompileRun("asdf");
3357 CompileRun("Array.prototype.pop = fail;");
3358 CompileRun("Object.prototype.hasOwnProperty = fail;");
3359 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003360 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3361 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003362 CompileRun("ReferenceError.prototype.toString ="
3363 " function() { return 'Whoops' }");
3364 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003365 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3366 CompileRun("asdf;");
3367 CompileRun("ReferenceError.prototype.constructor = void 0;");
3368 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003369 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3370 CompileRun("asdf;");
3371 CompileRun("ReferenceError.prototype = new Object();");
3372 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003373 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3374 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003375 CompileRun("ReferenceError.prototype.constructor = new Object();"
3376 "ReferenceError.prototype.constructor.name = 1;"
3377 "Number.prototype.toString = function() { return 'Whoops'; };"
3378 "ReferenceError.prototype.toString = Object.prototype.toString;");
3379 CompileRun("asdf;");
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003380 v8::V8::RemoveMessageListeners(check_reference_error_message);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003381}
3382
3383
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003384static void check_custom_error_message(
3385 v8::Handle<v8::Message> message,
3386 v8::Handle<v8::Value> data) {
3387 const char* uncaught_error = "Uncaught MyError toString";
3388 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3389}
3390
3391
3392TEST(CustomErrorToString) {
3393 v8::HandleScope scope;
3394 v8::V8::AddMessageListener(check_custom_error_message);
3395 LocalContext context;
3396 CompileRun(
3397 "function MyError(name, message) { "
3398 " this.name = name; "
3399 " this.message = message; "
3400 "} "
3401 "MyError.prototype = Object.create(Error.prototype); "
3402 "MyError.prototype.toString = function() { "
3403 " return 'MyError toString'; "
3404 "}; "
3405 "throw new MyError('my name', 'my message'); ");
3406 v8::V8::RemoveMessageListeners(check_custom_error_message);
3407}
3408
3409
ager@chromium.org8bb60582008-12-11 12:02:20 +00003410static void receive_message(v8::Handle<v8::Message> message,
3411 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003412 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003413 message_received = true;
3414}
3415
3416
3417TEST(APIThrowMessage) {
3418 message_received = false;
3419 v8::HandleScope scope;
3420 v8::V8::AddMessageListener(receive_message);
3421 Local<ObjectTemplate> templ = ObjectTemplate::New();
3422 templ->Set(v8_str("ThrowFromC"),
3423 v8::FunctionTemplate::New(ThrowFromC));
3424 LocalContext context(0, templ);
3425 CompileRun("ThrowFromC();");
3426 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003427 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003428}
3429
3430
3431TEST(APIThrowMessageAndVerboseTryCatch) {
3432 message_received = false;
3433 v8::HandleScope scope;
3434 v8::V8::AddMessageListener(receive_message);
3435 Local<ObjectTemplate> templ = ObjectTemplate::New();
3436 templ->Set(v8_str("ThrowFromC"),
3437 v8::FunctionTemplate::New(ThrowFromC));
3438 LocalContext context(0, templ);
3439 v8::TryCatch try_catch;
3440 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003441 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003442 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003443 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003444 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003445 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003446}
3447
3448
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003449TEST(APIStackOverflowAndVerboseTryCatch) {
3450 message_received = false;
3451 v8::HandleScope scope;
3452 v8::V8::AddMessageListener(receive_message);
3453 LocalContext context;
3454 v8::TryCatch try_catch;
3455 try_catch.SetVerbose(true);
3456 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3457 CHECK(try_catch.HasCaught());
3458 CHECK(result.IsEmpty());
3459 CHECK(message_received);
3460 v8::V8::RemoveMessageListeners(receive_message);
3461}
3462
3463
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003464THREADED_TEST(ExternalScriptException) {
3465 v8::HandleScope scope;
3466 Local<ObjectTemplate> templ = ObjectTemplate::New();
3467 templ->Set(v8_str("ThrowFromC"),
3468 v8::FunctionTemplate::New(ThrowFromC));
3469 LocalContext context(0, templ);
3470
3471 v8::TryCatch try_catch;
3472 Local<Script> script
3473 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3474 Local<Value> result = script->Run();
3475 CHECK(result.IsEmpty());
3476 CHECK(try_catch.HasCaught());
3477 String::AsciiValue exception_value(try_catch.Exception());
3478 CHECK_EQ("konto", *exception_value);
3479}
3480
3481
3482
3483v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3484 ApiTestFuzzer::Fuzz();
3485 CHECK_EQ(4, args.Length());
3486 int count = args[0]->Int32Value();
3487 int cInterval = args[2]->Int32Value();
3488 if (count == 0) {
3489 return v8::ThrowException(v8_str("FromC"));
3490 } else {
3491 Local<v8::Object> global = Context::GetCurrent()->Global();
3492 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3493 v8::Handle<Value> argv[] = { v8_num(count - 1),
3494 args[1],
3495 args[2],
3496 args[3] };
3497 if (count % cInterval == 0) {
3498 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003499 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003500 int expected = args[3]->Int32Value();
3501 if (try_catch.HasCaught()) {
3502 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003503 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003504 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003505 } else {
3506 CHECK_NE(expected, count);
3507 }
3508 return result;
3509 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003510 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003511 }
3512 }
3513}
3514
3515
3516v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3517 ApiTestFuzzer::Fuzz();
3518 CHECK_EQ(3, args.Length());
3519 bool equality = args[0]->BooleanValue();
3520 int count = args[1]->Int32Value();
3521 int expected = args[2]->Int32Value();
3522 if (equality) {
3523 CHECK_EQ(count, expected);
3524 } else {
3525 CHECK_NE(count, expected);
3526 }
3527 return v8::Undefined();
3528}
3529
3530
ager@chromium.org8bb60582008-12-11 12:02:20 +00003531THREADED_TEST(EvalInTryFinally) {
3532 v8::HandleScope scope;
3533 LocalContext context;
3534 v8::TryCatch try_catch;
3535 CompileRun("(function() {"
3536 " try {"
3537 " eval('asldkf (*&^&*^');"
3538 " } finally {"
3539 " return;"
3540 " }"
3541 "})()");
3542 CHECK(!try_catch.HasCaught());
3543}
3544
3545
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003546// This test works by making a stack of alternating JavaScript and C
3547// activations. These activations set up exception handlers with regular
3548// intervals, one interval for C activations and another for JavaScript
3549// activations. When enough activations have been created an exception is
3550// thrown and we check that the right activation catches the exception and that
3551// no other activations do. The right activation is always the topmost one with
3552// a handler, regardless of whether it is in JavaScript or C.
3553//
3554// The notation used to describe a test case looks like this:
3555//
3556// *JS[4] *C[3] @JS[2] C[1] JS[0]
3557//
3558// Each entry is an activation, either JS or C. The index is the count at that
3559// level. Stars identify activations with exception handlers, the @ identifies
3560// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003561//
3562// BUG(271): Some of the exception propagation does not work on the
3563// ARM simulator because the simulator separates the C++ stack and the
3564// JS stack. This test therefore fails on the simulator. The test is
3565// not threaded to allow the threading tests to run on the simulator.
3566TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003567 v8::HandleScope scope;
3568 Local<ObjectTemplate> templ = ObjectTemplate::New();
3569 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3570 templ->Set(v8_str("CThrowCountDown"),
3571 v8::FunctionTemplate::New(CThrowCountDown));
3572 LocalContext context(0, templ);
3573 CompileRun(
3574 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3575 " if (count == 0) throw 'FromJS';"
3576 " if (count % jsInterval == 0) {"
3577 " try {"
3578 " var value = CThrowCountDown(count - 1,"
3579 " jsInterval,"
3580 " cInterval,"
3581 " expected);"
3582 " check(false, count, expected);"
3583 " return value;"
3584 " } catch (e) {"
3585 " check(true, count, expected);"
3586 " }"
3587 " } else {"
3588 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3589 " }"
3590 "}");
3591 Local<Function> fun =
3592 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3593
3594 const int argc = 4;
3595 // count jsInterval cInterval expected
3596
3597 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3598 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3599 fun->Call(fun, argc, a0);
3600
3601 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3602 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3603 fun->Call(fun, argc, a1);
3604
3605 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3606 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3607 fun->Call(fun, argc, a2);
3608
3609 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3610 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3611 fun->Call(fun, argc, a3);
3612
3613 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3614 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3615 fun->Call(fun, argc, a4);
3616
3617 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3618 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3619 fun->Call(fun, argc, a5);
3620}
3621
3622
3623v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3624 ApiTestFuzzer::Fuzz();
3625 CHECK_EQ(1, args.Length());
3626 return v8::ThrowException(args[0]);
3627}
3628
3629
3630THREADED_TEST(ThrowValues) {
3631 v8::HandleScope scope;
3632 Local<ObjectTemplate> templ = ObjectTemplate::New();
3633 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3634 LocalContext context(0, templ);
3635 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3636 "function Run(obj) {"
3637 " try {"
3638 " Throw(obj);"
3639 " } catch (e) {"
3640 " return e;"
3641 " }"
3642 " return 'no exception';"
3643 "}"
3644 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3645 CHECK_EQ(5, result->Length());
3646 CHECK(result->Get(v8::Integer::New(0))->IsString());
3647 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3648 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3649 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3650 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3651 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3652 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3653}
3654
3655
3656THREADED_TEST(CatchZero) {
3657 v8::HandleScope scope;
3658 LocalContext context;
3659 v8::TryCatch try_catch;
3660 CHECK(!try_catch.HasCaught());
3661 Script::Compile(v8_str("throw 10"))->Run();
3662 CHECK(try_catch.HasCaught());
3663 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3664 try_catch.Reset();
3665 CHECK(!try_catch.HasCaught());
3666 Script::Compile(v8_str("throw 0"))->Run();
3667 CHECK(try_catch.HasCaught());
3668 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3669}
3670
3671
3672THREADED_TEST(CatchExceptionFromWith) {
3673 v8::HandleScope scope;
3674 LocalContext context;
3675 v8::TryCatch try_catch;
3676 CHECK(!try_catch.HasCaught());
3677 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3678 CHECK(try_catch.HasCaught());
3679}
3680
3681
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003682THREADED_TEST(TryCatchAndFinallyHidingException) {
3683 v8::HandleScope scope;
3684 LocalContext context;
3685 v8::TryCatch try_catch;
3686 CHECK(!try_catch.HasCaught());
3687 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3688 CompileRun("f({toString: function() { throw 42; }});");
3689 CHECK(!try_catch.HasCaught());
3690}
3691
3692
3693v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3694 v8::TryCatch try_catch;
3695 return v8::Undefined();
3696}
3697
3698
3699THREADED_TEST(TryCatchAndFinally) {
3700 v8::HandleScope scope;
3701 LocalContext context;
3702 context->Global()->Set(
3703 v8_str("native_with_try_catch"),
3704 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3705 v8::TryCatch try_catch;
3706 CHECK(!try_catch.HasCaught());
3707 CompileRun(
3708 "try {\n"
3709 " throw new Error('a');\n"
3710 "} finally {\n"
3711 " native_with_try_catch();\n"
3712 "}\n");
3713 CHECK(try_catch.HasCaught());
3714}
3715
3716
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003717THREADED_TEST(Equality) {
3718 v8::HandleScope scope;
3719 LocalContext context;
3720 // Check that equality works at all before relying on CHECK_EQ
3721 CHECK(v8_str("a")->Equals(v8_str("a")));
3722 CHECK(!v8_str("a")->Equals(v8_str("b")));
3723
3724 CHECK_EQ(v8_str("a"), v8_str("a"));
3725 CHECK_NE(v8_str("a"), v8_str("b"));
3726 CHECK_EQ(v8_num(1), v8_num(1));
3727 CHECK_EQ(v8_num(1.00), v8_num(1));
3728 CHECK_NE(v8_num(1), v8_num(2));
3729
3730 // Assume String is not symbol.
3731 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3732 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3733 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3734 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3735 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3736 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3737 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3738 CHECK(!not_a_number->StrictEquals(not_a_number));
3739 CHECK(v8::False()->StrictEquals(v8::False()));
3740 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3741
3742 v8::Handle<v8::Object> obj = v8::Object::New();
3743 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3744 CHECK(alias->StrictEquals(obj));
3745 alias.Dispose();
3746}
3747
3748
3749THREADED_TEST(MultiRun) {
3750 v8::HandleScope scope;
3751 LocalContext context;
3752 Local<Script> script = Script::Compile(v8_str("x"));
3753 for (int i = 0; i < 10; i++)
3754 script->Run();
3755}
3756
3757
3758static v8::Handle<Value> GetXValue(Local<String> name,
3759 const AccessorInfo& info) {
3760 ApiTestFuzzer::Fuzz();
3761 CHECK_EQ(info.Data(), v8_str("donut"));
3762 CHECK_EQ(name, v8_str("x"));
3763 return name;
3764}
3765
3766
3767THREADED_TEST(SimplePropertyRead) {
3768 v8::HandleScope scope;
3769 Local<ObjectTemplate> templ = ObjectTemplate::New();
3770 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3771 LocalContext context;
3772 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3773 Local<Script> script = Script::Compile(v8_str("obj.x"));
3774 for (int i = 0; i < 10; i++) {
3775 Local<Value> result = script->Run();
3776 CHECK_EQ(result, v8_str("x"));
3777 }
3778}
3779
ager@chromium.org5c838252010-02-19 08:53:10 +00003780THREADED_TEST(DefinePropertyOnAPIAccessor) {
3781 v8::HandleScope scope;
3782 Local<ObjectTemplate> templ = ObjectTemplate::New();
3783 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3784 LocalContext context;
3785 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3786
3787 // Uses getOwnPropertyDescriptor to check the configurable status
3788 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003789 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003790 "obj, 'x');"
3791 "prop.configurable;"));
3792 Local<Value> result = script_desc->Run();
3793 CHECK_EQ(result->BooleanValue(), true);
3794
3795 // Redefine get - but still configurable
3796 Local<Script> script_define
3797 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3798 " configurable: true };"
3799 "Object.defineProperty(obj, 'x', desc);"
3800 "obj.x"));
3801 result = script_define->Run();
3802 CHECK_EQ(result, v8_num(42));
3803
3804 // Check that the accessor is still configurable
3805 result = script_desc->Run();
3806 CHECK_EQ(result->BooleanValue(), true);
3807
3808 // Redefine to a non-configurable
3809 script_define
3810 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3811 " configurable: false };"
3812 "Object.defineProperty(obj, 'x', desc);"
3813 "obj.x"));
3814 result = script_define->Run();
3815 CHECK_EQ(result, v8_num(43));
3816 result = script_desc->Run();
3817 CHECK_EQ(result->BooleanValue(), false);
3818
3819 // Make sure that it is not possible to redefine again
3820 v8::TryCatch try_catch;
3821 result = script_define->Run();
3822 CHECK(try_catch.HasCaught());
3823 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003824 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003825}
3826
3827THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3828 v8::HandleScope scope;
3829 Local<ObjectTemplate> templ = ObjectTemplate::New();
3830 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3831 LocalContext context;
3832 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3833
3834 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3835 "Object.getOwnPropertyDescriptor( "
3836 "obj, 'x');"
3837 "prop.configurable;"));
3838 Local<Value> result = script_desc->Run();
3839 CHECK_EQ(result->BooleanValue(), true);
3840
3841 Local<Script> script_define =
3842 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3843 " configurable: true };"
3844 "Object.defineProperty(obj, 'x', desc);"
3845 "obj.x"));
3846 result = script_define->Run();
3847 CHECK_EQ(result, v8_num(42));
3848
3849
3850 result = script_desc->Run();
3851 CHECK_EQ(result->BooleanValue(), true);
3852
3853
3854 script_define =
3855 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3856 " configurable: false };"
3857 "Object.defineProperty(obj, 'x', desc);"
3858 "obj.x"));
3859 result = script_define->Run();
3860 CHECK_EQ(result, v8_num(43));
3861 result = script_desc->Run();
3862
3863 CHECK_EQ(result->BooleanValue(), false);
3864
3865 v8::TryCatch try_catch;
3866 result = script_define->Run();
3867 CHECK(try_catch.HasCaught());
3868 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003869 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003870}
3871
3872
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003873static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3874 char const* name) {
3875 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3876}
ager@chromium.org5c838252010-02-19 08:53:10 +00003877
3878
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003879THREADED_TEST(DefineAPIAccessorOnObject) {
3880 v8::HandleScope scope;
3881 Local<ObjectTemplate> templ = ObjectTemplate::New();
3882 LocalContext context;
3883
3884 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3885 CompileRun("var obj2 = {};");
3886
3887 CHECK(CompileRun("obj1.x")->IsUndefined());
3888 CHECK(CompileRun("obj2.x")->IsUndefined());
3889
3890 CHECK(GetGlobalProperty(&context, "obj1")->
3891 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3892
3893 ExpectString("obj1.x", "x");
3894 CHECK(CompileRun("obj2.x")->IsUndefined());
3895
3896 CHECK(GetGlobalProperty(&context, "obj2")->
3897 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3898
3899 ExpectString("obj1.x", "x");
3900 ExpectString("obj2.x", "x");
3901
3902 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3903 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3904
3905 CompileRun("Object.defineProperty(obj1, 'x',"
3906 "{ get: function() { return 'y'; }, configurable: true })");
3907
3908 ExpectString("obj1.x", "y");
3909 ExpectString("obj2.x", "x");
3910
3911 CompileRun("Object.defineProperty(obj2, 'x',"
3912 "{ get: function() { return 'y'; }, configurable: true })");
3913
3914 ExpectString("obj1.x", "y");
3915 ExpectString("obj2.x", "y");
3916
3917 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3918 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3919
3920 CHECK(GetGlobalProperty(&context, "obj1")->
3921 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3922 CHECK(GetGlobalProperty(&context, "obj2")->
3923 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3924
3925 ExpectString("obj1.x", "x");
3926 ExpectString("obj2.x", "x");
3927
3928 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3929 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3930
3931 // Define getters/setters, but now make them not configurable.
3932 CompileRun("Object.defineProperty(obj1, 'x',"
3933 "{ get: function() { return 'z'; }, configurable: false })");
3934 CompileRun("Object.defineProperty(obj2, 'x',"
3935 "{ get: function() { return 'z'; }, configurable: false })");
3936
3937 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3938 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3939
3940 ExpectString("obj1.x", "z");
3941 ExpectString("obj2.x", "z");
3942
3943 CHECK(!GetGlobalProperty(&context, "obj1")->
3944 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3945 CHECK(!GetGlobalProperty(&context, "obj2")->
3946 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3947
3948 ExpectString("obj1.x", "z");
3949 ExpectString("obj2.x", "z");
3950}
3951
3952
3953THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3954 v8::HandleScope scope;
3955 Local<ObjectTemplate> templ = ObjectTemplate::New();
3956 LocalContext context;
3957
3958 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3959 CompileRun("var obj2 = {};");
3960
3961 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3962 v8_str("x"),
3963 GetXValue, NULL,
3964 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3965 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3966 v8_str("x"),
3967 GetXValue, NULL,
3968 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3969
3970 ExpectString("obj1.x", "x");
3971 ExpectString("obj2.x", "x");
3972
3973 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3974 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3975
3976 CHECK(!GetGlobalProperty(&context, "obj1")->
3977 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3978 CHECK(!GetGlobalProperty(&context, "obj2")->
3979 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3980
3981 {
3982 v8::TryCatch try_catch;
3983 CompileRun("Object.defineProperty(obj1, 'x',"
3984 "{get: function() { return 'func'; }})");
3985 CHECK(try_catch.HasCaught());
3986 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003987 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003988 }
3989 {
3990 v8::TryCatch try_catch;
3991 CompileRun("Object.defineProperty(obj2, 'x',"
3992 "{get: function() { return 'func'; }})");
3993 CHECK(try_catch.HasCaught());
3994 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003995 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003996 }
3997}
3998
3999
4000static v8::Handle<Value> Get239Value(Local<String> name,
4001 const AccessorInfo& info) {
4002 ApiTestFuzzer::Fuzz();
4003 CHECK_EQ(info.Data(), v8_str("donut"));
4004 CHECK_EQ(name, v8_str("239"));
4005 return name;
4006}
4007
4008
4009THREADED_TEST(ElementAPIAccessor) {
4010 v8::HandleScope scope;
4011 Local<ObjectTemplate> templ = ObjectTemplate::New();
4012 LocalContext context;
4013
4014 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4015 CompileRun("var obj2 = {};");
4016
4017 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4018 v8_str("239"),
4019 Get239Value, NULL,
4020 v8_str("donut")));
4021 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4022 v8_str("239"),
4023 Get239Value, NULL,
4024 v8_str("donut")));
4025
4026 ExpectString("obj1[239]", "239");
4027 ExpectString("obj2[239]", "239");
4028 ExpectString("obj1['239']", "239");
4029 ExpectString("obj2['239']", "239");
4030}
4031
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004032
4033v8::Persistent<Value> xValue;
4034
4035
4036static void SetXValue(Local<String> name,
4037 Local<Value> value,
4038 const AccessorInfo& info) {
4039 CHECK_EQ(value, v8_num(4));
4040 CHECK_EQ(info.Data(), v8_str("donut"));
4041 CHECK_EQ(name, v8_str("x"));
4042 CHECK(xValue.IsEmpty());
4043 xValue = v8::Persistent<Value>::New(value);
4044}
4045
4046
4047THREADED_TEST(SimplePropertyWrite) {
4048 v8::HandleScope scope;
4049 Local<ObjectTemplate> templ = ObjectTemplate::New();
4050 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
4051 LocalContext context;
4052 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4053 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
4054 for (int i = 0; i < 10; i++) {
4055 CHECK(xValue.IsEmpty());
4056 script->Run();
4057 CHECK_EQ(v8_num(4), xValue);
4058 xValue.Dispose();
4059 xValue = v8::Persistent<Value>();
4060 }
4061}
4062
4063
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004064THREADED_TEST(SetterOnly) {
4065 v8::HandleScope scope;
4066 Local<ObjectTemplate> templ = ObjectTemplate::New();
4067 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
4068 LocalContext context;
4069 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4070 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4071 for (int i = 0; i < 10; i++) {
4072 CHECK(xValue.IsEmpty());
4073 script->Run();
4074 CHECK_EQ(v8_num(4), xValue);
4075 xValue.Dispose();
4076 xValue = v8::Persistent<Value>();
4077 }
4078}
4079
4080
4081THREADED_TEST(NoAccessors) {
4082 v8::HandleScope scope;
4083 Local<ObjectTemplate> templ = ObjectTemplate::New();
4084 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
4085 LocalContext context;
4086 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4087 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4088 for (int i = 0; i < 10; i++) {
4089 script->Run();
4090 }
4091}
4092
4093
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004094static v8::Handle<Value> XPropertyGetter(Local<String> property,
4095 const AccessorInfo& info) {
4096 ApiTestFuzzer::Fuzz();
4097 CHECK(info.Data()->IsUndefined());
4098 return property;
4099}
4100
4101
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004102THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 v8::HandleScope scope;
4104 Local<ObjectTemplate> templ = ObjectTemplate::New();
4105 templ->SetNamedPropertyHandler(XPropertyGetter);
4106 LocalContext context;
4107 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4108 Local<Script> script = Script::Compile(v8_str("obj.x"));
4109 for (int i = 0; i < 10; i++) {
4110 Local<Value> result = script->Run();
4111 CHECK_EQ(result, v8_str("x"));
4112 }
4113}
4114
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004115
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004116THREADED_TEST(NamedInterceptorDictionaryIC) {
4117 v8::HandleScope scope;
4118 Local<ObjectTemplate> templ = ObjectTemplate::New();
4119 templ->SetNamedPropertyHandler(XPropertyGetter);
4120 LocalContext context;
4121 // Create an object with a named interceptor.
4122 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
4123 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
4124 for (int i = 0; i < 10; i++) {
4125 Local<Value> result = script->Run();
4126 CHECK_EQ(result, v8_str("x"));
4127 }
4128 // Create a slow case object and a function accessing a property in
4129 // that slow case object (with dictionary probing in generated
4130 // code). Then force object with a named interceptor into slow-case,
4131 // pass it to the function, and check that the interceptor is called
4132 // instead of accessing the local property.
4133 Local<Value> result =
4134 CompileRun("function get_x(o) { return o.x; };"
4135 "var obj = { x : 42, y : 0 };"
4136 "delete obj.y;"
4137 "for (var i = 0; i < 10; i++) get_x(obj);"
4138 "interceptor_obj.x = 42;"
4139 "interceptor_obj.y = 10;"
4140 "delete interceptor_obj.y;"
4141 "get_x(interceptor_obj)");
4142 CHECK_EQ(result, v8_str("x"));
4143}
4144
4145
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004146THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
4147 v8::HandleScope scope;
4148
4149 v8::Persistent<Context> context1 = Context::New();
4150
4151 context1->Enter();
4152 Local<ObjectTemplate> templ = ObjectTemplate::New();
4153 templ->SetNamedPropertyHandler(XPropertyGetter);
4154 // Create an object with a named interceptor.
4155 v8::Local<v8::Object> object = templ->NewInstance();
4156 context1->Global()->Set(v8_str("interceptor_obj"), object);
4157
4158 // Force the object into the slow case.
4159 CompileRun("interceptor_obj.y = 0;"
4160 "delete interceptor_obj.y;");
4161 context1->Exit();
4162
4163 {
4164 // Introduce the object into a different context.
4165 // Repeat named loads to exercise ICs.
4166 LocalContext context2;
4167 context2->Global()->Set(v8_str("interceptor_obj"), object);
4168 Local<Value> result =
4169 CompileRun("function get_x(o) { return o.x; }"
4170 "interceptor_obj.x = 42;"
4171 "for (var i=0; i != 10; i++) {"
4172 " get_x(interceptor_obj);"
4173 "}"
4174 "get_x(interceptor_obj)");
4175 // Check that the interceptor was actually invoked.
4176 CHECK_EQ(result, v8_str("x"));
4177 }
4178
4179 // Return to the original context and force some object to the slow case
4180 // to cause the NormalizedMapCache to verify.
4181 context1->Enter();
4182 CompileRun("var obj = { x : 0 }; delete obj.x;");
4183 context1->Exit();
4184
4185 context1.Dispose();
4186}
4187
4188
ager@chromium.org5c838252010-02-19 08:53:10 +00004189static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
4190 const AccessorInfo& info) {
4191 // Set x on the prototype object and do not handle the get request.
4192 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004193 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00004194 return v8::Handle<Value>();
4195}
4196
4197
4198// This is a regression test for http://crbug.com/20104. Map
4199// transitions should not interfere with post interceptor lookup.
4200THREADED_TEST(NamedInterceptorMapTransitionRead) {
4201 v8::HandleScope scope;
4202 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
4203 Local<v8::ObjectTemplate> instance_template
4204 = function_template->InstanceTemplate();
4205 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
4206 LocalContext context;
4207 context->Global()->Set(v8_str("F"), function_template->GetFunction());
4208 // Create an instance of F and introduce a map transition for x.
4209 CompileRun("var o = new F(); o.x = 23;");
4210 // Create an instance of F and invoke the getter. The result should be 23.
4211 Local<Value> result = CompileRun("o = new F(); o.x");
4212 CHECK_EQ(result->Int32Value(), 23);
4213}
4214
4215
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004216static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4217 const AccessorInfo& info) {
4218 ApiTestFuzzer::Fuzz();
4219 if (index == 37) {
4220 return v8::Handle<Value>(v8_num(625));
4221 }
4222 return v8::Handle<Value>();
4223}
4224
4225
4226static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4227 Local<Value> value,
4228 const AccessorInfo& info) {
4229 ApiTestFuzzer::Fuzz();
4230 if (index == 39) {
4231 return value;
4232 }
4233 return v8::Handle<Value>();
4234}
4235
4236
4237THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4238 v8::HandleScope scope;
4239 Local<ObjectTemplate> templ = ObjectTemplate::New();
4240 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4241 IndexedPropertySetter);
4242 LocalContext context;
4243 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4244 Local<Script> getter_script = Script::Compile(v8_str(
4245 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4246 Local<Script> setter_script = Script::Compile(v8_str(
4247 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4248 "obj[17] = 23;"
4249 "obj.foo;"));
4250 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4251 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4252 "obj[39] = 47;"
4253 "obj.foo;")); // This setter should not run, due to the interceptor.
4254 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4255 "obj[37];"));
4256 Local<Value> result = getter_script->Run();
4257 CHECK_EQ(v8_num(5), result);
4258 result = setter_script->Run();
4259 CHECK_EQ(v8_num(23), result);
4260 result = interceptor_setter_script->Run();
4261 CHECK_EQ(v8_num(23), result);
4262 result = interceptor_getter_script->Run();
4263 CHECK_EQ(v8_num(625), result);
4264}
4265
4266
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004267static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4268 uint32_t index,
4269 const AccessorInfo& info) {
4270 ApiTestFuzzer::Fuzz();
4271 if (index < 25) {
4272 return v8::Handle<Value>(v8_num(index));
4273 }
4274 return v8::Handle<Value>();
4275}
4276
4277
4278static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4279 uint32_t index,
4280 Local<Value> value,
4281 const AccessorInfo& info) {
4282 ApiTestFuzzer::Fuzz();
4283 if (index < 25) {
4284 return v8::Handle<Value>(v8_num(index));
4285 }
4286 return v8::Handle<Value>();
4287}
4288
4289
4290Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4291 const AccessorInfo& info) {
4292 // Force the list of returned keys to be stored in a FastDoubleArray.
4293 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4294 "keys = new Array(); keys[125000] = 1;"
4295 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4296 "keys.length = 25; keys;"));
4297 Local<Value> result = indexed_property_names_script->Run();
4298 return Local<v8::Array>(::v8::Array::Cast(*result));
4299}
4300
4301
4302// Make sure that the the interceptor code in the runtime properly handles
4303// merging property name lists for double-array-backed arrays.
4304THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4305 v8::HandleScope scope;
4306 Local<ObjectTemplate> templ = ObjectTemplate::New();
4307 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4308 UnboxedDoubleIndexedPropertySetter,
4309 0,
4310 0,
4311 UnboxedDoubleIndexedPropertyEnumerator);
4312 LocalContext context;
4313 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4314 // When obj is created, force it to be Stored in a FastDoubleArray.
4315 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4316 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4317 "key_count = 0; "
4318 "for (x in obj) {key_count++;};"
4319 "obj;"));
4320 Local<Value> result = create_unboxed_double_script->Run();
4321 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4322 Local<Script> key_count_check = Script::Compile(v8_str(
4323 "key_count;"));
4324 result = key_count_check->Run();
4325 CHECK_EQ(v8_num(40013), result);
4326}
4327
4328
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004329Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4330 const AccessorInfo& info) {
4331 // Force the list of returned keys to be stored in a Arguments object.
4332 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4333 "function f(w,x) {"
4334 " return arguments;"
4335 "}"
4336 "keys = f(0, 1, 2, 3);"
4337 "keys;"));
4338 Local<Value> result = indexed_property_names_script->Run();
4339 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4340}
4341
4342
4343static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4344 uint32_t index,
4345 const AccessorInfo& info) {
4346 ApiTestFuzzer::Fuzz();
4347 if (index < 4) {
4348 return v8::Handle<Value>(v8_num(index));
4349 }
4350 return v8::Handle<Value>();
4351}
4352
4353
4354// Make sure that the the interceptor code in the runtime properly handles
4355// merging property name lists for non-string arguments arrays.
4356THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4357 v8::HandleScope scope;
4358 Local<ObjectTemplate> templ = ObjectTemplate::New();
4359 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4360 0,
4361 0,
4362 0,
4363 NonStrictArgsIndexedPropertyEnumerator);
4364 LocalContext context;
4365 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4366 Local<Script> create_args_script =
4367 Script::Compile(v8_str(
4368 "var key_count = 0;"
4369 "for (x in obj) {key_count++;} key_count;"));
4370 Local<Value> result = create_args_script->Run();
4371 CHECK_EQ(v8_num(4), result);
4372}
4373
4374
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004375static v8::Handle<Value> IdentityIndexedPropertyGetter(
4376 uint32_t index,
4377 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004378 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004379}
4380
4381
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004382THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4383 v8::HandleScope scope;
4384 Local<ObjectTemplate> templ = ObjectTemplate::New();
4385 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4386
4387 LocalContext context;
4388 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4389
4390 // Check fast object case.
4391 const char* fast_case_code =
4392 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4393 ExpectString(fast_case_code, "0");
4394
4395 // Check slow case.
4396 const char* slow_case_code =
4397 "obj.x = 1; delete obj.x;"
4398 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4399 ExpectString(slow_case_code, "1");
4400}
4401
4402
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004403THREADED_TEST(IndexedInterceptorWithNoSetter) {
4404 v8::HandleScope scope;
4405 Local<ObjectTemplate> templ = ObjectTemplate::New();
4406 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4407
4408 LocalContext context;
4409 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4410
4411 const char* code =
4412 "try {"
4413 " obj[0] = 239;"
4414 " for (var i = 0; i < 100; i++) {"
4415 " var v = obj[0];"
4416 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4417 " }"
4418 " 'PASSED'"
4419 "} catch(e) {"
4420 " e"
4421 "}";
4422 ExpectString(code, "PASSED");
4423}
4424
4425
ager@chromium.org5c838252010-02-19 08:53:10 +00004426THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4427 v8::HandleScope scope;
4428 Local<ObjectTemplate> templ = ObjectTemplate::New();
4429 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4430
4431 LocalContext context;
4432 Local<v8::Object> obj = templ->NewInstance();
4433 obj->TurnOnAccessCheck();
4434 context->Global()->Set(v8_str("obj"), obj);
4435
4436 const char* code =
4437 "try {"
4438 " for (var i = 0; i < 100; i++) {"
4439 " var v = obj[0];"
4440 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4441 " }"
4442 " 'PASSED'"
4443 "} catch(e) {"
4444 " e"
4445 "}";
4446 ExpectString(code, "PASSED");
4447}
4448
4449
4450THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4451 i::FLAG_allow_natives_syntax = true;
4452 v8::HandleScope scope;
4453 Local<ObjectTemplate> templ = ObjectTemplate::New();
4454 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4455
4456 LocalContext context;
4457 Local<v8::Object> obj = templ->NewInstance();
4458 context->Global()->Set(v8_str("obj"), obj);
4459
4460 const char* code =
4461 "try {"
4462 " for (var i = 0; i < 100; i++) {"
4463 " var expected = i;"
4464 " if (i == 5) {"
4465 " %EnableAccessChecks(obj);"
4466 " expected = undefined;"
4467 " }"
4468 " var v = obj[i];"
4469 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4470 " if (i == 5) %DisableAccessChecks(obj);"
4471 " }"
4472 " 'PASSED'"
4473 "} catch(e) {"
4474 " e"
4475 "}";
4476 ExpectString(code, "PASSED");
4477}
4478
4479
4480THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4481 v8::HandleScope scope;
4482 Local<ObjectTemplate> templ = ObjectTemplate::New();
4483 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4484
4485 LocalContext context;
4486 Local<v8::Object> obj = templ->NewInstance();
4487 context->Global()->Set(v8_str("obj"), obj);
4488
4489 const char* code =
4490 "try {"
4491 " for (var i = 0; i < 100; i++) {"
4492 " var v = obj[i];"
4493 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4494 " }"
4495 " 'PASSED'"
4496 "} catch(e) {"
4497 " e"
4498 "}";
4499 ExpectString(code, "PASSED");
4500}
4501
4502
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004503THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4504 v8::HandleScope scope;
4505 Local<ObjectTemplate> templ = ObjectTemplate::New();
4506 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4507
4508 LocalContext context;
4509 Local<v8::Object> obj = templ->NewInstance();
4510 context->Global()->Set(v8_str("obj"), obj);
4511
4512 const char* code =
4513 "try {"
4514 " for (var i = 0; i < 100; i++) {"
4515 " var expected = i;"
4516 " var key = i;"
4517 " if (i == 25) {"
4518 " key = -1;"
4519 " expected = undefined;"
4520 " }"
4521 " if (i == 50) {"
4522 " /* probe minimal Smi number on 32-bit platforms */"
4523 " key = -(1 << 30);"
4524 " expected = undefined;"
4525 " }"
4526 " if (i == 75) {"
4527 " /* probe minimal Smi number on 64-bit platforms */"
4528 " key = 1 << 31;"
4529 " expected = undefined;"
4530 " }"
4531 " var v = obj[key];"
4532 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4533 " }"
4534 " 'PASSED'"
4535 "} catch(e) {"
4536 " e"
4537 "}";
4538 ExpectString(code, "PASSED");
4539}
4540
4541
ager@chromium.org5c838252010-02-19 08:53:10 +00004542THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4543 v8::HandleScope scope;
4544 Local<ObjectTemplate> templ = ObjectTemplate::New();
4545 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4546
4547 LocalContext context;
4548 Local<v8::Object> obj = templ->NewInstance();
4549 context->Global()->Set(v8_str("obj"), obj);
4550
4551 const char* code =
4552 "try {"
4553 " for (var i = 0; i < 100; i++) {"
4554 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004555 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004556 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004557 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004558 " expected = undefined;"
4559 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004560 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004561 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4562 " }"
4563 " 'PASSED'"
4564 "} catch(e) {"
4565 " e"
4566 "}";
4567 ExpectString(code, "PASSED");
4568}
4569
4570
4571THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4572 v8::HandleScope scope;
4573 Local<ObjectTemplate> templ = ObjectTemplate::New();
4574 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4575
4576 LocalContext context;
4577 Local<v8::Object> obj = templ->NewInstance();
4578 context->Global()->Set(v8_str("obj"), obj);
4579
4580 const char* code =
4581 "var original = obj;"
4582 "try {"
4583 " for (var i = 0; i < 100; i++) {"
4584 " var expected = i;"
4585 " if (i == 50) {"
4586 " obj = {50: 'foobar'};"
4587 " expected = 'foobar';"
4588 " }"
4589 " var v = obj[i];"
4590 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4591 " if (i == 50) obj = original;"
4592 " }"
4593 " 'PASSED'"
4594 "} catch(e) {"
4595 " e"
4596 "}";
4597 ExpectString(code, "PASSED");
4598}
4599
4600
4601THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4602 v8::HandleScope scope;
4603 Local<ObjectTemplate> templ = ObjectTemplate::New();
4604 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4605
4606 LocalContext context;
4607 Local<v8::Object> obj = templ->NewInstance();
4608 context->Global()->Set(v8_str("obj"), obj);
4609
4610 const char* code =
4611 "var original = obj;"
4612 "try {"
4613 " for (var i = 0; i < 100; i++) {"
4614 " var expected = i;"
4615 " if (i == 5) {"
4616 " obj = 239;"
4617 " expected = undefined;"
4618 " }"
4619 " var v = obj[i];"
4620 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4621 " if (i == 5) obj = original;"
4622 " }"
4623 " 'PASSED'"
4624 "} catch(e) {"
4625 " e"
4626 "}";
4627 ExpectString(code, "PASSED");
4628}
4629
4630
4631THREADED_TEST(IndexedInterceptorOnProto) {
4632 v8::HandleScope scope;
4633 Local<ObjectTemplate> templ = ObjectTemplate::New();
4634 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4635
4636 LocalContext context;
4637 Local<v8::Object> obj = templ->NewInstance();
4638 context->Global()->Set(v8_str("obj"), obj);
4639
4640 const char* code =
4641 "var o = {__proto__: obj};"
4642 "try {"
4643 " for (var i = 0; i < 100; i++) {"
4644 " var v = o[i];"
4645 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4646 " }"
4647 " 'PASSED'"
4648 "} catch(e) {"
4649 " e"
4650 "}";
4651 ExpectString(code, "PASSED");
4652}
4653
4654
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004655THREADED_TEST(MultiContexts) {
4656 v8::HandleScope scope;
4657 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4658 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4659
4660 Local<String> password = v8_str("Password");
4661
4662 // Create an environment
4663 LocalContext context0(0, templ);
4664 context0->SetSecurityToken(password);
4665 v8::Handle<v8::Object> global0 = context0->Global();
4666 global0->Set(v8_str("custom"), v8_num(1234));
4667 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4668
4669 // Create an independent environment
4670 LocalContext context1(0, templ);
4671 context1->SetSecurityToken(password);
4672 v8::Handle<v8::Object> global1 = context1->Global();
4673 global1->Set(v8_str("custom"), v8_num(1234));
4674 CHECK_NE(global0, global1);
4675 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4676 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4677
4678 // Now create a new context with the old global
4679 LocalContext context2(0, templ, global1);
4680 context2->SetSecurityToken(password);
4681 v8::Handle<v8::Object> global2 = context2->Global();
4682 CHECK_EQ(global1, global2);
4683 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4684 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4685}
4686
4687
4688THREADED_TEST(FunctionPrototypeAcrossContexts) {
4689 // Make sure that functions created by cloning boilerplates cannot
4690 // communicate through their __proto__ field.
4691
4692 v8::HandleScope scope;
4693
4694 LocalContext env0;
4695 v8::Handle<v8::Object> global0 =
4696 env0->Global();
4697 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004698 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004699 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004700 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004701 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004702 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004703 proto0->Set(v8_str("custom"), v8_num(1234));
4704
4705 LocalContext env1;
4706 v8::Handle<v8::Object> global1 =
4707 env1->Global();
4708 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004709 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004710 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004711 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004712 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004713 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004714 CHECK(!proto1->Has(v8_str("custom")));
4715}
4716
4717
4718THREADED_TEST(Regress892105) {
4719 // Make sure that object and array literals created by cloning
4720 // boilerplates cannot communicate through their __proto__
4721 // field. This is rather difficult to check, but we try to add stuff
4722 // to Object.prototype and Array.prototype and create a new
4723 // environment. This should succeed.
4724
4725 v8::HandleScope scope;
4726
4727 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4728 "Array.prototype.arr = 4567;"
4729 "8901");
4730
4731 LocalContext env0;
4732 Local<Script> script0 = Script::Compile(source);
4733 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4734
4735 LocalContext env1;
4736 Local<Script> script1 = Script::Compile(source);
4737 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4738}
4739
4740
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004741THREADED_TEST(UndetectableObject) {
4742 v8::HandleScope scope;
4743 LocalContext env;
4744
4745 Local<v8::FunctionTemplate> desc =
4746 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4747 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4748
4749 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4750 env->Global()->Set(v8_str("undetectable"), obj);
4751
4752 ExpectString("undetectable.toString()", "[object Object]");
4753 ExpectString("typeof undetectable", "undefined");
4754 ExpectString("typeof(undetectable)", "undefined");
4755 ExpectBoolean("typeof undetectable == 'undefined'", true);
4756 ExpectBoolean("typeof undetectable == 'object'", false);
4757 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4758 ExpectBoolean("!undetectable", true);
4759
4760 ExpectObject("true&&undetectable", obj);
4761 ExpectBoolean("false&&undetectable", false);
4762 ExpectBoolean("true||undetectable", true);
4763 ExpectObject("false||undetectable", obj);
4764
4765 ExpectObject("undetectable&&true", obj);
4766 ExpectObject("undetectable&&false", obj);
4767 ExpectBoolean("undetectable||true", true);
4768 ExpectBoolean("undetectable||false", false);
4769
4770 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004771 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004772 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004773 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004774 ExpectBoolean("undetectable==undetectable", true);
4775
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004776
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004777 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004778 ExpectBoolean("null===undetectable", false);
4779 ExpectBoolean("undetectable===undefined", false);
4780 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004781 ExpectBoolean("undetectable===undetectable", true);
4782}
4783
4784
ager@chromium.org04921a82011-06-27 13:21:41 +00004785THREADED_TEST(VoidLiteral) {
4786 v8::HandleScope scope;
4787 LocalContext env;
4788
4789 Local<v8::FunctionTemplate> desc =
4790 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4791 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4792
4793 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4794 env->Global()->Set(v8_str("undetectable"), obj);
4795
4796 ExpectBoolean("undefined == void 0", true);
4797 ExpectBoolean("undetectable == void 0", true);
4798 ExpectBoolean("null == void 0", true);
4799 ExpectBoolean("undefined === void 0", true);
4800 ExpectBoolean("undetectable === void 0", false);
4801 ExpectBoolean("null === void 0", false);
4802
4803 ExpectBoolean("void 0 == undefined", true);
4804 ExpectBoolean("void 0 == undetectable", true);
4805 ExpectBoolean("void 0 == null", true);
4806 ExpectBoolean("void 0 === undefined", true);
4807 ExpectBoolean("void 0 === undetectable", false);
4808 ExpectBoolean("void 0 === null", false);
4809
4810 ExpectString("(function() {"
4811 " try {"
4812 " return x === void 0;"
4813 " } catch(e) {"
4814 " return e.toString();"
4815 " }"
4816 "})()",
4817 "ReferenceError: x is not defined");
4818 ExpectString("(function() {"
4819 " try {"
4820 " return void 0 === x;"
4821 " } catch(e) {"
4822 " return e.toString();"
4823 " }"
4824 "})()",
4825 "ReferenceError: x is not defined");
4826}
4827
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004828
4829THREADED_TEST(ExtensibleOnUndetectable) {
4830 v8::HandleScope scope;
4831 LocalContext env;
4832
4833 Local<v8::FunctionTemplate> desc =
4834 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4835 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4836
4837 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4838 env->Global()->Set(v8_str("undetectable"), obj);
4839
4840 Local<String> source = v8_str("undetectable.x = 42;"
4841 "undetectable.x");
4842
4843 Local<Script> script = Script::Compile(source);
4844
4845 CHECK_EQ(v8::Integer::New(42), script->Run());
4846
4847 ExpectBoolean("Object.isExtensible(undetectable)", true);
4848
4849 source = v8_str("Object.preventExtensions(undetectable);");
4850 script = Script::Compile(source);
4851 script->Run();
4852 ExpectBoolean("Object.isExtensible(undetectable)", false);
4853
4854 source = v8_str("undetectable.y = 2000;");
4855 script = Script::Compile(source);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004856 script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004857 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004858}
4859
4860
4861
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004862THREADED_TEST(UndetectableString) {
4863 v8::HandleScope scope;
4864 LocalContext env;
4865
4866 Local<String> obj = String::NewUndetectable("foo");
4867 env->Global()->Set(v8_str("undetectable"), obj);
4868
4869 ExpectString("undetectable", "foo");
4870 ExpectString("typeof undetectable", "undefined");
4871 ExpectString("typeof(undetectable)", "undefined");
4872 ExpectBoolean("typeof undetectable == 'undefined'", true);
4873 ExpectBoolean("typeof undetectable == 'string'", false);
4874 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4875 ExpectBoolean("!undetectable", true);
4876
4877 ExpectObject("true&&undetectable", obj);
4878 ExpectBoolean("false&&undetectable", false);
4879 ExpectBoolean("true||undetectable", true);
4880 ExpectObject("false||undetectable", obj);
4881
4882 ExpectObject("undetectable&&true", obj);
4883 ExpectObject("undetectable&&false", obj);
4884 ExpectBoolean("undetectable||true", true);
4885 ExpectBoolean("undetectable||false", false);
4886
4887 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004888 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004889 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004890 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004891 ExpectBoolean("undetectable==undetectable", true);
4892
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004893
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004894 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004895 ExpectBoolean("null===undetectable", false);
4896 ExpectBoolean("undetectable===undefined", false);
4897 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004898 ExpectBoolean("undetectable===undetectable", true);
4899}
4900
4901
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004902TEST(UndetectableOptimized) {
4903 i::FLAG_allow_natives_syntax = true;
4904 v8::HandleScope scope;
4905 LocalContext env;
4906
4907 Local<String> obj = String::NewUndetectable("foo");
4908 env->Global()->Set(v8_str("undetectable"), obj);
4909 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4910
4911 ExpectString(
4912 "function testBranch() {"
4913 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4914 " if (%_IsUndetectableObject(detectable)) throw 2;"
4915 "}\n"
4916 "function testBool() {"
4917 " var b1 = !%_IsUndetectableObject(undetectable);"
4918 " var b2 = %_IsUndetectableObject(detectable);"
4919 " if (b1) throw 3;"
4920 " if (b2) throw 4;"
4921 " return b1 == b2;"
4922 "}\n"
4923 "%OptimizeFunctionOnNextCall(testBranch);"
4924 "%OptimizeFunctionOnNextCall(testBool);"
4925 "for (var i = 0; i < 10; i++) {"
4926 " testBranch();"
4927 " testBool();"
4928 "}\n"
4929 "\"PASS\"",
4930 "PASS");
4931}
4932
4933
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004934template <typename T> static void USE(T) { }
4935
4936
4937// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004938static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004939 USE(PersistentHandles);
4940 Local<String> str = v8_str("foo");
4941 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4942 USE(p_str);
4943 Local<Script> scr = Script::Compile(v8_str(""));
4944 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4945 USE(p_scr);
4946 Local<ObjectTemplate> templ = ObjectTemplate::New();
4947 v8::Persistent<ObjectTemplate> p_templ =
4948 v8::Persistent<ObjectTemplate>::New(templ);
4949 USE(p_templ);
4950}
4951
4952
4953static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4954 ApiTestFuzzer::Fuzz();
4955 return v8::Undefined();
4956}
4957
4958
4959THREADED_TEST(GlobalObjectTemplate) {
4960 v8::HandleScope handle_scope;
4961 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4962 global_template->Set(v8_str("JSNI_Log"),
4963 v8::FunctionTemplate::New(HandleLogDelegator));
4964 v8::Persistent<Context> context = Context::New(0, global_template);
4965 Context::Scope context_scope(context);
4966 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4967 context.Dispose();
4968}
4969
4970
4971static const char* kSimpleExtensionSource =
4972 "function Foo() {"
4973 " return 4;"
4974 "}";
4975
4976
4977THREADED_TEST(SimpleExtensions) {
4978 v8::HandleScope handle_scope;
4979 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4980 const char* extension_names[] = { "simpletest" };
4981 v8::ExtensionConfiguration extensions(1, extension_names);
4982 v8::Handle<Context> context = Context::New(&extensions);
4983 Context::Scope lock(context);
4984 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4985 CHECK_EQ(result, v8::Integer::New(4));
4986}
4987
4988
danno@chromium.org412fa512012-09-14 13:28:26 +00004989THREADED_TEST(NullExtensions) {
4990 v8::HandleScope handle_scope;
4991 v8::RegisterExtension(new Extension("nulltest", NULL));
4992 const char* extension_names[] = { "nulltest" };
4993 v8::ExtensionConfiguration extensions(1, extension_names);
4994 v8::Handle<Context> context = Context::New(&extensions);
4995 Context::Scope lock(context);
4996 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
4997 CHECK_EQ(result, v8::Integer::New(4));
4998}
4999
5000
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005001static const char* kEmbeddedExtensionSource =
5002 "function Ret54321(){return 54321;}~~@@$"
5003 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5004static const int kEmbeddedExtensionSourceValidLen = 34;
5005
5006
5007THREADED_TEST(ExtensionMissingSourceLength) {
5008 v8::HandleScope handle_scope;
5009 v8::RegisterExtension(new Extension("srclentest_fail",
5010 kEmbeddedExtensionSource));
5011 const char* extension_names[] = { "srclentest_fail" };
5012 v8::ExtensionConfiguration extensions(1, extension_names);
5013 v8::Handle<Context> context = Context::New(&extensions);
5014 CHECK_EQ(0, *context);
5015}
5016
5017
5018THREADED_TEST(ExtensionWithSourceLength) {
5019 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5020 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5021 v8::HandleScope handle_scope;
5022 i::ScopedVector<char> extension_name(32);
5023 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5024 v8::RegisterExtension(new Extension(extension_name.start(),
5025 kEmbeddedExtensionSource, 0, 0,
5026 source_len));
5027 const char* extension_names[1] = { extension_name.start() };
5028 v8::ExtensionConfiguration extensions(1, extension_names);
5029 v8::Handle<Context> context = Context::New(&extensions);
5030 if (source_len == kEmbeddedExtensionSourceValidLen) {
5031 Context::Scope lock(context);
5032 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
5033 CHECK_EQ(v8::Integer::New(54321), result);
5034 } else {
5035 // Anything but exactly the right length should fail to compile.
5036 CHECK_EQ(0, *context);
5037 }
5038 }
5039}
5040
5041
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005042static const char* kEvalExtensionSource1 =
5043 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005044 " var x = 42;"
5045 " return eval('x');"
5046 "}";
5047
5048
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005049static const char* kEvalExtensionSource2 =
5050 "(function() {"
5051 " var x = 42;"
5052 " function e() {"
5053 " return eval('x');"
5054 " }"
5055 " this.UseEval2 = e;"
5056 "})()";
5057
5058
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005059THREADED_TEST(UseEvalFromExtension) {
5060 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005061 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
5062 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
5063 const char* extension_names[] = { "evaltest1", "evaltest2" };
5064 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005065 v8::Handle<Context> context = Context::New(&extensions);
5066 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005067 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
5068 CHECK_EQ(result, v8::Integer::New(42));
5069 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005070 CHECK_EQ(result, v8::Integer::New(42));
5071}
5072
5073
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005074static const char* kWithExtensionSource1 =
5075 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005076 " var x = 42;"
5077 " with({x:87}) { return x; }"
5078 "}";
5079
5080
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005081
5082static const char* kWithExtensionSource2 =
5083 "(function() {"
5084 " var x = 42;"
5085 " function e() {"
5086 " with ({x:87}) { return x; }"
5087 " }"
5088 " this.UseWith2 = e;"
5089 "})()";
5090
5091
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005092THREADED_TEST(UseWithFromExtension) {
5093 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005094 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
5095 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
5096 const char* extension_names[] = { "withtest1", "withtest2" };
5097 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005098 v8::Handle<Context> context = Context::New(&extensions);
5099 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005100 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
5101 CHECK_EQ(result, v8::Integer::New(87));
5102 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005103 CHECK_EQ(result, v8::Integer::New(87));
5104}
5105
5106
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005107THREADED_TEST(AutoExtensions) {
5108 v8::HandleScope handle_scope;
5109 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5110 extension->set_auto_enable(true);
5111 v8::RegisterExtension(extension);
5112 v8::Handle<Context> context = Context::New();
5113 Context::Scope lock(context);
5114 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5115 CHECK_EQ(result, v8::Integer::New(4));
5116}
5117
5118
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005119static const char* kSyntaxErrorInExtensionSource =
5120 "[";
5121
5122
5123// Test that a syntax error in an extension does not cause a fatal
5124// error but results in an empty context.
5125THREADED_TEST(SyntaxErrorExtensions) {
5126 v8::HandleScope handle_scope;
5127 v8::RegisterExtension(new Extension("syntaxerror",
5128 kSyntaxErrorInExtensionSource));
5129 const char* extension_names[] = { "syntaxerror" };
5130 v8::ExtensionConfiguration extensions(1, extension_names);
5131 v8::Handle<Context> context = Context::New(&extensions);
5132 CHECK(context.IsEmpty());
5133}
5134
5135
5136static const char* kExceptionInExtensionSource =
5137 "throw 42";
5138
5139
5140// Test that an exception when installing an extension does not cause
5141// a fatal error but results in an empty context.
5142THREADED_TEST(ExceptionExtensions) {
5143 v8::HandleScope handle_scope;
5144 v8::RegisterExtension(new Extension("exception",
5145 kExceptionInExtensionSource));
5146 const char* extension_names[] = { "exception" };
5147 v8::ExtensionConfiguration extensions(1, extension_names);
5148 v8::Handle<Context> context = Context::New(&extensions);
5149 CHECK(context.IsEmpty());
5150}
5151
5152
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005153static const char* kNativeCallInExtensionSource =
5154 "function call_runtime_last_index_of(x) {"
5155 " return %StringLastIndexOf(x, 'bob', 10);"
5156 "}";
5157
5158
5159static const char* kNativeCallTest =
5160 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
5161
5162// Test that a native runtime calls are supported in extensions.
5163THREADED_TEST(NativeCallInExtensions) {
5164 v8::HandleScope handle_scope;
5165 v8::RegisterExtension(new Extension("nativecall",
5166 kNativeCallInExtensionSource));
5167 const char* extension_names[] = { "nativecall" };
5168 v8::ExtensionConfiguration extensions(1, extension_names);
5169 v8::Handle<Context> context = Context::New(&extensions);
5170 Context::Scope lock(context);
5171 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
5172 CHECK_EQ(result, v8::Integer::New(3));
5173}
5174
5175
whesse@chromium.org7b260152011-06-20 15:33:18 +00005176class NativeFunctionExtension : public Extension {
5177 public:
5178 NativeFunctionExtension(const char* name,
5179 const char* source,
5180 v8::InvocationCallback fun = &Echo)
5181 : Extension(name, source),
5182 function_(fun) { }
5183
5184 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5185 v8::Handle<v8::String> name) {
5186 return v8::FunctionTemplate::New(function_);
5187 }
5188
5189 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
5190 if (args.Length() >= 1) return (args[0]);
5191 return v8::Undefined();
5192 }
5193 private:
5194 v8::InvocationCallback function_;
5195};
5196
5197
5198THREADED_TEST(NativeFunctionDeclaration) {
5199 v8::HandleScope handle_scope;
5200 const char* name = "nativedecl";
5201 v8::RegisterExtension(new NativeFunctionExtension(name,
5202 "native function foo();"));
5203 const char* extension_names[] = { name };
5204 v8::ExtensionConfiguration extensions(1, extension_names);
5205 v8::Handle<Context> context = Context::New(&extensions);
5206 Context::Scope lock(context);
5207 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
5208 CHECK_EQ(result, v8::Integer::New(42));
5209}
5210
5211
5212THREADED_TEST(NativeFunctionDeclarationError) {
5213 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005214 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005215 // Syntax error in extension code.
5216 v8::RegisterExtension(new NativeFunctionExtension(name,
5217 "native\nfunction foo();"));
5218 const char* extension_names[] = { name };
5219 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005220 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005221 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005222}
5223
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005224
whesse@chromium.org7b260152011-06-20 15:33:18 +00005225THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5226 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005227 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005228 // Syntax error in extension code - escape code in "native" means that
5229 // it's not treated as a keyword.
5230 v8::RegisterExtension(new NativeFunctionExtension(
5231 name,
5232 "nativ\\u0065 function foo();"));
5233 const char* extension_names[] = { name };
5234 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005235 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005236 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005237}
5238
5239
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005240static void CheckDependencies(const char* name, const char* expected) {
5241 v8::HandleScope handle_scope;
5242 v8::ExtensionConfiguration config(1, &name);
5243 LocalContext context(&config);
5244 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5245}
5246
5247
5248/*
5249 * Configuration:
5250 *
5251 * /-- B <--\
5252 * A <- -- D <-- E
5253 * \-- C <--/
5254 */
5255THREADED_TEST(ExtensionDependency) {
5256 static const char* kEDeps[] = { "D" };
5257 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5258 static const char* kDDeps[] = { "B", "C" };
5259 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5260 static const char* kBCDeps[] = { "A" };
5261 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5262 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5263 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5264 CheckDependencies("A", "undefinedA");
5265 CheckDependencies("B", "undefinedAB");
5266 CheckDependencies("C", "undefinedAC");
5267 CheckDependencies("D", "undefinedABCD");
5268 CheckDependencies("E", "undefinedABCDE");
5269 v8::HandleScope handle_scope;
5270 static const char* exts[2] = { "C", "E" };
5271 v8::ExtensionConfiguration config(2, exts);
5272 LocalContext context(&config);
5273 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5274}
5275
5276
5277static const char* kExtensionTestScript =
5278 "native function A();"
5279 "native function B();"
5280 "native function C();"
5281 "function Foo(i) {"
5282 " if (i == 0) return A();"
5283 " if (i == 1) return B();"
5284 " if (i == 2) return C();"
5285 "}";
5286
5287
5288static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5289 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005290 if (args.IsConstructCall()) {
5291 args.This()->Set(v8_str("data"), args.Data());
5292 return v8::Null();
5293 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005294 return args.Data();
5295}
5296
5297
5298class FunctionExtension : public Extension {
5299 public:
5300 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5301 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5302 v8::Handle<String> name);
5303};
5304
5305
5306static int lookup_count = 0;
5307v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5308 v8::Handle<String> name) {
5309 lookup_count++;
5310 if (name->Equals(v8_str("A"))) {
5311 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5312 } else if (name->Equals(v8_str("B"))) {
5313 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5314 } else if (name->Equals(v8_str("C"))) {
5315 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5316 } else {
5317 return v8::Handle<v8::FunctionTemplate>();
5318 }
5319}
5320
5321
5322THREADED_TEST(FunctionLookup) {
5323 v8::RegisterExtension(new FunctionExtension());
5324 v8::HandleScope handle_scope;
5325 static const char* exts[1] = { "functiontest" };
5326 v8::ExtensionConfiguration config(1, exts);
5327 LocalContext context(&config);
5328 CHECK_EQ(3, lookup_count);
5329 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5330 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5331 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5332}
5333
5334
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005335THREADED_TEST(NativeFunctionConstructCall) {
5336 v8::RegisterExtension(new FunctionExtension());
5337 v8::HandleScope handle_scope;
5338 static const char* exts[1] = { "functiontest" };
5339 v8::ExtensionConfiguration config(1, exts);
5340 LocalContext context(&config);
5341 for (int i = 0; i < 10; i++) {
5342 // Run a few times to ensure that allocation of objects doesn't
5343 // change behavior of a constructor function.
5344 CHECK_EQ(v8::Integer::New(8),
5345 Script::Compile(v8_str("(new A()).data"))->Run());
5346 CHECK_EQ(v8::Integer::New(7),
5347 Script::Compile(v8_str("(new B()).data"))->Run());
5348 CHECK_EQ(v8::Integer::New(6),
5349 Script::Compile(v8_str("(new C()).data"))->Run());
5350 }
5351}
5352
5353
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005354static const char* last_location;
5355static const char* last_message;
5356void StoringErrorCallback(const char* location, const char* message) {
5357 if (last_location == NULL) {
5358 last_location = location;
5359 last_message = message;
5360 }
5361}
5362
5363
5364// ErrorReporting creates a circular extensions configuration and
5365// tests that the fatal error handler gets called. This renders V8
5366// unusable and therefore this test cannot be run in parallel.
5367TEST(ErrorReporting) {
5368 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5369 static const char* aDeps[] = { "B" };
5370 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5371 static const char* bDeps[] = { "A" };
5372 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5373 last_location = NULL;
5374 v8::ExtensionConfiguration config(1, bDeps);
5375 v8::Handle<Context> context = Context::New(&config);
5376 CHECK(context.IsEmpty());
5377 CHECK_NE(last_location, NULL);
5378}
5379
5380
ager@chromium.org7c537e22008-10-16 08:43:32 +00005381static const char* js_code_causing_huge_string_flattening =
5382 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00005383 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00005384 " str = str + str;"
5385 "}"
5386 "str.match(/X/);";
5387
5388
5389void OOMCallback(const char* location, const char* message) {
5390 exit(0);
5391}
5392
5393
5394TEST(RegexpOutOfMemory) {
5395 // Execute a script that causes out of memory when flattening a string.
5396 v8::HandleScope scope;
5397 v8::V8::SetFatalErrorHandler(OOMCallback);
5398 LocalContext context;
5399 Local<Script> script =
5400 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5401 last_location = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005402 script->Run();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005403
5404 CHECK(false); // Should not return.
5405}
5406
5407
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005408static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5409 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005410 CHECK(message->GetScriptResourceName()->IsUndefined());
5411 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005412 message->GetLineNumber();
5413 message->GetSourceLine();
5414}
5415
5416
5417THREADED_TEST(ErrorWithMissingScriptInfo) {
5418 v8::HandleScope scope;
5419 LocalContext context;
5420 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5421 Script::Compile(v8_str("throw Error()"))->Run();
5422 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5423}
5424
5425
5426int global_index = 0;
5427
5428class Snorkel {
5429 public:
5430 Snorkel() { index_ = global_index++; }
5431 int index_;
5432};
5433
5434class Whammy {
5435 public:
5436 Whammy() {
5437 cursor_ = 0;
5438 }
5439 ~Whammy() {
5440 script_.Dispose();
5441 }
5442 v8::Handle<Script> getScript() {
5443 if (script_.IsEmpty())
5444 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5445 return Local<Script>(*script_);
5446 }
5447
5448 public:
5449 static const int kObjectCount = 256;
5450 int cursor_;
5451 v8::Persistent<v8::Object> objects_[kObjectCount];
5452 v8::Persistent<Script> script_;
5453};
5454
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005455static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005456 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5457 delete snorkel;
5458 obj.ClearWeak();
5459}
5460
5461v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5462 const AccessorInfo& info) {
5463 Whammy* whammy =
5464 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5465
5466 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5467
5468 v8::Handle<v8::Object> obj = v8::Object::New();
5469 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5470 if (!prev.IsEmpty()) {
5471 prev->Set(v8_str("next"), obj);
5472 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5473 whammy->objects_[whammy->cursor_].Clear();
5474 }
5475 whammy->objects_[whammy->cursor_] = global;
5476 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5477 return whammy->getScript()->Run();
5478}
5479
5480THREADED_TEST(WeakReference) {
5481 v8::HandleScope handle_scope;
5482 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005483 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005484 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5485 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005486 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005487 const char* extension_list[] = { "v8/gc" };
5488 v8::ExtensionConfiguration extensions(1, extension_list);
5489 v8::Persistent<Context> context = Context::New(&extensions);
5490 Context::Scope context_scope(context);
5491
5492 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5493 context->Global()->Set(v8_str("whammy"), interceptor);
5494 const char* code =
5495 "var last;"
5496 "for (var i = 0; i < 10000; i++) {"
5497 " var obj = whammy.length;"
5498 " if (last) last.next = obj;"
5499 " last = obj;"
5500 "}"
5501 "gc();"
5502 "4";
5503 v8::Handle<Value> result = CompileRun(code);
5504 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005505 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005506 context.Dispose();
5507}
5508
5509
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005510static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005511 obj.Dispose();
5512 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005513 *(reinterpret_cast<bool*>(data)) = true;
5514}
5515
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005516
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005517THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005518 v8::Persistent<Context> context = Context::New();
5519 Context::Scope context_scope(context);
5520
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005521 v8::Persistent<v8::Object> object_a, object_b;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005522
5523 {
5524 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005525 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005526 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005527 }
5528
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005529 v8::Isolate* isolate = v8::Isolate::GetCurrent();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005530 bool object_a_disposed = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005531 bool object_b_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005532 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005533 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005534 CHECK(!object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005535 CHECK(!object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005536 object_a.MarkIndependent();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005537 object_b.MarkIndependent(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005538 CHECK(object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005539 CHECK(object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005540 HEAP->PerformScavenge();
5541 CHECK(object_a_disposed);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005542 CHECK(object_b_disposed);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005543}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005544
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005545
5546static void InvokeScavenge() {
5547 HEAP->PerformScavenge();
5548}
5549
5550
5551static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005552 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005553}
5554
5555
5556static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5557 obj.Dispose();
5558 obj.Clear();
5559 *(reinterpret_cast<bool*>(data)) = true;
5560 InvokeScavenge();
5561}
5562
5563
5564static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5565 obj.Dispose();
5566 obj.Clear();
5567 *(reinterpret_cast<bool*>(data)) = true;
5568 InvokeMarkSweep();
5569}
5570
5571
5572THREADED_TEST(GCFromWeakCallbacks) {
5573 v8::Persistent<Context> context = Context::New();
5574 Context::Scope context_scope(context);
5575
5576 static const int kNumberOfGCTypes = 2;
5577 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5578 {&ForceScavenge, &ForceMarkSweep};
5579
5580 typedef void (*GCInvoker)();
5581 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5582
5583 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5584 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5585 v8::Persistent<v8::Object> object;
5586 {
5587 v8::HandleScope handle_scope;
5588 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5589 }
5590 bool disposed = false;
5591 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5592 object.MarkIndependent();
5593 invoke_gc[outer_gc]();
5594 CHECK(disposed);
5595 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005596 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005597}
5598
5599
5600static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5601 obj.ClearWeak();
5602 *(reinterpret_cast<bool*>(data)) = true;
5603}
5604
5605
5606THREADED_TEST(IndependentHandleRevival) {
5607 v8::Persistent<Context> context = Context::New();
5608 Context::Scope context_scope(context);
5609
5610 v8::Persistent<v8::Object> object;
5611 {
5612 v8::HandleScope handle_scope;
5613 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5614 object->Set(v8_str("x"), v8::Integer::New(1));
5615 v8::Local<String> y_str = v8_str("y");
5616 object->Set(y_str, y_str);
5617 }
5618 bool revived = false;
5619 object.MakeWeak(&revived, &RevivingCallback);
5620 object.MarkIndependent();
5621 HEAP->PerformScavenge();
5622 CHECK(revived);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00005623 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005624 {
5625 v8::HandleScope handle_scope;
5626 v8::Local<String> y_str = v8_str("y");
5627 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5628 CHECK(object->Get(y_str)->Equals(y_str));
5629 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005630}
5631
5632
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005633v8::Handle<Function> args_fun;
5634
5635
5636static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5637 ApiTestFuzzer::Fuzz();
5638 CHECK_EQ(args_fun, args.Callee());
5639 CHECK_EQ(3, args.Length());
5640 CHECK_EQ(v8::Integer::New(1), args[0]);
5641 CHECK_EQ(v8::Integer::New(2), args[1]);
5642 CHECK_EQ(v8::Integer::New(3), args[2]);
5643 CHECK_EQ(v8::Undefined(), args[3]);
5644 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005645 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005646 return v8::Undefined();
5647}
5648
5649
5650THREADED_TEST(Arguments) {
5651 v8::HandleScope scope;
5652 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5653 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5654 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005655 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005656 v8_compile("f(1, 2, 3)")->Run();
5657}
5658
5659
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005660static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5661 const AccessorInfo&) {
5662 return v8::Handle<Value>();
5663}
5664
5665
5666static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5667 const AccessorInfo&) {
5668 return v8::Handle<Value>();
5669}
5670
5671
5672static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5673 const AccessorInfo&) {
5674 if (!name->Equals(v8_str("foo"))) {
5675 return v8::Handle<v8::Boolean>(); // not intercepted
5676 }
5677
5678 return v8::False(); // intercepted, and don't delete the property
5679}
5680
5681
5682static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5683 if (index != 2) {
5684 return v8::Handle<v8::Boolean>(); // not intercepted
5685 }
5686
5687 return v8::False(); // intercepted, and don't delete the property
5688}
5689
5690
5691THREADED_TEST(Deleter) {
5692 v8::HandleScope scope;
5693 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5694 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5695 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5696 LocalContext context;
5697 context->Global()->Set(v8_str("k"), obj->NewInstance());
5698 CompileRun(
5699 "k.foo = 'foo';"
5700 "k.bar = 'bar';"
5701 "k[2] = 2;"
5702 "k[4] = 4;");
5703 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5704 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5705
5706 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5707 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5708
5709 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5710 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5711
5712 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5713 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5714}
5715
5716
5717static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5718 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005719 if (name->Equals(v8_str("foo")) ||
5720 name->Equals(v8_str("bar")) ||
5721 name->Equals(v8_str("baz"))) {
5722 return v8::Undefined();
5723 }
5724 return v8::Handle<Value>();
5725}
5726
5727
5728static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5729 ApiTestFuzzer::Fuzz();
5730 if (index == 0 || index == 1) return v8::Undefined();
5731 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005732}
5733
5734
5735static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5736 ApiTestFuzzer::Fuzz();
5737 v8::Handle<v8::Array> result = v8::Array::New(3);
5738 result->Set(v8::Integer::New(0), v8_str("foo"));
5739 result->Set(v8::Integer::New(1), v8_str("bar"));
5740 result->Set(v8::Integer::New(2), v8_str("baz"));
5741 return result;
5742}
5743
5744
5745static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5746 ApiTestFuzzer::Fuzz();
5747 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005748 result->Set(v8::Integer::New(0), v8_str("0"));
5749 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005750 return result;
5751}
5752
5753
5754THREADED_TEST(Enumerators) {
5755 v8::HandleScope scope;
5756 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5757 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005758 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005759 LocalContext context;
5760 context->Global()->Set(v8_str("k"), obj->NewInstance());
5761 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005762 "k[10] = 0;"
5763 "k.a = 0;"
5764 "k[5] = 0;"
5765 "k.b = 0;"
5766 "k[4294967295] = 0;"
5767 "k.c = 0;"
5768 "k[4294967296] = 0;"
5769 "k.d = 0;"
5770 "k[140000] = 0;"
5771 "k.e = 0;"
5772 "k[30000000000] = 0;"
5773 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005774 "var result = [];"
5775 "for (var prop in k) {"
5776 " result.push(prop);"
5777 "}"
5778 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005779 // Check that we get all the property names returned including the
5780 // ones from the enumerators in the right order: indexed properties
5781 // in numerical order, indexed interceptor properties, named
5782 // properties in insertion order, named interceptor properties.
5783 // This order is not mandated by the spec, so this test is just
5784 // documenting our behavior.
5785 CHECK_EQ(17, result->Length());
5786 // Indexed properties in numerical order.
5787 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5788 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5789 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5790 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5791 // Indexed interceptor properties in the order they are returned
5792 // from the enumerator interceptor.
5793 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5794 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5795 // Named properties in insertion order.
5796 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5797 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5798 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5799 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5800 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5801 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5802 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5803 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5804 // Named interceptor properties.
5805 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5806 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5807 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005808}
5809
5810
5811int p_getter_count;
5812int p_getter_count2;
5813
5814
5815static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5816 ApiTestFuzzer::Fuzz();
5817 p_getter_count++;
5818 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5819 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5820 if (name->Equals(v8_str("p1"))) {
5821 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5822 } else if (name->Equals(v8_str("p2"))) {
5823 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5824 } else if (name->Equals(v8_str("p3"))) {
5825 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5826 } else if (name->Equals(v8_str("p4"))) {
5827 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5828 }
5829 return v8::Undefined();
5830}
5831
5832
5833static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5834 ApiTestFuzzer::Fuzz();
5835 LocalContext context;
5836 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5837 CompileRun(
5838 "o1.__proto__ = { };"
5839 "var o2 = { __proto__: o1 };"
5840 "var o3 = { __proto__: o2 };"
5841 "var o4 = { __proto__: o3 };"
5842 "for (var i = 0; i < 10; i++) o4.p4;"
5843 "for (var i = 0; i < 10; i++) o3.p3;"
5844 "for (var i = 0; i < 10; i++) o2.p2;"
5845 "for (var i = 0; i < 10; i++) o1.p1;");
5846}
5847
5848
5849static v8::Handle<Value> PGetter2(Local<String> name,
5850 const AccessorInfo& info) {
5851 ApiTestFuzzer::Fuzz();
5852 p_getter_count2++;
5853 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5854 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5855 if (name->Equals(v8_str("p1"))) {
5856 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5857 } else if (name->Equals(v8_str("p2"))) {
5858 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5859 } else if (name->Equals(v8_str("p3"))) {
5860 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5861 } else if (name->Equals(v8_str("p4"))) {
5862 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5863 }
5864 return v8::Undefined();
5865}
5866
5867
5868THREADED_TEST(GetterHolders) {
5869 v8::HandleScope scope;
5870 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5871 obj->SetAccessor(v8_str("p1"), PGetter);
5872 obj->SetAccessor(v8_str("p2"), PGetter);
5873 obj->SetAccessor(v8_str("p3"), PGetter);
5874 obj->SetAccessor(v8_str("p4"), PGetter);
5875 p_getter_count = 0;
5876 RunHolderTest(obj);
5877 CHECK_EQ(40, p_getter_count);
5878}
5879
5880
5881THREADED_TEST(PreInterceptorHolders) {
5882 v8::HandleScope scope;
5883 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5884 obj->SetNamedPropertyHandler(PGetter2);
5885 p_getter_count2 = 0;
5886 RunHolderTest(obj);
5887 CHECK_EQ(40, p_getter_count2);
5888}
5889
5890
5891THREADED_TEST(ObjectInstantiation) {
5892 v8::HandleScope scope;
5893 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5894 templ->SetAccessor(v8_str("t"), PGetter2);
5895 LocalContext context;
5896 context->Global()->Set(v8_str("o"), templ->NewInstance());
5897 for (int i = 0; i < 100; i++) {
5898 v8::HandleScope inner_scope;
5899 v8::Handle<v8::Object> obj = templ->NewInstance();
5900 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5901 context->Global()->Set(v8_str("o2"), obj);
5902 v8::Handle<Value> value =
5903 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5904 CHECK_EQ(v8::True(), value);
5905 context->Global()->Set(v8_str("o"), obj);
5906 }
5907}
5908
5909
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005910static int StrCmp16(uint16_t* a, uint16_t* b) {
5911 while (true) {
5912 if (*a == 0 && *b == 0) return 0;
5913 if (*a != *b) return 0 + *a - *b;
5914 a++;
5915 b++;
5916 }
5917}
5918
5919
5920static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5921 while (true) {
5922 if (n-- == 0) return 0;
5923 if (*a == 0 && *b == 0) return 0;
5924 if (*a != *b) return 0 + *a - *b;
5925 a++;
5926 b++;
5927 }
5928}
5929
5930
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005931int GetUtf8Length(Handle<String> str) {
5932 int len = str->Utf8Length();
5933 if (len < 0) {
5934 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5935 i::FlattenString(istr);
5936 len = str->Utf8Length();
5937 }
5938 return len;
5939}
5940
5941
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005942THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005943 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005944 v8::HandleScope scope;
5945 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005946 // abc<Icelandic eth><Unicode snowman>.
5947 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005948 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005949 const int kStride = 4; // Must match stride in for loops in JS below.
5950 CompileRun(
5951 "var left = '';"
5952 "for (var i = 0; i < 0xd800; i += 4) {"
5953 " left = left + String.fromCharCode(i);"
5954 "}");
5955 CompileRun(
5956 "var right = '';"
5957 "for (var i = 0; i < 0xd800; i += 4) {"
5958 " right = String.fromCharCode(i) + right;"
5959 "}");
5960 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5961 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5962 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005963
5964 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005965 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5966 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005967
5968 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005969 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005970 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005971 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005972 int charlen;
5973
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005974 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005975 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005976 CHECK_EQ(9, len);
5977 CHECK_EQ(5, charlen);
5978 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005979
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005980 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005981 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005982 CHECK_EQ(8, len);
5983 CHECK_EQ(5, charlen);
5984 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005985
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005986 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005987 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005988 CHECK_EQ(5, len);
5989 CHECK_EQ(4, charlen);
5990 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005991
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005992 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005993 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005994 CHECK_EQ(5, len);
5995 CHECK_EQ(4, charlen);
5996 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005997
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005998 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005999 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006000 CHECK_EQ(5, len);
6001 CHECK_EQ(4, charlen);
6002 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006003
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006004 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006005 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006006 CHECK_EQ(3, len);
6007 CHECK_EQ(3, charlen);
6008 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006010 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006011 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006012 CHECK_EQ(3, len);
6013 CHECK_EQ(3, charlen);
6014 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006015
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006016 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006017 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006018 CHECK_EQ(2, len);
6019 CHECK_EQ(2, charlen);
6020 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006021
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006022 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006023 len = GetUtf8Length(left_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006024 int utf8_expected =
6025 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
6026 CHECK_EQ(utf8_expected, len);
6027 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6028 CHECK_EQ(utf8_expected, len);
6029 CHECK_EQ(0xd800 / kStride, charlen);
6030 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
6031 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
6032 CHECK_EQ(0xc0 - kStride,
6033 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
6034 CHECK_EQ(1, utf8buf[utf8_expected]);
6035
6036 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006037 len = GetUtf8Length(right_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006038 CHECK_EQ(utf8_expected, len);
6039 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6040 CHECK_EQ(utf8_expected, len);
6041 CHECK_EQ(0xd800 / kStride, charlen);
6042 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
6043 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
6044 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
6045 CHECK_EQ(1, utf8buf[utf8_expected]);
6046
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006047 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006048 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006049 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006050 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006051 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006052 CHECK_EQ(5, len);
6053 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006054 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006055 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006056
6057 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006058 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006059 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006060 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006061 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006062 CHECK_EQ(4, len);
6063 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006064 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006065 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006066
6067 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006068 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006069 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006070 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006071 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006072 CHECK_EQ(5, len);
6073 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006074 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006075 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006076
6077 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006078 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006079 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006080 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006081 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006082 CHECK_EQ(5, len);
6083 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006084 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006085 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006086
6087 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006088 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006089 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006090 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006091 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006092 CHECK_EQ(1, len);
6093 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006094 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006095 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006096
6097 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006098 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006099 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006100 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006101 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006102 CHECK_EQ(1, len);
6103 CHECK_EQ(0, strcmp("e", buf));
6104 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006105
6106 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006107 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006108 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006109 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006110 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006111 CHECK_EQ(1, len);
6112 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006113 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006114 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006115
6116 memset(buf, 0x1, sizeof(buf));
6117 memset(wbuf, 0x1, sizeof(wbuf));
6118 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006119 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006120 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006121 CHECK_EQ(1, len);
6122 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006123 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006124 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006125
6126 memset(wbuf, 0x1, sizeof(wbuf));
6127 wbuf[5] = 'X';
6128 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
6129 CHECK_EQ(5, len);
6130 CHECK_EQ('X', wbuf[5]);
6131 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
6132 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6133 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
6134 CHECK_NE(0, StrCmp16(answer8b, wbuf));
6135 wbuf[5] = '\0';
6136 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
6137
6138 memset(buf, 0x1, sizeof(buf));
6139 buf[5] = 'X';
6140 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
6141 CHECK_EQ(5, len);
6142 CHECK_EQ('X', buf[5]);
6143 CHECK_EQ(0, strncmp("abcde", buf, 5));
6144 CHECK_NE(0, strcmp("abcde", buf));
6145 buf[5] = '\0';
6146 CHECK_EQ(0, strcmp("abcde", buf));
6147
6148 memset(utf8buf, 0x1, sizeof(utf8buf));
6149 utf8buf[8] = 'X';
6150 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6151 String::NO_NULL_TERMINATION);
6152 CHECK_EQ(8, len);
6153 CHECK_EQ('X', utf8buf[8]);
6154 CHECK_EQ(5, charlen);
6155 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
6156 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6157 utf8buf[8] = '\0';
6158 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006159
6160 memset(utf8buf, 0x1, sizeof(utf8buf));
6161 utf8buf[5] = 'X';
6162 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6163 String::NO_NULL_TERMINATION);
6164 CHECK_EQ(5, len);
6165 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
6166 CHECK_EQ(5, charlen);
6167 utf8buf[5] = '\0';
6168 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
6169
6170 memset(buf, 0x1, sizeof(buf));
6171 len = str3->WriteAscii(buf);
6172 CHECK_EQ(7, len);
6173 CHECK_EQ(0, strcmp("abc def", buf));
6174
6175 memset(buf, 0x1, sizeof(buf));
6176 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
6177 CHECK_EQ(7, len);
6178 CHECK_EQ(0, strcmp("abc", buf));
6179 CHECK_EQ(0, buf[3]);
6180 CHECK_EQ(0, strcmp("def", buf + 4));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006181}
6182
6183
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006184static void Utf16Helper(
6185 LocalContext& context,
6186 const char* name,
6187 const char* lengths_name,
6188 int len) {
6189 Local<v8::Array> a =
6190 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6191 Local<v8::Array> alens =
6192 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6193 for (int i = 0; i < len; i++) {
6194 Local<v8::String> string =
6195 Local<v8::String>::Cast(a->Get(i));
6196 Local<v8::Number> expected_len =
6197 Local<v8::Number>::Cast(alens->Get(i));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006198 CHECK_EQ(expected_len->Value() != string->Length(),
6199 string->MayContainNonAscii());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006200 int length = GetUtf8Length(string);
6201 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
6202 }
6203}
6204
6205
6206static uint16_t StringGet(Handle<String> str, int index) {
6207 i::Handle<i::String> istring =
6208 v8::Utils::OpenHandle(String::Cast(*str));
6209 return istring->Get(index);
6210}
6211
6212
6213static void WriteUtf8Helper(
6214 LocalContext& context,
6215 const char* name,
6216 const char* lengths_name,
6217 int len) {
6218 Local<v8::Array> b =
6219 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6220 Local<v8::Array> alens =
6221 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6222 char buffer[1000];
6223 char buffer2[1000];
6224 for (int i = 0; i < len; i++) {
6225 Local<v8::String> string =
6226 Local<v8::String>::Cast(b->Get(i));
6227 Local<v8::Number> expected_len =
6228 Local<v8::Number>::Cast(alens->Get(i));
6229 int utf8_length = static_cast<int>(expected_len->Value());
6230 for (int j = utf8_length + 1; j >= 0; j--) {
6231 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6232 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6233 int nchars;
6234 int utf8_written =
6235 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6236 int utf8_written2 =
6237 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6238 CHECK_GE(utf8_length + 1, utf8_written);
6239 CHECK_GE(utf8_length, utf8_written2);
6240 for (int k = 0; k < utf8_written2; k++) {
6241 CHECK_EQ(buffer[k], buffer2[k]);
6242 }
6243 CHECK(nchars * 3 >= utf8_written - 1);
6244 CHECK(nchars <= utf8_written);
6245 if (j == utf8_length + 1) {
6246 CHECK_EQ(utf8_written2, utf8_length);
6247 CHECK_EQ(utf8_written2 + 1, utf8_written);
6248 }
6249 CHECK_EQ(buffer[utf8_written], 42);
6250 if (j > utf8_length) {
6251 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6252 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6253 Handle<String> roundtrip = v8_str(buffer);
6254 CHECK(roundtrip->Equals(string));
6255 } else {
6256 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6257 }
6258 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6259 if (nchars >= 2) {
6260 uint16_t trail = StringGet(string, nchars - 1);
6261 uint16_t lead = StringGet(string, nchars - 2);
6262 if (((lead & 0xfc00) == 0xd800) &&
6263 ((trail & 0xfc00) == 0xdc00)) {
6264 unsigned char u1 = buffer2[utf8_written2 - 4];
6265 unsigned char u2 = buffer2[utf8_written2 - 3];
6266 unsigned char u3 = buffer2[utf8_written2 - 2];
6267 unsigned char u4 = buffer2[utf8_written2 - 1];
6268 CHECK_EQ((u1 & 0xf8), 0xf0);
6269 CHECK_EQ((u2 & 0xc0), 0x80);
6270 CHECK_EQ((u3 & 0xc0), 0x80);
6271 CHECK_EQ((u4 & 0xc0), 0x80);
6272 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6273 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6274 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6275 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6276 CHECK_EQ((u1 & 0x3), c >> 18);
6277 }
6278 }
6279 }
6280 }
6281}
6282
6283
6284THREADED_TEST(Utf16) {
6285 LocalContext context;
6286 v8::HandleScope scope;
6287 CompileRun(
6288 "var pad = '01234567890123456789';"
6289 "var p = [];"
6290 "var plens = [20, 3, 3];"
6291 "p.push('01234567890123456789');"
6292 "var lead = 0xd800;"
6293 "var trail = 0xdc00;"
6294 "p.push(String.fromCharCode(0xd800));"
6295 "p.push(String.fromCharCode(0xdc00));"
6296 "var a = [];"
6297 "var b = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006298 "var c = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006299 "var alens = [];"
6300 "for (var i = 0; i < 3; i++) {"
6301 " p[1] = String.fromCharCode(lead++);"
6302 " for (var j = 0; j < 3; j++) {"
6303 " p[2] = String.fromCharCode(trail++);"
6304 " a.push(p[i] + p[j]);"
6305 " b.push(p[i] + p[j]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006306 " c.push(p[i] + p[j]);"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006307 " alens.push(plens[i] + plens[j]);"
6308 " }"
6309 "}"
6310 "alens[5] -= 2;" // Here the surrogate pairs match up.
6311 "var a2 = [];"
6312 "var b2 = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006313 "var c2 = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006314 "var a2lens = [];"
6315 "for (var m = 0; m < 9; m++) {"
6316 " for (var n = 0; n < 9; n++) {"
6317 " a2.push(a[m] + a[n]);"
6318 " b2.push(b[m] + b[n]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006319 " var newc = 'x' + c[m] + c[n] + 'y';"
6320 " c2.push(newc.substring(1, newc.length - 1));"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006321 " var utf = alens[m] + alens[n];" // And here.
6322 // The 'n's that start with 0xdc.. are 6-8
6323 // The 'm's that end with 0xd8.. are 1, 4 and 7
6324 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6325 " a2lens.push(utf);"
6326 " }"
6327 "}");
6328 Utf16Helper(context, "a", "alens", 9);
6329 Utf16Helper(context, "a2", "a2lens", 81);
6330 WriteUtf8Helper(context, "b", "alens", 9);
6331 WriteUtf8Helper(context, "b2", "a2lens", 81);
danno@chromium.org88aa0582012-03-23 15:11:57 +00006332 WriteUtf8Helper(context, "c2", "a2lens", 81);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006333}
6334
6335
6336static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6337 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6338 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6339 return *is1 == *is2;
6340}
6341
6342
6343static void SameSymbolHelper(const char* a, const char* b) {
6344 Handle<String> symbol1 = v8::String::NewSymbol(a);
6345 Handle<String> symbol2 = v8::String::NewSymbol(b);
6346 CHECK(SameSymbol(symbol1, symbol2));
6347}
6348
6349
6350THREADED_TEST(Utf16Symbol) {
6351 LocalContext context;
6352 v8::HandleScope scope;
6353
6354 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6355 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6356 CHECK(SameSymbol(symbol1, symbol2));
6357
6358 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6359 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6360 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6361 "\360\220\220\206"); // 4 byte encoding.
6362 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6363 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6364 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6365 "x\360\220\220\206"); // 4 byte encoding.
6366 CompileRun(
6367 "var sym0 = 'benedictus';"
6368 "var sym0b = 'S\303\270ren';"
6369 "var sym1 = '\355\240\201\355\260\207';"
6370 "var sym2 = '\360\220\220\210';"
6371 "var sym3 = 'x\355\240\201\355\260\207';"
6372 "var sym4 = 'x\360\220\220\210';"
6373 "if (sym1.length != 2) throw sym1;"
6374 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6375 "if (sym2.length != 2) throw sym2;"
6376 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6377 "if (sym3.length != 3) throw sym3;"
6378 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6379 "if (sym4.length != 3) throw sym4;"
6380 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6381 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6382 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6383 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6384 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6385 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6386 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6387 v8::Local<v8::Object> global = context->Global();
6388 Local<Value> s0 = global->Get(v8_str("sym0"));
6389 Local<Value> s0b = global->Get(v8_str("sym0b"));
6390 Local<Value> s1 = global->Get(v8_str("sym1"));
6391 Local<Value> s2 = global->Get(v8_str("sym2"));
6392 Local<Value> s3 = global->Get(v8_str("sym3"));
6393 Local<Value> s4 = global->Get(v8_str("sym4"));
6394 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6395 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6396 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6397 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6398 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6399 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6400}
6401
6402
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006403THREADED_TEST(ToArrayIndex) {
6404 v8::HandleScope scope;
6405 LocalContext context;
6406
6407 v8::Handle<String> str = v8_str("42");
6408 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6409 CHECK(!index.IsEmpty());
6410 CHECK_EQ(42.0, index->Uint32Value());
6411 str = v8_str("42asdf");
6412 index = str->ToArrayIndex();
6413 CHECK(index.IsEmpty());
6414 str = v8_str("-42");
6415 index = str->ToArrayIndex();
6416 CHECK(index.IsEmpty());
6417 str = v8_str("4294967295");
6418 index = str->ToArrayIndex();
6419 CHECK(!index.IsEmpty());
6420 CHECK_EQ(4294967295.0, index->Uint32Value());
6421 v8::Handle<v8::Number> num = v8::Number::New(1);
6422 index = num->ToArrayIndex();
6423 CHECK(!index.IsEmpty());
6424 CHECK_EQ(1.0, index->Uint32Value());
6425 num = v8::Number::New(-1);
6426 index = num->ToArrayIndex();
6427 CHECK(index.IsEmpty());
6428 v8::Handle<v8::Object> obj = v8::Object::New();
6429 index = obj->ToArrayIndex();
6430 CHECK(index.IsEmpty());
6431}
6432
6433
6434THREADED_TEST(ErrorConstruction) {
6435 v8::HandleScope scope;
6436 LocalContext context;
6437
6438 v8::Handle<String> foo = v8_str("foo");
6439 v8::Handle<String> message = v8_str("message");
6440 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6441 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006443 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6444 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006445 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006446 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6447 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006448 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006449 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6450 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006451 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006452 v8::Handle<Value> error = v8::Exception::Error(foo);
6453 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006454 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006455}
6456
6457
6458static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6459 ApiTestFuzzer::Fuzz();
6460 return v8_num(10);
6461}
6462
6463
6464static void YSetter(Local<String> name,
6465 Local<Value> value,
6466 const AccessorInfo& info) {
6467 if (info.This()->Has(name)) {
6468 info.This()->Delete(name);
6469 }
6470 info.This()->Set(name, value);
6471}
6472
6473
6474THREADED_TEST(DeleteAccessor) {
6475 v8::HandleScope scope;
6476 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6477 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6478 LocalContext context;
6479 v8::Handle<v8::Object> holder = obj->NewInstance();
6480 context->Global()->Set(v8_str("holder"), holder);
6481 v8::Handle<Value> result = CompileRun(
6482 "holder.y = 11; holder.y = 12; holder.y");
6483 CHECK_EQ(12, result->Uint32Value());
6484}
6485
6486
6487THREADED_TEST(TypeSwitch) {
6488 v8::HandleScope scope;
6489 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6490 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6491 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6492 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6493 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6494 LocalContext context;
6495 v8::Handle<v8::Object> obj0 = v8::Object::New();
6496 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6497 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6498 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6499 for (int i = 0; i < 10; i++) {
6500 CHECK_EQ(0, type_switch->match(obj0));
6501 CHECK_EQ(1, type_switch->match(obj1));
6502 CHECK_EQ(2, type_switch->match(obj2));
6503 CHECK_EQ(3, type_switch->match(obj3));
6504 CHECK_EQ(3, type_switch->match(obj3));
6505 CHECK_EQ(2, type_switch->match(obj2));
6506 CHECK_EQ(1, type_switch->match(obj1));
6507 CHECK_EQ(0, type_switch->match(obj0));
6508 }
6509}
6510
6511
6512// For use within the TestSecurityHandler() test.
6513static bool g_security_callback_result = false;
6514static bool NamedSecurityTestCallback(Local<v8::Object> global,
6515 Local<Value> name,
6516 v8::AccessType type,
6517 Local<Value> data) {
6518 // Always allow read access.
6519 if (type == v8::ACCESS_GET)
6520 return true;
6521
6522 // Sometimes allow other access.
6523 return g_security_callback_result;
6524}
6525
6526
6527static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6528 uint32_t key,
6529 v8::AccessType type,
6530 Local<Value> data) {
6531 // Always allow read access.
6532 if (type == v8::ACCESS_GET)
6533 return true;
6534
6535 // Sometimes allow other access.
6536 return g_security_callback_result;
6537}
6538
6539
6540static int trouble_nesting = 0;
6541static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6542 ApiTestFuzzer::Fuzz();
6543 trouble_nesting++;
6544
6545 // Call a JS function that throws an uncaught exception.
6546 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6547 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6548 arg_this->Get(v8_str("trouble_callee")) :
6549 arg_this->Get(v8_str("trouble_caller"));
6550 CHECK(trouble_callee->IsFunction());
6551 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6552}
6553
6554
6555static int report_count = 0;
6556static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6557 v8::Handle<Value>) {
6558 report_count++;
6559}
6560
6561
6562// Counts uncaught exceptions, but other tests running in parallel
6563// also have uncaught exceptions.
6564TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006565 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006566 v8::HandleScope scope;
6567 LocalContext env;
6568 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6569
6570 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6571 v8::Local<v8::Object> global = env->Global();
6572 global->Set(v8_str("trouble"), fun->GetFunction());
6573
6574 Script::Compile(v8_str("function trouble_callee() {"
6575 " var x = null;"
6576 " return x.foo;"
6577 "};"
6578 "function trouble_caller() {"
6579 " trouble();"
6580 "};"))->Run();
6581 Local<Value> trouble = global->Get(v8_str("trouble"));
6582 CHECK(trouble->IsFunction());
6583 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6584 CHECK(trouble_callee->IsFunction());
6585 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6586 CHECK(trouble_caller->IsFunction());
6587 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6588 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006589 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6590}
6591
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006592static const char* script_resource_name = "ExceptionInNativeScript.js";
6593static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6594 v8::Handle<Value>) {
6595 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6596 CHECK(!name_val.IsEmpty() && name_val->IsString());
6597 v8::String::AsciiValue name(message->GetScriptResourceName());
6598 CHECK_EQ(script_resource_name, *name);
6599 CHECK_EQ(3, message->GetLineNumber());
6600 v8::String::AsciiValue source_line(message->GetSourceLine());
6601 CHECK_EQ(" new o.foo();", *source_line);
6602}
6603
6604TEST(ExceptionInNativeScript) {
6605 v8::HandleScope scope;
6606 LocalContext env;
6607 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6608
6609 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6610 v8::Local<v8::Object> global = env->Global();
6611 global->Set(v8_str("trouble"), fun->GetFunction());
6612
6613 Script::Compile(v8_str("function trouble() {\n"
6614 " var o = {};\n"
6615 " new o.foo();\n"
6616 "};"), v8::String::New(script_resource_name))->Run();
6617 Local<Value> trouble = global->Get(v8_str("trouble"));
6618 CHECK(trouble->IsFunction());
6619 Function::Cast(*trouble)->Call(global, 0, NULL);
6620 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6621}
6622
ager@chromium.org8bb60582008-12-11 12:02:20 +00006623
6624TEST(CompilationErrorUsingTryCatchHandler) {
6625 v8::HandleScope scope;
6626 LocalContext env;
6627 v8::TryCatch try_catch;
6628 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6629 CHECK_NE(NULL, *try_catch.Exception());
6630 CHECK(try_catch.HasCaught());
6631}
6632
6633
6634TEST(TryCatchFinallyUsingTryCatchHandler) {
6635 v8::HandleScope scope;
6636 LocalContext env;
6637 v8::TryCatch try_catch;
6638 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6639 CHECK(!try_catch.HasCaught());
6640 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6641 CHECK(try_catch.HasCaught());
6642 try_catch.Reset();
6643 Script::Compile(v8_str("(function() {"
6644 "try { throw ''; } finally { return; }"
6645 "})()"))->Run();
6646 CHECK(!try_catch.HasCaught());
6647 Script::Compile(v8_str("(function()"
6648 " { try { throw ''; } finally { throw 0; }"
6649 "})()"))->Run();
6650 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006651}
6652
6653
6654// SecurityHandler can't be run twice
6655TEST(SecurityHandler) {
6656 v8::HandleScope scope0;
6657 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6658 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6659 IndexedSecurityTestCallback);
6660 // Create an environment
6661 v8::Persistent<Context> context0 =
6662 Context::New(NULL, global_template);
6663 context0->Enter();
6664
6665 v8::Handle<v8::Object> global0 = context0->Global();
6666 v8::Handle<Script> script0 = v8_compile("foo = 111");
6667 script0->Run();
6668 global0->Set(v8_str("0"), v8_num(999));
6669 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6670 CHECK_EQ(111, foo0->Int32Value());
6671 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6672 CHECK_EQ(999, z0->Int32Value());
6673
6674 // Create another environment, should fail security checks.
6675 v8::HandleScope scope1;
6676
6677 v8::Persistent<Context> context1 =
6678 Context::New(NULL, global_template);
6679 context1->Enter();
6680
6681 v8::Handle<v8::Object> global1 = context1->Global();
6682 global1->Set(v8_str("othercontext"), global0);
6683 // This set will fail the security check.
6684 v8::Handle<Script> script1 =
6685 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6686 script1->Run();
6687 // This read will pass the security check.
6688 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6689 CHECK_EQ(111, foo1->Int32Value());
6690 // This read will pass the security check.
6691 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6692 CHECK_EQ(999, z1->Int32Value());
6693
6694 // Create another environment, should pass security checks.
6695 { g_security_callback_result = true; // allow security handler to pass.
6696 v8::HandleScope scope2;
6697 LocalContext context2;
6698 v8::Handle<v8::Object> global2 = context2->Global();
6699 global2->Set(v8_str("othercontext"), global0);
6700 v8::Handle<Script> script2 =
6701 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6702 script2->Run();
6703 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6704 CHECK_EQ(333, foo2->Int32Value());
6705 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6706 CHECK_EQ(888, z2->Int32Value());
6707 }
6708
6709 context1->Exit();
6710 context1.Dispose();
6711
6712 context0->Exit();
6713 context0.Dispose();
6714}
6715
6716
6717THREADED_TEST(SecurityChecks) {
6718 v8::HandleScope handle_scope;
6719 LocalContext env1;
6720 v8::Persistent<Context> env2 = Context::New();
6721
6722 Local<Value> foo = v8_str("foo");
6723 Local<Value> bar = v8_str("bar");
6724
6725 // Set to the same domain.
6726 env1->SetSecurityToken(foo);
6727
6728 // Create a function in env1.
6729 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6730 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6731 CHECK(spy->IsFunction());
6732
6733 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006734 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006735 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6736 CHECK(spy2->IsFunction());
6737
6738 // Switch to env2 in the same domain and invoke spy on env2.
6739 {
6740 env2->SetSecurityToken(foo);
6741 // Enter env2
6742 Context::Scope scope_env2(env2);
6743 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6744 CHECK(result->IsFunction());
6745 }
6746
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006747 {
6748 env2->SetSecurityToken(bar);
6749 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006750
6751 // Call cross_domain_call, it should throw an exception
6752 v8::TryCatch try_catch;
6753 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6754 CHECK(try_catch.HasCaught());
6755 }
6756
6757 env2.Dispose();
6758}
6759
6760
6761// Regression test case for issue 1183439.
6762THREADED_TEST(SecurityChecksForPrototypeChain) {
6763 v8::HandleScope scope;
6764 LocalContext current;
6765 v8::Persistent<Context> other = Context::New();
6766
6767 // Change context to be able to get to the Object function in the
6768 // other context without hitting the security checks.
6769 v8::Local<Value> other_object;
6770 { Context::Scope scope(other);
6771 other_object = other->Global()->Get(v8_str("Object"));
6772 other->Global()->Set(v8_num(42), v8_num(87));
6773 }
6774
6775 current->Global()->Set(v8_str("other"), other->Global());
6776 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6777
6778 // Make sure the security check fails here and we get an undefined
6779 // result instead of getting the Object function. Repeat in a loop
6780 // to make sure to exercise the IC code.
6781 v8::Local<Script> access_other0 = v8_compile("other.Object");
6782 v8::Local<Script> access_other1 = v8_compile("other[42]");
6783 for (int i = 0; i < 5; i++) {
6784 CHECK(!access_other0->Run()->Equals(other_object));
6785 CHECK(access_other0->Run()->IsUndefined());
6786 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6787 CHECK(access_other1->Run()->IsUndefined());
6788 }
6789
6790 // Create an object that has 'other' in its prototype chain and make
6791 // sure we cannot access the Object function indirectly through
6792 // that. Repeat in a loop to make sure to exercise the IC code.
6793 v8_compile("function F() { };"
6794 "F.prototype = other;"
6795 "var f = new F();")->Run();
6796 v8::Local<Script> access_f0 = v8_compile("f.Object");
6797 v8::Local<Script> access_f1 = v8_compile("f[42]");
6798 for (int j = 0; j < 5; j++) {
6799 CHECK(!access_f0->Run()->Equals(other_object));
6800 CHECK(access_f0->Run()->IsUndefined());
6801 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6802 CHECK(access_f1->Run()->IsUndefined());
6803 }
6804
6805 // Now it gets hairy: Set the prototype for the other global object
6806 // to be the current global object. The prototype chain for 'f' now
6807 // goes through 'other' but ends up in the current global object.
6808 { Context::Scope scope(other);
6809 other->Global()->Set(v8_str("__proto__"), current->Global());
6810 }
6811 // Set a named and an index property on the current global
6812 // object. To force the lookup to go through the other global object,
6813 // the properties must not exist in the other global object.
6814 current->Global()->Set(v8_str("foo"), v8_num(100));
6815 current->Global()->Set(v8_num(99), v8_num(101));
6816 // Try to read the properties from f and make sure that the access
6817 // gets stopped by the security checks on the other global object.
6818 Local<Script> access_f2 = v8_compile("f.foo");
6819 Local<Script> access_f3 = v8_compile("f[99]");
6820 for (int k = 0; k < 5; k++) {
6821 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6822 CHECK(access_f2->Run()->IsUndefined());
6823 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6824 CHECK(access_f3->Run()->IsUndefined());
6825 }
6826 other.Dispose();
6827}
6828
6829
6830THREADED_TEST(CrossDomainDelete) {
6831 v8::HandleScope handle_scope;
6832 LocalContext env1;
6833 v8::Persistent<Context> env2 = Context::New();
6834
6835 Local<Value> foo = v8_str("foo");
6836 Local<Value> bar = v8_str("bar");
6837
6838 // Set to the same domain.
6839 env1->SetSecurityToken(foo);
6840 env2->SetSecurityToken(foo);
6841
6842 env1->Global()->Set(v8_str("prop"), v8_num(3));
6843 env2->Global()->Set(v8_str("env1"), env1->Global());
6844
6845 // Change env2 to a different domain and delete env1.prop.
6846 env2->SetSecurityToken(bar);
6847 {
6848 Context::Scope scope_env2(env2);
6849 Local<Value> result =
6850 Script::Compile(v8_str("delete env1.prop"))->Run();
6851 CHECK(result->IsFalse());
6852 }
6853
6854 // Check that env1.prop still exists.
6855 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6856 CHECK(v->IsNumber());
6857 CHECK_EQ(3, v->Int32Value());
6858
6859 env2.Dispose();
6860}
6861
6862
ager@chromium.org870a0b62008-11-04 11:43:05 +00006863THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6864 v8::HandleScope handle_scope;
6865 LocalContext env1;
6866 v8::Persistent<Context> env2 = Context::New();
6867
6868 Local<Value> foo = v8_str("foo");
6869 Local<Value> bar = v8_str("bar");
6870
6871 // Set to the same domain.
6872 env1->SetSecurityToken(foo);
6873 env2->SetSecurityToken(foo);
6874
6875 env1->Global()->Set(v8_str("prop"), v8_num(3));
6876 env2->Global()->Set(v8_str("env1"), env1->Global());
6877
6878 // env1.prop is enumerable in env2.
6879 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6880 {
6881 Context::Scope scope_env2(env2);
6882 Local<Value> result = Script::Compile(test)->Run();
6883 CHECK(result->IsTrue());
6884 }
6885
6886 // Change env2 to a different domain and test again.
6887 env2->SetSecurityToken(bar);
6888 {
6889 Context::Scope scope_env2(env2);
6890 Local<Value> result = Script::Compile(test)->Run();
6891 CHECK(result->IsFalse());
6892 }
6893
6894 env2.Dispose();
6895}
6896
6897
ager@chromium.org236ad962008-09-25 09:45:57 +00006898THREADED_TEST(CrossDomainForIn) {
6899 v8::HandleScope handle_scope;
6900 LocalContext env1;
6901 v8::Persistent<Context> env2 = Context::New();
6902
6903 Local<Value> foo = v8_str("foo");
6904 Local<Value> bar = v8_str("bar");
6905
6906 // Set to the same domain.
6907 env1->SetSecurityToken(foo);
6908 env2->SetSecurityToken(foo);
6909
6910 env1->Global()->Set(v8_str("prop"), v8_num(3));
6911 env2->Global()->Set(v8_str("env1"), env1->Global());
6912
6913 // Change env2 to a different domain and set env1's global object
6914 // as the __proto__ of an object in env2 and enumerate properties
6915 // in for-in. It shouldn't enumerate properties on env1's global
6916 // object.
6917 env2->SetSecurityToken(bar);
6918 {
6919 Context::Scope scope_env2(env2);
6920 Local<Value> result =
6921 CompileRun("(function(){var obj = {'__proto__':env1};"
6922 "for (var p in obj)"
6923 " if (p == 'prop') return false;"
6924 "return true;})()");
6925 CHECK(result->IsTrue());
6926 }
6927 env2.Dispose();
6928}
6929
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006930
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006931TEST(ContextDetachGlobal) {
6932 v8::HandleScope handle_scope;
6933 LocalContext env1;
6934 v8::Persistent<Context> env2 = Context::New();
6935
6936 Local<v8::Object> global1 = env1->Global();
6937
6938 Local<Value> foo = v8_str("foo");
6939
6940 // Set to the same domain.
6941 env1->SetSecurityToken(foo);
6942 env2->SetSecurityToken(foo);
6943
6944 // Enter env2
6945 env2->Enter();
6946
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006947 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006948 Local<v8::Object> global2 = env2->Global();
6949 global2->Set(v8_str("prop"), v8::Integer::New(1));
6950 CompileRun("function getProp() {return prop;}");
6951
6952 env1->Global()->Set(v8_str("getProp"),
6953 global2->Get(v8_str("getProp")));
6954
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006955 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006956 env2->Exit();
6957 env2->DetachGlobal();
6958 // env2 has a new global object.
6959 CHECK(!env2->Global()->Equals(global2));
6960
6961 v8::Persistent<Context> env3 =
6962 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6963 env3->SetSecurityToken(v8_str("bar"));
6964 env3->Enter();
6965
6966 Local<v8::Object> global3 = env3->Global();
6967 CHECK_EQ(global2, global3);
6968 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6969 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6970 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6971 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6972 env3->Exit();
6973
6974 // Call getProp in env1, and it should return the value 1
6975 {
6976 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6977 CHECK(get_prop->IsFunction());
6978 v8::TryCatch try_catch;
6979 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6980 CHECK(!try_catch.HasCaught());
6981 CHECK_EQ(1, r->Int32Value());
6982 }
6983
6984 // Check that env3 is not accessible from env1
6985 {
6986 Local<Value> r = global3->Get(v8_str("prop2"));
6987 CHECK(r->IsUndefined());
6988 }
6989
6990 env2.Dispose();
6991 env3.Dispose();
6992}
6993
6994
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006995TEST(DetachAndReattachGlobal) {
6996 v8::HandleScope scope;
6997 LocalContext env1;
6998
6999 // Create second environment.
7000 v8::Persistent<Context> env2 = Context::New();
7001
7002 Local<Value> foo = v8_str("foo");
7003
7004 // Set same security token for env1 and env2.
7005 env1->SetSecurityToken(foo);
7006 env2->SetSecurityToken(foo);
7007
7008 // Create a property on the global object in env2.
7009 {
7010 v8::Context::Scope scope(env2);
7011 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7012 }
7013
7014 // Create a reference to env2 global from env1 global.
7015 env1->Global()->Set(v8_str("other"), env2->Global());
7016
7017 // Check that we have access to other.p in env2 from env1.
7018 Local<Value> result = CompileRun("other.p");
7019 CHECK(result->IsInt32());
7020 CHECK_EQ(42, result->Int32Value());
7021
7022 // Hold on to global from env2 and detach global from env2.
7023 Local<v8::Object> global2 = env2->Global();
7024 env2->DetachGlobal();
7025
7026 // Check that the global has been detached. No other.p property can
7027 // be found.
7028 result = CompileRun("other.p");
7029 CHECK(result->IsUndefined());
7030
7031 // Reuse global2 for env3.
7032 v8::Persistent<Context> env3 =
7033 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7034 CHECK_EQ(global2, env3->Global());
7035
7036 // Start by using the same security token for env3 as for env1 and env2.
7037 env3->SetSecurityToken(foo);
7038
7039 // Create a property on the global object in env3.
7040 {
7041 v8::Context::Scope scope(env3);
7042 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
7043 }
7044
7045 // Check that other.p is now the property in env3 and that we have access.
7046 result = CompileRun("other.p");
7047 CHECK(result->IsInt32());
7048 CHECK_EQ(24, result->Int32Value());
7049
7050 // Change security token for env3 to something different from env1 and env2.
7051 env3->SetSecurityToken(v8_str("bar"));
7052
7053 // Check that we do not have access to other.p in env1. |other| is now
7054 // the global object for env3 which has a different security token,
7055 // so access should be blocked.
7056 result = CompileRun("other.p");
7057 CHECK(result->IsUndefined());
7058
7059 // Detach the global for env3 and reattach it to env2.
7060 env3->DetachGlobal();
7061 env2->ReattachGlobal(global2);
7062
7063 // Check that we have access to other.p again in env1. |other| is now
7064 // the global object for env2 which has the same security token as env1.
7065 result = CompileRun("other.p");
7066 CHECK(result->IsInt32());
7067 CHECK_EQ(42, result->Int32Value());
7068
7069 env2.Dispose();
7070 env3.Dispose();
7071}
7072
7073
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007074static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007075static bool NamedAccessBlocker(Local<v8::Object> global,
7076 Local<Value> name,
7077 v8::AccessType type,
7078 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007079 return Context::GetCurrent()->Global()->Equals(global) ||
7080 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007081}
7082
7083
7084static bool IndexedAccessBlocker(Local<v8::Object> global,
7085 uint32_t key,
7086 v8::AccessType type,
7087 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007088 return Context::GetCurrent()->Global()->Equals(global) ||
7089 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007090}
7091
7092
7093static int g_echo_value = -1;
7094static v8::Handle<Value> EchoGetter(Local<String> name,
7095 const AccessorInfo& info) {
7096 return v8_num(g_echo_value);
7097}
7098
7099
7100static void EchoSetter(Local<String> name,
7101 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007102 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007103 if (value->IsNumber())
7104 g_echo_value = value->Int32Value();
7105}
7106
7107
7108static v8::Handle<Value> UnreachableGetter(Local<String> name,
7109 const AccessorInfo& info) {
7110 CHECK(false); // This function should not be called..
7111 return v8::Undefined();
7112}
7113
7114
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007115static void UnreachableSetter(Local<String>, Local<Value>,
7116 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007117 CHECK(false); // This function should nto be called.
7118}
7119
7120
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007121TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007122 v8::HandleScope handle_scope;
7123 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7124
7125 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7126 IndexedAccessBlocker);
7127
7128 // Add an accessor accessible by cross-domain JS code.
7129 global_template->SetAccessor(
7130 v8_str("accessible_prop"),
7131 EchoGetter, EchoSetter,
7132 v8::Handle<Value>(),
7133 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7134
7135 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00007136 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007137 UnreachableGetter, UnreachableSetter,
7138 v8::Handle<Value>(),
7139 v8::DEFAULT);
7140
7141 // Create an environment
7142 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7143 context0->Enter();
7144
7145 v8::Handle<v8::Object> global0 = context0->Global();
7146
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007147 // Define a property with JS getter and setter.
7148 CompileRun(
7149 "function getter() { return 'getter'; };\n"
7150 "function setter() { return 'setter'; }\n"
7151 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
7152
7153 Local<Value> getter = global0->Get(v8_str("getter"));
7154 Local<Value> setter = global0->Get(v8_str("setter"));
7155
7156 // And define normal element.
7157 global0->Set(239, v8_str("239"));
7158
7159 // Define an element with JS getter and setter.
7160 CompileRun(
7161 "function el_getter() { return 'el_getter'; };\n"
7162 "function el_setter() { return 'el_setter'; };\n"
7163 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
7164
7165 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
7166 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
7167
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007168 v8::HandleScope scope1;
7169
7170 v8::Persistent<Context> context1 = Context::New();
7171 context1->Enter();
7172
7173 v8::Handle<v8::Object> global1 = context1->Global();
7174 global1->Set(v8_str("other"), global0);
7175
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007176 // Access blocked property.
7177 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007178
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007179 ExpectUndefined("other.blocked_prop");
7180 ExpectUndefined(
7181 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7182 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007183
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007184 // Enable ACCESS_HAS
7185 allowed_access_type[v8::ACCESS_HAS] = true;
7186 ExpectUndefined("other.blocked_prop");
7187 // ... and now we can get the descriptor...
7188 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007189 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007190 // ... and enumerate the property.
7191 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
7192 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007193
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007194 // Access blocked element.
7195 CompileRun("other[239] = 1");
7196
7197 ExpectUndefined("other[239]");
7198 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
7199 ExpectFalse("propertyIsEnumerable.call(other, '239')");
7200
7201 // Enable ACCESS_HAS
7202 allowed_access_type[v8::ACCESS_HAS] = true;
7203 ExpectUndefined("other[239]");
7204 // ... and now we can get the descriptor...
7205 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
7206 // ... and enumerate the property.
7207 ExpectTrue("propertyIsEnumerable.call(other, '239')");
7208 allowed_access_type[v8::ACCESS_HAS] = false;
7209
7210 // Access a property with JS accessor.
7211 CompileRun("other.js_accessor_p = 2");
7212
7213 ExpectUndefined("other.js_accessor_p");
7214 ExpectUndefined(
7215 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7216
7217 // Enable ACCESS_HAS.
7218 allowed_access_type[v8::ACCESS_HAS] = true;
7219 ExpectUndefined("other.js_accessor_p");
7220 ExpectUndefined(
7221 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7222 ExpectUndefined(
7223 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7224 ExpectUndefined(
7225 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7226 allowed_access_type[v8::ACCESS_HAS] = false;
7227
7228 // Enable both ACCESS_HAS and ACCESS_GET.
7229 allowed_access_type[v8::ACCESS_HAS] = true;
7230 allowed_access_type[v8::ACCESS_GET] = true;
7231
7232 ExpectString("other.js_accessor_p", "getter");
7233 ExpectObject(
7234 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7235 ExpectUndefined(
7236 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7237 ExpectUndefined(
7238 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7239
7240 allowed_access_type[v8::ACCESS_GET] = false;
7241 allowed_access_type[v8::ACCESS_HAS] = false;
7242
7243 // Enable both ACCESS_HAS and ACCESS_SET.
7244 allowed_access_type[v8::ACCESS_HAS] = true;
7245 allowed_access_type[v8::ACCESS_SET] = true;
7246
7247 ExpectUndefined("other.js_accessor_p");
7248 ExpectUndefined(
7249 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7250 ExpectObject(
7251 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7252 ExpectUndefined(
7253 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7254
7255 allowed_access_type[v8::ACCESS_SET] = false;
7256 allowed_access_type[v8::ACCESS_HAS] = false;
7257
7258 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7259 allowed_access_type[v8::ACCESS_HAS] = true;
7260 allowed_access_type[v8::ACCESS_GET] = true;
7261 allowed_access_type[v8::ACCESS_SET] = true;
7262
7263 ExpectString("other.js_accessor_p", "getter");
7264 ExpectObject(
7265 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7266 ExpectObject(
7267 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7268 ExpectUndefined(
7269 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7270
7271 allowed_access_type[v8::ACCESS_SET] = false;
7272 allowed_access_type[v8::ACCESS_GET] = false;
7273 allowed_access_type[v8::ACCESS_HAS] = false;
7274
7275 // Access an element with JS accessor.
7276 CompileRun("other[42] = 2");
7277
7278 ExpectUndefined("other[42]");
7279 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7280
7281 // Enable ACCESS_HAS.
7282 allowed_access_type[v8::ACCESS_HAS] = true;
7283 ExpectUndefined("other[42]");
7284 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7285 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7286 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7287 allowed_access_type[v8::ACCESS_HAS] = false;
7288
7289 // Enable both ACCESS_HAS and ACCESS_GET.
7290 allowed_access_type[v8::ACCESS_HAS] = true;
7291 allowed_access_type[v8::ACCESS_GET] = true;
7292
7293 ExpectString("other[42]", "el_getter");
7294 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7295 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7296 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7297
7298 allowed_access_type[v8::ACCESS_GET] = false;
7299 allowed_access_type[v8::ACCESS_HAS] = false;
7300
7301 // Enable both ACCESS_HAS and ACCESS_SET.
7302 allowed_access_type[v8::ACCESS_HAS] = true;
7303 allowed_access_type[v8::ACCESS_SET] = true;
7304
7305 ExpectUndefined("other[42]");
7306 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7307 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7308 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7309
7310 allowed_access_type[v8::ACCESS_SET] = false;
7311 allowed_access_type[v8::ACCESS_HAS] = false;
7312
7313 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7314 allowed_access_type[v8::ACCESS_HAS] = true;
7315 allowed_access_type[v8::ACCESS_GET] = true;
7316 allowed_access_type[v8::ACCESS_SET] = true;
7317
7318 ExpectString("other[42]", "el_getter");
7319 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7320 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7321 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7322
7323 allowed_access_type[v8::ACCESS_SET] = false;
7324 allowed_access_type[v8::ACCESS_GET] = false;
7325 allowed_access_type[v8::ACCESS_HAS] = false;
7326
7327 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007328
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007329 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007330 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007331 CHECK(value->IsNumber());
7332 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007333 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007334
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007335 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007336 CHECK(value->IsNumber());
7337 CHECK_EQ(3, value->Int32Value());
7338
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007339 value = CompileRun(
7340 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7341 CHECK(value->IsNumber());
7342 CHECK_EQ(3, value->Int32Value());
7343
7344 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00007345 CHECK(value->IsTrue());
7346
7347 // Enumeration doesn't enumerate accessors from inaccessible objects in
7348 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007349 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00007350 CompileRun("(function(){var obj = {'__proto__':other};"
7351 "for (var p in obj)"
7352 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7353 " return false;"
7354 " }"
7355 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007356 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00007357
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007358 context1->Exit();
7359 context0->Exit();
7360 context1.Dispose();
7361 context0.Dispose();
7362}
7363
7364
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007365TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00007366 v8::HandleScope handle_scope;
7367 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7368
7369 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7370 IndexedAccessBlocker);
7371
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007372 // Add accessible accessor.
7373 global_template->SetAccessor(
7374 v8_str("accessible_prop"),
7375 EchoGetter, EchoSetter,
7376 v8::Handle<Value>(),
7377 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7378
7379
ricow@chromium.org65001782011-02-15 13:36:41 +00007380 // Add an accessor that is not accessible by cross-domain JS code.
7381 global_template->SetAccessor(v8_str("blocked_prop"),
7382 UnreachableGetter, UnreachableSetter,
7383 v8::Handle<Value>(),
7384 v8::DEFAULT);
7385
7386 // Create an environment
7387 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7388 context0->Enter();
7389
7390 v8::Handle<v8::Object> global0 = context0->Global();
7391
7392 v8::Persistent<Context> context1 = Context::New();
7393 context1->Enter();
7394 v8::Handle<v8::Object> global1 = context1->Global();
7395 global1->Set(v8_str("other"), global0);
7396
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007397 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00007398 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007399
7400 ExpectUndefined("other.blocked_prop");
7401
7402 // Regression test for issue 1027.
7403 CompileRun("Object.defineProperty(\n"
7404 " other, 'blocked_prop', {configurable: false})");
7405 ExpectUndefined("other.blocked_prop");
7406 ExpectUndefined(
7407 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7408
7409 // Regression test for issue 1171.
7410 ExpectTrue("Object.isExtensible(other)");
7411 CompileRun("Object.preventExtensions(other)");
7412 ExpectTrue("Object.isExtensible(other)");
7413
7414 // Object.seal and Object.freeze.
7415 CompileRun("Object.freeze(other)");
7416 ExpectTrue("Object.isExtensible(other)");
7417
7418 CompileRun("Object.seal(other)");
7419 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007420
7421 // Regression test for issue 1250.
7422 // Make sure that we can set the accessible accessors value using normal
7423 // assignment.
7424 CompileRun("other.accessible_prop = 42");
7425 CHECK_EQ(42, g_echo_value);
7426
7427 v8::Handle<Value> value;
7428 // We follow Safari in ignoring assignments to host object accessors.
7429 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7430 value = CompileRun("other.accessible_prop == 42");
7431 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00007432}
7433
7434
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007435static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7436 Local<Value> name,
7437 v8::AccessType type,
7438 Local<Value> data) {
7439 return false;
7440}
7441
7442
7443static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7444 uint32_t key,
7445 v8::AccessType type,
7446 Local<Value> data) {
7447 return false;
7448}
7449
7450
7451THREADED_TEST(AccessControlGetOwnPropertyNames) {
7452 v8::HandleScope handle_scope;
7453 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7454
7455 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7456 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7457 GetOwnPropertyNamesIndexedBlocker);
7458
7459 // Create an environment
7460 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7461 context0->Enter();
7462
7463 v8::Handle<v8::Object> global0 = context0->Global();
7464
7465 v8::HandleScope scope1;
7466
7467 v8::Persistent<Context> context1 = Context::New();
7468 context1->Enter();
7469
7470 v8::Handle<v8::Object> global1 = context1->Global();
7471 global1->Set(v8_str("other"), global0);
7472 global1->Set(v8_str("object"), obj_template->NewInstance());
7473
7474 v8::Handle<Value> value;
7475
7476 // Attempt to get the property names of the other global object and
7477 // of an object that requires access checks. Accessing the other
7478 // global object should be blocked by access checks on the global
7479 // proxy object. Accessing the object that requires access checks
7480 // is blocked by the access checks on the object itself.
7481 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7482 CHECK(value->IsTrue());
7483
7484 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7485 CHECK(value->IsTrue());
7486
7487 context1->Exit();
7488 context0->Exit();
7489 context1.Dispose();
7490 context0.Dispose();
7491}
7492
7493
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007494static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7495 v8::Handle<v8::Array> result = v8::Array::New(1);
7496 result->Set(0, v8_str("x"));
7497 return result;
7498}
7499
7500
7501THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7502 v8::HandleScope handle_scope;
7503 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7504
7505 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7506 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7507 NamedPropertyEnumerator);
7508
7509 LocalContext context;
7510 v8::Handle<v8::Object> global = context->Global();
7511 global->Set(v8_str("object"), obj_template->NewInstance());
7512
7513 v8::Handle<Value> value =
7514 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7515 CHECK_EQ(v8_str("x"), value);
7516}
7517
7518
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007519static v8::Handle<Value> ConstTenGetter(Local<String> name,
7520 const AccessorInfo& info) {
7521 return v8_num(10);
7522}
7523
7524
7525THREADED_TEST(CrossDomainAccessors) {
7526 v8::HandleScope handle_scope;
7527
7528 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7529
7530 v8::Handle<v8::ObjectTemplate> global_template =
7531 func_template->InstanceTemplate();
7532
7533 v8::Handle<v8::ObjectTemplate> proto_template =
7534 func_template->PrototypeTemplate();
7535
7536 // Add an accessor to proto that's accessible by cross-domain JS code.
7537 proto_template->SetAccessor(v8_str("accessible"),
7538 ConstTenGetter, 0,
7539 v8::Handle<Value>(),
7540 v8::ALL_CAN_READ);
7541
7542 // Add an accessor that is not accessible by cross-domain JS code.
7543 global_template->SetAccessor(v8_str("unreachable"),
7544 UnreachableGetter, 0,
7545 v8::Handle<Value>(),
7546 v8::DEFAULT);
7547
7548 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7549 context0->Enter();
7550
7551 Local<v8::Object> global = context0->Global();
7552 // Add a normal property that shadows 'accessible'
7553 global->Set(v8_str("accessible"), v8_num(11));
7554
7555 // Enter a new context.
7556 v8::HandleScope scope1;
7557 v8::Persistent<Context> context1 = Context::New();
7558 context1->Enter();
7559
7560 v8::Handle<v8::Object> global1 = context1->Global();
7561 global1->Set(v8_str("other"), global);
7562
7563 // Should return 10, instead of 11
7564 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7565 CHECK(value->IsNumber());
7566 CHECK_EQ(10, value->Int32Value());
7567
7568 value = v8_compile("other.unreachable")->Run();
7569 CHECK(value->IsUndefined());
7570
7571 context1->Exit();
7572 context0->Exit();
7573 context1.Dispose();
7574 context0.Dispose();
7575}
7576
7577
7578static int named_access_count = 0;
7579static int indexed_access_count = 0;
7580
7581static bool NamedAccessCounter(Local<v8::Object> global,
7582 Local<Value> name,
7583 v8::AccessType type,
7584 Local<Value> data) {
7585 named_access_count++;
7586 return true;
7587}
7588
7589
7590static bool IndexedAccessCounter(Local<v8::Object> global,
7591 uint32_t key,
7592 v8::AccessType type,
7593 Local<Value> data) {
7594 indexed_access_count++;
7595 return true;
7596}
7597
7598
7599// This one is too easily disturbed by other tests.
7600TEST(AccessControlIC) {
7601 named_access_count = 0;
7602 indexed_access_count = 0;
7603
7604 v8::HandleScope handle_scope;
7605
7606 // Create an environment.
7607 v8::Persistent<Context> context0 = Context::New();
7608 context0->Enter();
7609
7610 // Create an object that requires access-check functions to be
7611 // called for cross-domain access.
7612 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7613 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7614 IndexedAccessCounter);
7615 Local<v8::Object> object = object_template->NewInstance();
7616
7617 v8::HandleScope scope1;
7618
7619 // Create another environment.
7620 v8::Persistent<Context> context1 = Context::New();
7621 context1->Enter();
7622
7623 // Make easy access to the object from the other environment.
7624 v8::Handle<v8::Object> global1 = context1->Global();
7625 global1->Set(v8_str("obj"), object);
7626
7627 v8::Handle<Value> value;
7628
7629 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007630 CompileRun("function testProp(obj) {"
7631 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7632 " for (var j = 0; j < 10; j++) obj.prop;"
7633 " return obj.prop"
7634 "}");
7635 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007636 CHECK(value->IsNumber());
7637 CHECK_EQ(1, value->Int32Value());
7638 CHECK_EQ(21, named_access_count);
7639
7640 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007641 CompileRun("var p = 'prop';"
7642 "function testKeyed(obj) {"
7643 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7644 " for (var j = 0; j < 10; j++) obj[p];"
7645 " return obj[p];"
7646 "}");
7647 // Use obj which requires access checks. No inline caching is used
7648 // in that case.
7649 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007650 CHECK(value->IsNumber());
7651 CHECK_EQ(1, value->Int32Value());
7652 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007653 // Force the inline caches into generic state and try again.
7654 CompileRun("testKeyed({ a: 0 })");
7655 CompileRun("testKeyed({ b: 0 })");
7656 value = CompileRun("testKeyed(obj)");
7657 CHECK(value->IsNumber());
7658 CHECK_EQ(1, value->Int32Value());
7659 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007660
7661 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007662 CompileRun("function testIndexed(obj) {"
7663 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7664 " for (var j = 0; j < 10; j++) obj[0];"
7665 " return obj[0]"
7666 "}");
7667 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007668 CHECK(value->IsNumber());
7669 CHECK_EQ(1, value->Int32Value());
7670 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007671 // Force the inline caches into generic state.
7672 CompileRun("testIndexed(new Array(1))");
7673 // Test that the indexed access check is called.
7674 value = CompileRun("testIndexed(obj)");
7675 CHECK(value->IsNumber());
7676 CHECK_EQ(1, value->Int32Value());
7677 CHECK_EQ(42, indexed_access_count);
7678
7679 // Check that the named access check is called when invoking
7680 // functions on an object that requires access checks.
7681 CompileRun("obj.f = function() {}");
7682 CompileRun("function testCallNormal(obj) {"
7683 " for (var i = 0; i < 10; i++) obj.f();"
7684 "}");
7685 CompileRun("testCallNormal(obj)");
7686 CHECK_EQ(74, named_access_count);
7687
7688 // Force obj into slow case.
7689 value = CompileRun("delete obj.prop");
7690 CHECK(value->BooleanValue());
7691 // Force inline caches into dictionary probing mode.
7692 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7693 // Test that the named access check is called.
7694 value = CompileRun("testProp(obj);");
7695 CHECK(value->IsNumber());
7696 CHECK_EQ(1, value->Int32Value());
7697 CHECK_EQ(96, named_access_count);
7698
7699 // Force the call inline cache into dictionary probing mode.
7700 CompileRun("o.f = function() {}; testCallNormal(o)");
7701 // Test that the named access check is still called for each
7702 // invocation of the function.
7703 value = CompileRun("testCallNormal(obj)");
7704 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007705
7706 context1->Exit();
7707 context0->Exit();
7708 context1.Dispose();
7709 context0.Dispose();
7710}
7711
7712
7713static bool NamedAccessFlatten(Local<v8::Object> global,
7714 Local<Value> name,
7715 v8::AccessType type,
7716 Local<Value> data) {
7717 char buf[100];
7718 int len;
7719
7720 CHECK(name->IsString());
7721
7722 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007723 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007724 CHECK_EQ(4, len);
7725
7726 uint16_t buf2[100];
7727
7728 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007729 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007730 CHECK_EQ(4, len);
7731
7732 return true;
7733}
7734
7735
7736static bool IndexedAccessFlatten(Local<v8::Object> global,
7737 uint32_t key,
7738 v8::AccessType type,
7739 Local<Value> data) {
7740 return true;
7741}
7742
7743
7744// Regression test. In access checks, operations that may cause
7745// garbage collection are not allowed. It used to be the case that
7746// using the Write operation on a string could cause a garbage
7747// collection due to flattening of the string. This is no longer the
7748// case.
7749THREADED_TEST(AccessControlFlatten) {
7750 named_access_count = 0;
7751 indexed_access_count = 0;
7752
7753 v8::HandleScope handle_scope;
7754
7755 // Create an environment.
7756 v8::Persistent<Context> context0 = Context::New();
7757 context0->Enter();
7758
7759 // Create an object that requires access-check functions to be
7760 // called for cross-domain access.
7761 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7762 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7763 IndexedAccessFlatten);
7764 Local<v8::Object> object = object_template->NewInstance();
7765
7766 v8::HandleScope scope1;
7767
7768 // Create another environment.
7769 v8::Persistent<Context> context1 = Context::New();
7770 context1->Enter();
7771
7772 // Make easy access to the object from the other environment.
7773 v8::Handle<v8::Object> global1 = context1->Global();
7774 global1->Set(v8_str("obj"), object);
7775
7776 v8::Handle<Value> value;
7777
7778 value = v8_compile("var p = 'as' + 'df';")->Run();
7779 value = v8_compile("obj[p];")->Run();
7780
7781 context1->Exit();
7782 context0->Exit();
7783 context1.Dispose();
7784 context0.Dispose();
7785}
7786
7787
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007788static v8::Handle<Value> AccessControlNamedGetter(
7789 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007790 return v8::Integer::New(42);
7791}
7792
7793
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007794static v8::Handle<Value> AccessControlNamedSetter(
7795 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007796 return value;
7797}
7798
7799
7800static v8::Handle<Value> AccessControlIndexedGetter(
7801 uint32_t index,
7802 const AccessorInfo& info) {
7803 return v8_num(42);
7804}
7805
7806
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007807static v8::Handle<Value> AccessControlIndexedSetter(
7808 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007809 return value;
7810}
7811
7812
7813THREADED_TEST(AccessControlInterceptorIC) {
7814 named_access_count = 0;
7815 indexed_access_count = 0;
7816
7817 v8::HandleScope handle_scope;
7818
7819 // Create an environment.
7820 v8::Persistent<Context> context0 = Context::New();
7821 context0->Enter();
7822
7823 // Create an object that requires access-check functions to be
7824 // called for cross-domain access. The object also has interceptors
7825 // interceptor.
7826 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7827 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7828 IndexedAccessCounter);
7829 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7830 AccessControlNamedSetter);
7831 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7832 AccessControlIndexedSetter);
7833 Local<v8::Object> object = object_template->NewInstance();
7834
7835 v8::HandleScope scope1;
7836
7837 // Create another environment.
7838 v8::Persistent<Context> context1 = Context::New();
7839 context1->Enter();
7840
7841 // Make easy access to the object from the other environment.
7842 v8::Handle<v8::Object> global1 = context1->Global();
7843 global1->Set(v8_str("obj"), object);
7844
7845 v8::Handle<Value> value;
7846
7847 // Check that the named access-control function is called every time
7848 // eventhough there is an interceptor on the object.
7849 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7850 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7851 "obj.x")->Run();
7852 CHECK(value->IsNumber());
7853 CHECK_EQ(42, value->Int32Value());
7854 CHECK_EQ(21, named_access_count);
7855
7856 value = v8_compile("var p = 'x';")->Run();
7857 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7858 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7859 "obj[p]")->Run();
7860 CHECK(value->IsNumber());
7861 CHECK_EQ(42, value->Int32Value());
7862 CHECK_EQ(42, named_access_count);
7863
7864 // Check that the indexed access-control function is called every
7865 // time eventhough there is an interceptor on the object.
7866 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7867 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7868 "obj[0]")->Run();
7869 CHECK(value->IsNumber());
7870 CHECK_EQ(42, value->Int32Value());
7871 CHECK_EQ(21, indexed_access_count);
7872
7873 context1->Exit();
7874 context0->Exit();
7875 context1.Dispose();
7876 context0.Dispose();
7877}
7878
7879
7880THREADED_TEST(Version) {
7881 v8::V8::GetVersion();
7882}
7883
7884
7885static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7886 ApiTestFuzzer::Fuzz();
7887 return v8_num(12);
7888}
7889
7890
7891THREADED_TEST(InstanceProperties) {
7892 v8::HandleScope handle_scope;
7893 LocalContext context;
7894
7895 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7896 Local<ObjectTemplate> instance = t->InstanceTemplate();
7897
7898 instance->Set(v8_str("x"), v8_num(42));
7899 instance->Set(v8_str("f"),
7900 v8::FunctionTemplate::New(InstanceFunctionCallback));
7901
7902 Local<Value> o = t->GetFunction()->NewInstance();
7903
7904 context->Global()->Set(v8_str("i"), o);
7905 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7906 CHECK_EQ(42, value->Int32Value());
7907
7908 value = Script::Compile(v8_str("i.f()"))->Run();
7909 CHECK_EQ(12, value->Int32Value());
7910}
7911
7912
7913static v8::Handle<Value>
7914GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7915 ApiTestFuzzer::Fuzz();
7916 return v8::Handle<Value>();
7917}
7918
7919
7920THREADED_TEST(GlobalObjectInstanceProperties) {
7921 v8::HandleScope handle_scope;
7922
7923 Local<Value> global_object;
7924
7925 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7926 t->InstanceTemplate()->SetNamedPropertyHandler(
7927 GlobalObjectInstancePropertiesGet);
7928 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7929 instance_template->Set(v8_str("x"), v8_num(42));
7930 instance_template->Set(v8_str("f"),
7931 v8::FunctionTemplate::New(InstanceFunctionCallback));
7932
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007933 // The script to check how Crankshaft compiles missing global function
7934 // invocations. function g is not defined and should throw on call.
7935 const char* script =
7936 "function wrapper(call) {"
7937 " var x = 0, y = 1;"
7938 " for (var i = 0; i < 1000; i++) {"
7939 " x += i * 100;"
7940 " y += i * 100;"
7941 " }"
7942 " if (call) g();"
7943 "}"
7944 "for (var i = 0; i < 17; i++) wrapper(false);"
7945 "var thrown = 0;"
7946 "try { wrapper(true); } catch (e) { thrown = 1; };"
7947 "thrown";
7948
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007949 {
7950 LocalContext env(NULL, instance_template);
7951 // Hold on to the global object so it can be used again in another
7952 // environment initialization.
7953 global_object = env->Global();
7954
7955 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7956 CHECK_EQ(42, value->Int32Value());
7957 value = Script::Compile(v8_str("f()"))->Run();
7958 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007959 value = Script::Compile(v8_str(script))->Run();
7960 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007961 }
7962
7963 {
7964 // Create new environment reusing the global object.
7965 LocalContext env(NULL, instance_template, global_object);
7966 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7967 CHECK_EQ(42, value->Int32Value());
7968 value = Script::Compile(v8_str("f()"))->Run();
7969 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007970 value = Script::Compile(v8_str(script))->Run();
7971 CHECK_EQ(1, value->Int32Value());
7972 }
7973}
7974
7975
7976THREADED_TEST(CallKnownGlobalReceiver) {
7977 v8::HandleScope handle_scope;
7978
7979 Local<Value> global_object;
7980
7981 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7982 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7983
7984 // The script to check that we leave global object not
7985 // global object proxy on stack when we deoptimize from inside
7986 // arguments evaluation.
7987 // To provoke error we need to both force deoptimization
7988 // from arguments evaluation and to force CallIC to take
7989 // CallIC_Miss code path that can't cope with global proxy.
7990 const char* script =
7991 "function bar(x, y) { try { } finally { } }"
7992 "function baz(x) { try { } finally { } }"
7993 "function bom(x) { try { } finally { } }"
7994 "function foo(x) { bar([x], bom(2)); }"
7995 "for (var i = 0; i < 10000; i++) foo(1);"
7996 "foo";
7997
7998 Local<Value> foo;
7999 {
8000 LocalContext env(NULL, instance_template);
8001 // Hold on to the global object so it can be used again in another
8002 // environment initialization.
8003 global_object = env->Global();
8004 foo = Script::Compile(v8_str(script))->Run();
8005 }
8006
8007 {
8008 // Create new environment reusing the global object.
8009 LocalContext env(NULL, instance_template, global_object);
8010 env->Global()->Set(v8_str("foo"), foo);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008011 Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008012 }
8013}
8014
8015
8016static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
8017 ApiTestFuzzer::Fuzz();
8018 return v8_num(42);
8019}
8020
8021
8022static int shadow_y;
8023static int shadow_y_setter_call_count;
8024static int shadow_y_getter_call_count;
8025
8026
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008027static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008028 shadow_y_setter_call_count++;
8029 shadow_y = 42;
8030}
8031
8032
8033static v8::Handle<Value> ShadowYGetter(Local<String> name,
8034 const AccessorInfo& info) {
8035 ApiTestFuzzer::Fuzz();
8036 shadow_y_getter_call_count++;
8037 return v8_num(shadow_y);
8038}
8039
8040
8041static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
8042 const AccessorInfo& info) {
8043 return v8::Handle<Value>();
8044}
8045
8046
8047static v8::Handle<Value> ShadowNamedGet(Local<String> key,
8048 const AccessorInfo&) {
8049 return v8::Handle<Value>();
8050}
8051
8052
8053THREADED_TEST(ShadowObject) {
8054 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
8055 v8::HandleScope handle_scope;
8056
8057 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
8058 LocalContext context(NULL, global_template);
8059
8060 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8061 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
8062 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
8063 Local<ObjectTemplate> proto = t->PrototypeTemplate();
8064 Local<ObjectTemplate> instance = t->InstanceTemplate();
8065
8066 // Only allow calls of f on instances of t.
8067 Local<v8::Signature> signature = v8::Signature::New(t);
8068 proto->Set(v8_str("f"),
8069 v8::FunctionTemplate::New(ShadowFunctionCallback,
8070 Local<Value>(),
8071 signature));
8072 proto->Set(v8_str("x"), v8_num(12));
8073
8074 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
8075
8076 Local<Value> o = t->GetFunction()->NewInstance();
8077 context->Global()->Set(v8_str("__proto__"), o);
8078
8079 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008080 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008081 CHECK(value->IsBoolean());
8082 CHECK(!value->BooleanValue());
8083
8084 value = Script::Compile(v8_str("x"))->Run();
8085 CHECK_EQ(12, value->Int32Value());
8086
8087 value = Script::Compile(v8_str("f()"))->Run();
8088 CHECK_EQ(42, value->Int32Value());
8089
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008090 Script::Compile(v8_str("y = 43"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008091 CHECK_EQ(1, shadow_y_setter_call_count);
8092 value = Script::Compile(v8_str("y"))->Run();
8093 CHECK_EQ(1, shadow_y_getter_call_count);
8094 CHECK_EQ(42, value->Int32Value());
8095}
8096
8097
8098THREADED_TEST(HiddenPrototype) {
8099 v8::HandleScope handle_scope;
8100 LocalContext context;
8101
8102 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8103 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8104 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8105 t1->SetHiddenPrototype(true);
8106 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8107 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8108 t2->SetHiddenPrototype(true);
8109 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8110 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8111 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8112
8113 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8114 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8115 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8116 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8117
8118 // Setting the prototype on an object skips hidden prototypes.
8119 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8120 o0->Set(v8_str("__proto__"), o1);
8121 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8122 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8123 o0->Set(v8_str("__proto__"), o2);
8124 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8125 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8126 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8127 o0->Set(v8_str("__proto__"), o3);
8128 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8129 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8130 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8131 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8132
8133 // Getting the prototype of o0 should get the first visible one
8134 // which is o3. Therefore, z should not be defined on the prototype
8135 // object.
8136 Local<Value> proto = o0->Get(v8_str("__proto__"));
8137 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008138 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008139}
8140
8141
ager@chromium.org5c838252010-02-19 08:53:10 +00008142THREADED_TEST(SetPrototype) {
8143 v8::HandleScope handle_scope;
8144 LocalContext context;
8145
8146 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8147 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8148 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8149 t1->SetHiddenPrototype(true);
8150 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8151 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8152 t2->SetHiddenPrototype(true);
8153 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8154 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8155 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8156
8157 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8158 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8159 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8160 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8161
8162 // Setting the prototype on an object does not skip hidden prototypes.
8163 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8164 CHECK(o0->SetPrototype(o1));
8165 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8166 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8167 CHECK(o1->SetPrototype(o2));
8168 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8169 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8170 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8171 CHECK(o2->SetPrototype(o3));
8172 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8173 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8174 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8175 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8176
8177 // Getting the prototype of o0 should get the first visible one
8178 // which is o3. Therefore, z should not be defined on the prototype
8179 // object.
8180 Local<Value> proto = o0->Get(v8_str("__proto__"));
8181 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008182 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008183
8184 // However, Object::GetPrototype ignores hidden prototype.
8185 Local<Value> proto0 = o0->GetPrototype();
8186 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008187 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00008188
8189 Local<Value> proto1 = o1->GetPrototype();
8190 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008191 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00008192
8193 Local<Value> proto2 = o2->GetPrototype();
8194 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008195 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008196}
8197
8198
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008199// Getting property names of an object with a prototype chain that
8200// triggers dictionary elements in GetLocalPropertyNames() shouldn't
8201// crash the runtime.
8202THREADED_TEST(Regress91517) {
8203 i::FLAG_allow_natives_syntax = true;
8204 v8::HandleScope handle_scope;
8205 LocalContext context;
8206
8207 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8208 t1->SetHiddenPrototype(true);
8209 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
8210 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8211 t2->SetHiddenPrototype(true);
8212 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
8213 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
8214 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
8215 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8216 t3->SetHiddenPrototype(true);
8217 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8218 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8219 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8220
8221 // Force dictionary-based properties.
8222 i::ScopedVector<char> name_buf(1024);
8223 for (int i = 1; i <= 1000; i++) {
8224 i::OS::SNPrintF(name_buf, "sdf%d", i);
8225 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8226 }
8227
8228 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8229 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8230 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8231 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8232
8233 // Create prototype chain of hidden prototypes.
8234 CHECK(o4->SetPrototype(o3));
8235 CHECK(o3->SetPrototype(o2));
8236 CHECK(o2->SetPrototype(o1));
8237
8238 // Call the runtime version of GetLocalPropertyNames() on the natively
8239 // created object through JavaScript.
8240 context->Global()->Set(v8_str("obj"), o4);
8241 CompileRun("var names = %GetLocalPropertyNames(obj);");
8242
8243 ExpectInt32("names.length", 1006);
8244 ExpectTrue("names.indexOf(\"baz\") >= 0");
8245 ExpectTrue("names.indexOf(\"boo\") >= 0");
8246 ExpectTrue("names.indexOf(\"foo\") >= 0");
8247 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8248 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8249 ExpectFalse("names[1005] == undefined");
8250}
8251
8252
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008253THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00008254 v8::HandleScope handle_scope;
8255 LocalContext context;
8256
8257 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008258 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8259 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00008260 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008261 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008262 CHECK(CompileRun(
8263 "(function() {"
8264 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008265 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008266 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008267 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8268 CHECK_EQ(42,
8269 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008270
8271 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008272 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00008273 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008274 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008275 CHECK(CompileRun(
8276 "(function() {"
8277 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008278 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008279 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008280 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008281}
8282
8283
ager@chromium.org5c838252010-02-19 08:53:10 +00008284THREADED_TEST(SetPrototypeThrows) {
8285 v8::HandleScope handle_scope;
8286 LocalContext context;
8287
8288 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8289
8290 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8291 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8292
8293 CHECK(o0->SetPrototype(o1));
8294 // If setting the prototype leads to the cycle, SetPrototype should
8295 // return false and keep VM in sane state.
8296 v8::TryCatch try_catch;
8297 CHECK(!o1->SetPrototype(o0));
8298 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00008300
8301 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8302}
8303
8304
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008305THREADED_TEST(GetterSetterExceptions) {
8306 v8::HandleScope handle_scope;
8307 LocalContext context;
8308 CompileRun(
8309 "function Foo() { };"
8310 "function Throw() { throw 5; };"
8311 "var x = { };"
8312 "x.__defineSetter__('set', Throw);"
8313 "x.__defineGetter__('get', Throw);");
8314 Local<v8::Object> x =
8315 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8316 v8::TryCatch try_catch;
8317 x->Set(v8_str("set"), v8::Integer::New(8));
8318 x->Get(v8_str("get"));
8319 x->Set(v8_str("set"), v8::Integer::New(8));
8320 x->Get(v8_str("get"));
8321 x->Set(v8_str("set"), v8::Integer::New(8));
8322 x->Get(v8_str("get"));
8323 x->Set(v8_str("set"), v8::Integer::New(8));
8324 x->Get(v8_str("get"));
8325}
8326
8327
8328THREADED_TEST(Constructor) {
8329 v8::HandleScope handle_scope;
8330 LocalContext context;
8331 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8332 templ->SetClassName(v8_str("Fun"));
8333 Local<Function> cons = templ->GetFunction();
8334 context->Global()->Set(v8_str("Fun"), cons);
8335 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008336 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008337 CHECK(obj->IsJSObject());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008338 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8339 CHECK(value->BooleanValue());
8340}
8341
lrn@chromium.org1c092762011-05-09 09:42:16 +00008342
8343static Handle<Value> ConstructorCallback(const Arguments& args) {
8344 ApiTestFuzzer::Fuzz();
8345 Local<Object> This;
8346
8347 if (args.IsConstructCall()) {
8348 Local<Object> Holder = args.Holder();
8349 This = Object::New();
8350 Local<Value> proto = Holder->GetPrototype();
8351 if (proto->IsObject()) {
8352 This->SetPrototype(proto);
8353 }
8354 } else {
8355 This = args.This();
8356 }
8357
8358 This->Set(v8_str("a"), args[0]);
8359 return This;
8360}
8361
8362
8363static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8364 ApiTestFuzzer::Fuzz();
8365 return args[0];
8366}
8367
8368
8369THREADED_TEST(ConstructorForObject) {
8370 v8::HandleScope handle_scope;
8371 LocalContext context;
8372
8373 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8374 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8375 Local<Object> instance = instance_template->NewInstance();
8376 context->Global()->Set(v8_str("obj"), instance);
8377 v8::TryCatch try_catch;
8378 Local<Value> value;
8379 CHECK(!try_catch.HasCaught());
8380
8381 // Call the Object's constructor with a 32-bit signed integer.
8382 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8383 CHECK(!try_catch.HasCaught());
8384 CHECK(value->IsInt32());
8385 CHECK_EQ(28, value->Int32Value());
8386
8387 Local<Value> args1[] = { v8_num(28) };
8388 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8389 CHECK(value_obj1->IsObject());
8390 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8391 value = object1->Get(v8_str("a"));
8392 CHECK(value->IsInt32());
8393 CHECK(!try_catch.HasCaught());
8394 CHECK_EQ(28, value->Int32Value());
8395
8396 // Call the Object's constructor with a String.
8397 value = CompileRun(
8398 "(function() { var o = new obj('tipli'); return o.a; })()");
8399 CHECK(!try_catch.HasCaught());
8400 CHECK(value->IsString());
8401 String::AsciiValue string_value1(value->ToString());
8402 CHECK_EQ("tipli", *string_value1);
8403
8404 Local<Value> args2[] = { v8_str("tipli") };
8405 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8406 CHECK(value_obj2->IsObject());
8407 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8408 value = object2->Get(v8_str("a"));
8409 CHECK(!try_catch.HasCaught());
8410 CHECK(value->IsString());
8411 String::AsciiValue string_value2(value->ToString());
8412 CHECK_EQ("tipli", *string_value2);
8413
8414 // Call the Object's constructor with a Boolean.
8415 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8416 CHECK(!try_catch.HasCaught());
8417 CHECK(value->IsBoolean());
8418 CHECK_EQ(true, value->BooleanValue());
8419
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008420 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00008421 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8422 CHECK(value_obj3->IsObject());
8423 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8424 value = object3->Get(v8_str("a"));
8425 CHECK(!try_catch.HasCaught());
8426 CHECK(value->IsBoolean());
8427 CHECK_EQ(true, value->BooleanValue());
8428
8429 // Call the Object's constructor with undefined.
8430 Handle<Value> args4[] = { v8::Undefined() };
8431 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8432 CHECK(value_obj4->IsObject());
8433 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8434 value = object4->Get(v8_str("a"));
8435 CHECK(!try_catch.HasCaught());
8436 CHECK(value->IsUndefined());
8437
8438 // Call the Object's constructor with null.
8439 Handle<Value> args5[] = { v8::Null() };
8440 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8441 CHECK(value_obj5->IsObject());
8442 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8443 value = object5->Get(v8_str("a"));
8444 CHECK(!try_catch.HasCaught());
8445 CHECK(value->IsNull());
8446 }
8447
8448 // Check exception handling when there is no constructor set for the Object.
8449 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8450 Local<Object> instance = instance_template->NewInstance();
8451 context->Global()->Set(v8_str("obj2"), instance);
8452 v8::TryCatch try_catch;
8453 Local<Value> value;
8454 CHECK(!try_catch.HasCaught());
8455
8456 value = CompileRun("new obj2(28)");
8457 CHECK(try_catch.HasCaught());
8458 String::AsciiValue exception_value1(try_catch.Exception());
8459 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8460 try_catch.Reset();
8461
8462 Local<Value> args[] = { v8_num(29) };
8463 value = instance->CallAsConstructor(1, args);
8464 CHECK(try_catch.HasCaught());
8465 String::AsciiValue exception_value2(try_catch.Exception());
8466 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8467 try_catch.Reset();
8468 }
8469
8470 // Check the case when constructor throws exception.
8471 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8472 instance_template->SetCallAsFunctionHandler(ThrowValue);
8473 Local<Object> instance = instance_template->NewInstance();
8474 context->Global()->Set(v8_str("obj3"), instance);
8475 v8::TryCatch try_catch;
8476 Local<Value> value;
8477 CHECK(!try_catch.HasCaught());
8478
8479 value = CompileRun("new obj3(22)");
8480 CHECK(try_catch.HasCaught());
8481 String::AsciiValue exception_value1(try_catch.Exception());
8482 CHECK_EQ("22", *exception_value1);
8483 try_catch.Reset();
8484
8485 Local<Value> args[] = { v8_num(23) };
8486 value = instance->CallAsConstructor(1, args);
8487 CHECK(try_catch.HasCaught());
8488 String::AsciiValue exception_value2(try_catch.Exception());
8489 CHECK_EQ("23", *exception_value2);
8490 try_catch.Reset();
8491 }
8492
8493 // Check whether constructor returns with an object or non-object.
8494 { Local<FunctionTemplate> function_template =
8495 FunctionTemplate::New(FakeConstructorCallback);
8496 Local<Function> function = function_template->GetFunction();
8497 Local<Object> instance1 = function;
8498 context->Global()->Set(v8_str("obj4"), instance1);
8499 v8::TryCatch try_catch;
8500 Local<Value> value;
8501 CHECK(!try_catch.HasCaught());
8502
8503 CHECK(instance1->IsObject());
8504 CHECK(instance1->IsFunction());
8505
8506 value = CompileRun("new obj4(28)");
8507 CHECK(!try_catch.HasCaught());
8508 CHECK(value->IsObject());
8509
8510 Local<Value> args1[] = { v8_num(28) };
8511 value = instance1->CallAsConstructor(1, args1);
8512 CHECK(!try_catch.HasCaught());
8513 CHECK(value->IsObject());
8514
8515 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8516 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8517 Local<Object> instance2 = instance_template->NewInstance();
8518 context->Global()->Set(v8_str("obj5"), instance2);
8519 CHECK(!try_catch.HasCaught());
8520
8521 CHECK(instance2->IsObject());
8522 CHECK(!instance2->IsFunction());
8523
8524 value = CompileRun("new obj5(28)");
8525 CHECK(!try_catch.HasCaught());
8526 CHECK(!value->IsObject());
8527
8528 Local<Value> args2[] = { v8_num(28) };
8529 value = instance2->CallAsConstructor(1, args2);
8530 CHECK(!try_catch.HasCaught());
8531 CHECK(!value->IsObject());
8532 }
8533}
8534
8535
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008536THREADED_TEST(FunctionDescriptorException) {
8537 v8::HandleScope handle_scope;
8538 LocalContext context;
8539 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8540 templ->SetClassName(v8_str("Fun"));
8541 Local<Function> cons = templ->GetFunction();
8542 context->Global()->Set(v8_str("Fun"), cons);
8543 Local<Value> value = CompileRun(
8544 "function test() {"
8545 " try {"
8546 " (new Fun()).blah()"
8547 " } catch (e) {"
8548 " var str = String(e);"
8549 " if (str.indexOf('TypeError') == -1) return 1;"
8550 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00008551 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008552 " return 0;"
8553 " }"
8554 " return 4;"
8555 "}"
8556 "test();");
8557 CHECK_EQ(0, value->Int32Value());
8558}
8559
8560
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008561THREADED_TEST(EvalAliasedDynamic) {
8562 v8::HandleScope scope;
8563 LocalContext current;
8564
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008565 // Tests where aliased eval can only be resolved dynamically.
8566 Local<Script> script =
8567 Script::Compile(v8_str("function f(x) { "
8568 " var foo = 2;"
8569 " with (x) { return eval('foo'); }"
8570 "}"
8571 "foo = 0;"
8572 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008573 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008574 "var x = new Object();"
8575 "x.eval = function(x) { return 1; };"
8576 "result3 = f(x);"));
8577 script->Run();
8578 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8579 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8580 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8581
8582 v8::TryCatch try_catch;
8583 script =
8584 Script::Compile(v8_str("function f(x) { "
8585 " var bar = 2;"
8586 " with (x) { return eval('bar'); }"
8587 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008588 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008589 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008590 CHECK(!try_catch.HasCaught());
8591 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8592
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008593 try_catch.Reset();
8594}
8595
8596
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008597THREADED_TEST(CrossEval) {
8598 v8::HandleScope scope;
8599 LocalContext other;
8600 LocalContext current;
8601
8602 Local<String> token = v8_str("<security token>");
8603 other->SetSecurityToken(token);
8604 current->SetSecurityToken(token);
8605
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008606 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008607 current->Global()->Set(v8_str("other"), other->Global());
8608
8609 // Check that new variables are introduced in other context.
8610 Local<Script> script =
8611 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8612 script->Run();
8613 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8614 CHECK_EQ(1234, foo->Int32Value());
8615 CHECK(!current->Global()->Has(v8_str("foo")));
8616
8617 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008618 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008619 script =
8620 Script::Compile(v8_str("other.eval('na = 1234')"));
8621 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008622 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8623 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008624
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008625 // Check that global variables in current context are not visible in other
8626 // context.
8627 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008628 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008629 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008630 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008631 CHECK(try_catch.HasCaught());
8632 try_catch.Reset();
8633
8634 // Check that local variables in current context are not visible in other
8635 // context.
8636 script =
8637 Script::Compile(v8_str("(function() { "
8638 " var baz = 87;"
8639 " return other.eval('baz');"
8640 "})();"));
8641 result = script->Run();
8642 CHECK(try_catch.HasCaught());
8643 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008644
8645 // Check that global variables in the other environment are visible
8646 // when evaluting code.
8647 other->Global()->Set(v8_str("bis"), v8_num(1234));
8648 script = Script::Compile(v8_str("other.eval('bis')"));
8649 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008650 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008651
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008652 // Check that the 'this' pointer points to the global object evaluating
8653 // code.
8654 other->Global()->Set(v8_str("t"), other->Global());
8655 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008656 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008657 CHECK(result->IsTrue());
8658 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008659
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008660 // Check that variables introduced in with-statement are not visible in
8661 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008662 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008663 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008664 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008665 CHECK(try_catch.HasCaught());
8666 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008667
8668 // Check that you cannot use 'eval.call' with another object than the
8669 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008670 script =
8671 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8672 result = script->Run();
8673 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008674}
8675
8676
ager@chromium.orge2902be2009-06-08 12:21:35 +00008677// Test that calling eval in a context which has been detached from
8678// its global throws an exception. This behavior is consistent with
8679// other JavaScript implementations.
8680THREADED_TEST(EvalInDetachedGlobal) {
8681 v8::HandleScope scope;
8682
8683 v8::Persistent<Context> context0 = Context::New();
8684 v8::Persistent<Context> context1 = Context::New();
8685
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008686 // Set up function in context0 that uses eval from context0.
ager@chromium.orge2902be2009-06-08 12:21:35 +00008687 context0->Enter();
8688 v8::Handle<v8::Value> fun =
8689 CompileRun("var x = 42;"
8690 "(function() {"
8691 " var e = eval;"
8692 " return function(s) { return e(s); }"
8693 "})()");
8694 context0->Exit();
8695
8696 // Put the function into context1 and call it before and after
8697 // detaching the global. Before detaching, the call succeeds and
8698 // after detaching and exception is thrown.
8699 context1->Enter();
8700 context1->Global()->Set(v8_str("fun"), fun);
8701 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8702 CHECK_EQ(42, x_value->Int32Value());
8703 context0->DetachGlobal();
8704 v8::TryCatch catcher;
8705 x_value = CompileRun("fun('x')");
8706 CHECK(x_value.IsEmpty());
8707 CHECK(catcher.HasCaught());
8708 context1->Exit();
8709
8710 context1.Dispose();
8711 context0.Dispose();
8712}
8713
8714
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008715THREADED_TEST(CrossLazyLoad) {
8716 v8::HandleScope scope;
8717 LocalContext other;
8718 LocalContext current;
8719
8720 Local<String> token = v8_str("<security token>");
8721 other->SetSecurityToken(token);
8722 current->SetSecurityToken(token);
8723
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008724 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008725 current->Global()->Set(v8_str("other"), other->Global());
8726
8727 // Trigger lazy loading in other context.
8728 Local<Script> script =
8729 Script::Compile(v8_str("other.eval('new Date(42)')"));
8730 Local<Value> value = script->Run();
8731 CHECK_EQ(42.0, value->NumberValue());
8732}
8733
8734
8735static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8736 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008737 if (args.IsConstructCall()) {
8738 if (args[0]->IsInt32()) {
8739 return v8_num(-args[0]->Int32Value());
8740 }
8741 }
8742
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008743 return args[0];
8744}
8745
8746
8747// Test that a call handler can be set for objects which will allow
8748// non-function objects created through the API to be called as
8749// functions.
8750THREADED_TEST(CallAsFunction) {
8751 v8::HandleScope scope;
8752 LocalContext context;
8753
lrn@chromium.org1c092762011-05-09 09:42:16 +00008754 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8755 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8756 instance_template->SetCallAsFunctionHandler(call_as_function);
8757 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8758 context->Global()->Set(v8_str("obj"), instance);
8759 v8::TryCatch try_catch;
8760 Local<Value> value;
8761 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008762
lrn@chromium.org1c092762011-05-09 09:42:16 +00008763 value = CompileRun("obj(42)");
8764 CHECK(!try_catch.HasCaught());
8765 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008766
lrn@chromium.org1c092762011-05-09 09:42:16 +00008767 value = CompileRun("(function(o){return o(49)})(obj)");
8768 CHECK(!try_catch.HasCaught());
8769 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008770
lrn@chromium.org1c092762011-05-09 09:42:16 +00008771 // test special case of call as function
8772 value = CompileRun("[obj]['0'](45)");
8773 CHECK(!try_catch.HasCaught());
8774 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008775
lrn@chromium.org1c092762011-05-09 09:42:16 +00008776 value = CompileRun("obj.call = Function.prototype.call;"
8777 "obj.call(null, 87)");
8778 CHECK(!try_catch.HasCaught());
8779 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008780
lrn@chromium.org1c092762011-05-09 09:42:16 +00008781 // Regression tests for bug #1116356: Calling call through call/apply
8782 // must work for non-function receivers.
8783 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8784 value = CompileRun(apply_99);
8785 CHECK(!try_catch.HasCaught());
8786 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008787
lrn@chromium.org1c092762011-05-09 09:42:16 +00008788 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8789 value = CompileRun(call_17);
8790 CHECK(!try_catch.HasCaught());
8791 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008792
lrn@chromium.org1c092762011-05-09 09:42:16 +00008793 // Check that the call-as-function handler can be called through
8794 // new.
8795 value = CompileRun("new obj(43)");
8796 CHECK(!try_catch.HasCaught());
8797 CHECK_EQ(-43, value->Int32Value());
8798
8799 // Check that the call-as-function handler can be called through
8800 // the API.
8801 v8::Handle<Value> args[] = { v8_num(28) };
8802 value = instance->CallAsFunction(instance, 1, args);
8803 CHECK(!try_catch.HasCaught());
8804 CHECK_EQ(28, value->Int32Value());
8805 }
8806
8807 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008808 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008809 USE(instance_template);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008810 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8811 context->Global()->Set(v8_str("obj2"), instance);
8812 v8::TryCatch try_catch;
8813 Local<Value> value;
8814 CHECK(!try_catch.HasCaught());
8815
8816 // Call an object without call-as-function handler through the JS
8817 value = CompileRun("obj2(28)");
8818 CHECK(value.IsEmpty());
8819 CHECK(try_catch.HasCaught());
8820 String::AsciiValue exception_value1(try_catch.Exception());
8821 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8822 *exception_value1);
8823 try_catch.Reset();
8824
8825 // Call an object without call-as-function handler through the API
8826 value = CompileRun("obj2(28)");
8827 v8::Handle<Value> args[] = { v8_num(28) };
8828 value = instance->CallAsFunction(instance, 1, args);
8829 CHECK(value.IsEmpty());
8830 CHECK(try_catch.HasCaught());
8831 String::AsciiValue exception_value2(try_catch.Exception());
8832 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8833 try_catch.Reset();
8834 }
8835
8836 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8837 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8838 instance_template->SetCallAsFunctionHandler(ThrowValue);
8839 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8840 context->Global()->Set(v8_str("obj3"), instance);
8841 v8::TryCatch try_catch;
8842 Local<Value> value;
8843 CHECK(!try_catch.HasCaught());
8844
8845 // Catch the exception which is thrown by call-as-function handler
8846 value = CompileRun("obj3(22)");
8847 CHECK(try_catch.HasCaught());
8848 String::AsciiValue exception_value1(try_catch.Exception());
8849 CHECK_EQ("22", *exception_value1);
8850 try_catch.Reset();
8851
8852 v8::Handle<Value> args[] = { v8_num(23) };
8853 value = instance->CallAsFunction(instance, 1, args);
8854 CHECK(try_catch.HasCaught());
8855 String::AsciiValue exception_value2(try_catch.Exception());
8856 CHECK_EQ("23", *exception_value2);
8857 try_catch.Reset();
8858 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008859}
8860
8861
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008862// Check whether a non-function object is callable.
8863THREADED_TEST(CallableObject) {
8864 v8::HandleScope scope;
8865 LocalContext context;
8866
8867 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8868 instance_template->SetCallAsFunctionHandler(call_as_function);
8869 Local<Object> instance = instance_template->NewInstance();
8870 v8::TryCatch try_catch;
8871
8872 CHECK(instance->IsCallable());
8873 CHECK(!try_catch.HasCaught());
8874 }
8875
8876 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8877 Local<Object> instance = instance_template->NewInstance();
8878 v8::TryCatch try_catch;
8879
8880 CHECK(!instance->IsCallable());
8881 CHECK(!try_catch.HasCaught());
8882 }
8883
8884 { Local<FunctionTemplate> function_template =
8885 FunctionTemplate::New(call_as_function);
8886 Local<Function> function = function_template->GetFunction();
8887 Local<Object> instance = function;
8888 v8::TryCatch try_catch;
8889
8890 CHECK(instance->IsCallable());
8891 CHECK(!try_catch.HasCaught());
8892 }
8893
8894 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8895 Local<Function> function = function_template->GetFunction();
8896 Local<Object> instance = function;
8897 v8::TryCatch try_catch;
8898
8899 CHECK(instance->IsCallable());
8900 CHECK(!try_catch.HasCaught());
8901 }
8902}
8903
8904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008905static int CountHandles() {
8906 return v8::HandleScope::NumberOfHandles();
8907}
8908
8909
8910static int Recurse(int depth, int iterations) {
8911 v8::HandleScope scope;
8912 if (depth == 0) return CountHandles();
8913 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008914 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008915 }
8916 return Recurse(depth - 1, iterations);
8917}
8918
8919
8920THREADED_TEST(HandleIteration) {
8921 static const int kIterations = 500;
8922 static const int kNesting = 200;
8923 CHECK_EQ(0, CountHandles());
8924 {
8925 v8::HandleScope scope1;
8926 CHECK_EQ(0, CountHandles());
8927 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008928 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008929 CHECK_EQ(i + 1, CountHandles());
8930 }
8931
8932 CHECK_EQ(kIterations, CountHandles());
8933 {
8934 v8::HandleScope scope2;
8935 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008936 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008937 CHECK_EQ(j + 1 + kIterations, CountHandles());
8938 }
8939 }
8940 CHECK_EQ(kIterations, CountHandles());
8941 }
8942 CHECK_EQ(0, CountHandles());
8943 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8944}
8945
8946
8947static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8948 Local<String> name,
8949 const AccessorInfo& info) {
8950 ApiTestFuzzer::Fuzz();
8951 return v8::Handle<Value>();
8952}
8953
8954
8955THREADED_TEST(InterceptorHasOwnProperty) {
8956 v8::HandleScope scope;
8957 LocalContext context;
8958 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8959 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8960 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8961 Local<Function> function = fun_templ->GetFunction();
8962 context->Global()->Set(v8_str("constructor"), function);
8963 v8::Handle<Value> value = CompileRun(
8964 "var o = new constructor();"
8965 "o.hasOwnProperty('ostehaps');");
8966 CHECK_EQ(false, value->BooleanValue());
8967 value = CompileRun(
8968 "o.ostehaps = 42;"
8969 "o.hasOwnProperty('ostehaps');");
8970 CHECK_EQ(true, value->BooleanValue());
8971 value = CompileRun(
8972 "var p = new constructor();"
8973 "p.hasOwnProperty('ostehaps');");
8974 CHECK_EQ(false, value->BooleanValue());
8975}
8976
8977
ager@chromium.org9085a012009-05-11 19:22:57 +00008978static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8979 Local<String> name,
8980 const AccessorInfo& info) {
8981 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008982 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00008983 return v8::Handle<Value>();
8984}
8985
8986
8987THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8988 v8::HandleScope scope;
8989 LocalContext context;
8990 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8991 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8992 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8993 Local<Function> function = fun_templ->GetFunction();
8994 context->Global()->Set(v8_str("constructor"), function);
8995 // Let's first make some stuff so we can be sure to get a good GC.
8996 CompileRun(
8997 "function makestr(size) {"
8998 " switch (size) {"
8999 " case 1: return 'f';"
9000 " case 2: return 'fo';"
9001 " case 3: return 'foo';"
9002 " }"
9003 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
9004 "}"
9005 "var x = makestr(12345);"
9006 "x = makestr(31415);"
9007 "x = makestr(23456);");
9008 v8::Handle<Value> value = CompileRun(
9009 "var o = new constructor();"
9010 "o.__proto__ = new String(x);"
9011 "o.hasOwnProperty('ostehaps');");
9012 CHECK_EQ(false, value->BooleanValue());
9013}
9014
9015
ager@chromium.orge2902be2009-06-08 12:21:35 +00009016typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
9017 const AccessorInfo& info);
9018
9019
9020static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
9021 const char* source,
9022 int expected) {
9023 v8::HandleScope scope;
9024 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009025 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00009026 LocalContext context;
9027 context->Global()->Set(v8_str("o"), templ->NewInstance());
9028 v8::Handle<Value> value = CompileRun(source);
9029 CHECK_EQ(expected, value->Int32Value());
9030}
9031
9032
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009033static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
9034 const AccessorInfo& info) {
9035 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009036 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9037 CHECK_EQ(isolate, info.GetIsolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009038 CHECK_EQ(v8_str("data"), info.Data());
9039 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009040 return v8::Integer::New(42);
9041}
9042
9043
9044// This test should hit the load IC for the interceptor case.
9045THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00009046 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009047 "var result = 0;"
9048 "for (var i = 0; i < 1000; i++) {"
9049 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00009050 "}",
9051 42);
9052}
9053
9054
9055// Below go several tests which verify that JITing for various
9056// configurations of interceptor and explicit fields works fine
9057// (those cases are special cased to get better performance).
9058
9059static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
9060 const AccessorInfo& info) {
9061 ApiTestFuzzer::Fuzz();
9062 return v8_str("x")->Equals(name)
9063 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
9064}
9065
9066
9067THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
9068 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9069 "var result = 0;"
9070 "o.y = 239;"
9071 "for (var i = 0; i < 1000; i++) {"
9072 " result = o.y;"
9073 "}",
9074 239);
9075}
9076
9077
9078THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
9079 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9080 "var result = 0;"
9081 "o.__proto__ = { 'y': 239 };"
9082 "for (var i = 0; i < 1000; i++) {"
9083 " result = o.y + o.x;"
9084 "}",
9085 239 + 42);
9086}
9087
9088
9089THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
9090 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9091 "var result = 0;"
9092 "o.__proto__.y = 239;"
9093 "for (var i = 0; i < 1000; i++) {"
9094 " result = o.y + o.x;"
9095 "}",
9096 239 + 42);
9097}
9098
9099
9100THREADED_TEST(InterceptorLoadICUndefined) {
9101 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9102 "var result = 0;"
9103 "for (var i = 0; i < 1000; i++) {"
9104 " result = (o.y == undefined) ? 239 : 42;"
9105 "}",
9106 239);
9107}
9108
9109
9110THREADED_TEST(InterceptorLoadICWithOverride) {
9111 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9112 "fst = new Object(); fst.__proto__ = o;"
9113 "snd = new Object(); snd.__proto__ = fst;"
9114 "var result1 = 0;"
9115 "for (var i = 0; i < 1000; i++) {"
9116 " result1 = snd.x;"
9117 "}"
9118 "fst.x = 239;"
9119 "var result = 0;"
9120 "for (var i = 0; i < 1000; i++) {"
9121 " result = snd.x;"
9122 "}"
9123 "result + result1",
9124 239 + 42);
9125}
9126
9127
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009128// Test the case when we stored field into
9129// a stub, but interceptor produced value on its own.
9130THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
9131 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9132 "proto = new Object();"
9133 "o.__proto__ = proto;"
9134 "proto.x = 239;"
9135 "for (var i = 0; i < 1000; i++) {"
9136 " o.x;"
9137 // Now it should be ICed and keep a reference to x defined on proto
9138 "}"
9139 "var result = 0;"
9140 "for (var i = 0; i < 1000; i++) {"
9141 " result += o.x;"
9142 "}"
9143 "result;",
9144 42 * 1000);
9145}
9146
9147
9148// Test the case when we stored field into
9149// a stub, but it got invalidated later on.
9150THREADED_TEST(InterceptorLoadICInvalidatedField) {
9151 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9152 "proto1 = new Object();"
9153 "proto2 = new Object();"
9154 "o.__proto__ = proto1;"
9155 "proto1.__proto__ = proto2;"
9156 "proto2.y = 239;"
9157 "for (var i = 0; i < 1000; i++) {"
9158 " o.y;"
9159 // Now it should be ICed and keep a reference to y defined on proto2
9160 "}"
9161 "proto1.y = 42;"
9162 "var result = 0;"
9163 "for (var i = 0; i < 1000; i++) {"
9164 " result += o.y;"
9165 "}"
9166 "result;",
9167 42 * 1000);
9168}
9169
9170
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00009171static int interceptor_load_not_handled_calls = 0;
9172static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
9173 const AccessorInfo& info) {
9174 ++interceptor_load_not_handled_calls;
9175 return v8::Handle<v8::Value>();
9176}
9177
9178
9179// Test how post-interceptor lookups are done in the non-cacheable
9180// case: the interceptor should not be invoked during this lookup.
9181THREADED_TEST(InterceptorLoadICPostInterceptor) {
9182 interceptor_load_not_handled_calls = 0;
9183 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
9184 "receiver = new Object();"
9185 "receiver.__proto__ = o;"
9186 "proto = new Object();"
9187 "/* Make proto a slow-case object. */"
9188 "for (var i = 0; i < 1000; i++) {"
9189 " proto[\"xxxxxxxx\" + i] = [];"
9190 "}"
9191 "proto.x = 17;"
9192 "o.__proto__ = proto;"
9193 "var result = 0;"
9194 "for (var i = 0; i < 1000; i++) {"
9195 " result += receiver.x;"
9196 "}"
9197 "result;",
9198 17 * 1000);
9199 CHECK_EQ(1000, interceptor_load_not_handled_calls);
9200}
9201
9202
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009203// Test the case when we stored field into
9204// a stub, but it got invalidated later on due to override on
9205// global object which is between interceptor and fields' holders.
9206THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
9207 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9208 "o.__proto__ = this;" // set a global to be a proto of o.
9209 "this.__proto__.y = 239;"
9210 "for (var i = 0; i < 10; i++) {"
9211 " if (o.y != 239) throw 'oops: ' + o.y;"
9212 // Now it should be ICed and keep a reference to y defined on field_holder.
9213 "}"
9214 "this.y = 42;" // Assign on a global.
9215 "var result = 0;"
9216 "for (var i = 0; i < 10; i++) {"
9217 " result += o.y;"
9218 "}"
9219 "result;",
9220 42 * 10);
9221}
9222
9223
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009224static void SetOnThis(Local<String> name,
9225 Local<Value> value,
9226 const AccessorInfo& info) {
9227 info.This()->ForceSet(name, value);
9228}
9229
9230
9231THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9232 v8::HandleScope scope;
9233 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9234 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9235 templ->SetAccessor(v8_str("y"), Return239);
9236 LocalContext context;
9237 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009238
9239 // Check the case when receiver and interceptor's holder
9240 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009241 v8::Handle<Value> value = CompileRun(
9242 "var result = 0;"
9243 "for (var i = 0; i < 7; i++) {"
9244 " result = o.y;"
9245 "}");
9246 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009247
9248 // Check the case when interceptor's holder is in proto chain
9249 // of receiver.
9250 value = CompileRun(
9251 "r = { __proto__: o };"
9252 "var result = 0;"
9253 "for (var i = 0; i < 7; i++) {"
9254 " result = r.y;"
9255 "}");
9256 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009257}
9258
9259
9260THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9261 v8::HandleScope scope;
9262 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9263 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9264 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9265 templ_p->SetAccessor(v8_str("y"), Return239);
9266
9267 LocalContext context;
9268 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9269 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9270
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009271 // Check the case when receiver and interceptor's holder
9272 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009273 v8::Handle<Value> value = CompileRun(
9274 "o.__proto__ = p;"
9275 "var result = 0;"
9276 "for (var i = 0; i < 7; i++) {"
9277 " result = o.x + o.y;"
9278 "}");
9279 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009280
9281 // Check the case when interceptor's holder is in proto chain
9282 // of receiver.
9283 value = CompileRun(
9284 "r = { __proto__: o };"
9285 "var result = 0;"
9286 "for (var i = 0; i < 7; i++) {"
9287 " result = r.x + r.y;"
9288 "}");
9289 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009290}
9291
9292
9293THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9294 v8::HandleScope scope;
9295 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9296 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9297 templ->SetAccessor(v8_str("y"), Return239);
9298
9299 LocalContext context;
9300 context->Global()->Set(v8_str("o"), templ->NewInstance());
9301
9302 v8::Handle<Value> value = CompileRun(
9303 "fst = new Object(); fst.__proto__ = o;"
9304 "snd = new Object(); snd.__proto__ = fst;"
9305 "var result1 = 0;"
9306 "for (var i = 0; i < 7; i++) {"
9307 " result1 = snd.x;"
9308 "}"
9309 "fst.x = 239;"
9310 "var result = 0;"
9311 "for (var i = 0; i < 7; i++) {"
9312 " result = snd.x;"
9313 "}"
9314 "result + result1");
9315 CHECK_EQ(239 + 42, value->Int32Value());
9316}
9317
9318
9319// Test the case when we stored callback into
9320// a stub, but interceptor produced value on its own.
9321THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9322 v8::HandleScope scope;
9323 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9324 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9325 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9326 templ_p->SetAccessor(v8_str("y"), Return239);
9327
9328 LocalContext context;
9329 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9330 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9331
9332 v8::Handle<Value> value = CompileRun(
9333 "o.__proto__ = p;"
9334 "for (var i = 0; i < 7; i++) {"
9335 " o.x;"
9336 // Now it should be ICed and keep a reference to x defined on p
9337 "}"
9338 "var result = 0;"
9339 "for (var i = 0; i < 7; i++) {"
9340 " result += o.x;"
9341 "}"
9342 "result");
9343 CHECK_EQ(42 * 7, value->Int32Value());
9344}
9345
9346
9347// Test the case when we stored callback into
9348// a stub, but it got invalidated later on.
9349THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9350 v8::HandleScope scope;
9351 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9352 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9353 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9354 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9355
9356 LocalContext context;
9357 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9358 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9359
9360 v8::Handle<Value> value = CompileRun(
9361 "inbetween = new Object();"
9362 "o.__proto__ = inbetween;"
9363 "inbetween.__proto__ = p;"
9364 "for (var i = 0; i < 10; i++) {"
9365 " o.y;"
9366 // Now it should be ICed and keep a reference to y defined on p
9367 "}"
9368 "inbetween.y = 42;"
9369 "var result = 0;"
9370 "for (var i = 0; i < 10; i++) {"
9371 " result += o.y;"
9372 "}"
9373 "result");
9374 CHECK_EQ(42 * 10, value->Int32Value());
9375}
9376
9377
9378// Test the case when we stored callback into
9379// a stub, but it got invalidated later on due to override on
9380// global object which is between interceptor and callbacks' holders.
9381THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9382 v8::HandleScope scope;
9383 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9384 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9385 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9386 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9387
9388 LocalContext context;
9389 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9390 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9391
9392 v8::Handle<Value> value = CompileRun(
9393 "o.__proto__ = this;"
9394 "this.__proto__ = p;"
9395 "for (var i = 0; i < 10; i++) {"
9396 " if (o.y != 239) throw 'oops: ' + o.y;"
9397 // Now it should be ICed and keep a reference to y defined on p
9398 "}"
9399 "this.y = 42;"
9400 "var result = 0;"
9401 "for (var i = 0; i < 10; i++) {"
9402 " result += o.y;"
9403 "}"
9404 "result");
9405 CHECK_EQ(42 * 10, value->Int32Value());
9406}
9407
9408
ager@chromium.orge2902be2009-06-08 12:21:35 +00009409static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9410 const AccessorInfo& info) {
9411 ApiTestFuzzer::Fuzz();
9412 CHECK(v8_str("x")->Equals(name));
9413 return v8::Integer::New(0);
9414}
9415
9416
9417THREADED_TEST(InterceptorReturningZero) {
9418 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9419 "o.x == undefined ? 1 : 0",
9420 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009421}
9422
9423
9424static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009425 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009426 CHECK(v8_str("x")->Equals(key));
9427 CHECK_EQ(42, value->Int32Value());
9428 return value;
9429}
9430
9431
9432// This test should hit the store IC for the interceptor case.
9433THREADED_TEST(InterceptorStoreIC) {
9434 v8::HandleScope scope;
9435 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9436 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009437 InterceptorStoreICSetter,
9438 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009439 LocalContext context;
9440 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009441 CompileRun(
9442 "for (var i = 0; i < 1000; i++) {"
9443 " o.x = 42;"
9444 "}");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009445}
9446
9447
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009448THREADED_TEST(InterceptorStoreICWithNoSetter) {
9449 v8::HandleScope scope;
9450 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9451 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9452 LocalContext context;
9453 context->Global()->Set(v8_str("o"), templ->NewInstance());
9454 v8::Handle<Value> value = CompileRun(
9455 "for (var i = 0; i < 1000; i++) {"
9456 " o.y = 239;"
9457 "}"
9458 "42 + o.y");
9459 CHECK_EQ(239 + 42, value->Int32Value());
9460}
9461
9462
9463
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009464
9465v8::Handle<Value> call_ic_function;
9466v8::Handle<Value> call_ic_function2;
9467v8::Handle<Value> call_ic_function3;
9468
9469static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9470 const AccessorInfo& info) {
9471 ApiTestFuzzer::Fuzz();
9472 CHECK(v8_str("x")->Equals(name));
9473 return call_ic_function;
9474}
9475
9476
9477// This test should hit the call IC for the interceptor case.
9478THREADED_TEST(InterceptorCallIC) {
9479 v8::HandleScope scope;
9480 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9481 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9482 LocalContext context;
9483 context->Global()->Set(v8_str("o"), templ->NewInstance());
9484 call_ic_function =
9485 v8_compile("function f(x) { return x + 1; }; f")->Run();
9486 v8::Handle<Value> value = CompileRun(
9487 "var result = 0;"
9488 "for (var i = 0; i < 1000; i++) {"
9489 " result = o.x(41);"
9490 "}");
9491 CHECK_EQ(42, value->Int32Value());
9492}
9493
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009494
9495// This test checks that if interceptor doesn't provide
9496// a value, we can fetch regular value.
9497THREADED_TEST(InterceptorCallICSeesOthers) {
9498 v8::HandleScope scope;
9499 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9500 templ->SetNamedPropertyHandler(NoBlockGetterX);
9501 LocalContext context;
9502 context->Global()->Set(v8_str("o"), templ->NewInstance());
9503 v8::Handle<Value> value = CompileRun(
9504 "o.x = function f(x) { return x + 1; };"
9505 "var result = 0;"
9506 "for (var i = 0; i < 7; i++) {"
9507 " result = o.x(41);"
9508 "}");
9509 CHECK_EQ(42, value->Int32Value());
9510}
9511
9512
9513static v8::Handle<Value> call_ic_function4;
9514static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9515 const AccessorInfo& info) {
9516 ApiTestFuzzer::Fuzz();
9517 CHECK(v8_str("x")->Equals(name));
9518 return call_ic_function4;
9519}
9520
9521
9522// This test checks that if interceptor provides a function,
9523// even if we cached shadowed variant, interceptor's function
9524// is invoked
9525THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9526 v8::HandleScope scope;
9527 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9528 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9529 LocalContext context;
9530 context->Global()->Set(v8_str("o"), templ->NewInstance());
9531 call_ic_function4 =
9532 v8_compile("function f(x) { return x - 1; }; f")->Run();
9533 v8::Handle<Value> value = CompileRun(
9534 "o.__proto__.x = function(x) { return x + 1; };"
9535 "var result = 0;"
9536 "for (var i = 0; i < 1000; i++) {"
9537 " result = o.x(42);"
9538 "}");
9539 CHECK_EQ(41, value->Int32Value());
9540}
9541
9542
9543// Test the case when we stored cacheable lookup into
9544// a stub, but it got invalidated later on
9545THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9546 v8::HandleScope scope;
9547 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9548 templ->SetNamedPropertyHandler(NoBlockGetterX);
9549 LocalContext context;
9550 context->Global()->Set(v8_str("o"), templ->NewInstance());
9551 v8::Handle<Value> value = CompileRun(
9552 "proto1 = new Object();"
9553 "proto2 = new Object();"
9554 "o.__proto__ = proto1;"
9555 "proto1.__proto__ = proto2;"
9556 "proto2.y = function(x) { return x + 1; };"
9557 // Invoke it many times to compile a stub
9558 "for (var i = 0; i < 7; i++) {"
9559 " o.y(42);"
9560 "}"
9561 "proto1.y = function(x) { return x - 1; };"
9562 "var result = 0;"
9563 "for (var i = 0; i < 7; i++) {"
9564 " result += o.y(42);"
9565 "}");
9566 CHECK_EQ(41 * 7, value->Int32Value());
9567}
9568
9569
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009570// This test checks that if interceptor doesn't provide a function,
9571// cached constant function is used
9572THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9573 v8::HandleScope scope;
9574 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9575 templ->SetNamedPropertyHandler(NoBlockGetterX);
9576 LocalContext context;
9577 context->Global()->Set(v8_str("o"), templ->NewInstance());
9578 v8::Handle<Value> value = CompileRun(
9579 "function inc(x) { return x + 1; };"
9580 "inc(1);"
9581 "o.x = inc;"
9582 "var result = 0;"
9583 "for (var i = 0; i < 1000; i++) {"
9584 " result = o.x(42);"
9585 "}");
9586 CHECK_EQ(43, value->Int32Value());
9587}
9588
9589
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009590static v8::Handle<Value> call_ic_function5;
9591static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9592 const AccessorInfo& info) {
9593 ApiTestFuzzer::Fuzz();
9594 if (v8_str("x")->Equals(name))
9595 return call_ic_function5;
9596 else
9597 return Local<Value>();
9598}
9599
9600
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009601// This test checks that if interceptor provides a function,
9602// even if we cached constant function, interceptor's function
9603// is invoked
9604THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9605 v8::HandleScope scope;
9606 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9607 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9608 LocalContext context;
9609 context->Global()->Set(v8_str("o"), templ->NewInstance());
9610 call_ic_function5 =
9611 v8_compile("function f(x) { return x - 1; }; f")->Run();
9612 v8::Handle<Value> value = CompileRun(
9613 "function inc(x) { return x + 1; };"
9614 "inc(1);"
9615 "o.x = inc;"
9616 "var result = 0;"
9617 "for (var i = 0; i < 1000; i++) {"
9618 " result = o.x(42);"
9619 "}");
9620 CHECK_EQ(41, value->Int32Value());
9621}
9622
9623
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009624static v8::Handle<Value> call_ic_function6;
9625static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9626 const AccessorInfo& info) {
9627 ApiTestFuzzer::Fuzz();
9628 if (v8_str("x")->Equals(name))
9629 return call_ic_function6;
9630 else
9631 return Local<Value>();
9632}
9633
9634
9635// Same test as above, except the code is wrapped in a function
9636// to test the optimized compiler.
9637THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9638 i::FLAG_allow_natives_syntax = true;
9639 v8::HandleScope scope;
9640 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9641 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9642 LocalContext context;
9643 context->Global()->Set(v8_str("o"), templ->NewInstance());
9644 call_ic_function6 =
9645 v8_compile("function f(x) { return x - 1; }; f")->Run();
9646 v8::Handle<Value> value = CompileRun(
9647 "function inc(x) { return x + 1; };"
9648 "inc(1);"
9649 "o.x = inc;"
9650 "function test() {"
9651 " var result = 0;"
9652 " for (var i = 0; i < 1000; i++) {"
9653 " result = o.x(42);"
9654 " }"
9655 " return result;"
9656 "};"
9657 "test();"
9658 "test();"
9659 "test();"
9660 "%OptimizeFunctionOnNextCall(test);"
9661 "test()");
9662 CHECK_EQ(41, value->Int32Value());
9663}
9664
9665
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009666// Test the case when we stored constant function into
9667// a stub, but it got invalidated later on
9668THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9669 v8::HandleScope scope;
9670 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9671 templ->SetNamedPropertyHandler(NoBlockGetterX);
9672 LocalContext context;
9673 context->Global()->Set(v8_str("o"), templ->NewInstance());
9674 v8::Handle<Value> value = CompileRun(
9675 "function inc(x) { return x + 1; };"
9676 "inc(1);"
9677 "proto1 = new Object();"
9678 "proto2 = new Object();"
9679 "o.__proto__ = proto1;"
9680 "proto1.__proto__ = proto2;"
9681 "proto2.y = inc;"
9682 // Invoke it many times to compile a stub
9683 "for (var i = 0; i < 7; i++) {"
9684 " o.y(42);"
9685 "}"
9686 "proto1.y = function(x) { return x - 1; };"
9687 "var result = 0;"
9688 "for (var i = 0; i < 7; i++) {"
9689 " result += o.y(42);"
9690 "}");
9691 CHECK_EQ(41 * 7, value->Int32Value());
9692}
9693
9694
9695// Test the case when we stored constant function into
9696// a stub, but it got invalidated later on due to override on
9697// global object which is between interceptor and constant function' holders.
9698THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9699 v8::HandleScope scope;
9700 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9701 templ->SetNamedPropertyHandler(NoBlockGetterX);
9702 LocalContext context;
9703 context->Global()->Set(v8_str("o"), templ->NewInstance());
9704 v8::Handle<Value> value = CompileRun(
9705 "function inc(x) { return x + 1; };"
9706 "inc(1);"
9707 "o.__proto__ = this;"
9708 "this.__proto__.y = inc;"
9709 // Invoke it many times to compile a stub
9710 "for (var i = 0; i < 7; i++) {"
9711 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9712 "}"
9713 "this.y = function(x) { return x - 1; };"
9714 "var result = 0;"
9715 "for (var i = 0; i < 7; i++) {"
9716 " result += o.y(42);"
9717 "}");
9718 CHECK_EQ(41 * 7, value->Int32Value());
9719}
9720
9721
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009722// Test the case when actual function to call sits on global object.
9723THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9724 v8::HandleScope scope;
9725 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9726 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9727
9728 LocalContext context;
9729 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9730
9731 v8::Handle<Value> value = CompileRun(
9732 "try {"
9733 " o.__proto__ = this;"
9734 " for (var i = 0; i < 10; i++) {"
9735 " var v = o.parseFloat('239');"
9736 " if (v != 239) throw v;"
9737 // Now it should be ICed and keep a reference to parseFloat.
9738 " }"
9739 " var result = 0;"
9740 " for (var i = 0; i < 10; i++) {"
9741 " result += o.parseFloat('239');"
9742 " }"
9743 " result"
9744 "} catch(e) {"
9745 " e"
9746 "};");
9747 CHECK_EQ(239 * 10, value->Int32Value());
9748}
9749
ager@chromium.org5c838252010-02-19 08:53:10 +00009750static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9751 const AccessorInfo& info) {
9752 ApiTestFuzzer::Fuzz();
9753 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9754 ++(*call_count);
9755 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009756 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009757 }
9758 return v8::Handle<Value>();
9759}
9760
9761static v8::Handle<Value> FastApiCallback_TrivialSignature(
9762 const v8::Arguments& args) {
9763 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009764 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9765 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009766 CHECK_EQ(args.This(), args.Holder());
9767 CHECK(args.Data()->Equals(v8_str("method_data")));
9768 return v8::Integer::New(args[0]->Int32Value() + 1);
9769}
9770
9771static v8::Handle<Value> FastApiCallback_SimpleSignature(
9772 const v8::Arguments& args) {
9773 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009774 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9775 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009776 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9777 CHECK(args.Data()->Equals(v8_str("method_data")));
9778 // Note, we're using HasRealNamedProperty instead of Has to avoid
9779 // invoking the interceptor again.
9780 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9781 return v8::Integer::New(args[0]->Int32Value() + 1);
9782}
9783
9784// Helper to maximize the odds of object moving.
9785static void GenerateSomeGarbage() {
9786 CompileRun(
9787 "var garbage;"
9788 "for (var i = 0; i < 1000; i++) {"
9789 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9790 "}"
9791 "garbage = undefined;");
9792}
9793
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009795v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9796 static int count = 0;
9797 if (count++ % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009798 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9799 // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009800 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9801 }
9802 return v8::Handle<v8::Value>();
9803}
9804
9805
9806THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9807 v8::HandleScope scope;
9808 LocalContext context;
9809 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9810 nativeobject_templ->Set("callback",
9811 v8::FunctionTemplate::New(DirectApiCallback));
9812 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9813 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9814 // call the api function multiple times to ensure direct call stub creation.
9815 CompileRun(
9816 "function f() {"
9817 " for (var i = 1; i <= 30; i++) {"
9818 " nativeobject.callback();"
9819 " }"
9820 "}"
9821 "f();");
9822}
9823
9824
9825v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9826 return v8::ThrowException(v8_str("g"));
9827}
9828
9829
9830THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9831 v8::HandleScope scope;
9832 LocalContext context;
9833 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9834 nativeobject_templ->Set("callback",
9835 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9836 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9837 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9838 // call the api function multiple times to ensure direct call stub creation.
9839 v8::Handle<Value> result = CompileRun(
9840 "var result = '';"
9841 "function f() {"
9842 " for (var i = 1; i <= 5; i++) {"
9843 " try { nativeobject.callback(); } catch (e) { result += e; }"
9844 " }"
9845 "}"
9846 "f(); result;");
9847 CHECK_EQ(v8_str("ggggg"), result);
9848}
9849
9850
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009851v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9852 const v8::AccessorInfo& info) {
9853 if (++p_getter_count % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009854 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 GenerateSomeGarbage();
9856 }
9857 return v8::Handle<v8::Value>();
9858}
9859
9860
9861THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9862 v8::HandleScope scope;
9863 LocalContext context;
9864 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9865 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9866 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9867 p_getter_count = 0;
9868 CompileRun(
9869 "function f() {"
9870 " for (var i = 0; i < 30; i++) o1.p1;"
9871 "}"
9872 "f();");
9873 CHECK_EQ(30, p_getter_count);
9874}
9875
9876
9877v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9878 Local<String> name, const v8::AccessorInfo& info) {
9879 return v8::ThrowException(v8_str("g"));
9880}
9881
9882
9883THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9884 v8::HandleScope scope;
9885 LocalContext context;
9886 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9887 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9888 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9889 v8::Handle<Value> result = CompileRun(
9890 "var result = '';"
9891 "for (var i = 0; i < 5; i++) {"
9892 " try { o1.p1; } catch (e) { result += e; }"
9893 "}"
9894 "result;");
9895 CHECK_EQ(v8_str("ggggg"), result);
9896}
9897
9898
ager@chromium.org5c838252010-02-19 08:53:10 +00009899THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9900 int interceptor_call_count = 0;
9901 v8::HandleScope scope;
9902 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9903 v8::Handle<v8::FunctionTemplate> method_templ =
9904 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9905 v8_str("method_data"),
9906 v8::Handle<v8::Signature>());
9907 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9908 proto_templ->Set(v8_str("method"), method_templ);
9909 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9910 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9911 NULL, NULL, NULL, NULL,
9912 v8::External::Wrap(&interceptor_call_count));
9913 LocalContext context;
9914 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9915 GenerateSomeGarbage();
9916 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009917 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009918 "var result = 0;"
9919 "for (var i = 0; i < 100; i++) {"
9920 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009921 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009922 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9923 CHECK_EQ(100, interceptor_call_count);
9924}
9925
9926THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9927 int interceptor_call_count = 0;
9928 v8::HandleScope scope;
9929 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9930 v8::Handle<v8::FunctionTemplate> method_templ =
9931 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9932 v8_str("method_data"),
9933 v8::Signature::New(fun_templ));
9934 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9935 proto_templ->Set(v8_str("method"), method_templ);
9936 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9937 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9938 NULL, NULL, NULL, NULL,
9939 v8::External::Wrap(&interceptor_call_count));
9940 LocalContext context;
9941 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9942 GenerateSomeGarbage();
9943 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009944 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009945 "o.foo = 17;"
9946 "var receiver = {};"
9947 "receiver.__proto__ = o;"
9948 "var result = 0;"
9949 "for (var i = 0; i < 100; i++) {"
9950 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009951 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009952 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9953 CHECK_EQ(100, interceptor_call_count);
9954}
9955
9956THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9957 int interceptor_call_count = 0;
9958 v8::HandleScope scope;
9959 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9960 v8::Handle<v8::FunctionTemplate> method_templ =
9961 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9962 v8_str("method_data"),
9963 v8::Signature::New(fun_templ));
9964 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9965 proto_templ->Set(v8_str("method"), method_templ);
9966 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9967 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9968 NULL, NULL, NULL, NULL,
9969 v8::External::Wrap(&interceptor_call_count));
9970 LocalContext context;
9971 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9972 GenerateSomeGarbage();
9973 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009974 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009975 "o.foo = 17;"
9976 "var receiver = {};"
9977 "receiver.__proto__ = o;"
9978 "var result = 0;"
9979 "var saved_result = 0;"
9980 "for (var i = 0; i < 100; i++) {"
9981 " result = receiver.method(41);"
9982 " if (i == 50) {"
9983 " saved_result = result;"
9984 " receiver = {method: function(x) { return x - 1 }};"
9985 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009986 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009987 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9988 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9989 CHECK_GE(interceptor_call_count, 50);
9990}
9991
9992THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9993 int interceptor_call_count = 0;
9994 v8::HandleScope scope;
9995 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9996 v8::Handle<v8::FunctionTemplate> method_templ =
9997 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9998 v8_str("method_data"),
9999 v8::Signature::New(fun_templ));
10000 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10001 proto_templ->Set(v8_str("method"), method_templ);
10002 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10003 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10004 NULL, NULL, NULL, NULL,
10005 v8::External::Wrap(&interceptor_call_count));
10006 LocalContext context;
10007 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10008 GenerateSomeGarbage();
10009 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010010 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010011 "o.foo = 17;"
10012 "var receiver = {};"
10013 "receiver.__proto__ = o;"
10014 "var result = 0;"
10015 "var saved_result = 0;"
10016 "for (var i = 0; i < 100; i++) {"
10017 " result = receiver.method(41);"
10018 " if (i == 50) {"
10019 " saved_result = result;"
10020 " o.method = function(x) { return x - 1 };"
10021 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010022 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010023 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10024 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10025 CHECK_GE(interceptor_call_count, 50);
10026}
10027
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010028THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10029 int interceptor_call_count = 0;
10030 v8::HandleScope scope;
10031 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10032 v8::Handle<v8::FunctionTemplate> method_templ =
10033 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10034 v8_str("method_data"),
10035 v8::Signature::New(fun_templ));
10036 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10037 proto_templ->Set(v8_str("method"), method_templ);
10038 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10039 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10040 NULL, NULL, NULL, NULL,
10041 v8::External::Wrap(&interceptor_call_count));
10042 LocalContext context;
10043 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10044 GenerateSomeGarbage();
10045 context->Global()->Set(v8_str("o"), fun->NewInstance());
10046 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010047 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010048 "o.foo = 17;"
10049 "var receiver = {};"
10050 "receiver.__proto__ = o;"
10051 "var result = 0;"
10052 "var saved_result = 0;"
10053 "for (var i = 0; i < 100; i++) {"
10054 " result = receiver.method(41);"
10055 " if (i == 50) {"
10056 " saved_result = result;"
10057 " receiver = 333;"
10058 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010059 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010060 CHECK(try_catch.HasCaught());
10061 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10062 try_catch.Exception()->ToString());
10063 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10064 CHECK_GE(interceptor_call_count, 50);
10065}
10066
ager@chromium.org5c838252010-02-19 08:53:10 +000010067THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10068 int interceptor_call_count = 0;
10069 v8::HandleScope scope;
10070 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10071 v8::Handle<v8::FunctionTemplate> method_templ =
10072 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10073 v8_str("method_data"),
10074 v8::Signature::New(fun_templ));
10075 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10076 proto_templ->Set(v8_str("method"), method_templ);
10077 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10078 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10079 NULL, NULL, NULL, NULL,
10080 v8::External::Wrap(&interceptor_call_count));
10081 LocalContext context;
10082 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10083 GenerateSomeGarbage();
10084 context->Global()->Set(v8_str("o"), fun->NewInstance());
10085 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010086 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010087 "o.foo = 17;"
10088 "var receiver = {};"
10089 "receiver.__proto__ = o;"
10090 "var result = 0;"
10091 "var saved_result = 0;"
10092 "for (var i = 0; i < 100; i++) {"
10093 " result = receiver.method(41);"
10094 " if (i == 50) {"
10095 " saved_result = result;"
10096 " receiver = {method: receiver.method};"
10097 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010098 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010099 CHECK(try_catch.HasCaught());
10100 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10101 try_catch.Exception()->ToString());
10102 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10103 CHECK_GE(interceptor_call_count, 50);
10104}
10105
10106THREADED_TEST(CallICFastApi_TrivialSignature) {
10107 v8::HandleScope scope;
10108 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10109 v8::Handle<v8::FunctionTemplate> method_templ =
10110 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10111 v8_str("method_data"),
10112 v8::Handle<v8::Signature>());
10113 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10114 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010115 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010116 USE(templ);
ager@chromium.org5c838252010-02-19 08:53:10 +000010117 LocalContext context;
10118 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10119 GenerateSomeGarbage();
10120 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010121 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010122 "var result = 0;"
10123 "for (var i = 0; i < 100; i++) {"
10124 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010125 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010126
10127 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10128}
10129
10130THREADED_TEST(CallICFastApi_SimpleSignature) {
10131 v8::HandleScope scope;
10132 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10133 v8::Handle<v8::FunctionTemplate> method_templ =
10134 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10135 v8_str("method_data"),
10136 v8::Signature::New(fun_templ));
10137 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10138 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010139 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010140 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010141 LocalContext context;
10142 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10143 GenerateSomeGarbage();
10144 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010145 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010146 "o.foo = 17;"
10147 "var receiver = {};"
10148 "receiver.__proto__ = o;"
10149 "var result = 0;"
10150 "for (var i = 0; i < 100; i++) {"
10151 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010152 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010153
10154 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10155}
10156
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010157THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010158 v8::HandleScope scope;
10159 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10160 v8::Handle<v8::FunctionTemplate> method_templ =
10161 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10162 v8_str("method_data"),
10163 v8::Signature::New(fun_templ));
10164 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10165 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010166 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010167 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010168 LocalContext context;
10169 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10170 GenerateSomeGarbage();
10171 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010172 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010173 "o.foo = 17;"
10174 "var receiver = {};"
10175 "receiver.__proto__ = o;"
10176 "var result = 0;"
10177 "var saved_result = 0;"
10178 "for (var i = 0; i < 100; i++) {"
10179 " result = receiver.method(41);"
10180 " if (i == 50) {"
10181 " saved_result = result;"
10182 " receiver = {method: function(x) { return x - 1 }};"
10183 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010184 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010185 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10186 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10187}
10188
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010189THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10190 v8::HandleScope scope;
10191 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10192 v8::Handle<v8::FunctionTemplate> method_templ =
10193 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10194 v8_str("method_data"),
10195 v8::Signature::New(fun_templ));
10196 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10197 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010198 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010199 CHECK(!templ.IsEmpty());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010200 LocalContext context;
10201 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10202 GenerateSomeGarbage();
10203 context->Global()->Set(v8_str("o"), fun->NewInstance());
10204 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010205 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010206 "o.foo = 17;"
10207 "var receiver = {};"
10208 "receiver.__proto__ = o;"
10209 "var result = 0;"
10210 "var saved_result = 0;"
10211 "for (var i = 0; i < 100; i++) {"
10212 " result = receiver.method(41);"
10213 " if (i == 50) {"
10214 " saved_result = result;"
10215 " receiver = 333;"
10216 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010217 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010218 CHECK(try_catch.HasCaught());
10219 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10220 try_catch.Exception()->ToString());
10221 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10222}
10223
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010224
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010225v8::Handle<Value> keyed_call_ic_function;
10226
10227static v8::Handle<Value> InterceptorKeyedCallICGetter(
10228 Local<String> name, const AccessorInfo& info) {
10229 ApiTestFuzzer::Fuzz();
10230 if (v8_str("x")->Equals(name)) {
10231 return keyed_call_ic_function;
10232 }
10233 return v8::Handle<Value>();
10234}
10235
10236
10237// Test the case when we stored cacheable lookup into
10238// a stub, but the function name changed (to another cacheable function).
10239THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10240 v8::HandleScope scope;
10241 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10242 templ->SetNamedPropertyHandler(NoBlockGetterX);
10243 LocalContext context;
10244 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010245 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010246 "proto = new Object();"
10247 "proto.y = function(x) { return x + 1; };"
10248 "proto.z = function(x) { return x - 1; };"
10249 "o.__proto__ = proto;"
10250 "var result = 0;"
10251 "var method = 'y';"
10252 "for (var i = 0; i < 10; i++) {"
10253 " if (i == 5) { method = 'z'; };"
10254 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010255 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010256 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10257}
10258
10259
10260// Test the case when we stored cacheable lookup into
10261// a stub, but the function name changed (and the new function is present
10262// both before and after the interceptor in the prototype chain).
10263THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10264 v8::HandleScope scope;
10265 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10266 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10267 LocalContext context;
10268 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10269 keyed_call_ic_function =
10270 v8_compile("function f(x) { return x - 1; }; f")->Run();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010271 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010272 "o = new Object();"
10273 "proto2 = new Object();"
10274 "o.y = function(x) { return x + 1; };"
10275 "proto2.y = function(x) { return x + 2; };"
10276 "o.__proto__ = proto1;"
10277 "proto1.__proto__ = proto2;"
10278 "var result = 0;"
10279 "var method = 'x';"
10280 "for (var i = 0; i < 10; i++) {"
10281 " if (i == 5) { method = 'y'; };"
10282 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010283 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010284 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10285}
10286
10287
10288// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10289// on the global object.
10290THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10291 v8::HandleScope scope;
10292 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10293 templ->SetNamedPropertyHandler(NoBlockGetterX);
10294 LocalContext context;
10295 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010296 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010297 "function inc(x) { return x + 1; };"
10298 "inc(1);"
10299 "function dec(x) { return x - 1; };"
10300 "dec(1);"
10301 "o.__proto__ = this;"
10302 "this.__proto__.x = inc;"
10303 "this.__proto__.y = dec;"
10304 "var result = 0;"
10305 "var method = 'x';"
10306 "for (var i = 0; i < 10; i++) {"
10307 " if (i == 5) { method = 'y'; };"
10308 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010309 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010310 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10311}
10312
10313
10314// Test the case when actual function to call sits on global object.
10315THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10316 v8::HandleScope scope;
10317 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10318 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10319 LocalContext context;
10320 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10321
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010322 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010323 "function len(x) { return x.length; };"
10324 "o.__proto__ = this;"
10325 "var m = 'parseFloat';"
10326 "var result = 0;"
10327 "for (var i = 0; i < 10; i++) {"
10328 " if (i == 5) {"
10329 " m = 'len';"
10330 " saved_result = result;"
10331 " };"
10332 " result = o[m]('239');"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010333 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010334 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10335 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10336}
10337
10338// Test the map transition before the interceptor.
10339THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10340 v8::HandleScope scope;
10341 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10342 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10343 LocalContext context;
10344 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10345
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010346 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010347 "var o = new Object();"
10348 "o.__proto__ = proto;"
10349 "o.method = function(x) { return x + 1; };"
10350 "var m = 'method';"
10351 "var result = 0;"
10352 "for (var i = 0; i < 10; i++) {"
10353 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10354 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010355 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010356 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10357}
10358
10359
10360// Test the map transition after the interceptor.
10361THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10362 v8::HandleScope scope;
10363 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10364 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10365 LocalContext context;
10366 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10367
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010368 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010369 "var proto = new Object();"
10370 "o.__proto__ = proto;"
10371 "proto.method = function(x) { return x + 1; };"
10372 "var m = 'method';"
10373 "var result = 0;"
10374 "for (var i = 0; i < 10; i++) {"
10375 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10376 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010377 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010378 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10379}
10380
10381
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010382static int interceptor_call_count = 0;
10383
10384static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10385 const AccessorInfo& info) {
10386 ApiTestFuzzer::Fuzz();
10387 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10388 return call_ic_function2;
10389 }
10390 return v8::Handle<Value>();
10391}
10392
10393
10394// This test should hit load and call ICs for the interceptor case.
10395// Once in a while, the interceptor will reply that a property was not
10396// found in which case we should get a reference error.
10397THREADED_TEST(InterceptorICReferenceErrors) {
10398 v8::HandleScope scope;
10399 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10400 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10401 LocalContext context(0, templ, v8::Handle<Value>());
10402 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10403 v8::Handle<Value> value = CompileRun(
10404 "function f() {"
10405 " for (var i = 0; i < 1000; i++) {"
10406 " try { x; } catch(e) { return true; }"
10407 " }"
10408 " return false;"
10409 "};"
10410 "f();");
10411 CHECK_EQ(true, value->BooleanValue());
10412 interceptor_call_count = 0;
10413 value = CompileRun(
10414 "function g() {"
10415 " for (var i = 0; i < 1000; i++) {"
10416 " try { x(42); } catch(e) { return true; }"
10417 " }"
10418 " return false;"
10419 "};"
10420 "g();");
10421 CHECK_EQ(true, value->BooleanValue());
10422}
10423
10424
10425static int interceptor_ic_exception_get_count = 0;
10426
10427static v8::Handle<Value> InterceptorICExceptionGetter(
10428 Local<String> name,
10429 const AccessorInfo& info) {
10430 ApiTestFuzzer::Fuzz();
10431 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10432 return call_ic_function3;
10433 }
10434 if (interceptor_ic_exception_get_count == 20) {
10435 return v8::ThrowException(v8_num(42));
10436 }
10437 // Do not handle get for properties other than x.
10438 return v8::Handle<Value>();
10439}
10440
10441// Test interceptor load/call IC where the interceptor throws an
10442// exception once in a while.
10443THREADED_TEST(InterceptorICGetterExceptions) {
10444 interceptor_ic_exception_get_count = 0;
10445 v8::HandleScope scope;
10446 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10447 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10448 LocalContext context(0, templ, v8::Handle<Value>());
10449 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10450 v8::Handle<Value> value = CompileRun(
10451 "function f() {"
10452 " for (var i = 0; i < 100; i++) {"
10453 " try { x; } catch(e) { return true; }"
10454 " }"
10455 " return false;"
10456 "};"
10457 "f();");
10458 CHECK_EQ(true, value->BooleanValue());
10459 interceptor_ic_exception_get_count = 0;
10460 value = CompileRun(
10461 "function f() {"
10462 " for (var i = 0; i < 100; i++) {"
10463 " try { x(42); } catch(e) { return true; }"
10464 " }"
10465 " return false;"
10466 "};"
10467 "f();");
10468 CHECK_EQ(true, value->BooleanValue());
10469}
10470
10471
10472static int interceptor_ic_exception_set_count = 0;
10473
10474static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010475 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010476 ApiTestFuzzer::Fuzz();
10477 if (++interceptor_ic_exception_set_count > 20) {
10478 return v8::ThrowException(v8_num(42));
10479 }
10480 // Do not actually handle setting.
10481 return v8::Handle<Value>();
10482}
10483
10484// Test interceptor store IC where the interceptor throws an exception
10485// once in a while.
10486THREADED_TEST(InterceptorICSetterExceptions) {
10487 interceptor_ic_exception_set_count = 0;
10488 v8::HandleScope scope;
10489 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10490 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10491 LocalContext context(0, templ, v8::Handle<Value>());
10492 v8::Handle<Value> value = CompileRun(
10493 "function f() {"
10494 " for (var i = 0; i < 100; i++) {"
10495 " try { x = 42; } catch(e) { return true; }"
10496 " }"
10497 " return false;"
10498 "};"
10499 "f();");
10500 CHECK_EQ(true, value->BooleanValue());
10501}
10502
10503
10504// Test that we ignore null interceptors.
10505THREADED_TEST(NullNamedInterceptor) {
10506 v8::HandleScope scope;
10507 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10508 templ->SetNamedPropertyHandler(0);
10509 LocalContext context;
10510 templ->Set("x", v8_num(42));
10511 v8::Handle<v8::Object> obj = templ->NewInstance();
10512 context->Global()->Set(v8_str("obj"), obj);
10513 v8::Handle<Value> value = CompileRun("obj.x");
10514 CHECK(value->IsInt32());
10515 CHECK_EQ(42, value->Int32Value());
10516}
10517
10518
10519// Test that we ignore null interceptors.
10520THREADED_TEST(NullIndexedInterceptor) {
10521 v8::HandleScope scope;
10522 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10523 templ->SetIndexedPropertyHandler(0);
10524 LocalContext context;
10525 templ->Set("42", v8_num(42));
10526 v8::Handle<v8::Object> obj = templ->NewInstance();
10527 context->Global()->Set(v8_str("obj"), obj);
10528 v8::Handle<Value> value = CompileRun("obj[42]");
10529 CHECK(value->IsInt32());
10530 CHECK_EQ(42, value->Int32Value());
10531}
10532
10533
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010534THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10535 v8::HandleScope scope;
10536 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10537 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10538 LocalContext env;
10539 env->Global()->Set(v8_str("obj"),
10540 templ->GetFunction()->NewInstance());
10541 ExpectTrue("obj.x === 42");
10542 ExpectTrue("!obj.propertyIsEnumerable('x')");
10543}
10544
10545
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010546static Handle<Value> ThrowingGetter(Local<String> name,
10547 const AccessorInfo& info) {
10548 ApiTestFuzzer::Fuzz();
10549 ThrowException(Handle<Value>());
10550 return Undefined();
10551}
10552
10553
10554THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10555 HandleScope scope;
10556 LocalContext context;
10557
10558 Local<FunctionTemplate> templ = FunctionTemplate::New();
10559 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10560 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10561
10562 Local<Object> instance = templ->GetFunction()->NewInstance();
10563
10564 Local<Object> another = Object::New();
10565 another->SetPrototype(instance);
10566
10567 Local<Object> with_js_getter = CompileRun(
10568 "o = {};\n"
10569 "o.__defineGetter__('f', function() { throw undefined; });\n"
10570 "o\n").As<Object>();
10571 CHECK(!with_js_getter.IsEmpty());
10572
10573 TryCatch try_catch;
10574
10575 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10576 CHECK(try_catch.HasCaught());
10577 try_catch.Reset();
10578 CHECK(result.IsEmpty());
10579
10580 result = another->GetRealNamedProperty(v8_str("f"));
10581 CHECK(try_catch.HasCaught());
10582 try_catch.Reset();
10583 CHECK(result.IsEmpty());
10584
10585 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10586 CHECK(try_catch.HasCaught());
10587 try_catch.Reset();
10588 CHECK(result.IsEmpty());
10589
10590 result = another->Get(v8_str("f"));
10591 CHECK(try_catch.HasCaught());
10592 try_catch.Reset();
10593 CHECK(result.IsEmpty());
10594
10595 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10596 CHECK(try_catch.HasCaught());
10597 try_catch.Reset();
10598 CHECK(result.IsEmpty());
10599
10600 result = with_js_getter->Get(v8_str("f"));
10601 CHECK(try_catch.HasCaught());
10602 try_catch.Reset();
10603 CHECK(result.IsEmpty());
10604}
10605
10606
10607static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10608 TryCatch try_catch;
10609 // Verboseness is important: it triggers message delivery which can call into
10610 // external code.
10611 try_catch.SetVerbose(true);
10612 CompileRun("throw 'from JS';");
10613 CHECK(try_catch.HasCaught());
10614 CHECK(!i::Isolate::Current()->has_pending_exception());
10615 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10616 return Undefined();
10617}
10618
10619
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010620static int call_depth;
10621
10622
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010623static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10624 TryCatch try_catch;
10625}
10626
10627
10628static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010629 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010630}
10631
10632
10633static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010634 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010635}
10636
10637
10638static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10639 Handle<String> errorMessageString = message->Get();
10640 CHECK(!errorMessageString.IsEmpty());
10641 message->GetStackTrace();
10642 message->GetScriptResourceName();
10643}
10644
10645THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10646 HandleScope scope;
10647 LocalContext context;
10648
10649 Local<Function> func =
10650 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10651 context->Global()->Set(v8_str("func"), func);
10652
10653 MessageCallback callbacks[] =
10654 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10655 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10656 MessageCallback callback = callbacks[i];
10657 if (callback != NULL) {
10658 V8::AddMessageListener(callback);
10659 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +000010660 // Some small number to control number of times message handler should
10661 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010662 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010663 ExpectFalse(
10664 "var thrown = false;\n"
10665 "try { func(); } catch(e) { thrown = true; }\n"
10666 "thrown\n");
10667 if (callback != NULL) {
10668 V8::RemoveMessageListeners(callback);
10669 }
10670 }
10671}
10672
10673
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010674static v8::Handle<Value> ParentGetter(Local<String> name,
10675 const AccessorInfo& info) {
10676 ApiTestFuzzer::Fuzz();
10677 return v8_num(1);
10678}
10679
10680
10681static v8::Handle<Value> ChildGetter(Local<String> name,
10682 const AccessorInfo& info) {
10683 ApiTestFuzzer::Fuzz();
10684 return v8_num(42);
10685}
10686
10687
10688THREADED_TEST(Overriding) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010689 i::FLAG_es5_readonly = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010690 v8::HandleScope scope;
10691 LocalContext context;
10692
10693 // Parent template.
10694 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10695 Local<ObjectTemplate> parent_instance_templ =
10696 parent_templ->InstanceTemplate();
10697 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10698
10699 // Template that inherits from the parent template.
10700 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10701 Local<ObjectTemplate> child_instance_templ =
10702 child_templ->InstanceTemplate();
10703 child_templ->Inherit(parent_templ);
10704 // Override 'f'. The child version of 'f' should get called for child
10705 // instances.
10706 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10707 // Add 'g' twice. The 'g' added last should get called for instances.
10708 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10709 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10710
10711 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10712 // so 'h' can be shadowed on the instance object.
10713 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10714 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10715 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10716
10717 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10718 // but the attribute does not have effect because it is duplicated with
10719 // NULL setter.
10720 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10721 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10722
10723
10724
10725 // Instantiate the child template.
10726 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10727
10728 // Check that the child function overrides the parent one.
10729 context->Global()->Set(v8_str("o"), instance);
10730 Local<Value> value = v8_compile("o.f")->Run();
10731 // Check that the 'g' that was added last is hit.
10732 CHECK_EQ(42, value->Int32Value());
10733 value = v8_compile("o.g")->Run();
10734 CHECK_EQ(42, value->Int32Value());
10735
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010736 // Check that 'h' cannot be shadowed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010737 value = v8_compile("o.h = 3; o.h")->Run();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010738 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010739
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010740 // Check that 'i' cannot be shadowed or changed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010741 value = v8_compile("o.i = 3; o.i")->Run();
10742 CHECK_EQ(42, value->Int32Value());
10743}
10744
10745
10746static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10747 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010748 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010749}
10750
10751
10752THREADED_TEST(IsConstructCall) {
10753 v8::HandleScope scope;
10754
10755 // Function template with call handler.
10756 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10757 templ->SetCallHandler(IsConstructHandler);
10758
10759 LocalContext context;
10760
10761 context->Global()->Set(v8_str("f"), templ->GetFunction());
10762 Local<Value> value = v8_compile("f()")->Run();
10763 CHECK(!value->BooleanValue());
10764 value = v8_compile("new f()")->Run();
10765 CHECK(value->BooleanValue());
10766}
10767
10768
10769THREADED_TEST(ObjectProtoToString) {
10770 v8::HandleScope scope;
10771 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10772 templ->SetClassName(v8_str("MyClass"));
10773
10774 LocalContext context;
10775
10776 Local<String> customized_tostring = v8_str("customized toString");
10777
10778 // Replace Object.prototype.toString
10779 v8_compile("Object.prototype.toString = function() {"
10780 " return 'customized toString';"
10781 "}")->Run();
10782
10783 // Normal ToString call should call replaced Object.prototype.toString
10784 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10785 Local<String> value = instance->ToString();
10786 CHECK(value->IsString() && value->Equals(customized_tostring));
10787
10788 // ObjectProtoToString should not call replace toString function.
10789 value = instance->ObjectProtoToString();
10790 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10791
10792 // Check global
10793 value = context->Global()->ObjectProtoToString();
10794 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10795
10796 // Check ordinary object
10797 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010798 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010799 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10800}
10801
10802
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010803THREADED_TEST(ObjectGetConstructorName) {
10804 v8::HandleScope scope;
10805 LocalContext context;
10806 v8_compile("function Parent() {};"
10807 "function Child() {};"
10808 "Child.prototype = new Parent();"
10809 "var outer = { inner: function() { } };"
10810 "var p = new Parent();"
10811 "var c = new Child();"
10812 "var x = new outer.inner();")->Run();
10813
10814 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10815 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10816 v8_str("Parent")));
10817
10818 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10819 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10820 v8_str("Child")));
10821
10822 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10823 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10824 v8_str("outer.inner")));
10825}
10826
10827
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010828bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010829i::Semaphore* ApiTestFuzzer::all_tests_done_=
10830 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010831int ApiTestFuzzer::active_tests_;
10832int ApiTestFuzzer::tests_being_run_;
10833int ApiTestFuzzer::current_;
10834
10835
10836// We are in a callback and want to switch to another thread (if we
10837// are currently running the thread fuzzing test).
10838void ApiTestFuzzer::Fuzz() {
10839 if (!fuzzing_) return;
10840 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10841 test->ContextSwitch();
10842}
10843
10844
10845// Let the next thread go. Since it is also waiting on the V8 lock it may
10846// not start immediately.
10847bool ApiTestFuzzer::NextThread() {
10848 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010849 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010850 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010851 if (kLogThreading)
10852 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010853 return false;
10854 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010855 if (kLogThreading) {
10856 printf("Switch from %s to %s\n",
10857 test_name,
10858 RegisterThreadedTest::nth(test_position)->name());
10859 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010860 current_ = test_position;
10861 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10862 return true;
10863}
10864
10865
10866void ApiTestFuzzer::Run() {
10867 // When it is our turn...
10868 gate_->Wait();
10869 {
10870 // ... get the V8 lock and start running the test.
10871 v8::Locker locker;
10872 CallTest();
10873 }
10874 // This test finished.
10875 active_ = false;
10876 active_tests_--;
10877 // If it was the last then signal that fact.
10878 if (active_tests_ == 0) {
10879 all_tests_done_->Signal();
10880 } else {
10881 // Otherwise select a new test and start that.
10882 NextThread();
10883 }
10884}
10885
10886
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010887static unsigned linear_congruential_generator;
10888
10889
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010890void ApiTestFuzzer::SetUp(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010891 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010892 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000010893 int count = RegisterThreadedTest::count();
10894 int start = count * part / (LAST_PART + 1);
10895 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10896 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010897 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010898 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010899 }
10900 for (int i = 0; i < active_tests_; i++) {
10901 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10902 }
10903}
10904
10905
10906static void CallTestNumber(int test_number) {
10907 (RegisterThreadedTest::nth(test_number)->callback())();
10908}
10909
10910
10911void ApiTestFuzzer::RunAllTests() {
10912 // Set off the first test.
10913 current_ = -1;
10914 NextThread();
10915 // Wait till they are all done.
10916 all_tests_done_->Wait();
10917}
10918
10919
10920int ApiTestFuzzer::GetNextTestNumber() {
10921 int next_test;
10922 do {
10923 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10924 linear_congruential_generator *= 1664525u;
10925 linear_congruential_generator += 1013904223u;
10926 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10927 return next_test;
10928}
10929
10930
10931void ApiTestFuzzer::ContextSwitch() {
10932 // If the new thread is the same as the current thread there is nothing to do.
10933 if (NextThread()) {
10934 // Now it can start.
10935 v8::Unlocker unlocker;
10936 // Wait till someone starts us again.
10937 gate_->Wait();
10938 // And we're off.
10939 }
10940}
10941
10942
10943void ApiTestFuzzer::TearDown() {
10944 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000010945 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10946 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10947 if (fuzzer != NULL) fuzzer->Join();
10948 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010949}
10950
10951
10952// Lets not be needlessly self-referential.
10953TEST(Threading) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010954 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010955 ApiTestFuzzer::RunAllTests();
10956 ApiTestFuzzer::TearDown();
10957}
10958
10959TEST(Threading2) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010960 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010961 ApiTestFuzzer::RunAllTests();
10962 ApiTestFuzzer::TearDown();
10963}
10964
lrn@chromium.org1c092762011-05-09 09:42:16 +000010965TEST(Threading3) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010966 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010967 ApiTestFuzzer::RunAllTests();
10968 ApiTestFuzzer::TearDown();
10969}
10970
10971TEST(Threading4) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010972 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010973 ApiTestFuzzer::RunAllTests();
10974 ApiTestFuzzer::TearDown();
10975}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010976
10977void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010978 if (kLogThreading)
10979 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010980 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010981 if (kLogThreading)
10982 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010983}
10984
10985
10986static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010987 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010988 ApiTestFuzzer::Fuzz();
10989 v8::Unlocker unlocker;
10990 const char* code = "throw 7;";
10991 {
10992 v8::Locker nested_locker;
10993 v8::HandleScope scope;
10994 v8::Handle<Value> exception;
10995 { v8::TryCatch try_catch;
10996 v8::Handle<Value> value = CompileRun(code);
10997 CHECK(value.IsEmpty());
10998 CHECK(try_catch.HasCaught());
10999 // Make sure to wrap the exception in a new handle because
11000 // the handle returned from the TryCatch is destroyed
11001 // when the TryCatch is destroyed.
11002 exception = Local<Value>::New(try_catch.Exception());
11003 }
11004 return v8::ThrowException(exception);
11005 }
11006}
11007
11008
11009static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011010 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011011 ApiTestFuzzer::Fuzz();
11012 v8::Unlocker unlocker;
11013 const char* code = "throw 7;";
11014 {
11015 v8::Locker nested_locker;
11016 v8::HandleScope scope;
11017 v8::Handle<Value> value = CompileRun(code);
11018 CHECK(value.IsEmpty());
11019 return v8_str("foo");
11020 }
11021}
11022
11023
11024// These are locking tests that don't need to be run again
11025// as part of the locking aggregation tests.
11026TEST(NestedLockers) {
11027 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011028 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011029 v8::HandleScope scope;
11030 LocalContext env;
11031 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
11032 Local<Function> fun = fun_templ->GetFunction();
11033 env->Global()->Set(v8_str("throw_in_js"), fun);
11034 Local<Script> script = v8_compile("(function () {"
11035 " try {"
11036 " throw_in_js();"
11037 " return 42;"
11038 " } catch (e) {"
11039 " return e * 13;"
11040 " }"
11041 "})();");
11042 CHECK_EQ(91, script->Run()->Int32Value());
11043}
11044
11045
11046// These are locking tests that don't need to be run again
11047// as part of the locking aggregation tests.
11048TEST(NestedLockersNoTryCatch) {
11049 v8::Locker locker;
11050 v8::HandleScope scope;
11051 LocalContext env;
11052 Local<v8::FunctionTemplate> fun_templ =
11053 v8::FunctionTemplate::New(ThrowInJSNoCatch);
11054 Local<Function> fun = fun_templ->GetFunction();
11055 env->Global()->Set(v8_str("throw_in_js"), fun);
11056 Local<Script> script = v8_compile("(function () {"
11057 " try {"
11058 " throw_in_js();"
11059 " return 42;"
11060 " } catch (e) {"
11061 " return e * 13;"
11062 " }"
11063 "})();");
11064 CHECK_EQ(91, script->Run()->Int32Value());
11065}
11066
11067
11068THREADED_TEST(RecursiveLocking) {
11069 v8::Locker locker;
11070 {
11071 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011072 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011073 }
11074}
11075
11076
11077static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
11078 ApiTestFuzzer::Fuzz();
11079 v8::Unlocker unlocker;
11080 return v8::Undefined();
11081}
11082
11083
11084THREADED_TEST(LockUnlockLock) {
11085 {
11086 v8::Locker locker;
11087 v8::HandleScope scope;
11088 LocalContext env;
11089 Local<v8::FunctionTemplate> fun_templ =
11090 v8::FunctionTemplate::New(UnlockForAMoment);
11091 Local<Function> fun = fun_templ->GetFunction();
11092 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11093 Local<Script> script = v8_compile("(function () {"
11094 " unlock_for_a_moment();"
11095 " return 42;"
11096 "})();");
11097 CHECK_EQ(42, script->Run()->Int32Value());
11098 }
11099 {
11100 v8::Locker locker;
11101 v8::HandleScope scope;
11102 LocalContext env;
11103 Local<v8::FunctionTemplate> fun_templ =
11104 v8::FunctionTemplate::New(UnlockForAMoment);
11105 Local<Function> fun = fun_templ->GetFunction();
11106 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11107 Local<Script> script = v8_compile("(function () {"
11108 " unlock_for_a_moment();"
11109 " return 42;"
11110 "})();");
11111 CHECK_EQ(42, script->Run()->Int32Value());
11112 }
11113}
11114
11115
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011116static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011117 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011118 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011119 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011120 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11121 if (object->IsJSGlobalObject()) count++;
11122 return count;
11123}
11124
11125
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011126static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011127 // We need to collect all garbage twice to be sure that everything
11128 // has been collected. This is because inline caches are cleared in
11129 // the first garbage collection but some of the maps have already
11130 // been marked at that point. Therefore some of the maps are not
11131 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011132 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11133 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011134 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011135#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011136 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011137#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011138 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011139}
11140
11141
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011142TEST(DontLeakGlobalObjects) {
11143 // Regression test for issues 1139850 and 1174891.
11144
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011145 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011146
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011147 for (int i = 0; i < 5; i++) {
11148 { v8::HandleScope scope;
11149 LocalContext context;
11150 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011151 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011152 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011153
11154 { v8::HandleScope scope;
11155 LocalContext context;
11156 v8_compile("Date")->Run();
11157 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011158 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011159 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011160
11161 { v8::HandleScope scope;
11162 LocalContext context;
11163 v8_compile("/aaa/")->Run();
11164 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011165 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011166 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011167
11168 { v8::HandleScope scope;
11169 const char* extension_list[] = { "v8/gc" };
11170 v8::ExtensionConfiguration extensions(1, extension_list);
11171 LocalContext context(&extensions);
11172 v8_compile("gc();")->Run();
11173 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011174 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011175 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011176 }
11177}
11178
11179
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011180v8::Persistent<v8::Object> some_object;
11181v8::Persistent<v8::Object> bad_handle;
11182
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011183void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011184 v8::HandleScope scope;
11185 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011186 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011187}
11188
11189
11190THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11191 LocalContext context;
11192
11193 v8::Persistent<v8::Object> handle1, handle2;
11194 {
11195 v8::HandleScope scope;
11196 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
11197 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11198 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11199 }
11200 // Note: order is implementation dependent alas: currently
11201 // global handle nodes are processed by PostGarbageCollectionProcessing
11202 // in reverse allocation order, so if second allocated handle is deleted,
11203 // weak callback of the first handle would be able to 'reallocate' it.
11204 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
11205 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011206 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011207}
11208
11209
11210v8::Persistent<v8::Object> to_be_disposed;
11211
11212void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
11213 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011214 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011215 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011216}
11217
11218
11219THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11220 LocalContext context;
11221
11222 v8::Persistent<v8::Object> handle1, handle2;
11223 {
11224 v8::HandleScope scope;
11225 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11226 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11227 }
11228 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11229 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011230 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011231}
11232
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011233void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11234 handle.Dispose();
11235}
11236
11237void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11238 v8::HandleScope scope;
11239 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011240 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011241}
11242
11243
11244THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11245 LocalContext context;
11246
11247 v8::Persistent<v8::Object> handle1, handle2, handle3;
11248 {
11249 v8::HandleScope scope;
11250 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
11251 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11252 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11253 }
11254 handle2.MakeWeak(NULL, DisposingCallback);
11255 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011256 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011257}
11258
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011259
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011260THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011261 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011262
11263 const int nof = 2;
11264 const char* sources[nof] = {
11265 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11266 "Object()"
11267 };
11268
11269 for (int i = 0; i < nof; i++) {
11270 const char* source = sources[i];
11271 { v8::HandleScope scope;
11272 LocalContext context;
11273 CompileRun(source);
11274 }
11275 { v8::HandleScope scope;
11276 LocalContext context;
11277 CompileRun(source);
11278 }
11279 }
11280}
11281
11282
11283static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11284 v8::HandleScope inner;
11285 env->Enter();
11286 v8::Handle<Value> three = v8_num(3);
11287 v8::Handle<Value> value = inner.Close(three);
11288 env->Exit();
11289 return value;
11290}
11291
11292
11293THREADED_TEST(NestedHandleScopeAndContexts) {
11294 v8::HandleScope outer;
11295 v8::Persistent<Context> env = Context::New();
11296 env->Enter();
11297 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011298 v8::Handle<String> str(value->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011299 CHECK(!str.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011300 env->Exit();
11301 env.Dispose();
11302}
11303
11304
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011305static i::Handle<i::JSFunction>* foo_ptr = NULL;
11306static int foo_count = 0;
11307static i::Handle<i::JSFunction>* bar_ptr = NULL;
11308static int bar_count = 0;
11309
11310
11311static void entry_hook(uintptr_t function,
11312 uintptr_t return_addr_location) {
11313 i::Code* code = i::Code::GetCodeFromTargetAddress(
11314 reinterpret_cast<i::Address>(function));
11315 CHECK(code != NULL);
11316
11317 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11318 ++bar_count;
11319
11320 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11321 ++foo_count;
11322
11323 // TODO(siggi): Verify return_addr_location.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011324 // This can be done by capturing JitCodeEvents, but requires an ordered
11325 // collection.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011326}
11327
11328
11329static void RunLoopInNewEnv() {
11330 bar_ptr = NULL;
11331 foo_ptr = NULL;
11332
11333 v8::HandleScope outer;
11334 v8::Persistent<Context> env = Context::New();
11335 env->Enter();
11336
11337 const char* script =
11338 "function bar() {"
11339 " var sum = 0;"
11340 " for (i = 0; i < 100; ++i)"
11341 " sum = foo(i);"
11342 " return sum;"
11343 "}"
11344 "function foo(i) { return i * i; }";
11345 CompileRun(script);
11346 i::Handle<i::JSFunction> bar =
11347 i::Handle<i::JSFunction>::cast(
11348 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11349 ASSERT(*bar);
11350
11351 i::Handle<i::JSFunction> foo =
11352 i::Handle<i::JSFunction>::cast(
11353 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11354 ASSERT(*foo);
11355
11356 bar_ptr = &bar;
11357 foo_ptr = &foo;
11358
11359 v8::Handle<v8::Value> value = CompileRun("bar();");
11360 CHECK(value->IsNumber());
11361 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11362
11363 // Test the optimized codegen path.
11364 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11365 "bar();");
11366 CHECK(value->IsNumber());
11367 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11368
11369 env->Exit();
11370}
11371
11372
11373TEST(SetFunctionEntryHook) {
11374 i::FLAG_allow_natives_syntax = true;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011375 i::FLAG_use_inlining = false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011376
11377 // Test setting and resetting the entry hook.
11378 // Nulling it should always succeed.
11379 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11380
11381 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11382 // Setting a hook while one's active should fail.
11383 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11384
11385 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11386
11387 // Reset the entry count to zero and set the entry hook.
11388 bar_count = 0;
11389 foo_count = 0;
11390 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11391 RunLoopInNewEnv();
11392
11393 CHECK_EQ(2, bar_count);
11394 CHECK_EQ(200, foo_count);
11395
11396 // Clear the entry hook and count.
11397 bar_count = 0;
11398 foo_count = 0;
11399 v8::V8::SetFunctionEntryHook(NULL);
11400
11401 // Clear the compilation cache to make sure we don't reuse the
11402 // functions from the previous invocation.
11403 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11404
11405 // Verify that entry hooking is now disabled.
11406 RunLoopInNewEnv();
11407 CHECK_EQ(0u, bar_count);
11408 CHECK_EQ(0u, foo_count);
11409}
11410
11411
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011412static i::HashMap* code_map = NULL;
11413static int saw_bar = 0;
11414static int move_events = 0;
11415
11416
11417static bool FunctionNameIs(const char* expected,
11418 const v8::JitCodeEvent* event) {
11419 // Log lines for functions are of the general form:
11420 // "LazyCompile:<type><function_name>", where the type is one of
11421 // "*", "~" or "".
11422 static const char kPreamble[] = "LazyCompile:";
11423 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11424
11425 if (event->name.len < sizeof(kPreamble) - 1 ||
11426 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11427 return false;
11428 }
11429
11430 const char* tail = event->name.str + kPreambleLen;
11431 size_t tail_len = event->name.len - kPreambleLen;
11432 size_t expected_len = strlen(expected);
11433 if (tail_len == expected_len + 1) {
11434 if (*tail == '*' || *tail == '~') {
11435 --tail_len;
11436 ++tail;
11437 } else {
11438 return false;
11439 }
11440 }
11441
11442 if (tail_len != expected_len)
11443 return false;
11444
11445 return strncmp(tail, expected, expected_len) == 0;
11446}
11447
11448
11449static void event_handler(const v8::JitCodeEvent* event) {
11450 CHECK(event != NULL);
11451 CHECK(code_map != NULL);
11452
11453 switch (event->type) {
11454 case v8::JitCodeEvent::CODE_ADDED: {
11455 CHECK(event->code_start != NULL);
11456 CHECK_NE(0, static_cast<int>(event->code_len));
11457 CHECK(event->name.str != NULL);
11458 i::HashMap::Entry* entry =
11459 code_map->Lookup(event->code_start,
11460 i::ComputePointerHash(event->code_start),
11461 true);
11462 entry->value = reinterpret_cast<void*>(event->code_len);
11463
11464 if (FunctionNameIs("bar", event)) {
11465 ++saw_bar;
11466 }
11467 }
11468 break;
11469
11470 case v8::JitCodeEvent::CODE_MOVED: {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011471 uint32_t hash = i::ComputePointerHash(event->code_start);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011472 // We would like to never see code move that we haven't seen before,
11473 // but the code creation event does not happen until the line endings
11474 // have been calculated (this is so that we can report the line in the
11475 // script at which the function source is found, see
11476 // Compiler::RecordFunctionCompilation) and the line endings
11477 // calculations can cause a GC, which can move the newly created code
11478 // before its existence can be logged.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011479 i::HashMap::Entry* entry =
11480 code_map->Lookup(event->code_start, hash, false);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011481 if (entry != NULL) {
11482 ++move_events;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011483
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011484 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11485 code_map->Remove(event->code_start, hash);
11486
11487 entry = code_map->Lookup(event->new_code_start,
11488 i::ComputePointerHash(event->new_code_start),
11489 true);
11490 CHECK(entry != NULL);
11491 entry->value = reinterpret_cast<void*>(event->code_len);
11492 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011493 }
11494 break;
11495
11496 case v8::JitCodeEvent::CODE_REMOVED:
11497 // Object/code removal events are currently not dispatched from the GC.
11498 CHECK(false);
11499 break;
11500 default:
11501 // Impossible event.
11502 CHECK(false);
11503 break;
11504 }
11505}
11506
11507
11508// Implemented in the test-alloc.cc test suite.
11509void SimulateFullSpace(i::PagedSpace* space);
11510
11511
11512static bool MatchPointers(void* key1, void* key2) {
11513 return key1 == key2;
11514}
11515
11516
11517TEST(SetJitCodeEventHandler) {
11518 const char* script =
11519 "function bar() {"
11520 " var sum = 0;"
11521 " for (i = 0; i < 100; ++i)"
11522 " sum = foo(i);"
11523 " return sum;"
11524 "}"
11525 "function foo(i) { return i * i; };"
11526 "bar();";
11527
11528 // Run this test in a new isolate to make sure we don't
11529 // have remnants of state from other code.
11530 v8::Isolate* isolate = v8::Isolate::New();
11531 isolate->Enter();
11532
11533 {
11534 i::HashMap code(MatchPointers);
11535 code_map = &code;
11536
11537 saw_bar = 0;
11538 move_events = 0;
11539
11540 i::FLAG_stress_compaction = true;
11541 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11542
11543 v8::HandleScope scope;
11544 // Generate new code objects sparsely distributed across several
11545 // different fragmented code-space pages.
11546 const int kIterations = 10;
11547 for (int i = 0; i < kIterations; ++i) {
11548 LocalContext env;
11549
11550 v8::Handle<v8::Script> compiled_script;
11551 {
11552 i::AlwaysAllocateScope always_allocate;
11553 SimulateFullSpace(HEAP->code_space());
11554 compiled_script = v8_compile(script);
11555 }
11556 compiled_script->Run();
11557
11558 // Clear the compilation cache to get more wastage.
11559 ISOLATE->compilation_cache()->Clear();
11560 }
11561
11562 // Force code movement.
11563 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11564
11565 CHECK_LE(kIterations, saw_bar);
11566 CHECK_NE(0, move_events);
11567
11568 code_map = NULL;
11569 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11570 }
11571
11572 isolate->Exit();
11573 isolate->Dispose();
11574
11575 // Do this in a new isolate.
11576 isolate = v8::Isolate::New();
11577 isolate->Enter();
11578
11579 // Verify that we get callbacks for existing code objects when we
11580 // request enumeration of existing code.
11581 {
11582 v8::HandleScope scope;
11583 LocalContext env;
11584 CompileRun(script);
11585
11586 // Now get code through initial iteration.
11587 i::HashMap code(MatchPointers);
11588 code_map = &code;
11589
11590 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11591 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11592
11593 code_map = NULL;
11594
11595 // We expect that we got some events. Note that if we could get code removal
11596 // notifications, we could compare two collections, one created by listening
11597 // from the time of creation of an isolate, and the other by subscribing
11598 // with EnumExisting.
11599 CHECK_NE(0, code.occupancy());
11600 }
11601
11602 isolate->Exit();
11603 isolate->Dispose();
11604}
11605
11606
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011607static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11608
11609
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011610THREADED_TEST(ExternalAllocatedMemory) {
11611 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011612 v8::Persistent<Context> env(Context::New());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011613 CHECK(!env.IsEmpty());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011614 const intptr_t kSize = 1024*1024;
11615 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
11616 cast(kSize));
11617 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11618 cast(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011619}
11620
11621
11622THREADED_TEST(DisposeEnteredContext) {
11623 v8::HandleScope scope;
11624 LocalContext outer;
11625 { v8::Persistent<v8::Context> inner = v8::Context::New();
11626 inner->Enter();
11627 inner.Dispose();
11628 inner.Clear();
11629 inner->Exit();
11630 }
11631}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011632
11633
11634// Regression test for issue 54, object templates with internal fields
11635// but no accessors or interceptors did not get their internal field
11636// count set on instances.
11637THREADED_TEST(Regress54) {
11638 v8::HandleScope outer;
11639 LocalContext context;
11640 static v8::Persistent<v8::ObjectTemplate> templ;
11641 if (templ.IsEmpty()) {
11642 v8::HandleScope inner;
11643 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11644 local->SetInternalFieldCount(1);
11645 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11646 }
11647 v8::Handle<v8::Object> result = templ->NewInstance();
11648 CHECK_EQ(1, result->InternalFieldCount());
11649}
11650
11651
11652// If part of the threaded tests, this test makes ThreadingTest fail
11653// on mac.
11654TEST(CatchStackOverflow) {
11655 v8::HandleScope scope;
11656 LocalContext context;
11657 v8::TryCatch try_catch;
11658 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11659 "function f() {"
11660 " return f();"
11661 "}"
11662 ""
11663 "f();"));
11664 v8::Handle<v8::Value> result = script->Run();
11665 CHECK(result.IsEmpty());
11666}
11667
11668
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011669static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11670 const char* resource_name,
11671 int line_offset) {
11672 v8::HandleScope scope;
11673 v8::TryCatch try_catch;
11674 v8::Handle<v8::Value> result = script->Run();
11675 CHECK(result.IsEmpty());
11676 CHECK(try_catch.HasCaught());
11677 v8::Handle<v8::Message> message = try_catch.Message();
11678 CHECK(!message.IsEmpty());
11679 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11680 CHECK_EQ(91, message->GetStartPosition());
11681 CHECK_EQ(92, message->GetEndPosition());
11682 CHECK_EQ(2, message->GetStartColumn());
11683 CHECK_EQ(3, message->GetEndColumn());
11684 v8::String::AsciiValue line(message->GetSourceLine());
11685 CHECK_EQ(" throw 'nirk';", *line);
11686 v8::String::AsciiValue name(message->GetScriptResourceName());
11687 CHECK_EQ(resource_name, *name);
11688}
11689
11690
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011691THREADED_TEST(TryCatchSourceInfo) {
11692 v8::HandleScope scope;
11693 LocalContext context;
11694 v8::Handle<v8::String> source = v8::String::New(
11695 "function Foo() {\n"
11696 " return Bar();\n"
11697 "}\n"
11698 "\n"
11699 "function Bar() {\n"
11700 " return Baz();\n"
11701 "}\n"
11702 "\n"
11703 "function Baz() {\n"
11704 " throw 'nirk';\n"
11705 "}\n"
11706 "\n"
11707 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011708
11709 const char* resource_name;
11710 v8::Handle<v8::Script> script;
11711 resource_name = "test.js";
11712 script = v8::Script::Compile(source, v8::String::New(resource_name));
11713 CheckTryCatchSourceInfo(script, resource_name, 0);
11714
11715 resource_name = "test1.js";
11716 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11717 script = v8::Script::Compile(source, &origin1);
11718 CheckTryCatchSourceInfo(script, resource_name, 0);
11719
11720 resource_name = "test2.js";
11721 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11722 script = v8::Script::Compile(source, &origin2);
11723 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011724}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011725
11726
11727THREADED_TEST(CompilationCache) {
11728 v8::HandleScope scope;
11729 LocalContext context;
11730 v8::Handle<v8::String> source0 = v8::String::New("1234");
11731 v8::Handle<v8::String> source1 = v8::String::New("1234");
11732 v8::Handle<v8::Script> script0 =
11733 v8::Script::Compile(source0, v8::String::New("test.js"));
11734 v8::Handle<v8::Script> script1 =
11735 v8::Script::Compile(source1, v8::String::New("test.js"));
11736 v8::Handle<v8::Script> script2 =
11737 v8::Script::Compile(source0); // different origin
11738 CHECK_EQ(1234, script0->Run()->Int32Value());
11739 CHECK_EQ(1234, script1->Run()->Int32Value());
11740 CHECK_EQ(1234, script2->Run()->Int32Value());
11741}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011742
11743
11744static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11745 ApiTestFuzzer::Fuzz();
11746 return v8_num(42);
11747}
11748
11749
11750THREADED_TEST(CallbackFunctionName) {
11751 v8::HandleScope scope;
11752 LocalContext context;
11753 Local<ObjectTemplate> t = ObjectTemplate::New();
11754 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11755 context->Global()->Set(v8_str("obj"), t->NewInstance());
11756 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11757 CHECK(value->IsString());
11758 v8::String::AsciiValue name(value);
11759 CHECK_EQ("asdf", *name);
11760}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011761
11762
11763THREADED_TEST(DateAccess) {
11764 v8::HandleScope scope;
11765 LocalContext context;
11766 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11767 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011768 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011769}
11770
11771
11772void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011773 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011774 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11775 CHECK_EQ(elmc, props->Length());
11776 for (int i = 0; i < elmc; i++) {
11777 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11778 CHECK_EQ(elmv[i], *elm);
11779 }
11780}
11781
11782
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011783void CheckOwnProperties(v8::Handle<v8::Value> val,
11784 int elmc,
11785 const char* elmv[]) {
11786 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11787 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11788 CHECK_EQ(elmc, props->Length());
11789 for (int i = 0; i < elmc; i++) {
11790 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11791 CHECK_EQ(elmv[i], *elm);
11792 }
11793}
11794
11795
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011796THREADED_TEST(PropertyEnumeration) {
11797 v8::HandleScope scope;
11798 LocalContext context;
11799 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11800 "var result = [];"
11801 "result[0] = {};"
11802 "result[1] = {a: 1, b: 2};"
11803 "result[2] = [1, 2, 3];"
11804 "var proto = {x: 1, y: 2, z: 3};"
11805 "var x = { __proto__: proto, w: 0, z: 1 };"
11806 "result[3] = x;"
11807 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011808 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011809 CHECK_EQ(4, elms->Length());
11810 int elmc0 = 0;
11811 const char** elmv0 = NULL;
11812 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011813 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011814 int elmc1 = 2;
11815 const char* elmv1[] = {"a", "b"};
11816 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011817 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011818 int elmc2 = 3;
11819 const char* elmv2[] = {"0", "1", "2"};
11820 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011821 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011822 int elmc3 = 4;
11823 const char* elmv3[] = {"w", "z", "x", "y"};
11824 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011825 int elmc4 = 2;
11826 const char* elmv4[] = {"w", "z"};
11827 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011828}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830THREADED_TEST(PropertyEnumeration2) {
11831 v8::HandleScope scope;
11832 LocalContext context;
11833 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11834 "var result = [];"
11835 "result[0] = {};"
11836 "result[1] = {a: 1, b: 2};"
11837 "result[2] = [1, 2, 3];"
11838 "var proto = {x: 1, y: 2, z: 3};"
11839 "var x = { __proto__: proto, w: 0, z: 1 };"
11840 "result[3] = x;"
11841 "result;"))->Run();
11842 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11843 CHECK_EQ(4, elms->Length());
11844 int elmc0 = 0;
11845 const char** elmv0 = NULL;
11846 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11847
11848 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11849 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11850 CHECK_EQ(0, props->Length());
11851 for (uint32_t i = 0; i < props->Length(); i++) {
11852 printf("p[%d]\n", i);
11853 }
11854}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011855
ager@chromium.org870a0b62008-11-04 11:43:05 +000011856static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11857 Local<Value> name,
11858 v8::AccessType type,
11859 Local<Value> data) {
11860 return type != v8::ACCESS_SET;
11861}
11862
11863
11864static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11865 uint32_t key,
11866 v8::AccessType type,
11867 Local<Value> data) {
11868 return type != v8::ACCESS_SET;
11869}
11870
11871
11872THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11873 v8::HandleScope scope;
11874 LocalContext context;
11875 Local<ObjectTemplate> templ = ObjectTemplate::New();
11876 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11877 IndexedSetAccessBlocker);
11878 templ->Set(v8_str("x"), v8::True());
11879 Local<v8::Object> instance = templ->NewInstance();
11880 context->Global()->Set(v8_str("obj"), instance);
11881 Local<Value> value = CompileRun("obj.x");
11882 CHECK(value->BooleanValue());
11883}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011884
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011885
ager@chromium.org32912102009-01-16 10:38:43 +000011886static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11887 Local<Value> name,
11888 v8::AccessType type,
11889 Local<Value> data) {
11890 return false;
11891}
11892
11893
11894static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11895 uint32_t key,
11896 v8::AccessType type,
11897 Local<Value> data) {
11898 return false;
11899}
11900
11901
11902
11903THREADED_TEST(AccessChecksReenabledCorrectly) {
11904 v8::HandleScope scope;
11905 LocalContext context;
11906 Local<ObjectTemplate> templ = ObjectTemplate::New();
11907 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11908 IndexedGetAccessBlocker);
11909 templ->Set(v8_str("a"), v8_str("a"));
11910 // Add more than 8 (see kMaxFastProperties) properties
11911 // so that the constructor will force copying map.
11912 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011913 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000011914 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011915 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000011916 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011917 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000011918 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011919 buf[2] = k;
11920 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000011921 templ->Set(v8_str(buf), v8::Number::New(k));
11922 }
11923 }
11924 }
11925
11926 Local<v8::Object> instance_1 = templ->NewInstance();
11927 context->Global()->Set(v8_str("obj_1"), instance_1);
11928
11929 Local<Value> value_1 = CompileRun("obj_1.a");
11930 CHECK(value_1->IsUndefined());
11931
11932 Local<v8::Object> instance_2 = templ->NewInstance();
11933 context->Global()->Set(v8_str("obj_2"), instance_2);
11934
11935 Local<Value> value_2 = CompileRun("obj_2.a");
11936 CHECK(value_2->IsUndefined());
11937}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011938
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011939
ager@chromium.org8bb60582008-12-11 12:02:20 +000011940// This tests that access check information remains on the global
11941// object template when creating contexts.
11942THREADED_TEST(AccessControlRepeatedContextCreation) {
11943 v8::HandleScope handle_scope;
11944 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11945 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11946 IndexedSetAccessBlocker);
11947 i::Handle<i::ObjectTemplateInfo> internal_template =
11948 v8::Utils::OpenHandle(*global_template);
11949 CHECK(!internal_template->constructor()->IsUndefined());
11950 i::Handle<i::FunctionTemplateInfo> constructor(
11951 i::FunctionTemplateInfo::cast(internal_template->constructor()));
11952 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011953 v8::Persistent<Context> context0(Context::New(NULL, global_template));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011954 CHECK(!context0.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +000011955 CHECK(!constructor->access_check_info()->IsUndefined());
11956}
11957
11958
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011959THREADED_TEST(TurnOnAccessCheck) {
11960 v8::HandleScope handle_scope;
11961
11962 // Create an environment with access check to the global object disabled by
11963 // default.
11964 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11965 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11966 IndexedGetAccessBlocker,
11967 v8::Handle<v8::Value>(),
11968 false);
11969 v8::Persistent<Context> context = Context::New(NULL, global_template);
11970 Context::Scope context_scope(context);
11971
11972 // Set up a property and a number of functions.
11973 context->Global()->Set(v8_str("a"), v8_num(1));
11974 CompileRun("function f1() {return a;}"
11975 "function f2() {return a;}"
11976 "function g1() {return h();}"
11977 "function g2() {return h();}"
11978 "function h() {return 1;}");
11979 Local<Function> f1 =
11980 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11981 Local<Function> f2 =
11982 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11983 Local<Function> g1 =
11984 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11985 Local<Function> g2 =
11986 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11987 Local<Function> h =
11988 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11989
11990 // Get the global object.
11991 v8::Handle<v8::Object> global = context->Global();
11992
11993 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11994 // uses the runtime system to retreive property a whereas f2 uses global load
11995 // inline cache.
11996 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11997 for (int i = 0; i < 4; i++) {
11998 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11999 }
12000
12001 // Same for g1 and g2.
12002 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12003 for (int i = 0; i < 4; i++) {
12004 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12005 }
12006
12007 // Detach the global and turn on access check.
12008 context->DetachGlobal();
12009 context->Global()->TurnOnAccessCheck();
12010
12011 // Failing access check to property get results in undefined.
12012 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12013 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12014
12015 // Failing access check to function call results in exception.
12016 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12017 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12018
12019 // No failing access check when just returning a constant.
12020 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12021}
12022
12023
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012024static const char* kPropertyA = "a";
12025static const char* kPropertyH = "h";
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012026
12027static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
12028 Local<Value> name,
12029 v8::AccessType type,
12030 Local<Value> data) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012031 if (!name->IsString()) return false;
12032 i::Handle<i::String> name_handle =
12033 v8::Utils::OpenHandle(String::Cast(*name));
12034 return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
12035 && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012036}
12037
12038
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012039THREADED_TEST(TurnOnAccessCheckAndRecompile) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012040 v8::HandleScope handle_scope;
12041
12042 // Create an environment with access check to the global object disabled by
12043 // default. When the registered access checker will block access to properties
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012044 // a and h.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012045 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12046 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
12047 IndexedGetAccessBlocker,
12048 v8::Handle<v8::Value>(),
12049 false);
12050 v8::Persistent<Context> context = Context::New(NULL, global_template);
12051 Context::Scope context_scope(context);
12052
12053 // Set up a property and a number of functions.
12054 context->Global()->Set(v8_str("a"), v8_num(1));
12055 static const char* source = "function f1() {return a;}"
12056 "function f2() {return a;}"
12057 "function g1() {return h();}"
12058 "function g2() {return h();}"
12059 "function h() {return 1;}";
12060
12061 CompileRun(source);
12062 Local<Function> f1;
12063 Local<Function> f2;
12064 Local<Function> g1;
12065 Local<Function> g2;
12066 Local<Function> h;
12067 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12068 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12069 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12070 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12071 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12072
12073 // Get the global object.
12074 v8::Handle<v8::Object> global = context->Global();
12075
12076 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12077 // uses the runtime system to retreive property a whereas f2 uses global load
12078 // inline cache.
12079 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12080 for (int i = 0; i < 4; i++) {
12081 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12082 }
12083
12084 // Same for g1 and g2.
12085 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12086 for (int i = 0; i < 4; i++) {
12087 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12088 }
12089
12090 // Detach the global and turn on access check now blocking access to property
12091 // a and function h.
12092 context->DetachGlobal();
12093 context->Global()->TurnOnAccessCheck();
12094
12095 // Failing access check to property get results in undefined.
12096 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12097 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12098
12099 // Failing access check to function call results in exception.
12100 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12101 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12102
12103 // No failing access check when just returning a constant.
12104 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12105
12106 // Now compile the source again. And get the newly compiled functions, except
12107 // for h for which access is blocked.
12108 CompileRun(source);
12109 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12110 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12111 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12112 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12113 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
12114
12115 // Failing access check to property get results in undefined.
12116 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12117 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12118
12119 // Failing access check to function call results in exception.
12120 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12121 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12122}
12123
12124
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012125// This test verifies that pre-compilation (aka preparsing) can be called
12126// without initializing the whole VM. Thus we cannot run this test in a
12127// multi-threaded setup.
12128TEST(PreCompile) {
12129 // TODO(155): This test would break without the initialization of V8. This is
12130 // a workaround for now to make this test not fail.
12131 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012132 const char* script = "function foo(a) { return a+1; }";
12133 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012134 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012135 CHECK_NE(sd->Length(), 0);
12136 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012137 CHECK(!sd->HasError());
12138 delete sd;
12139}
12140
12141
12142TEST(PreCompileWithError) {
12143 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012144 const char* script = "function foo(a) { return 1 * * 2; }";
12145 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012146 v8::ScriptData::PreCompile(script, i::StrLength(script));
12147 CHECK(sd->HasError());
12148 delete sd;
12149}
12150
12151
12152TEST(Regress31661) {
12153 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012154 const char* script = " The Definintive Guide";
12155 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012156 v8::ScriptData::PreCompile(script, i::StrLength(script));
12157 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012158 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012159}
12160
12161
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012162// Tests that ScriptData can be serialized and deserialized.
12163TEST(PreCompileSerialization) {
12164 v8::V8::Initialize();
12165 const char* script = "function foo(a) { return a+1; }";
12166 v8::ScriptData* sd =
12167 v8::ScriptData::PreCompile(script, i::StrLength(script));
12168
12169 // Serialize.
12170 int serialized_data_length = sd->Length();
12171 char* serialized_data = i::NewArray<char>(serialized_data_length);
12172 memcpy(serialized_data, sd->Data(), serialized_data_length);
12173
12174 // Deserialize.
12175 v8::ScriptData* deserialized_sd =
12176 v8::ScriptData::New(serialized_data, serialized_data_length);
12177
12178 // Verify that the original is the same as the deserialized.
12179 CHECK_EQ(sd->Length(), deserialized_sd->Length());
12180 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
12181 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
12182
12183 delete sd;
12184 delete deserialized_sd;
12185}
12186
12187
12188// Attempts to deserialize bad data.
12189TEST(PreCompileDeserializationError) {
12190 v8::V8::Initialize();
12191 const char* data = "DONT CARE";
12192 int invalid_size = 3;
12193 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
12194
12195 CHECK_EQ(0, sd->Length());
12196
12197 delete sd;
12198}
12199
12200
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012201// Attempts to deserialize bad data.
12202TEST(PreCompileInvalidPreparseDataError) {
12203 v8::V8::Initialize();
12204 v8::HandleScope scope;
12205 LocalContext context;
12206
12207 const char* script = "function foo(){ return 5;}\n"
12208 "function bar(){ return 6 + 7;} foo();";
12209 v8::ScriptData* sd =
12210 v8::ScriptData::PreCompile(script, i::StrLength(script));
12211 CHECK(!sd->HasError());
12212 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000012213 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000012214 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012215 const int kFunctionEntryStartOffset = 0;
12216 const int kFunctionEntryEndOffset = 1;
12217 unsigned* sd_data =
12218 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012219
12220 // Overwrite function bar's end position with 0.
12221 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12222 v8::TryCatch try_catch;
12223
12224 Local<String> source = String::New(script);
12225 Local<Script> compiled_script = Script::New(source, NULL, sd);
12226 CHECK(try_catch.HasCaught());
12227 String::AsciiValue exception_value(try_catch.Message()->Get());
12228 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12229 *exception_value);
12230
12231 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012232
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012233 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012234 // will not be found when searching for it by position and we should fall
12235 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000012236 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12237 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012238 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12239 200;
12240 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012241 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012242
12243 delete sd;
12244}
12245
12246
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012247// Verifies that the Handle<String> and const char* versions of the API produce
12248// the same results (at least for one trivial case).
12249TEST(PreCompileAPIVariationsAreSame) {
12250 v8::V8::Initialize();
12251 v8::HandleScope scope;
12252
12253 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012254
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012255 v8::ScriptData* sd_from_cstring =
12256 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12257
12258 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012259 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012260 v8::String::NewExternal(resource));
12261
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012262 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12263 v8::String::New(cstring));
12264
12265 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012266 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012267 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012268 sd_from_cstring->Length()));
12269
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012270 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12271 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12272 sd_from_string->Data(),
12273 sd_from_cstring->Length()));
12274
12275
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012276 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012277 delete sd_from_external_string;
12278 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012279}
12280
12281
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012282// This tests that we do not allow dictionary load/call inline caches
12283// to use functions that have not yet been compiled. The potential
12284// problem of loading a function that has not yet been compiled can
12285// arise because we share code between contexts via the compilation
12286// cache.
12287THREADED_TEST(DictionaryICLoadedFunction) {
12288 v8::HandleScope scope;
12289 // Test LoadIC.
12290 for (int i = 0; i < 2; i++) {
12291 LocalContext context;
12292 context->Global()->Set(v8_str("tmp"), v8::True());
12293 context->Global()->Delete(v8_str("tmp"));
12294 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12295 }
12296 // Test CallIC.
12297 for (int i = 0; i < 2; i++) {
12298 LocalContext context;
12299 context->Global()->Set(v8_str("tmp"), v8::True());
12300 context->Global()->Delete(v8_str("tmp"));
12301 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12302 }
12303}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012304
12305
12306// Test that cross-context new calls use the context of the callee to
12307// create the new JavaScript object.
12308THREADED_TEST(CrossContextNew) {
12309 v8::HandleScope scope;
12310 v8::Persistent<Context> context0 = Context::New();
12311 v8::Persistent<Context> context1 = Context::New();
12312
12313 // Allow cross-domain access.
12314 Local<String> token = v8_str("<security token>");
12315 context0->SetSecurityToken(token);
12316 context1->SetSecurityToken(token);
12317
12318 // Set an 'x' property on the Object prototype and define a
12319 // constructor function in context0.
12320 context0->Enter();
12321 CompileRun("Object.prototype.x = 42; function C() {};");
12322 context0->Exit();
12323
12324 // Call the constructor function from context0 and check that the
12325 // result has the 'x' property.
12326 context1->Enter();
12327 context1->Global()->Set(v8_str("other"), context0->Global());
12328 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12329 CHECK(value->IsInt32());
12330 CHECK_EQ(42, value->Int32Value());
12331 context1->Exit();
12332
12333 // Dispose the contexts to allow them to be garbage collected.
12334 context0.Dispose();
12335 context1.Dispose();
12336}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012337
12338
12339class RegExpInterruptTest {
12340 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012341 RegExpInterruptTest() : block_(NULL) {}
12342 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012343 void RunTest() {
12344 block_ = i::OS::CreateSemaphore(0);
12345 gc_count_ = 0;
12346 gc_during_regexp_ = 0;
12347 regexp_success_ = false;
12348 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012349 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012350 gc_thread.Start();
12351 v8::Locker::StartPreemption(1);
12352
12353 LongRunningRegExp();
12354 {
12355 v8::Unlocker unlock;
12356 gc_thread.Join();
12357 }
12358 v8::Locker::StopPreemption();
12359 CHECK(regexp_success_);
12360 CHECK(gc_success_);
12361 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012362
ager@chromium.org381abbb2009-02-25 13:23:22 +000012363 private:
12364 // Number of garbage collections required.
12365 static const int kRequiredGCs = 5;
12366
12367 class GCThread : public i::Thread {
12368 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012369 explicit GCThread(RegExpInterruptTest* test)
12370 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012371 virtual void Run() {
12372 test_->CollectGarbage();
12373 }
12374 private:
12375 RegExpInterruptTest* test_;
12376 };
12377
12378 void CollectGarbage() {
12379 block_->Wait();
12380 while (gc_during_regexp_ < kRequiredGCs) {
12381 {
12382 v8::Locker lock;
12383 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012385 gc_count_++;
12386 }
12387 i::OS::Sleep(1);
12388 }
12389 gc_success_ = true;
12390 }
12391
12392 void LongRunningRegExp() {
12393 block_->Signal(); // Enable garbage collection thread on next preemption.
12394 int rounds = 0;
12395 while (gc_during_regexp_ < kRequiredGCs) {
12396 int gc_before = gc_count_;
12397 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012398 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012399 const char* c_source =
12400 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12401 ".exec('aaaaaaaaaaaaaaab') === null";
12402 Local<String> source = String::New(c_source);
12403 Local<Script> script = Script::Compile(source);
12404 Local<Value> result = script->Run();
12405 if (!result->BooleanValue()) {
12406 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12407 return;
12408 }
12409 }
12410 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012411 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012412 const char* c_source =
12413 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12414 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12415 Local<String> source = String::New(c_source);
12416 Local<Script> script = Script::Compile(source);
12417 Local<Value> result = script->Run();
12418 if (!result->BooleanValue()) {
12419 gc_during_regexp_ = kRequiredGCs;
12420 return;
12421 }
12422 }
12423 int gc_after = gc_count_;
12424 gc_during_regexp_ += gc_after - gc_before;
12425 rounds++;
12426 i::OS::Sleep(1);
12427 }
12428 regexp_success_ = true;
12429 }
12430
12431 i::Semaphore* block_;
12432 int gc_count_;
12433 int gc_during_regexp_;
12434 bool regexp_success_;
12435 bool gc_success_;
12436};
12437
12438
12439// Test that a regular expression execution can be interrupted and
12440// survive a garbage collection.
12441TEST(RegExpInterruption) {
12442 v8::Locker lock;
12443 v8::V8::Initialize();
12444 v8::HandleScope scope;
12445 Local<Context> local_env;
12446 {
12447 LocalContext env;
12448 local_env = env.local();
12449 }
12450
12451 // Local context should still be live.
12452 CHECK(!local_env.IsEmpty());
12453 local_env->Enter();
12454
12455 // Should complete without problems.
12456 RegExpInterruptTest().RunTest();
12457
12458 local_env->Exit();
12459}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012460
12461
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012462class ApplyInterruptTest {
12463 public:
12464 ApplyInterruptTest() : block_(NULL) {}
12465 ~ApplyInterruptTest() { delete block_; }
12466 void RunTest() {
12467 block_ = i::OS::CreateSemaphore(0);
12468 gc_count_ = 0;
12469 gc_during_apply_ = 0;
12470 apply_success_ = false;
12471 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012472 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012473 gc_thread.Start();
12474 v8::Locker::StartPreemption(1);
12475
12476 LongRunningApply();
12477 {
12478 v8::Unlocker unlock;
12479 gc_thread.Join();
12480 }
12481 v8::Locker::StopPreemption();
12482 CHECK(apply_success_);
12483 CHECK(gc_success_);
12484 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012485
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012486 private:
12487 // Number of garbage collections required.
12488 static const int kRequiredGCs = 2;
12489
12490 class GCThread : public i::Thread {
12491 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012492 explicit GCThread(ApplyInterruptTest* test)
12493 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012494 virtual void Run() {
12495 test_->CollectGarbage();
12496 }
12497 private:
12498 ApplyInterruptTest* test_;
12499 };
12500
12501 void CollectGarbage() {
12502 block_->Wait();
12503 while (gc_during_apply_ < kRequiredGCs) {
12504 {
12505 v8::Locker lock;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012506 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012507 gc_count_++;
12508 }
12509 i::OS::Sleep(1);
12510 }
12511 gc_success_ = true;
12512 }
12513
12514 void LongRunningApply() {
12515 block_->Signal();
12516 int rounds = 0;
12517 while (gc_during_apply_ < kRequiredGCs) {
12518 int gc_before = gc_count_;
12519 {
12520 const char* c_source =
12521 "function do_very_little(bar) {"
12522 " this.foo = bar;"
12523 "}"
12524 "for (var i = 0; i < 100000; i++) {"
12525 " do_very_little.apply(this, ['bar']);"
12526 "}";
12527 Local<String> source = String::New(c_source);
12528 Local<Script> script = Script::Compile(source);
12529 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000012530 // Check that no exception was thrown.
12531 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012532 }
12533 int gc_after = gc_count_;
12534 gc_during_apply_ += gc_after - gc_before;
12535 rounds++;
12536 }
12537 apply_success_ = true;
12538 }
12539
12540 i::Semaphore* block_;
12541 int gc_count_;
12542 int gc_during_apply_;
12543 bool apply_success_;
12544 bool gc_success_;
12545};
12546
12547
12548// Test that nothing bad happens if we get a preemption just when we were
12549// about to do an apply().
12550TEST(ApplyInterruption) {
12551 v8::Locker lock;
12552 v8::V8::Initialize();
12553 v8::HandleScope scope;
12554 Local<Context> local_env;
12555 {
12556 LocalContext env;
12557 local_env = env.local();
12558 }
12559
12560 // Local context should still be live.
12561 CHECK(!local_env.IsEmpty());
12562 local_env->Enter();
12563
12564 // Should complete without problems.
12565 ApplyInterruptTest().RunTest();
12566
12567 local_env->Exit();
12568}
12569
12570
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012571// Verify that we can clone an object
12572TEST(ObjectClone) {
12573 v8::HandleScope scope;
12574 LocalContext env;
12575
12576 const char* sample =
12577 "var rv = {};" \
12578 "rv.alpha = 'hello';" \
12579 "rv.beta = 123;" \
12580 "rv;";
12581
12582 // Create an object, verify basics.
12583 Local<Value> val = CompileRun(sample);
12584 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012585 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012586 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12587
12588 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12589 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12590 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12591
12592 // Clone it.
12593 Local<v8::Object> clone = obj->Clone();
12594 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12595 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12596 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12597
12598 // Set a property on the clone, verify each object.
12599 clone->Set(v8_str("beta"), v8::Integer::New(456));
12600 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12601 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12602}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012603
12604
ager@chromium.org5ec48922009-05-05 07:25:34 +000012605class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12606 public:
12607 explicit AsciiVectorResource(i::Vector<const char> vector)
12608 : data_(vector) {}
12609 virtual ~AsciiVectorResource() {}
12610 virtual size_t length() const { return data_.length(); }
12611 virtual const char* data() const { return data_.start(); }
12612 private:
12613 i::Vector<const char> data_;
12614};
12615
12616
12617class UC16VectorResource : public v8::String::ExternalStringResource {
12618 public:
12619 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12620 : data_(vector) {}
12621 virtual ~UC16VectorResource() {}
12622 virtual size_t length() const { return data_.length(); }
12623 virtual const i::uc16* data() const { return data_.start(); }
12624 private:
12625 i::Vector<const i::uc16> data_;
12626};
12627
12628
12629static void MorphAString(i::String* string,
12630 AsciiVectorResource* ascii_resource,
12631 UC16VectorResource* uc16_resource) {
12632 CHECK(i::StringShape(string).IsExternal());
12633 if (string->IsAsciiRepresentation()) {
12634 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012635 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012636 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012638 i::ExternalTwoByteString* morphed =
12639 i::ExternalTwoByteString::cast(string);
12640 morphed->set_resource(uc16_resource);
12641 } else {
12642 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012644 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012646 i::ExternalAsciiString* morphed =
12647 i::ExternalAsciiString::cast(string);
12648 morphed->set_resource(ascii_resource);
12649 }
12650}
12651
12652
12653// Test that we can still flatten a string if the components it is built up
12654// from have been turned into 16 bit strings in the mean time.
12655THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012656 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000012657 const char* c_string = "Now is the time for all good men"
12658 " to come to the aid of the party";
12659 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12660 {
12661 v8::HandleScope scope;
12662 LocalContext env;
12663 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012664 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012665 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012666 i::Vector<const uint16_t>(two_byte_string,
12667 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012668
12669 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012671 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012672 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012673
12674 env->Global()->Set(v8_str("lhs"), lhs);
12675 env->Global()->Set(v8_str("rhs"), rhs);
12676
12677 CompileRun(
12678 "var cons = lhs + rhs;"
12679 "var slice = lhs.substring(1, lhs.length - 1);"
12680 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12681
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012682 CHECK(!lhs->MayContainNonAscii());
12683 CHECK(!rhs->MayContainNonAscii());
12684
ager@chromium.org5ec48922009-05-05 07:25:34 +000012685 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12686 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12687
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012688 // This should UTF-8 without flattening, since everything is ASCII.
12689 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12690 CHECK_EQ(128, cons->Utf8Length());
12691 int nchars = -1;
12692 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12693 CHECK_EQ(128, nchars);
12694 CHECK_EQ(0, strcmp(
12695 utf_buffer,
12696 "Now is the time for all good men to come to the aid of the party"
12697 "Now is the time for all good men to come to the aid of the party"));
12698
ager@chromium.org5ec48922009-05-05 07:25:34 +000012699 // Now do some stuff to make sure the strings are flattened, etc.
12700 CompileRun(
12701 "/[^a-z]/.test(cons);"
12702 "/[^a-z]/.test(slice);"
12703 "/[^a-z]/.test(slice_on_cons);");
12704 const char* expected_cons =
12705 "Now is the time for all good men to come to the aid of the party"
12706 "Now is the time for all good men to come to the aid of the party";
12707 const char* expected_slice =
12708 "ow is the time for all good men to come to the aid of the part";
12709 const char* expected_slice_on_cons =
12710 "ow is the time for all good men to come to the aid of the party"
12711 "Now is the time for all good men to come to the aid of the part";
12712 CHECK_EQ(String::New(expected_cons),
12713 env->Global()->Get(v8_str("cons")));
12714 CHECK_EQ(String::New(expected_slice),
12715 env->Global()->Get(v8_str("slice")));
12716 CHECK_EQ(String::New(expected_slice_on_cons),
12717 env->Global()->Get(v8_str("slice_on_cons")));
12718 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012719 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000012720}
12721
12722
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012723TEST(CompileExternalTwoByteSource) {
12724 v8::HandleScope scope;
12725 LocalContext context;
12726
12727 // This is a very short list of sources, which currently is to check for a
12728 // regression caused by r2703.
12729 const char* ascii_sources[] = {
12730 "0.5",
12731 "-0.5", // This mainly testes PushBack in the Scanner.
12732 "--0.5", // This mainly testes PushBack in the Scanner.
12733 NULL
12734 };
12735
12736 // Compile the sources as external two byte strings.
12737 for (int i = 0; ascii_sources[i] != NULL; i++) {
12738 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12739 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012740 i::Vector<const uint16_t>(two_byte_string,
12741 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012742 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12743 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012744 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012745 }
12746}
12747
12748
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012749class RegExpStringModificationTest {
12750 public:
12751 RegExpStringModificationTest()
12752 : block_(i::OS::CreateSemaphore(0)),
12753 morphs_(0),
12754 morphs_during_regexp_(0),
12755 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12756 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12757 ~RegExpStringModificationTest() { delete block_; }
12758 void RunTest() {
12759 regexp_success_ = false;
12760 morph_success_ = false;
12761
12762 // Initialize the contents of two_byte_content_ to be a uc16 representation
12763 // of "aaaaaaaaaaaaaab".
12764 for (int i = 0; i < 14; i++) {
12765 two_byte_content_[i] = 'a';
12766 }
12767 two_byte_content_[14] = 'b';
12768
12769 // Create the input string for the regexp - the one we are going to change
12770 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012771 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012772
12773 // Inject the input as a global variable.
12774 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012776 i::Isolate::Current()->native_context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012777 *input_name,
12778 *input_,
12779 NONE,
12780 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012781
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012782 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012783 morph_thread.Start();
12784 v8::Locker::StartPreemption(1);
12785 LongRunningRegExp();
12786 {
12787 v8::Unlocker unlock;
12788 morph_thread.Join();
12789 }
12790 v8::Locker::StopPreemption();
12791 CHECK(regexp_success_);
12792 CHECK(morph_success_);
12793 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012794
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012795 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012796 // Number of string modifications required.
12797 static const int kRequiredModifications = 5;
12798 static const int kMaxModifications = 100;
12799
12800 class MorphThread : public i::Thread {
12801 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012802 explicit MorphThread(RegExpStringModificationTest* test)
12803 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012804 virtual void Run() {
12805 test_->MorphString();
12806 }
12807 private:
12808 RegExpStringModificationTest* test_;
12809 };
12810
12811 void MorphString() {
12812 block_->Wait();
12813 while (morphs_during_regexp_ < kRequiredModifications &&
12814 morphs_ < kMaxModifications) {
12815 {
12816 v8::Locker lock;
12817 // Swap string between ascii and two-byte representation.
12818 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000012819 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012820 morphs_++;
12821 }
12822 i::OS::Sleep(1);
12823 }
12824 morph_success_ = true;
12825 }
12826
12827 void LongRunningRegExp() {
12828 block_->Signal(); // Enable morphing thread on next preemption.
12829 while (morphs_during_regexp_ < kRequiredModifications &&
12830 morphs_ < kMaxModifications) {
12831 int morphs_before = morphs_;
12832 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000012833 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012834 // Match 15-30 "a"'s against 14 and a "b".
12835 const char* c_source =
12836 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12837 ".exec(input) === null";
12838 Local<String> source = String::New(c_source);
12839 Local<Script> script = Script::Compile(source);
12840 Local<Value> result = script->Run();
12841 CHECK(result->IsTrue());
12842 }
12843 int morphs_after = morphs_;
12844 morphs_during_regexp_ += morphs_after - morphs_before;
12845 }
12846 regexp_success_ = true;
12847 }
12848
12849 i::uc16 two_byte_content_[15];
12850 i::Semaphore* block_;
12851 int morphs_;
12852 int morphs_during_regexp_;
12853 bool regexp_success_;
12854 bool morph_success_;
12855 i::Handle<i::String> input_;
12856 AsciiVectorResource ascii_resource_;
12857 UC16VectorResource uc16_resource_;
12858};
12859
12860
12861// Test that a regular expression execution can be interrupted and
12862// the string changed without failing.
12863TEST(RegExpStringModification) {
12864 v8::Locker lock;
12865 v8::V8::Initialize();
12866 v8::HandleScope scope;
12867 Local<Context> local_env;
12868 {
12869 LocalContext env;
12870 local_env = env.local();
12871 }
12872
12873 // Local context should still be live.
12874 CHECK(!local_env.IsEmpty());
12875 local_env->Enter();
12876
12877 // Should complete without problems.
12878 RegExpStringModificationTest().RunTest();
12879
12880 local_env->Exit();
12881}
12882
12883
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012884// Test that we cannot set a property on the global object if there
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012885// is a read-only property in the prototype chain.
12886TEST(ReadOnlyPropertyInGlobalProto) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012887 i::FLAG_es5_readonly = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012888 v8::HandleScope scope;
12889 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12890 LocalContext context(0, templ);
12891 v8::Handle<v8::Object> global = context->Global();
12892 v8::Handle<v8::Object> global_proto =
12893 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12894 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12895 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12896 // Check without 'eval' or 'with'.
12897 v8::Handle<v8::Value> res =
12898 CompileRun("function f() { x = 42; return x; }; f()");
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012899 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012900 // Check with 'eval'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012901 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12902 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012903 // Check with 'with'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012904 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12905 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012906}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012907
12908static int force_set_set_count = 0;
12909static int force_set_get_count = 0;
12910bool pass_on_get = false;
12911
12912static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12913 const v8::AccessorInfo& info) {
12914 force_set_get_count++;
12915 if (pass_on_get) {
12916 return v8::Handle<v8::Value>();
12917 } else {
12918 return v8::Int32::New(3);
12919 }
12920}
12921
12922static void ForceSetSetter(v8::Local<v8::String> name,
12923 v8::Local<v8::Value> value,
12924 const v8::AccessorInfo& info) {
12925 force_set_set_count++;
12926}
12927
12928static v8::Handle<v8::Value> ForceSetInterceptSetter(
12929 v8::Local<v8::String> name,
12930 v8::Local<v8::Value> value,
12931 const v8::AccessorInfo& info) {
12932 force_set_set_count++;
12933 return v8::Undefined();
12934}
12935
12936TEST(ForceSet) {
12937 force_set_get_count = 0;
12938 force_set_set_count = 0;
12939 pass_on_get = false;
12940
12941 v8::HandleScope scope;
12942 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12943 v8::Handle<v8::String> access_property = v8::String::New("a");
12944 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12945 LocalContext context(NULL, templ);
12946 v8::Handle<v8::Object> global = context->Global();
12947
12948 // Ordinary properties
12949 v8::Handle<v8::String> simple_property = v8::String::New("p");
12950 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12951 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12952 // This should fail because the property is read-only
12953 global->Set(simple_property, v8::Int32::New(5));
12954 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12955 // This should succeed even though the property is read-only
12956 global->ForceSet(simple_property, v8::Int32::New(6));
12957 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12958
12959 // Accessors
12960 CHECK_EQ(0, force_set_set_count);
12961 CHECK_EQ(0, force_set_get_count);
12962 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12963 // CHECK_EQ the property shouldn't override it, just call the setter
12964 // which in this case does nothing.
12965 global->Set(access_property, v8::Int32::New(7));
12966 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12967 CHECK_EQ(1, force_set_set_count);
12968 CHECK_EQ(2, force_set_get_count);
12969 // Forcing the property to be set should override the accessor without
12970 // calling it
12971 global->ForceSet(access_property, v8::Int32::New(8));
12972 CHECK_EQ(8, global->Get(access_property)->Int32Value());
12973 CHECK_EQ(1, force_set_set_count);
12974 CHECK_EQ(2, force_set_get_count);
12975}
12976
12977TEST(ForceSetWithInterceptor) {
12978 force_set_get_count = 0;
12979 force_set_set_count = 0;
12980 pass_on_get = false;
12981
12982 v8::HandleScope scope;
12983 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12984 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12985 LocalContext context(NULL, templ);
12986 v8::Handle<v8::Object> global = context->Global();
12987
12988 v8::Handle<v8::String> some_property = v8::String::New("a");
12989 CHECK_EQ(0, force_set_set_count);
12990 CHECK_EQ(0, force_set_get_count);
12991 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12992 // Setting the property shouldn't override it, just call the setter
12993 // which in this case does nothing.
12994 global->Set(some_property, v8::Int32::New(7));
12995 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12996 CHECK_EQ(1, force_set_set_count);
12997 CHECK_EQ(2, force_set_get_count);
12998 // Getting the property when the interceptor returns an empty handle
12999 // should yield undefined, since the property isn't present on the
13000 // object itself yet.
13001 pass_on_get = true;
13002 CHECK(global->Get(some_property)->IsUndefined());
13003 CHECK_EQ(1, force_set_set_count);
13004 CHECK_EQ(3, force_set_get_count);
13005 // Forcing the property to be set should cause the value to be
13006 // set locally without calling the interceptor.
13007 global->ForceSet(some_property, v8::Int32::New(8));
13008 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13009 CHECK_EQ(1, force_set_set_count);
13010 CHECK_EQ(4, force_set_get_count);
13011 // Reenabling the interceptor should cause it to take precedence over
13012 // the property
13013 pass_on_get = false;
13014 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13015 CHECK_EQ(1, force_set_set_count);
13016 CHECK_EQ(5, force_set_get_count);
13017 // The interceptor should also work for other properties
13018 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
13019 CHECK_EQ(1, force_set_set_count);
13020 CHECK_EQ(6, force_set_get_count);
13021}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013022
13023
ager@chromium.orge2902be2009-06-08 12:21:35 +000013024THREADED_TEST(ForceDelete) {
13025 v8::HandleScope scope;
13026 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13027 LocalContext context(NULL, templ);
13028 v8::Handle<v8::Object> global = context->Global();
13029
13030 // Ordinary properties
13031 v8::Handle<v8::String> simple_property = v8::String::New("p");
13032 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
13033 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13034 // This should fail because the property is dont-delete.
13035 CHECK(!global->Delete(simple_property));
13036 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13037 // This should succeed even though the property is dont-delete.
13038 CHECK(global->ForceDelete(simple_property));
13039 CHECK(global->Get(simple_property)->IsUndefined());
13040}
13041
13042
13043static int force_delete_interceptor_count = 0;
13044static bool pass_on_delete = false;
13045
13046
13047static v8::Handle<v8::Boolean> ForceDeleteDeleter(
13048 v8::Local<v8::String> name,
13049 const v8::AccessorInfo& info) {
13050 force_delete_interceptor_count++;
13051 if (pass_on_delete) {
13052 return v8::Handle<v8::Boolean>();
13053 } else {
13054 return v8::True();
13055 }
13056}
13057
13058
13059THREADED_TEST(ForceDeleteWithInterceptor) {
13060 force_delete_interceptor_count = 0;
13061 pass_on_delete = false;
13062
13063 v8::HandleScope scope;
13064 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13065 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
13066 LocalContext context(NULL, templ);
13067 v8::Handle<v8::Object> global = context->Global();
13068
13069 v8::Handle<v8::String> some_property = v8::String::New("a");
13070 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
13071
13072 // Deleting a property should get intercepted and nothing should
13073 // happen.
13074 CHECK_EQ(0, force_delete_interceptor_count);
13075 CHECK(global->Delete(some_property));
13076 CHECK_EQ(1, force_delete_interceptor_count);
13077 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13078 // Deleting the property when the interceptor returns an empty
13079 // handle should not delete the property since it is DontDelete.
13080 pass_on_delete = true;
13081 CHECK(!global->Delete(some_property));
13082 CHECK_EQ(2, force_delete_interceptor_count);
13083 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13084 // Forcing the property to be deleted should delete the value
13085 // without calling the interceptor.
13086 CHECK(global->ForceDelete(some_property));
13087 CHECK(global->Get(some_property)->IsUndefined());
13088 CHECK_EQ(2, force_delete_interceptor_count);
13089}
13090
13091
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013092// Make sure that forcing a delete invalidates any IC stubs, so we
13093// don't read the hole value.
13094THREADED_TEST(ForceDeleteIC) {
13095 v8::HandleScope scope;
13096 LocalContext context;
13097 // Create a DontDelete variable on the global object.
13098 CompileRun("this.__proto__ = { foo: 'horse' };"
13099 "var foo = 'fish';"
13100 "function f() { return foo.length; }");
13101 // Initialize the IC for foo in f.
13102 CompileRun("for (var i = 0; i < 4; i++) f();");
13103 // Make sure the value of foo is correct before the deletion.
13104 CHECK_EQ(4, CompileRun("f()")->Int32Value());
13105 // Force the deletion of foo.
13106 CHECK(context->Global()->ForceDelete(v8_str("foo")));
13107 // Make sure the value for foo is read from the prototype, and that
13108 // we don't get in trouble with reading the deleted cell value
13109 // sentinel.
13110 CHECK_EQ(5, CompileRun("f()")->Int32Value());
13111}
13112
13113
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013114TEST(InlinedFunctionAcrossContexts) {
13115 i::FLAG_allow_natives_syntax = true;
13116 v8::HandleScope outer_scope;
13117 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
13118 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
13119 ctx1->Enter();
13120
13121 {
13122 v8::HandleScope inner_scope;
13123 CompileRun("var G = 42; function foo() { return G; }");
13124 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
13125 ctx2->Enter();
13126 ctx2->Global()->Set(v8_str("o"), foo);
13127 v8::Local<v8::Value> res = CompileRun(
13128 "function f() { return o(); }"
13129 "for (var i = 0; i < 10; ++i) f();"
13130 "%OptimizeFunctionOnNextCall(f);"
13131 "f();");
13132 CHECK_EQ(42, res->Int32Value());
13133 ctx2->Exit();
13134 v8::Handle<v8::String> G_property = v8::String::New("G");
13135 CHECK(ctx1->Global()->ForceDelete(G_property));
13136 ctx2->Enter();
13137 ExpectString(
13138 "(function() {"
13139 " try {"
13140 " return f();"
13141 " } catch(e) {"
13142 " return e.toString();"
13143 " }"
13144 " })()",
13145 "ReferenceError: G is not defined");
13146 ctx2->Exit();
13147 ctx1->Exit();
13148 ctx1.Dispose();
13149 }
13150 ctx2.Dispose();
13151}
13152
13153
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013154v8::Persistent<Context> calling_context0;
13155v8::Persistent<Context> calling_context1;
13156v8::Persistent<Context> calling_context2;
13157
13158
13159// Check that the call to the callback is initiated in
13160// calling_context2, the directly calling context is calling_context1
13161// and the callback itself is in calling_context0.
13162static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
13163 ApiTestFuzzer::Fuzz();
13164 CHECK(Context::GetCurrent() == calling_context0);
13165 CHECK(Context::GetCalling() == calling_context1);
13166 CHECK(Context::GetEntered() == calling_context2);
13167 return v8::Integer::New(42);
13168}
13169
13170
13171THREADED_TEST(GetCallingContext) {
13172 v8::HandleScope scope;
13173
13174 calling_context0 = Context::New();
13175 calling_context1 = Context::New();
13176 calling_context2 = Context::New();
13177
13178 // Allow cross-domain access.
13179 Local<String> token = v8_str("<security token>");
13180 calling_context0->SetSecurityToken(token);
13181 calling_context1->SetSecurityToken(token);
13182 calling_context2->SetSecurityToken(token);
13183
13184 // Create an object with a C++ callback in context0.
13185 calling_context0->Enter();
13186 Local<v8::FunctionTemplate> callback_templ =
13187 v8::FunctionTemplate::New(GetCallingContextCallback);
13188 calling_context0->Global()->Set(v8_str("callback"),
13189 callback_templ->GetFunction());
13190 calling_context0->Exit();
13191
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013192 // Expose context0 in context1 and set up a function that calls the
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013193 // callback function.
13194 calling_context1->Enter();
13195 calling_context1->Global()->Set(v8_str("context0"),
13196 calling_context0->Global());
13197 CompileRun("function f() { context0.callback() }");
13198 calling_context1->Exit();
13199
13200 // Expose context1 in context2 and call the callback function in
13201 // context0 indirectly through f in context1.
13202 calling_context2->Enter();
13203 calling_context2->Global()->Set(v8_str("context1"),
13204 calling_context1->Global());
13205 CompileRun("context1.f()");
13206 calling_context2->Exit();
13207
13208 // Dispose the contexts to allow them to be garbage collected.
13209 calling_context0.Dispose();
13210 calling_context1.Dispose();
13211 calling_context2.Dispose();
13212 calling_context0.Clear();
13213 calling_context1.Clear();
13214 calling_context2.Clear();
13215}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013216
13217
13218// Check that a variable declaration with no explicit initialization
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013219// value does shadow an existing property in the prototype chain.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013220THREADED_TEST(InitGlobalVarInProtoChain) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013221 i::FLAG_es52_globals = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013222 v8::HandleScope scope;
13223 LocalContext context;
13224 // Introduce a variable in the prototype chain.
13225 CompileRun("__proto__.x = 42");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013226 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013227 CHECK(!result->IsUndefined());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013228 CHECK_EQ(43, result->Int32Value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013229}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013230
13231
13232// Regression test for issue 398.
13233// If a function is added to an object, creating a constant function
13234// field, and the result is cloned, replacing the constant function on the
13235// original should not affect the clone.
13236// See http://code.google.com/p/v8/issues/detail?id=398
13237THREADED_TEST(ReplaceConstantFunction) {
13238 v8::HandleScope scope;
13239 LocalContext context;
13240 v8::Handle<v8::Object> obj = v8::Object::New();
13241 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13242 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13243 obj->Set(foo_string, func_templ->GetFunction());
13244 v8::Handle<v8::Object> obj_clone = obj->Clone();
13245 obj_clone->Set(foo_string, v8::String::New("Hello"));
13246 CHECK(!obj->Get(foo_string)->IsUndefined());
13247}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013248
13249
13250// Regression test for http://crbug.com/16276.
13251THREADED_TEST(Regress16276) {
13252 v8::HandleScope scope;
13253 LocalContext context;
13254 // Force the IC in f to be a dictionary load IC.
13255 CompileRun("function f(obj) { return obj.x; }\n"
13256 "var obj = { x: { foo: 42 }, y: 87 };\n"
13257 "var x = obj.x;\n"
13258 "delete obj.y;\n"
13259 "for (var i = 0; i < 5; i++) f(obj);");
13260 // Detach the global object to make 'this' refer directly to the
13261 // global object (not the proxy), and make sure that the dictionary
13262 // load IC doesn't mess up loading directly from the global object.
13263 context->DetachGlobal();
13264 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13265}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013266
13267
13268THREADED_TEST(PixelArray) {
13269 v8::HandleScope scope;
13270 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013271 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013272 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013273 i::Handle<i::ExternalPixelArray> pixels =
13274 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013275 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013276 v8::kExternalPixelArray,
13277 pixel_data));
13278 // Force GC to trigger verification.
13279 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013280 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013281 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013282 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013283 // Force GC to trigger verification.
13284 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013285 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013286 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013287 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013288 }
13289
13290 v8::Handle<v8::Object> obj = v8::Object::New();
13291 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13292 // Set the elements to be the pixels.
13293 // jsobj->set_elements(*pixels);
13294 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013295 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013296 obj->Set(v8_str("field"), v8::Int32::New(1503));
13297 context->Global()->Set(v8_str("pixels"), obj);
13298 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13299 CHECK_EQ(1503, result->Int32Value());
13300 result = CompileRun("pixels[1]");
13301 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013302
13303 result = CompileRun("var sum = 0;"
13304 "for (var i = 0; i < 8; i++) {"
13305 " sum += pixels[i] = pixels[i] = -i;"
13306 "}"
13307 "sum;");
13308 CHECK_EQ(-28, result->Int32Value());
13309
13310 result = CompileRun("var sum = 0;"
13311 "for (var i = 0; i < 8; i++) {"
13312 " sum += pixels[i] = pixels[i] = 0;"
13313 "}"
13314 "sum;");
13315 CHECK_EQ(0, result->Int32Value());
13316
13317 result = CompileRun("var sum = 0;"
13318 "for (var i = 0; i < 8; i++) {"
13319 " sum += pixels[i] = pixels[i] = 255;"
13320 "}"
13321 "sum;");
13322 CHECK_EQ(8 * 255, result->Int32Value());
13323
13324 result = CompileRun("var sum = 0;"
13325 "for (var i = 0; i < 8; i++) {"
13326 " sum += pixels[i] = pixels[i] = 256 + i;"
13327 "}"
13328 "sum;");
13329 CHECK_EQ(2076, result->Int32Value());
13330
13331 result = CompileRun("var sum = 0;"
13332 "for (var i = 0; i < 8; i++) {"
13333 " sum += pixels[i] = pixels[i] = i;"
13334 "}"
13335 "sum;");
13336 CHECK_EQ(28, result->Int32Value());
13337
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013338 result = CompileRun("var sum = 0;"
13339 "for (var i = 0; i < 8; i++) {"
13340 " sum += pixels[i];"
13341 "}"
13342 "sum;");
13343 CHECK_EQ(28, result->Int32Value());
13344
13345 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013346 i::Handle<i::Object> no_failure;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013347 no_failure =
13348 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013349 ASSERT(!no_failure.is_null());
13350 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013351 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013352 *value.location() = i::Smi::FromInt(256);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013353 no_failure =
13354 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013355 ASSERT(!no_failure.is_null());
13356 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013357 CHECK_EQ(255,
13358 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013359 *value.location() = i::Smi::FromInt(-1);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013360 no_failure =
13361 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013362 ASSERT(!no_failure.is_null());
13363 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013364 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013365
13366 result = CompileRun("for (var i = 0; i < 8; i++) {"
13367 " pixels[i] = (i * 65) - 109;"
13368 "}"
13369 "pixels[1] + pixels[6];");
13370 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013371 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13372 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13373 CHECK_EQ(21,
13374 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13375 CHECK_EQ(86,
13376 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13377 CHECK_EQ(151,
13378 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13379 CHECK_EQ(216,
13380 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13381 CHECK_EQ(255,
13382 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13383 CHECK_EQ(255,
13384 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013385 result = CompileRun("var sum = 0;"
13386 "for (var i = 0; i < 8; i++) {"
13387 " sum += pixels[i];"
13388 "}"
13389 "sum;");
13390 CHECK_EQ(984, result->Int32Value());
13391
13392 result = CompileRun("for (var i = 0; i < 8; i++) {"
13393 " pixels[i] = (i * 1.1);"
13394 "}"
13395 "pixels[1] + pixels[6];");
13396 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013397 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13398 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13399 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13400 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13401 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13402 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13403 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13404 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013405
13406 result = CompileRun("for (var i = 0; i < 8; i++) {"
13407 " pixels[7] = undefined;"
13408 "}"
13409 "pixels[7];");
13410 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013411 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013412
13413 result = CompileRun("for (var i = 0; i < 8; i++) {"
13414 " pixels[6] = '2.3';"
13415 "}"
13416 "pixels[6];");
13417 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013418 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013419
13420 result = CompileRun("for (var i = 0; i < 8; i++) {"
13421 " pixels[5] = NaN;"
13422 "}"
13423 "pixels[5];");
13424 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013425 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013426
13427 result = CompileRun("for (var i = 0; i < 8; i++) {"
13428 " pixels[8] = Infinity;"
13429 "}"
13430 "pixels[8];");
13431 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013432 CHECK_EQ(255,
13433 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013434
13435 result = CompileRun("for (var i = 0; i < 8; i++) {"
13436 " pixels[9] = -Infinity;"
13437 "}"
13438 "pixels[9];");
13439 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013440 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013441
13442 result = CompileRun("pixels[3] = 33;"
13443 "delete pixels[3];"
13444 "pixels[3];");
13445 CHECK_EQ(33, result->Int32Value());
13446
13447 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13448 "pixels[2] = 12; pixels[3] = 13;"
13449 "pixels.__defineGetter__('2',"
13450 "function() { return 120; });"
13451 "pixels[2];");
13452 CHECK_EQ(12, result->Int32Value());
13453
13454 result = CompileRun("var js_array = new Array(40);"
13455 "js_array[0] = 77;"
13456 "js_array;");
13457 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13458
13459 result = CompileRun("pixels[1] = 23;"
13460 "pixels.__proto__ = [];"
13461 "js_array.__proto__ = pixels;"
13462 "js_array.concat(pixels);");
13463 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13464 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13465
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013466 result = CompileRun("pixels[1] = 23;");
13467 CHECK_EQ(23, result->Int32Value());
13468
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013469 // Test for index greater than 255. Regression test for:
13470 // http://code.google.com/p/chromium/issues/detail?id=26337.
13471 result = CompileRun("pixels[256] = 255;");
13472 CHECK_EQ(255, result->Int32Value());
13473 result = CompileRun("var i = 0;"
13474 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13475 "i");
13476 CHECK_EQ(255, result->Int32Value());
13477
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013478 // Make sure that pixel array ICs recognize when a non-pixel array
13479 // is passed to it.
13480 result = CompileRun("function pa_load(p) {"
13481 " var sum = 0;"
13482 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13483 " return sum;"
13484 "}"
13485 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13486 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13487 "just_ints = new Object();"
13488 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13489 "for (var i = 0; i < 10; ++i) {"
13490 " result = pa_load(just_ints);"
13491 "}"
13492 "result");
13493 CHECK_EQ(32640, result->Int32Value());
13494
13495 // Make sure that pixel array ICs recognize out-of-bound accesses.
13496 result = CompileRun("function pa_load(p, start) {"
13497 " var sum = 0;"
13498 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13499 " return sum;"
13500 "}"
13501 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13502 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13503 "for (var i = 0; i < 10; ++i) {"
13504 " result = pa_load(pixels,-10);"
13505 "}"
13506 "result");
13507 CHECK_EQ(0, result->Int32Value());
13508
13509 // Make sure that generic ICs properly handles a pixel array.
13510 result = CompileRun("function pa_load(p) {"
13511 " var sum = 0;"
13512 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13513 " return sum;"
13514 "}"
13515 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13516 "just_ints = new Object();"
13517 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13518 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13519 "for (var i = 0; i < 10; ++i) {"
13520 " result = pa_load(pixels);"
13521 "}"
13522 "result");
13523 CHECK_EQ(32640, result->Int32Value());
13524
13525 // Make sure that generic load ICs recognize out-of-bound accesses in
13526 // pixel arrays.
13527 result = CompileRun("function pa_load(p, start) {"
13528 " var sum = 0;"
13529 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13530 " return sum;"
13531 "}"
13532 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13533 "just_ints = new Object();"
13534 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13535 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13536 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13537 "for (var i = 0; i < 10; ++i) {"
13538 " result = pa_load(pixels,-10);"
13539 "}"
13540 "result");
13541 CHECK_EQ(0, result->Int32Value());
13542
13543 // Make sure that generic ICs properly handles other types than pixel
13544 // arrays (that the inlined fast pixel array test leaves the right information
13545 // in the right registers).
13546 result = CompileRun("function pa_load(p) {"
13547 " var sum = 0;"
13548 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13549 " return sum;"
13550 "}"
13551 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13552 "just_ints = new Object();"
13553 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13554 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13555 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13556 "sparse_array = new Object();"
13557 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13558 "sparse_array[1000000] = 3;"
13559 "for (var i = 0; i < 10; ++i) {"
13560 " result = pa_load(sparse_array);"
13561 "}"
13562 "result");
13563 CHECK_EQ(32640, result->Int32Value());
13564
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013565 // Make sure that pixel array store ICs clamp values correctly.
13566 result = CompileRun("function pa_store(p) {"
13567 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13568 "}"
13569 "pa_store(pixels);"
13570 "var sum = 0;"
13571 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13572 "sum");
13573 CHECK_EQ(48896, result->Int32Value());
13574
13575 // Make sure that pixel array stores correctly handle accesses outside
13576 // of the pixel array..
13577 result = CompileRun("function pa_store(p,start) {"
13578 " for (var j = 0; j < 256; j++) {"
13579 " p[j+start] = j * 2;"
13580 " }"
13581 "}"
13582 "pa_store(pixels,0);"
13583 "pa_store(pixels,-128);"
13584 "var sum = 0;"
13585 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13586 "sum");
13587 CHECK_EQ(65280, result->Int32Value());
13588
13589 // Make sure that the generic store stub correctly handle accesses outside
13590 // of the pixel array..
13591 result = CompileRun("function pa_store(p,start) {"
13592 " for (var j = 0; j < 256; j++) {"
13593 " p[j+start] = j * 2;"
13594 " }"
13595 "}"
13596 "pa_store(pixels,0);"
13597 "just_ints = new Object();"
13598 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13599 "pa_store(just_ints, 0);"
13600 "pa_store(pixels,-128);"
13601 "var sum = 0;"
13602 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13603 "sum");
13604 CHECK_EQ(65280, result->Int32Value());
13605
13606 // Make sure that the generic keyed store stub clamps pixel array values
13607 // correctly.
13608 result = CompileRun("function pa_store(p) {"
13609 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13610 "}"
13611 "pa_store(pixels);"
13612 "just_ints = new Object();"
13613 "pa_store(just_ints);"
13614 "pa_store(pixels);"
13615 "var sum = 0;"
13616 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13617 "sum");
13618 CHECK_EQ(48896, result->Int32Value());
13619
13620 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013621 result = CompileRun("function pa_load(p) {"
13622 " var sum = 0;"
13623 " for (var i=0; i<256; ++i) {"
13624 " sum += p[i];"
13625 " }"
13626 " return sum; "
13627 "}"
13628 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013629 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013630 " result = pa_load(pixels);"
13631 "}"
13632 "result");
13633 CHECK_EQ(32640, result->Int32Value());
13634
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013635 // Make sure that pixel array stores are optimized by crankshaft.
13636 result = CompileRun("function pa_init(p) {"
13637 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13638 "}"
13639 "function pa_load(p) {"
13640 " var sum = 0;"
13641 " for (var i=0; i<256; ++i) {"
13642 " sum += p[i];"
13643 " }"
13644 " return sum; "
13645 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013646 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013647 " pa_init(pixels);"
13648 "}"
13649 "result = pa_load(pixels);"
13650 "result");
13651 CHECK_EQ(32640, result->Int32Value());
13652
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013653 free(pixel_data);
13654}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013655
ager@chromium.org96c75b52009-08-26 09:13:16 +000013656
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013657THREADED_TEST(PixelArrayInfo) {
13658 v8::HandleScope scope;
13659 LocalContext context;
13660 for (int size = 0; size < 100; size += 10) {
13661 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13662 v8::Handle<v8::Object> obj = v8::Object::New();
13663 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13664 CHECK(obj->HasIndexedPropertiesInPixelData());
13665 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13666 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13667 free(pixel_data);
13668 }
13669}
13670
13671
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013672static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13673 uint32_t index,
13674 const AccessorInfo& info) {
13675 ApiTestFuzzer::Fuzz();
13676 return v8::Handle<Value>();
13677}
13678
13679
13680static v8::Handle<Value> NotHandledIndexedPropertySetter(
13681 uint32_t index,
13682 Local<Value> value,
13683 const AccessorInfo& info) {
13684 ApiTestFuzzer::Fuzz();
13685 return v8::Handle<Value>();
13686}
13687
13688
13689THREADED_TEST(PixelArrayWithInterceptor) {
13690 v8::HandleScope scope;
13691 LocalContext context;
13692 const int kElementCount = 260;
13693 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013694 i::Handle<i::ExternalPixelArray> pixels =
13695 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013696 FACTORY->NewExternalArray(kElementCount,
13697 v8::kExternalPixelArray,
13698 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013699 for (int i = 0; i < kElementCount; i++) {
13700 pixels->set(i, i % 256);
13701 }
13702 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13703 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13704 NotHandledIndexedPropertySetter);
13705 v8::Handle<v8::Object> obj = templ->NewInstance();
13706 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13707 context->Global()->Set(v8_str("pixels"), obj);
13708 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13709 CHECK_EQ(1, result->Int32Value());
13710 result = CompileRun("var sum = 0;"
13711 "for (var i = 0; i < 8; i++) {"
13712 " sum += pixels[i] = pixels[i] = -i;"
13713 "}"
13714 "sum;");
13715 CHECK_EQ(-28, result->Int32Value());
13716 result = CompileRun("pixels.hasOwnProperty('1')");
13717 CHECK(result->BooleanValue());
13718 free(pixel_data);
13719}
13720
13721
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013722static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13723 switch (array_type) {
13724 case v8::kExternalByteArray:
13725 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013726 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013727 return 1;
13728 break;
13729 case v8::kExternalShortArray:
13730 case v8::kExternalUnsignedShortArray:
13731 return 2;
13732 break;
13733 case v8::kExternalIntArray:
13734 case v8::kExternalUnsignedIntArray:
13735 case v8::kExternalFloatArray:
13736 return 4;
13737 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013738 case v8::kExternalDoubleArray:
13739 return 8;
13740 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013741 default:
13742 UNREACHABLE();
13743 return -1;
13744 }
13745 UNREACHABLE();
13746 return -1;
13747}
13748
13749
ager@chromium.org3811b432009-10-28 14:53:37 +000013750template <class ExternalArrayClass, class ElementType>
13751static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13752 int64_t low,
13753 int64_t high) {
13754 v8::HandleScope scope;
13755 LocalContext context;
13756 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013757 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000013758 ElementType* array_data =
13759 static_cast<ElementType*>(malloc(kElementCount * element_size));
13760 i::Handle<ExternalArrayClass> array =
13761 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013762 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013763 // Force GC to trigger verification.
13764 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013765 for (int i = 0; i < kElementCount; i++) {
13766 array->set(i, static_cast<ElementType>(i));
13767 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013768 // Force GC to trigger verification.
13769 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013770 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013771 CHECK_EQ(static_cast<int64_t>(i),
13772 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000013773 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13774 }
13775
13776 v8::Handle<v8::Object> obj = v8::Object::New();
13777 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13778 // Set the elements to be the external array.
13779 obj->SetIndexedPropertiesToExternalArrayData(array_data,
13780 array_type,
13781 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013782 CHECK_EQ(
13783 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013784 obj->Set(v8_str("field"), v8::Int32::New(1503));
13785 context->Global()->Set(v8_str("ext_array"), obj);
13786 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13787 CHECK_EQ(1503, result->Int32Value());
13788 result = CompileRun("ext_array[1]");
13789 CHECK_EQ(1, result->Int32Value());
13790
13791 // Check pass through of assigned smis
13792 result = CompileRun("var sum = 0;"
13793 "for (var i = 0; i < 8; i++) {"
13794 " sum += ext_array[i] = ext_array[i] = -i;"
13795 "}"
13796 "sum;");
13797 CHECK_EQ(-28, result->Int32Value());
13798
13799 // Check assigned smis
13800 result = CompileRun("for (var i = 0; i < 8; i++) {"
13801 " ext_array[i] = i;"
13802 "}"
13803 "var sum = 0;"
13804 "for (var i = 0; i < 8; i++) {"
13805 " sum += ext_array[i];"
13806 "}"
13807 "sum;");
13808 CHECK_EQ(28, result->Int32Value());
13809
13810 // Check assigned smis in reverse order
13811 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13812 " ext_array[i] = i;"
13813 "}"
13814 "var sum = 0;"
13815 "for (var i = 0; i < 8; i++) {"
13816 " sum += ext_array[i];"
13817 "}"
13818 "sum;");
13819 CHECK_EQ(28, result->Int32Value());
13820
13821 // Check pass through of assigned HeapNumbers
13822 result = CompileRun("var sum = 0;"
13823 "for (var i = 0; i < 16; i+=2) {"
13824 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13825 "}"
13826 "sum;");
13827 CHECK_EQ(-28, result->Int32Value());
13828
13829 // Check assigned HeapNumbers
13830 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13831 " ext_array[i] = (i * 0.5);"
13832 "}"
13833 "var sum = 0;"
13834 "for (var i = 0; i < 16; i+=2) {"
13835 " sum += ext_array[i];"
13836 "}"
13837 "sum;");
13838 CHECK_EQ(28, result->Int32Value());
13839
13840 // Check assigned HeapNumbers in reverse order
13841 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13842 " ext_array[i] = (i * 0.5);"
13843 "}"
13844 "var sum = 0;"
13845 "for (var i = 0; i < 16; i+=2) {"
13846 " sum += ext_array[i];"
13847 "}"
13848 "sum;");
13849 CHECK_EQ(28, result->Int32Value());
13850
13851 i::ScopedVector<char> test_buf(1024);
13852
13853 // Check legal boundary conditions.
13854 // The repeated loads and stores ensure the ICs are exercised.
13855 const char* boundary_program =
13856 "var res = 0;"
13857 "for (var i = 0; i < 16; i++) {"
13858 " ext_array[i] = %lld;"
13859 " if (i > 8) {"
13860 " res = ext_array[i];"
13861 " }"
13862 "}"
13863 "res;";
13864 i::OS::SNPrintF(test_buf,
13865 boundary_program,
13866 low);
13867 result = CompileRun(test_buf.start());
13868 CHECK_EQ(low, result->IntegerValue());
13869
13870 i::OS::SNPrintF(test_buf,
13871 boundary_program,
13872 high);
13873 result = CompileRun(test_buf.start());
13874 CHECK_EQ(high, result->IntegerValue());
13875
13876 // Check misprediction of type in IC.
13877 result = CompileRun("var tmp_array = ext_array;"
13878 "var sum = 0;"
13879 "for (var i = 0; i < 8; i++) {"
13880 " tmp_array[i] = i;"
13881 " sum += tmp_array[i];"
13882 " if (i == 4) {"
13883 " tmp_array = {};"
13884 " }"
13885 "}"
13886 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013887 // Force GC to trigger verification.
13888 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013889 CHECK_EQ(28, result->Int32Value());
13890
13891 // Make sure out-of-range loads do not throw.
13892 i::OS::SNPrintF(test_buf,
13893 "var caught_exception = false;"
13894 "try {"
13895 " ext_array[%d];"
13896 "} catch (e) {"
13897 " caught_exception = true;"
13898 "}"
13899 "caught_exception;",
13900 kElementCount);
13901 result = CompileRun(test_buf.start());
13902 CHECK_EQ(false, result->BooleanValue());
13903
13904 // Make sure out-of-range stores do not throw.
13905 i::OS::SNPrintF(test_buf,
13906 "var caught_exception = false;"
13907 "try {"
13908 " ext_array[%d] = 1;"
13909 "} catch (e) {"
13910 " caught_exception = true;"
13911 "}"
13912 "caught_exception;",
13913 kElementCount);
13914 result = CompileRun(test_buf.start());
13915 CHECK_EQ(false, result->BooleanValue());
13916
13917 // Check other boundary conditions, values and operations.
13918 result = CompileRun("for (var i = 0; i < 8; i++) {"
13919 " ext_array[7] = undefined;"
13920 "}"
13921 "ext_array[7];");
13922 CHECK_EQ(0, result->Int32Value());
yangguo@chromium.org56454712012-02-16 15:33:53 +000013923 if (array_type == v8::kExternalDoubleArray ||
13924 array_type == v8::kExternalFloatArray) {
13925 CHECK_EQ(
ulan@chromium.org812308e2012-02-29 15:58:45 +000013926 static_cast<int>(i::OS::nan_value()),
yangguo@chromium.org56454712012-02-16 15:33:53 +000013927 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13928 } else {
13929 CHECK_EQ(0, static_cast<int>(
13930 jsobj->GetElement(7)->ToObjectChecked()->Number()));
13931 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013932
13933 result = CompileRun("for (var i = 0; i < 8; i++) {"
13934 " ext_array[6] = '2.3';"
13935 "}"
13936 "ext_array[6];");
13937 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013938 CHECK_EQ(
13939 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013940
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013941 if (array_type != v8::kExternalFloatArray &&
13942 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013943 // Though the specification doesn't state it, be explicit about
13944 // converting NaNs and +/-Infinity to zero.
13945 result = CompileRun("for (var i = 0; i < 8; i++) {"
13946 " ext_array[i] = 5;"
13947 "}"
13948 "for (var i = 0; i < 8; i++) {"
13949 " ext_array[i] = NaN;"
13950 "}"
13951 "ext_array[5];");
13952 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013953 CHECK_EQ(0,
13954 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013955
13956 result = CompileRun("for (var i = 0; i < 8; i++) {"
13957 " ext_array[i] = 5;"
13958 "}"
13959 "for (var i = 0; i < 8; i++) {"
13960 " ext_array[i] = Infinity;"
13961 "}"
13962 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013963 int expected_value =
13964 (array_type == v8::kExternalPixelArray) ? 255 : 0;
13965 CHECK_EQ(expected_value, result->Int32Value());
13966 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013967 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013968
13969 result = CompileRun("for (var i = 0; i < 8; i++) {"
13970 " ext_array[i] = 5;"
13971 "}"
13972 "for (var i = 0; i < 8; i++) {"
13973 " ext_array[i] = -Infinity;"
13974 "}"
13975 "ext_array[5];");
13976 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013977 CHECK_EQ(0,
13978 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013979
13980 // Check truncation behavior of integral arrays.
13981 const char* unsigned_data =
13982 "var source_data = [0.6, 10.6];"
13983 "var expected_results = [0, 10];";
13984 const char* signed_data =
13985 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13986 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013987 const char* pixel_data =
13988 "var source_data = [0.6, 10.6];"
13989 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013990 bool is_unsigned =
13991 (array_type == v8::kExternalUnsignedByteArray ||
13992 array_type == v8::kExternalUnsignedShortArray ||
13993 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013994 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013995
13996 i::OS::SNPrintF(test_buf,
13997 "%s"
13998 "var all_passed = true;"
13999 "for (var i = 0; i < source_data.length; i++) {"
14000 " for (var j = 0; j < 8; j++) {"
14001 " ext_array[j] = source_data[i];"
14002 " }"
14003 " all_passed = all_passed &&"
14004 " (ext_array[5] == expected_results[i]);"
14005 "}"
14006 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014007 (is_unsigned ?
14008 unsigned_data :
14009 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014010 result = CompileRun(test_buf.start());
14011 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000014012 }
14013
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000014014 for (int i = 0; i < kElementCount; i++) {
14015 array->set(i, static_cast<ElementType>(i));
14016 }
14017 // Test complex assignments
14018 result = CompileRun("function ee_op_test_complex_func(sum) {"
14019 " for (var i = 0; i < 40; ++i) {"
14020 " sum += (ext_array[i] += 1);"
14021 " sum += (ext_array[i] -= 1);"
14022 " } "
14023 " return sum;"
14024 "}"
14025 "sum=0;"
14026 "for (var i=0;i<10000;++i) {"
14027 " sum=ee_op_test_complex_func(sum);"
14028 "}"
14029 "sum;");
14030 CHECK_EQ(16000000, result->Int32Value());
14031
14032 // Test count operations
14033 result = CompileRun("function ee_op_test_count_func(sum) {"
14034 " for (var i = 0; i < 40; ++i) {"
14035 " sum += (++ext_array[i]);"
14036 " sum += (--ext_array[i]);"
14037 " } "
14038 " return sum;"
14039 "}"
14040 "sum=0;"
14041 "for (var i=0;i<10000;++i) {"
14042 " sum=ee_op_test_count_func(sum);"
14043 "}"
14044 "sum;");
14045 CHECK_EQ(16000000, result->Int32Value());
14046
ager@chromium.org3811b432009-10-28 14:53:37 +000014047 result = CompileRun("ext_array[3] = 33;"
14048 "delete ext_array[3];"
14049 "ext_array[3];");
14050 CHECK_EQ(33, result->Int32Value());
14051
14052 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14053 "ext_array[2] = 12; ext_array[3] = 13;"
14054 "ext_array.__defineGetter__('2',"
14055 "function() { return 120; });"
14056 "ext_array[2];");
14057 CHECK_EQ(12, result->Int32Value());
14058
14059 result = CompileRun("var js_array = new Array(40);"
14060 "js_array[0] = 77;"
14061 "js_array;");
14062 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14063
14064 result = CompileRun("ext_array[1] = 23;"
14065 "ext_array.__proto__ = [];"
14066 "js_array.__proto__ = ext_array;"
14067 "js_array.concat(ext_array);");
14068 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14069 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14070
14071 result = CompileRun("ext_array[1] = 23;");
14072 CHECK_EQ(23, result->Int32Value());
14073
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014074 // Test more complex manipulations which cause eax to contain values
14075 // that won't be completely overwritten by loads from the arrays.
14076 // This catches bugs in the instructions used for the KeyedLoadIC
14077 // for byte and word types.
14078 {
14079 const int kXSize = 300;
14080 const int kYSize = 300;
14081 const int kLargeElementCount = kXSize * kYSize * 4;
14082 ElementType* large_array_data =
14083 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014084 v8::Handle<v8::Object> large_obj = v8::Object::New();
14085 // Set the elements to be the external array.
14086 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14087 array_type,
14088 kLargeElementCount);
14089 context->Global()->Set(v8_str("large_array"), large_obj);
14090 // Initialize contents of a few rows.
14091 for (int x = 0; x < 300; x++) {
14092 int row = 0;
14093 int offset = row * 300 * 4;
14094 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14095 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14096 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14097 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14098 row = 150;
14099 offset = row * 300 * 4;
14100 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14101 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14102 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14103 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14104 row = 298;
14105 offset = row * 300 * 4;
14106 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14107 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14108 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14109 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14110 }
14111 // The goal of the code below is to make "offset" large enough
14112 // that the computation of the index (which goes into eax) has
14113 // high bits set which will not be overwritten by a byte or short
14114 // load.
14115 result = CompileRun("var failed = false;"
14116 "var offset = 0;"
14117 "for (var i = 0; i < 300; i++) {"
14118 " if (large_array[4 * i] != 127 ||"
14119 " large_array[4 * i + 1] != 0 ||"
14120 " large_array[4 * i + 2] != 0 ||"
14121 " large_array[4 * i + 3] != 127) {"
14122 " failed = true;"
14123 " }"
14124 "}"
14125 "offset = 150 * 300 * 4;"
14126 "for (var i = 0; i < 300; i++) {"
14127 " if (large_array[offset + 4 * i] != 127 ||"
14128 " large_array[offset + 4 * i + 1] != 0 ||"
14129 " large_array[offset + 4 * i + 2] != 0 ||"
14130 " large_array[offset + 4 * i + 3] != 127) {"
14131 " failed = true;"
14132 " }"
14133 "}"
14134 "offset = 298 * 300 * 4;"
14135 "for (var i = 0; i < 300; i++) {"
14136 " if (large_array[offset + 4 * i] != 127 ||"
14137 " large_array[offset + 4 * i + 1] != 0 ||"
14138 " large_array[offset + 4 * i + 2] != 0 ||"
14139 " large_array[offset + 4 * i + 3] != 127) {"
14140 " failed = true;"
14141 " }"
14142 "}"
14143 "!failed;");
14144 CHECK_EQ(true, result->BooleanValue());
14145 free(large_array_data);
14146 }
14147
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014148 // The "" property descriptor is overloaded to store information about
14149 // the external array. Ensure that setting and accessing the "" property
14150 // works (it should overwrite the information cached about the external
14151 // array in the DescriptorArray) in various situations.
14152 result = CompileRun("ext_array[''] = 23; ext_array['']");
14153 CHECK_EQ(23, result->Int32Value());
14154
14155 // Property "" set after the external array is associated with the object.
14156 {
14157 v8::Handle<v8::Object> obj2 = v8::Object::New();
14158 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
14159 obj2->Set(v8_str(""), v8::Int32::New(1503));
14160 // Set the elements to be the external array.
14161 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14162 array_type,
14163 kElementCount);
14164 context->Global()->Set(v8_str("ext_array"), obj2);
14165 result = CompileRun("ext_array['']");
14166 CHECK_EQ(1503, result->Int32Value());
14167 }
14168
14169 // Property "" set after the external array is associated with the object.
14170 {
14171 v8::Handle<v8::Object> obj2 = v8::Object::New();
14172 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14173 // Set the elements to be the external array.
14174 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14175 array_type,
14176 kElementCount);
14177 obj2->Set(v8_str(""), v8::Int32::New(1503));
14178 context->Global()->Set(v8_str("ext_array"), obj2);
14179 result = CompileRun("ext_array['']");
14180 CHECK_EQ(1503, result->Int32Value());
14181 }
14182
14183 // Should reuse the map from previous test.
14184 {
14185 v8::Handle<v8::Object> obj2 = v8::Object::New();
14186 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14187 // Set the elements to be the external array. Should re-use the map
14188 // from previous test.
14189 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14190 array_type,
14191 kElementCount);
14192 context->Global()->Set(v8_str("ext_array"), obj2);
14193 result = CompileRun("ext_array['']");
14194 }
14195
14196 // Property "" is a constant function that shouldn't not be interfered with
14197 // when an external array is set.
14198 {
14199 v8::Handle<v8::Object> obj2 = v8::Object::New();
14200 // Start
14201 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14202
14203 // Add a constant function to an object.
14204 context->Global()->Set(v8_str("ext_array"), obj2);
14205 result = CompileRun("ext_array[''] = function() {return 1503;};"
14206 "ext_array['']();");
14207
14208 // Add an external array transition to the same map that
14209 // has the constant transition.
14210 v8::Handle<v8::Object> obj3 = v8::Object::New();
14211 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14212 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14213 array_type,
14214 kElementCount);
14215 context->Global()->Set(v8_str("ext_array"), obj3);
14216 }
14217
14218 // If a external array transition is in the map, it should get clobbered
14219 // by a constant function.
14220 {
14221 // Add an external array transition.
14222 v8::Handle<v8::Object> obj3 = v8::Object::New();
14223 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14224 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14225 array_type,
14226 kElementCount);
14227
14228 // Add a constant function to the same map that just got an external array
14229 // transition.
14230 v8::Handle<v8::Object> obj2 = v8::Object::New();
14231 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14232 context->Global()->Set(v8_str("ext_array"), obj2);
14233 result = CompileRun("ext_array[''] = function() {return 1503;};"
14234 "ext_array['']();");
14235 }
14236
ager@chromium.org3811b432009-10-28 14:53:37 +000014237 free(array_data);
14238}
14239
14240
14241THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014242 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014243 v8::kExternalByteArray,
14244 -128,
14245 127);
14246}
14247
14248
14249THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014250 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014251 v8::kExternalUnsignedByteArray,
14252 0,
14253 255);
14254}
14255
14256
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014257THREADED_TEST(ExternalPixelArray) {
14258 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14259 v8::kExternalPixelArray,
14260 0,
14261 255);
14262}
14263
14264
ager@chromium.org3811b432009-10-28 14:53:37 +000014265THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014266 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014267 v8::kExternalShortArray,
14268 -32768,
14269 32767);
14270}
14271
14272
14273THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014274 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014275 v8::kExternalUnsignedShortArray,
14276 0,
14277 65535);
14278}
14279
14280
14281THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014282 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014283 v8::kExternalIntArray,
14284 INT_MIN, // -2147483648
14285 INT_MAX); // 2147483647
14286}
14287
14288
14289THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014290 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014291 v8::kExternalUnsignedIntArray,
14292 0,
14293 UINT_MAX); // 4294967295
14294}
14295
14296
14297THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014298 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014299 v8::kExternalFloatArray,
14300 -500,
14301 500);
14302}
14303
14304
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014305THREADED_TEST(ExternalDoubleArray) {
14306 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14307 v8::kExternalDoubleArray,
14308 -500,
14309 500);
14310}
14311
14312
ager@chromium.org3811b432009-10-28 14:53:37 +000014313THREADED_TEST(ExternalArrays) {
14314 TestExternalByteArray();
14315 TestExternalUnsignedByteArray();
14316 TestExternalShortArray();
14317 TestExternalUnsignedShortArray();
14318 TestExternalIntArray();
14319 TestExternalUnsignedIntArray();
14320 TestExternalFloatArray();
14321}
14322
14323
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014324void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14325 v8::HandleScope scope;
14326 LocalContext context;
14327 for (int size = 0; size < 100; size += 10) {
14328 int element_size = ExternalArrayElementSize(array_type);
14329 void* external_data = malloc(size * element_size);
14330 v8::Handle<v8::Object> obj = v8::Object::New();
14331 obj->SetIndexedPropertiesToExternalArrayData(
14332 external_data, array_type, size);
14333 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14334 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14335 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14336 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14337 free(external_data);
14338 }
14339}
14340
14341
14342THREADED_TEST(ExternalArrayInfo) {
14343 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14344 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14345 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14346 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14347 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14348 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14349 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014350 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014351 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014352}
14353
14354
danno@chromium.org412fa512012-09-14 13:28:26 +000014355void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14356 v8::Handle<v8::Object> obj = v8::Object::New();
14357 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14358 last_location = last_message = NULL;
14359 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14360 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14361 CHECK_NE(NULL, last_location);
14362 CHECK_NE(NULL, last_message);
14363}
14364
14365
14366TEST(ExternalArrayLimits) {
14367 v8::HandleScope scope;
14368 LocalContext context;
14369 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14370 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14371 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14372 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14373 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14374 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14375 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14376 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14377 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14378 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14379 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14380 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14381 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14382 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14383 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14384 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14385 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14386 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14387}
14388
14389
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014390THREADED_TEST(ScriptContextDependence) {
14391 v8::HandleScope scope;
14392 LocalContext c1;
14393 const char *source = "foo";
14394 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14395 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14396 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14397 CHECK_EQ(dep->Run()->Int32Value(), 100);
14398 CHECK_EQ(indep->Run()->Int32Value(), 100);
14399 LocalContext c2;
14400 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14401 CHECK_EQ(dep->Run()->Int32Value(), 100);
14402 CHECK_EQ(indep->Run()->Int32Value(), 101);
14403}
14404
ager@chromium.org96c75b52009-08-26 09:13:16 +000014405
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014406THREADED_TEST(StackTrace) {
14407 v8::HandleScope scope;
14408 LocalContext context;
14409 v8::TryCatch try_catch;
14410 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14411 v8::Handle<v8::String> src = v8::String::New(source);
14412 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14413 v8::Script::New(src, origin)->Run();
14414 CHECK(try_catch.HasCaught());
14415 v8::String::Utf8Value stack(try_catch.StackTrace());
14416 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14417}
ager@chromium.org96c75b52009-08-26 09:13:16 +000014418
14419
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014420// Checks that a StackFrame has certain expected values.
14421void checkStackFrame(const char* expected_script_name,
14422 const char* expected_func_name, int expected_line_number,
14423 int expected_column, bool is_eval, bool is_constructor,
14424 v8::Handle<v8::StackFrame> frame) {
14425 v8::HandleScope scope;
14426 v8::String::Utf8Value func_name(frame->GetFunctionName());
14427 v8::String::Utf8Value script_name(frame->GetScriptName());
14428 if (*script_name == NULL) {
14429 // The situation where there is no associated script, like for evals.
14430 CHECK(expected_script_name == NULL);
14431 } else {
14432 CHECK(strstr(*script_name, expected_script_name) != NULL);
14433 }
14434 CHECK(strstr(*func_name, expected_func_name) != NULL);
14435 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14436 CHECK_EQ(expected_column, frame->GetColumn());
14437 CHECK_EQ(is_eval, frame->IsEval());
14438 CHECK_EQ(is_constructor, frame->IsConstructor());
14439}
14440
14441
14442v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
14443 v8::HandleScope scope;
14444 const char* origin = "capture-stack-trace-test";
14445 const int kOverviewTest = 1;
14446 const int kDetailedTest = 2;
14447
14448 ASSERT(args.Length() == 1);
14449
14450 int testGroup = args[0]->Int32Value();
14451 if (testGroup == kOverviewTest) {
14452 v8::Handle<v8::StackTrace> stackTrace =
14453 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14454 CHECK_EQ(4, stackTrace->GetFrameCount());
14455 checkStackFrame(origin, "bar", 2, 10, false, false,
14456 stackTrace->GetFrame(0));
14457 checkStackFrame(origin, "foo", 6, 3, false, false,
14458 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014459 // This is the source string inside the eval which has the call to foo.
14460 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014461 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014462 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014463 checkStackFrame(origin, "", 8, 7, false, false,
14464 stackTrace->GetFrame(3));
14465
14466 CHECK(stackTrace->AsArray()->IsArray());
14467 } else if (testGroup == kDetailedTest) {
14468 v8::Handle<v8::StackTrace> stackTrace =
14469 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14470 CHECK_EQ(4, stackTrace->GetFrameCount());
14471 checkStackFrame(origin, "bat", 4, 22, false, false,
14472 stackTrace->GetFrame(0));
14473 checkStackFrame(origin, "baz", 8, 3, false, true,
14474 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014475#ifdef ENABLE_DEBUGGER_SUPPORT
14476 bool is_eval = true;
14477#else // ENABLE_DEBUGGER_SUPPORT
14478 bool is_eval = false;
14479#endif // ENABLE_DEBUGGER_SUPPORT
14480
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014481 // This is the source string inside the eval which has the call to baz.
14482 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014483 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014484 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014485 checkStackFrame(origin, "", 10, 1, false, false,
14486 stackTrace->GetFrame(3));
14487
14488 CHECK(stackTrace->AsArray()->IsArray());
14489 }
14490 return v8::Undefined();
14491}
14492
14493
14494// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014495// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14496// THREADED_TEST(CaptureStackTrace) {
14497TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014498 v8::HandleScope scope;
14499 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14500 Local<ObjectTemplate> templ = ObjectTemplate::New();
14501 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14502 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14503 LocalContext context(0, templ);
14504
14505 // Test getting OVERVIEW information. Should ignore information that is not
14506 // script name, function name, line number, and column offset.
14507 const char *overview_source =
14508 "function bar() {\n"
14509 " var y; AnalyzeStackInNativeCode(1);\n"
14510 "}\n"
14511 "function foo() {\n"
14512 "\n"
14513 " bar();\n"
14514 "}\n"
14515 "var x;eval('new foo();');";
14516 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014517 v8::Handle<Value> overview_result(
14518 v8::Script::New(overview_src, origin)->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014519 CHECK(!overview_result.IsEmpty());
14520 CHECK(overview_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014521
14522 // Test getting DETAILED information.
14523 const char *detailed_source =
14524 "function bat() {AnalyzeStackInNativeCode(2);\n"
14525 "}\n"
14526 "\n"
14527 "function baz() {\n"
14528 " bat();\n"
14529 "}\n"
14530 "eval('new baz();');";
14531 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14532 // Make the script using a non-zero line and column offset.
14533 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14534 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14535 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14536 v8::Handle<v8::Script> detailed_script(
14537 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014538 v8::Handle<Value> detailed_result(detailed_script->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014539 CHECK(!detailed_result.IsEmpty());
14540 CHECK(detailed_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014541}
14542
14543
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014544static void StackTraceForUncaughtExceptionListener(
14545 v8::Handle<v8::Message> message,
14546 v8::Handle<Value>) {
14547 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14548 CHECK_EQ(2, stack_trace->GetFrameCount());
14549 checkStackFrame("origin", "foo", 2, 3, false, false,
14550 stack_trace->GetFrame(0));
14551 checkStackFrame("origin", "bar", 5, 3, false, false,
14552 stack_trace->GetFrame(1));
14553}
14554
14555TEST(CaptureStackTraceForUncaughtException) {
14556 report_count = 0;
14557 v8::HandleScope scope;
14558 LocalContext env;
14559 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14560 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14561
14562 Script::Compile(v8_str("function foo() {\n"
14563 " throw 1;\n"
14564 "};\n"
14565 "function bar() {\n"
14566 " foo();\n"
14567 "};"),
14568 v8_str("origin"))->Run();
14569 v8::Local<v8::Object> global = env->Global();
14570 Local<Value> trouble = global->Get(v8_str("bar"));
14571 CHECK(trouble->IsFunction());
14572 Function::Cast(*trouble)->Call(global, 0, NULL);
14573 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14574 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14575}
14576
14577
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014578TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14579 v8::HandleScope scope;
14580 LocalContext env;
14581 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14582 1024,
14583 v8::StackTrace::kDetailed);
14584
14585 CompileRun(
14586 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14587 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14588 " 'isConstructor'];\n"
14589 "for (var i = 0; i < setters.length; i++) {\n"
14590 " var prop = setters[i];\n"
14591 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14592 "}\n");
14593 CompileRun("throw 'exception';");
14594 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14595}
14596
14597
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014598static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14599 v8::Handle<v8::Value> data) {
14600 // Use the frame where JavaScript is called from.
14601 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14602 CHECK(!stack_trace.IsEmpty());
14603 int frame_count = stack_trace->GetFrameCount();
14604 CHECK_EQ(3, frame_count);
14605 int line_number[] = {1, 2, 5};
14606 for (int i = 0; i < frame_count; i++) {
14607 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14608 }
14609}
14610
14611
14612// Test that we only return the stack trace at the site where the exception
14613// is first thrown (not where it is rethrown).
14614TEST(RethrowStackTrace) {
14615 v8::HandleScope scope;
14616 LocalContext env;
14617 // We make sure that
14618 // - the stack trace of the ReferenceError in g() is reported.
14619 // - the stack trace is not overwritten when e1 is rethrown by t().
14620 // - the stack trace of e2 does not overwrite that of e1.
14621 const char* source =
14622 "function g() { error; } \n"
14623 "function f() { g(); } \n"
14624 "function t(e) { throw e; } \n"
14625 "try { \n"
14626 " f(); \n"
14627 "} catch (e1) { \n"
14628 " try { \n"
14629 " error; \n"
14630 " } catch (e2) { \n"
14631 " t(e1); \n"
14632 " } \n"
14633 "} \n";
14634 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14635 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14636 CompileRun(source);
14637 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14638 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14639}
14640
14641
14642static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14643 v8::Handle<v8::Value> data) {
14644 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14645 CHECK(!stack_trace.IsEmpty());
14646 int frame_count = stack_trace->GetFrameCount();
14647 CHECK_EQ(2, frame_count);
14648 int line_number[] = {3, 7};
14649 for (int i = 0; i < frame_count; i++) {
14650 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14651 }
14652}
14653
14654
14655// Test that we do not recognize identity for primitive exceptions.
14656TEST(RethrowPrimitiveStackTrace) {
14657 v8::HandleScope scope;
14658 LocalContext env;
14659 // We do not capture stack trace for non Error objects on creation time.
14660 // Instead, we capture the stack trace on last throw.
14661 const char* source =
14662 "function g() { throw 404; } \n"
14663 "function f() { g(); } \n"
14664 "function t(e) { throw e; } \n"
14665 "try { \n"
14666 " f(); \n"
14667 "} catch (e1) { \n"
14668 " t(e1) \n"
14669 "} \n";
14670 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14671 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14672 CompileRun(source);
14673 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14674 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14675}
14676
14677
14678static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14679 v8::Handle<v8::Value> data) {
14680 // Use the frame where JavaScript is called from.
14681 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14682 CHECK(!stack_trace.IsEmpty());
14683 CHECK_EQ(1, stack_trace->GetFrameCount());
14684 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14685}
14686
14687
14688// Test that the stack trace is captured when the error object is created and
14689// not where it is thrown.
14690TEST(RethrowExistingStackTrace) {
14691 v8::HandleScope scope;
14692 LocalContext env;
14693 const char* source =
14694 "var e = new Error(); \n"
14695 "throw e; \n";
14696 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14697 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14698 CompileRun(source);
14699 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14700 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14701}
14702
14703
14704static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14705 v8::Handle<v8::Value> data) {
14706 // Use the frame where JavaScript is called from.
14707 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14708 CHECK(!stack_trace.IsEmpty());
14709 CHECK_EQ(1, stack_trace->GetFrameCount());
14710 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14711}
14712
14713
14714// Test that the stack trace is captured where the bogus Error object is thrown.
14715TEST(RethrowBogusErrorStackTrace) {
14716 v8::HandleScope scope;
14717 LocalContext env;
14718 const char* source =
14719 "var e = {__proto__: new Error()} \n"
14720 "throw e; \n";
14721 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14722 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14723 CompileRun(source);
14724 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14725 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14726}
14727
14728
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014729v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
14730 v8::HandleScope scope;
14731 v8::Handle<v8::StackTrace> stackTrace =
14732 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14733 CHECK_EQ(5, stackTrace->GetFrameCount());
14734 v8::Handle<v8::String> url = v8_str("eval_url");
14735 for (int i = 0; i < 3; i++) {
14736 v8::Handle<v8::String> name =
14737 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14738 CHECK(!name.IsEmpty());
14739 CHECK_EQ(url, name);
14740 }
14741 return v8::Undefined();
14742}
14743
14744
14745TEST(SourceURLInStackTrace) {
14746 v8::HandleScope scope;
14747 Local<ObjectTemplate> templ = ObjectTemplate::New();
14748 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14749 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14750 LocalContext context(0, templ);
14751
14752 const char *source =
14753 "function outer() {\n"
14754 "function bar() {\n"
14755 " AnalyzeStackOfEvalWithSourceURL();\n"
14756 "}\n"
14757 "function foo() {\n"
14758 "\n"
14759 " bar();\n"
14760 "}\n"
14761 "foo();\n"
14762 "}\n"
14763 "eval('(' + outer +')()//@ sourceURL=eval_url');";
14764 CHECK(CompileRun(source)->IsUndefined());
14765}
14766
14767
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000014768v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
14769 const v8::Arguments& args) {
14770 v8::HandleScope scope;
14771 v8::Handle<v8::StackTrace> stackTrace =
14772 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14773 CHECK_EQ(4, stackTrace->GetFrameCount());
14774 v8::Handle<v8::String> url = v8_str("url");
14775 for (int i = 0; i < 3; i++) {
14776 v8::Handle<v8::String> name =
14777 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14778 CHECK(!name.IsEmpty());
14779 CHECK_EQ(url, name);
14780 }
14781 return v8::Undefined();
14782}
14783
14784
14785TEST(InlineScriptWithSourceURLInStackTrace) {
14786 v8::HandleScope scope;
14787 Local<ObjectTemplate> templ = ObjectTemplate::New();
14788 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14789 v8::FunctionTemplate::New(
14790 AnalyzeStackOfInlineScriptWithSourceURL));
14791 LocalContext context(0, templ);
14792
14793 const char *source =
14794 "function outer() {\n"
14795 "function bar() {\n"
14796 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14797 "}\n"
14798 "function foo() {\n"
14799 "\n"
14800 " bar();\n"
14801 "}\n"
14802 "foo();\n"
14803 "}\n"
14804 "outer()\n"
14805 "//@ sourceURL=source_url";
14806 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14807}
14808
14809
14810v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
14811 const v8::Arguments& args) {
14812 v8::HandleScope scope;
14813 v8::Handle<v8::StackTrace> stackTrace =
14814 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14815 CHECK_EQ(4, stackTrace->GetFrameCount());
14816 v8::Handle<v8::String> url = v8_str("source_url");
14817 for (int i = 0; i < 3; i++) {
14818 v8::Handle<v8::String> name =
14819 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14820 CHECK(!name.IsEmpty());
14821 CHECK_EQ(url, name);
14822 }
14823 return v8::Undefined();
14824}
14825
14826
14827TEST(DynamicWithSourceURLInStackTrace) {
14828 v8::HandleScope scope;
14829 Local<ObjectTemplate> templ = ObjectTemplate::New();
14830 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14831 v8::FunctionTemplate::New(
14832 AnalyzeStackOfDynamicScriptWithSourceURL));
14833 LocalContext context(0, templ);
14834
14835 const char *source =
14836 "function outer() {\n"
14837 "function bar() {\n"
14838 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14839 "}\n"
14840 "function foo() {\n"
14841 "\n"
14842 " bar();\n"
14843 "}\n"
14844 "foo();\n"
14845 "}\n"
14846 "outer()\n"
14847 "//@ sourceURL=source_url";
14848 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14849}
14850
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014851static void CreateGarbageInOldSpace() {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014852 v8::HandleScope scope;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014853 i::AlwaysAllocateScope always_allocate;
14854 for (int i = 0; i < 1000; i++) {
14855 FACTORY->NewFixedArray(1000, i::TENURED);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014856 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014857}
14858
14859// Test that idle notification can be handled and eventually returns true.
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014860TEST(IdleNotification) {
14861 const intptr_t MB = 1024 * 1024;
14862 v8::HandleScope scope;
14863 LocalContext env;
14864 intptr_t initial_size = HEAP->SizeOfObjects();
14865 CreateGarbageInOldSpace();
14866 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14867 CHECK_GT(size_with_garbage, initial_size + MB);
14868 bool finished = false;
14869 for (int i = 0; i < 200 && !finished; i++) {
14870 finished = v8::V8::IdleNotification();
14871 }
14872 intptr_t final_size = HEAP->SizeOfObjects();
14873 CHECK(finished);
14874 CHECK_LT(final_size, initial_size + 1);
14875}
14876
14877
14878// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014879TEST(IdleNotificationWithSmallHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014880 const intptr_t MB = 1024 * 1024;
14881 const int IdlePauseInMs = 900;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014882 v8::HandleScope scope;
14883 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014884 intptr_t initial_size = HEAP->SizeOfObjects();
14885 CreateGarbageInOldSpace();
14886 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14887 CHECK_GT(size_with_garbage, initial_size + MB);
14888 bool finished = false;
14889 for (int i = 0; i < 200 && !finished; i++) {
14890 finished = v8::V8::IdleNotification(IdlePauseInMs);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014891 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014892 intptr_t final_size = HEAP->SizeOfObjects();
14893 CHECK(finished);
14894 CHECK_LT(final_size, initial_size + 1);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014895}
14896
14897
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014898// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014899TEST(IdleNotificationWithLargeHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014900 const intptr_t MB = 1024 * 1024;
14901 const int IdlePauseInMs = 900;
yangguo@chromium.org56454712012-02-16 15:33:53 +000014902 v8::HandleScope scope;
14903 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014904 intptr_t initial_size = HEAP->SizeOfObjects();
14905 CreateGarbageInOldSpace();
14906 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14907 CHECK_GT(size_with_garbage, initial_size + MB);
14908 bool finished = false;
14909 for (int i = 0; i < 200 && !finished; i++) {
14910 finished = v8::V8::IdleNotification(IdlePauseInMs);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014911 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014912 intptr_t final_size = HEAP->SizeOfObjects();
14913 CHECK(finished);
14914 CHECK_LT(final_size, initial_size + 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014915}
14916
14917
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014918TEST(Regress2107) {
14919 const intptr_t MB = 1024 * 1024;
14920 const int kShortIdlePauseInMs = 100;
14921 const int kLongIdlePauseInMs = 1000;
14922 v8::HandleScope scope;
14923 LocalContext env;
14924 intptr_t initial_size = HEAP->SizeOfObjects();
14925 // Send idle notification to start a round of incremental GCs.
14926 v8::V8::IdleNotification(kShortIdlePauseInMs);
14927 // Emulate 7 page reloads.
14928 for (int i = 0; i < 7; i++) {
14929 v8::Persistent<v8::Context> ctx = v8::Context::New();
14930 ctx->Enter();
14931 CreateGarbageInOldSpace();
14932 ctx->Exit();
14933 ctx.Dispose();
14934 v8::V8::ContextDisposedNotification();
14935 v8::V8::IdleNotification(kLongIdlePauseInMs);
14936 }
14937 // Create garbage and check that idle notification still collects it.
14938 CreateGarbageInOldSpace();
14939 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14940 CHECK_GT(size_with_garbage, initial_size + MB);
14941 bool finished = false;
14942 for (int i = 0; i < 200 && !finished; i++) {
14943 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14944 }
14945 intptr_t final_size = HEAP->SizeOfObjects();
14946 CHECK_LT(final_size, initial_size + 1);
14947}
14948
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014949static uint32_t* stack_limit;
14950
14951static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014952 stack_limit = reinterpret_cast<uint32_t*>(
14953 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014954 return v8::Undefined();
14955}
14956
14957
14958// Uses the address of a local variable to determine the stack top now.
14959// Given a size, returns an address that is that far from the current
14960// top of stack.
14961static uint32_t* ComputeStackLimit(uint32_t size) {
14962 uint32_t* answer = &size - (size / sizeof(size));
14963 // If the size is very large and the stack is very near the bottom of
14964 // memory then the calculation above may wrap around and give an address
14965 // that is above the (downwards-growing) stack. In that case we return
14966 // a very low address.
14967 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14968 return answer;
14969}
14970
14971
14972TEST(SetResourceConstraints) {
14973 static const int K = 1024;
14974 uint32_t* set_limit = ComputeStackLimit(128 * K);
14975
14976 // Set stack limit.
14977 v8::ResourceConstraints constraints;
14978 constraints.set_stack_limit(set_limit);
14979 CHECK(v8::SetResourceConstraints(&constraints));
14980
14981 // Execute a script.
14982 v8::HandleScope scope;
14983 LocalContext env;
14984 Local<v8::FunctionTemplate> fun_templ =
14985 v8::FunctionTemplate::New(GetStackLimitCallback);
14986 Local<Function> fun = fun_templ->GetFunction();
14987 env->Global()->Set(v8_str("get_stack_limit"), fun);
14988 CompileRun("get_stack_limit();");
14989
14990 CHECK(stack_limit == set_limit);
14991}
14992
14993
14994TEST(SetResourceConstraintsInThread) {
14995 uint32_t* set_limit;
14996 {
14997 v8::Locker locker;
14998 static const int K = 1024;
14999 set_limit = ComputeStackLimit(128 * K);
15000
15001 // Set stack limit.
15002 v8::ResourceConstraints constraints;
15003 constraints.set_stack_limit(set_limit);
15004 CHECK(v8::SetResourceConstraints(&constraints));
15005
15006 // Execute a script.
15007 v8::HandleScope scope;
15008 LocalContext env;
15009 Local<v8::FunctionTemplate> fun_templ =
15010 v8::FunctionTemplate::New(GetStackLimitCallback);
15011 Local<Function> fun = fun_templ->GetFunction();
15012 env->Global()->Set(v8_str("get_stack_limit"), fun);
15013 CompileRun("get_stack_limit();");
15014
15015 CHECK(stack_limit == set_limit);
15016 }
15017 {
15018 v8::Locker locker;
15019 CHECK(stack_limit == set_limit);
15020 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000015021}
ager@chromium.org3811b432009-10-28 14:53:37 +000015022
15023
15024THREADED_TEST(GetHeapStatistics) {
15025 v8::HandleScope scope;
15026 LocalContext c1;
15027 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015028 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
15029 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015030 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015031 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15032 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015033}
15034
15035
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015036class VisitorImpl : public v8::ExternalResourceVisitor {
15037 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015038 explicit VisitorImpl(TestResource** resource) {
15039 for (int i = 0; i < 4; i++) {
15040 resource_[i] = resource[i];
15041 found_resource_[i] = false;
15042 }
15043 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015044 virtual ~VisitorImpl() {}
15045 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15046 if (!string->IsExternal()) {
15047 CHECK(string->IsExternalAscii());
15048 return;
15049 }
15050 v8::String::ExternalStringResource* resource =
15051 string->GetExternalStringResource();
15052 CHECK(resource);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015053 for (int i = 0; i < 4; i++) {
15054 if (resource_[i] == resource) {
15055 CHECK(!found_resource_[i]);
15056 found_resource_[i] = true;
15057 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015058 }
15059 }
15060 void CheckVisitedResources() {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015061 for (int i = 0; i < 4; i++) {
15062 CHECK(found_resource_[i]);
15063 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015064 }
15065
15066 private:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015067 v8::String::ExternalStringResource* resource_[4];
15068 bool found_resource_[4];
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015069};
15070
15071TEST(VisitExternalStrings) {
15072 v8::HandleScope scope;
15073 LocalContext env;
15074 const char* string = "Some string";
15075 uint16_t* two_byte_string = AsciiToTwoByteString(string);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015076 TestResource* resource[4];
15077 resource[0] = new TestResource(two_byte_string);
15078 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
15079 resource[1] = new TestResource(two_byte_string);
15080 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015081
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015082 // Externalized symbol.
15083 resource[2] = new TestResource(two_byte_string);
15084 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
15085 CHECK(string2->MakeExternal(resource[2]));
15086
15087 // Symbolized External.
15088 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15089 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
15090 HEAP->CollectAllAvailableGarbage(); // Tenure string.
15091 // Turn into a symbol.
15092 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15093 CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure());
15094 CHECK(string3_i->IsSymbol());
15095
15096 // We need to add usages for string* to avoid warnings in GCC 4.7
15097 CHECK(string0->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015098 CHECK(string1->IsExternal());
15099 CHECK(string2->IsExternal());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015100 CHECK(string3->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015101
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015102 VisitorImpl visitor(resource);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015103 v8::V8::VisitExternalResources(&visitor);
15104 visitor.CheckVisitedResources();
15105}
15106
15107
ager@chromium.org3811b432009-10-28 14:53:37 +000015108static double DoubleFromBits(uint64_t value) {
15109 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015110 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015111 return target;
15112}
15113
15114
15115static uint64_t DoubleToBits(double value) {
15116 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015117 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015118 return target;
15119}
15120
15121
15122static double DoubleToDateTime(double input) {
15123 double date_limit = 864e13;
15124 if (IsNaN(input) || input < -date_limit || input > date_limit) {
15125 return i::OS::nan_value();
15126 }
15127 return (input < 0) ? -(floor(-input)) : floor(input);
15128}
15129
15130// We don't have a consistent way to write 64-bit constants syntactically, so we
15131// split them into two 32-bit constants and combine them programmatically.
15132static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15133 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15134}
15135
15136
15137THREADED_TEST(QuietSignalingNaNs) {
15138 v8::HandleScope scope;
15139 LocalContext context;
15140 v8::TryCatch try_catch;
15141
15142 // Special double values.
15143 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15144 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15145 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15146 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15147 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15148 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15149 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15150
15151 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15152 // on either side of the epoch.
15153 double date_limit = 864e13;
15154
15155 double test_values[] = {
15156 snan,
15157 qnan,
15158 infinity,
15159 max_normal,
15160 date_limit + 1,
15161 date_limit,
15162 min_normal,
15163 max_denormal,
15164 min_denormal,
15165 0,
15166 -0,
15167 -min_denormal,
15168 -max_denormal,
15169 -min_normal,
15170 -date_limit,
15171 -date_limit - 1,
15172 -max_normal,
15173 -infinity,
15174 -qnan,
15175 -snan
15176 };
15177 int num_test_values = 20;
15178
15179 for (int i = 0; i < num_test_values; i++) {
15180 double test_value = test_values[i];
15181
15182 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15183 v8::Handle<v8::Value> number = v8::Number::New(test_value);
15184 double stored_number = number->NumberValue();
15185 if (!IsNaN(test_value)) {
15186 CHECK_EQ(test_value, stored_number);
15187 } else {
15188 uint64_t stored_bits = DoubleToBits(stored_number);
15189 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015190#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15191 // Most significant fraction bit for quiet nan is set to 0
15192 // on MIPS architecture. Allowed by IEEE-754.
15193 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15194#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015195 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015196#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015197 }
15198
15199 // Check that Date::New preserves non-NaNs in the date range and
15200 // quiets SNaNs.
15201 v8::Handle<v8::Value> date = v8::Date::New(test_value);
15202 double expected_stored_date = DoubleToDateTime(test_value);
15203 double stored_date = date->NumberValue();
15204 if (!IsNaN(expected_stored_date)) {
15205 CHECK_EQ(expected_stored_date, stored_date);
15206 } else {
15207 uint64_t stored_bits = DoubleToBits(stored_date);
15208 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015209#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15210 // Most significant fraction bit for quiet nan is set to 0
15211 // on MIPS architecture. Allowed by IEEE-754.
15212 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15213#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015214 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015215#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015216 }
15217 }
15218}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015219
15220
15221static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
15222 v8::HandleScope scope;
15223 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015224 v8::Handle<v8::String> str(args[0]->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015225 USE(str);
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015226 if (tc.HasCaught())
15227 return tc.ReThrow();
15228 return v8::Undefined();
15229}
15230
15231
15232// Test that an exception can be propagated down through a spaghetti
15233// stack using ReThrow.
15234THREADED_TEST(SpaghettiStackReThrow) {
15235 v8::HandleScope scope;
15236 LocalContext context;
15237 context->Global()->Set(
15238 v8::String::New("s"),
15239 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15240 v8::TryCatch try_catch;
15241 CompileRun(
15242 "var i = 0;"
15243 "var o = {"
15244 " toString: function () {"
15245 " if (i == 10) {"
15246 " throw 'Hey!';"
15247 " } else {"
15248 " i++;"
15249 " return s(o);"
15250 " }"
15251 " }"
15252 "};"
15253 "s(o);");
15254 CHECK(try_catch.HasCaught());
15255 v8::String::Utf8Value value(try_catch.Exception());
15256 CHECK_EQ(0, strcmp(*value, "Hey!"));
15257}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015258
15259
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015260TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015261 v8::V8::Initialize();
15262
15263 v8::HandleScope scope;
15264 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000015265 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015266 int gc_count;
15267
ager@chromium.org60121232009-12-03 11:25:37 +000015268 // Create a context used to keep the code from aging in the compilation
15269 // cache.
15270 other_context = Context::New();
15271
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015272 // Context-dependent context data creates reference from the compilation
15273 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015274 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015275 context = Context::New();
15276 {
15277 v8::HandleScope scope;
15278
15279 context->Enter();
15280 Local<v8::String> obj = v8::String::New("");
15281 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000015282 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015283 context->Exit();
15284 }
15285 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015286 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015287 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015288 other_context->Enter();
15289 CompileRun(source_simple);
15290 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015291 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015292 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015293 }
ager@chromium.org60121232009-12-03 11:25:37 +000015294 CHECK_GE(2, gc_count);
15295 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015296
15297 // Eval in a function creates reference from the compilation cache to the
15298 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015299 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015300 context = Context::New();
15301 {
15302 v8::HandleScope scope;
15303
15304 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000015305 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015306 context->Exit();
15307 }
15308 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015309 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015310 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015311 other_context->Enter();
15312 CompileRun(source_eval);
15313 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015314 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015315 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015316 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000015317 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015318 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015319
15320 // Looking up the line number for an exception creates reference from the
15321 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015322 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015323 context = Context::New();
15324 {
15325 v8::HandleScope scope;
15326
15327 context->Enter();
15328 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000015329 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015330 CHECK(try_catch.HasCaught());
15331 v8::Handle<v8::Message> message = try_catch.Message();
15332 CHECK(!message.IsEmpty());
15333 CHECK_EQ(1, message->GetLineNumber());
15334 context->Exit();
15335 }
15336 context.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000015337 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015338 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015339 other_context->Enter();
15340 CompileRun(source_exception);
15341 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015342 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015343 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015344 }
ager@chromium.org60121232009-12-03 11:25:37 +000015345 CHECK_GE(2, gc_count);
15346 CHECK_EQ(1, GetGlobalObjectsCount());
15347
15348 other_context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015349 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015350}
ager@chromium.org5c838252010-02-19 08:53:10 +000015351
15352
15353THREADED_TEST(ScriptOrigin) {
15354 v8::HandleScope scope;
15355 LocalContext env;
15356 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15357 v8::Handle<v8::String> script = v8::String::New(
15358 "function f() {}\n\nfunction g() {}");
15359 v8::Script::Compile(script, &origin)->Run();
15360 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15361 env->Global()->Get(v8::String::New("f")));
15362 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15363 env->Global()->Get(v8::String::New("g")));
15364
15365 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15366 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15367 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15368
15369 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15370 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15371 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15372}
15373
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015374THREADED_TEST(FunctionGetInferredName) {
15375 v8::HandleScope scope;
15376 LocalContext env;
15377 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15378 v8::Handle<v8::String> script = v8::String::New(
15379 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15380 v8::Script::Compile(script, &origin)->Run();
15381 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15382 env->Global()->Get(v8::String::New("f")));
15383 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15384}
ager@chromium.org5c838252010-02-19 08:53:10 +000015385
15386THREADED_TEST(ScriptLineNumber) {
15387 v8::HandleScope scope;
15388 LocalContext env;
15389 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15390 v8::Handle<v8::String> script = v8::String::New(
15391 "function f() {}\n\nfunction g() {}");
15392 v8::Script::Compile(script, &origin)->Run();
15393 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15394 env->Global()->Get(v8::String::New("f")));
15395 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15396 env->Global()->Get(v8::String::New("g")));
15397 CHECK_EQ(0, f->GetScriptLineNumber());
15398 CHECK_EQ(2, g->GetScriptLineNumber());
15399}
15400
15401
danno@chromium.orgc612e022011-11-10 11:38:15 +000015402THREADED_TEST(ScriptColumnNumber) {
15403 v8::HandleScope scope;
15404 LocalContext env;
15405 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15406 v8::Integer::New(3), v8::Integer::New(2));
15407 v8::Handle<v8::String> script = v8::String::New(
15408 "function foo() {}\n\n function bar() {}");
15409 v8::Script::Compile(script, &origin)->Run();
15410 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15411 env->Global()->Get(v8::String::New("foo")));
15412 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15413 env->Global()->Get(v8::String::New("bar")));
15414 CHECK_EQ(14, foo->GetScriptColumnNumber());
15415 CHECK_EQ(17, bar->GetScriptColumnNumber());
15416}
15417
15418
15419THREADED_TEST(FunctionGetScriptId) {
15420 v8::HandleScope scope;
15421 LocalContext env;
15422 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15423 v8::Integer::New(3), v8::Integer::New(2));
15424 v8::Handle<v8::String> scriptSource = v8::String::New(
15425 "function foo() {}\n\n function bar() {}");
15426 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15427 script->Run();
15428 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15429 env->Global()->Get(v8::String::New("foo")));
15430 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15431 env->Global()->Get(v8::String::New("bar")));
15432 CHECK_EQ(script->Id(), foo->GetScriptId());
15433 CHECK_EQ(script->Id(), bar->GetScriptId());
15434}
15435
15436
ager@chromium.org5c838252010-02-19 08:53:10 +000015437static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15438 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015439 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15440 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015441 return v8_num(42);
15442}
15443
15444
15445static void SetterWhichSetsYOnThisTo23(Local<String> name,
15446 Local<Value> value,
15447 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015448 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15449 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015450 info.This()->Set(v8_str("y"), v8_num(23));
15451}
15452
15453
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015454Handle<Value> FooGetInterceptor(Local<String> name,
15455 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015456 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15457 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015458 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15459 return v8_num(42);
15460}
15461
15462
15463Handle<Value> FooSetInterceptor(Local<String> name,
15464 Local<Value> value,
15465 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015466 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15467 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015468 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15469 info.This()->Set(v8_str("y"), v8_num(23));
15470 return v8_num(23);
15471}
15472
15473
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015474TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015475 v8::HandleScope scope;
15476 Local<ObjectTemplate> templ = ObjectTemplate::New();
15477 templ->SetAccessor(v8_str("x"),
15478 GetterWhichReturns42,
15479 SetterWhichSetsYOnThisTo23);
15480 LocalContext context;
15481 context->Global()->Set(v8_str("P"), templ->NewInstance());
15482 CompileRun("function C1() {"
15483 " this.x = 23;"
15484 "};"
15485 "C1.prototype = P;"
15486 "function C2() {"
15487 " this.x = 23"
15488 "};"
15489 "C2.prototype = { };"
15490 "C2.prototype.__proto__ = P;");
15491
15492 v8::Local<v8::Script> script;
15493 script = v8::Script::Compile(v8_str("new C1();"));
15494 for (int i = 0; i < 10; i++) {
15495 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15496 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15497 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15498 }
15499
15500 script = v8::Script::Compile(v8_str("new C2();"));
15501 for (int i = 0; i < 10; i++) {
15502 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15503 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15504 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15505 }
15506}
15507
15508
15509static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15510 Local<String> name, const AccessorInfo& info) {
15511 return v8_num(42);
15512}
15513
15514
15515static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15516 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15517 if (name->Equals(v8_str("x"))) {
15518 info.This()->Set(v8_str("y"), v8_num(23));
15519 }
15520 return v8::Handle<Value>();
15521}
15522
15523
15524THREADED_TEST(InterceptorOnConstructorPrototype) {
15525 v8::HandleScope scope;
15526 Local<ObjectTemplate> templ = ObjectTemplate::New();
15527 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15528 NamedPropertySetterWhichSetsYOnThisTo23);
15529 LocalContext context;
15530 context->Global()->Set(v8_str("P"), templ->NewInstance());
15531 CompileRun("function C1() {"
15532 " this.x = 23;"
15533 "};"
15534 "C1.prototype = P;"
15535 "function C2() {"
15536 " this.x = 23"
15537 "};"
15538 "C2.prototype = { };"
15539 "C2.prototype.__proto__ = P;");
15540
15541 v8::Local<v8::Script> script;
15542 script = v8::Script::Compile(v8_str("new C1();"));
15543 for (int i = 0; i < 10; i++) {
15544 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15545 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15546 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15547 }
15548
15549 script = v8::Script::Compile(v8_str("new C2();"));
15550 for (int i = 0; i < 10; i++) {
15551 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15552 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15553 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15554 }
15555}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015556
15557
15558TEST(Bug618) {
15559 const char* source = "function C1() {"
15560 " this.x = 23;"
15561 "};"
15562 "C1.prototype = P;";
15563
15564 v8::HandleScope scope;
15565 LocalContext context;
15566 v8::Local<v8::Script> script;
15567
15568 // Use a simple object as prototype.
15569 v8::Local<v8::Object> prototype = v8::Object::New();
15570 prototype->Set(v8_str("y"), v8_num(42));
15571 context->Global()->Set(v8_str("P"), prototype);
15572
15573 // This compile will add the code to the compilation cache.
15574 CompileRun(source);
15575
15576 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015577 // Allow enough iterations for the inobject slack tracking logic
15578 // to finalize instance size and install the fast construct stub.
15579 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015580 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15581 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15582 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15583 }
15584
15585 // Use an API object with accessors as prototype.
15586 Local<ObjectTemplate> templ = ObjectTemplate::New();
15587 templ->SetAccessor(v8_str("x"),
15588 GetterWhichReturns42,
15589 SetterWhichSetsYOnThisTo23);
15590 context->Global()->Set(v8_str("P"), templ->NewInstance());
15591
15592 // This compile will get the code from the compilation cache.
15593 CompileRun(source);
15594
15595 script = v8::Script::Compile(v8_str("new C1();"));
15596 for (int i = 0; i < 10; i++) {
15597 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15598 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15599 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15600 }
15601}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015602
15603int prologue_call_count = 0;
15604int epilogue_call_count = 0;
15605int prologue_call_count_second = 0;
15606int epilogue_call_count_second = 0;
15607
15608void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15609 ++prologue_call_count;
15610}
15611
15612void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15613 ++epilogue_call_count;
15614}
15615
15616void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15617 ++prologue_call_count_second;
15618}
15619
15620void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15621 ++epilogue_call_count_second;
15622}
15623
15624TEST(GCCallbacks) {
15625 LocalContext context;
15626
15627 v8::V8::AddGCPrologueCallback(PrologueCallback);
15628 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15629 CHECK_EQ(0, prologue_call_count);
15630 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015631 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015632 CHECK_EQ(1, prologue_call_count);
15633 CHECK_EQ(1, epilogue_call_count);
15634 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15635 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015636 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015637 CHECK_EQ(2, prologue_call_count);
15638 CHECK_EQ(2, epilogue_call_count);
15639 CHECK_EQ(1, prologue_call_count_second);
15640 CHECK_EQ(1, epilogue_call_count_second);
15641 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15642 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015643 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015644 CHECK_EQ(2, prologue_call_count);
15645 CHECK_EQ(2, epilogue_call_count);
15646 CHECK_EQ(2, prologue_call_count_second);
15647 CHECK_EQ(2, epilogue_call_count_second);
15648 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15649 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015650 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015651 CHECK_EQ(2, prologue_call_count);
15652 CHECK_EQ(2, epilogue_call_count);
15653 CHECK_EQ(2, prologue_call_count_second);
15654 CHECK_EQ(2, epilogue_call_count_second);
15655}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015656
15657
15658THREADED_TEST(AddToJSFunctionResultCache) {
15659 i::FLAG_allow_natives_syntax = true;
15660 v8::HandleScope scope;
15661
15662 LocalContext context;
15663
15664 const char* code =
15665 "(function() {"
15666 " var key0 = 'a';"
15667 " var key1 = 'b';"
15668 " var r0 = %_GetFromCache(0, key0);"
15669 " var r1 = %_GetFromCache(0, key1);"
15670 " var r0_ = %_GetFromCache(0, key0);"
15671 " if (r0 !== r0_)"
15672 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15673 " var r1_ = %_GetFromCache(0, key1);"
15674 " if (r1 !== r1_)"
15675 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15676 " return 'PASSED';"
15677 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015678 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015679 ExpectString(code, "PASSED");
15680}
15681
15682
15683static const int k0CacheSize = 16;
15684
15685THREADED_TEST(FillJSFunctionResultCache) {
15686 i::FLAG_allow_natives_syntax = true;
15687 v8::HandleScope scope;
15688
15689 LocalContext context;
15690
15691 const char* code =
15692 "(function() {"
15693 " var k = 'a';"
15694 " var r = %_GetFromCache(0, k);"
15695 " for (var i = 0; i < 16; i++) {"
15696 " %_GetFromCache(0, 'a' + i);"
15697 " };"
15698 " if (r === %_GetFromCache(0, k))"
15699 " return 'FAILED: k0CacheSize is too small';"
15700 " return 'PASSED';"
15701 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015702 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015703 ExpectString(code, "PASSED");
15704}
15705
15706
15707THREADED_TEST(RoundRobinGetFromCache) {
15708 i::FLAG_allow_natives_syntax = true;
15709 v8::HandleScope scope;
15710
15711 LocalContext context;
15712
15713 const char* code =
15714 "(function() {"
15715 " var keys = [];"
15716 " for (var i = 0; i < 16; i++) keys.push(i);"
15717 " var values = [];"
15718 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15719 " for (var i = 0; i < 16; i++) {"
15720 " var v = %_GetFromCache(0, keys[i]);"
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000015721 " if (v.toString() !== values[i].toString())"
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015722 " return 'Wrong value for ' + "
15723 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15724 " };"
15725 " return 'PASSED';"
15726 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015727 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015728 ExpectString(code, "PASSED");
15729}
15730
15731
15732THREADED_TEST(ReverseGetFromCache) {
15733 i::FLAG_allow_natives_syntax = true;
15734 v8::HandleScope scope;
15735
15736 LocalContext context;
15737
15738 const char* code =
15739 "(function() {"
15740 " var keys = [];"
15741 " for (var i = 0; i < 16; i++) keys.push(i);"
15742 " var values = [];"
15743 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15744 " for (var i = 15; i >= 16; i--) {"
15745 " var v = %_GetFromCache(0, keys[i]);"
15746 " if (v !== values[i])"
15747 " return 'Wrong value for ' + "
15748 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15749 " };"
15750 " return 'PASSED';"
15751 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015752 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015753 ExpectString(code, "PASSED");
15754}
15755
15756
15757THREADED_TEST(TestEviction) {
15758 i::FLAG_allow_natives_syntax = true;
15759 v8::HandleScope scope;
15760
15761 LocalContext context;
15762
15763 const char* code =
15764 "(function() {"
15765 " for (var i = 0; i < 2*16; i++) {"
15766 " %_GetFromCache(0, 'a' + i);"
15767 " };"
15768 " return 'PASSED';"
15769 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015770 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015771 ExpectString(code, "PASSED");
15772}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015773
15774
15775THREADED_TEST(TwoByteStringInAsciiCons) {
15776 // See Chromium issue 47824.
15777 v8::HandleScope scope;
15778
15779 LocalContext context;
15780 const char* init_code =
15781 "var str1 = 'abelspendabel';"
15782 "var str2 = str1 + str1 + str1;"
15783 "str2;";
15784 Local<Value> result = CompileRun(init_code);
15785
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015786 Local<Value> indexof = CompileRun("str2.indexOf('els')");
15787 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15788
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015789 CHECK(result->IsString());
15790 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15791 int length = string->length();
15792 CHECK(string->IsAsciiRepresentation());
15793
15794 FlattenString(string);
15795 i::Handle<i::String> flat_string = FlattenGetString(string);
15796
15797 CHECK(string->IsAsciiRepresentation());
15798 CHECK(flat_string->IsAsciiRepresentation());
15799
15800 // Create external resource.
15801 uint16_t* uc16_buffer = new uint16_t[length + 1];
15802
15803 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15804 uc16_buffer[length] = 0;
15805
15806 TestResource resource(uc16_buffer);
15807
15808 flat_string->MakeExternal(&resource);
15809
15810 CHECK(flat_string->IsTwoByteRepresentation());
15811
15812 // At this point, we should have a Cons string which is flat and ASCII,
15813 // with a first half that is a two-byte string (although it only contains
15814 // ASCII characters). This is a valid sequence of steps, and it can happen
15815 // in real pages.
15816
15817 CHECK(string->IsAsciiRepresentation());
15818 i::ConsString* cons = i::ConsString::cast(*string);
15819 CHECK_EQ(0, cons->second()->length());
15820 CHECK(cons->first()->IsTwoByteRepresentation());
15821
15822 // Check that some string operations work.
15823
15824 // Atom RegExp.
15825 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15826 CHECK_EQ(6, reresult->Int32Value());
15827
15828 // Nonatom RegExp.
15829 reresult = CompileRun("str2.match(/abe./g).length;");
15830 CHECK_EQ(6, reresult->Int32Value());
15831
15832 reresult = CompileRun("str2.search(/bel/g);");
15833 CHECK_EQ(1, reresult->Int32Value());
15834
15835 reresult = CompileRun("str2.search(/be./g);");
15836 CHECK_EQ(1, reresult->Int32Value());
15837
15838 ExpectTrue("/bel/g.test(str2);");
15839
15840 ExpectTrue("/be./g.test(str2);");
15841
15842 reresult = CompileRun("/bel/g.exec(str2);");
15843 CHECK(!reresult->IsNull());
15844
15845 reresult = CompileRun("/be./g.exec(str2);");
15846 CHECK(!reresult->IsNull());
15847
15848 ExpectString("str2.substring(2, 10);", "elspenda");
15849
15850 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15851
15852 ExpectString("str2.charAt(2);", "e");
15853
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015854 ExpectObject("str2.indexOf('els');", indexof);
15855
15856 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15857
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015858 reresult = CompileRun("str2.charCodeAt(2);");
15859 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
15860}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015861
15862
15863// Failed access check callback that performs a GC on each invocation.
15864void FailedAccessCheckCallbackGC(Local<v8::Object> target,
15865 v8::AccessType type,
15866 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015867 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015868}
15869
15870
15871TEST(GCInFailedAccessCheckCallback) {
15872 // Install a failed access check callback that performs a GC on each
15873 // invocation. Then force the callback to be called from va
15874
15875 v8::V8::Initialize();
15876 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
15877
15878 v8::HandleScope scope;
15879
15880 // Create an ObjectTemplate for global objects and install access
15881 // check callbacks that will block access.
15882 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
15883 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15884 IndexedGetAccessBlocker,
15885 v8::Handle<v8::Value>(),
15886 false);
15887
15888 // Create a context and set an x property on it's global object.
15889 LocalContext context0(NULL, global_template);
15890 context0->Global()->Set(v8_str("x"), v8_num(42));
15891 v8::Handle<v8::Object> global0 = context0->Global();
15892
15893 // Create a context with a different security token so that the
15894 // failed access check callback will be called on each access.
15895 LocalContext context1(NULL, global_template);
15896 context1->Global()->Set(v8_str("other"), global0);
15897
15898 // Get property with failed access check.
15899 ExpectUndefined("other.x");
15900
15901 // Get element with failed access check.
15902 ExpectUndefined("other[0]");
15903
15904 // Set property with failed access check.
15905 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15906 CHECK(result->IsObject());
15907
15908 // Set element with failed access check.
15909 result = CompileRun("other[0] = new Object()");
15910 CHECK(result->IsObject());
15911
15912 // Get property attribute with failed access check.
15913 ExpectFalse("\'x\' in other");
15914
15915 // Get property attribute for element with failed access check.
15916 ExpectFalse("0 in other");
15917
15918 // Delete property.
15919 ExpectFalse("delete other.x");
15920
15921 // Delete element.
15922 CHECK_EQ(false, global0->Delete(0));
15923
15924 // DefineAccessor.
15925 CHECK_EQ(false,
15926 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15927
15928 // Define JavaScript accessor.
15929 ExpectUndefined("Object.prototype.__defineGetter__.call("
15930 " other, \'x\', function() { return 42; })");
15931
15932 // LookupAccessor.
15933 ExpectUndefined("Object.prototype.__lookupGetter__.call("
15934 " other, \'x\')");
15935
15936 // HasLocalElement.
15937 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15938
15939 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15940 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15941 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15942
15943 // Reset the failed access check callback so it does not influence
15944 // the other tests.
15945 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
15946}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000015947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015948TEST(DefaultIsolateGetCurrent) {
15949 CHECK(v8::Isolate::GetCurrent() != NULL);
15950 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15951 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15952 printf("*** %s\n", "DefaultIsolateGetCurrent success");
15953}
15954
15955TEST(IsolateNewDispose) {
15956 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15957 v8::Isolate* isolate = v8::Isolate::New();
15958 CHECK(isolate != NULL);
15959 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15960 CHECK(current_isolate != isolate);
15961 CHECK(current_isolate == v8::Isolate::GetCurrent());
15962
15963 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15964 last_location = last_message = NULL;
15965 isolate->Dispose();
15966 CHECK_EQ(last_location, NULL);
15967 CHECK_EQ(last_message, NULL);
15968}
15969
15970TEST(IsolateEnterExitDefault) {
15971 v8::HandleScope scope;
15972 LocalContext context;
15973 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15974 CHECK(current_isolate != NULL); // Default isolate.
15975 ExpectString("'hello'", "hello");
15976 current_isolate->Enter();
15977 ExpectString("'still working'", "still working");
15978 current_isolate->Exit();
15979 ExpectString("'still working 2'", "still working 2");
15980 current_isolate->Exit();
15981 // Default isolate is always, well, 'default current'.
15982 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15983 // Still working since default isolate is auto-entering any thread
15984 // that has no isolate and attempts to execute V8 APIs.
15985 ExpectString("'still working 3'", "still working 3");
15986}
15987
15988TEST(DisposeDefaultIsolate) {
15989 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15990
15991 // Run some V8 code to trigger default isolate to become 'current'.
15992 v8::HandleScope scope;
15993 LocalContext context;
15994 ExpectString("'run some V8'", "run some V8");
15995
15996 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15997 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15998 last_location = last_message = NULL;
15999 isolate->Dispose();
16000 // It is not possible to dispose default isolate via Isolate API.
16001 CHECK_NE(last_location, NULL);
16002 CHECK_NE(last_message, NULL);
16003}
16004
16005TEST(RunDefaultAndAnotherIsolate) {
16006 v8::HandleScope scope;
16007 LocalContext context;
16008
16009 // Enter new isolate.
16010 v8::Isolate* isolate = v8::Isolate::New();
16011 CHECK(isolate);
16012 isolate->Enter();
16013 { // Need this block because subsequent Exit() will deallocate Heap,
16014 // so we need all scope objects to be deconstructed when it happens.
16015 v8::HandleScope scope_new;
16016 LocalContext context_new;
16017
16018 // Run something in new isolate.
16019 CompileRun("var foo = 153;");
16020 ExpectTrue("function f() { return foo == 153; }; f()");
16021 }
16022 isolate->Exit();
16023
16024 // This runs automatically in default isolate.
16025 // Variables in another isolate should be not available.
16026 ExpectTrue("function f() {"
16027 " try {"
16028 " foo;"
16029 " return false;"
16030 " } catch(e) {"
16031 " return true;"
16032 " }"
16033 "};"
16034 "var bar = 371;"
16035 "f()");
16036
16037 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16038 last_location = last_message = NULL;
16039 isolate->Dispose();
16040 CHECK_EQ(last_location, NULL);
16041 CHECK_EQ(last_message, NULL);
16042
16043 // Check that default isolate still runs.
16044 ExpectTrue("function f() { return bar == 371; }; f()");
16045}
16046
16047TEST(DisposeIsolateWhenInUse) {
16048 v8::Isolate* isolate = v8::Isolate::New();
16049 CHECK(isolate);
16050 isolate->Enter();
16051 v8::HandleScope scope;
16052 LocalContext context;
16053 // Run something in this isolate.
16054 ExpectTrue("true");
16055 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16056 last_location = last_message = NULL;
16057 // Still entered, should fail.
16058 isolate->Dispose();
16059 CHECK_NE(last_location, NULL);
16060 CHECK_NE(last_message, NULL);
16061}
16062
16063TEST(RunTwoIsolatesOnSingleThread) {
16064 // Run isolate 1.
16065 v8::Isolate* isolate1 = v8::Isolate::New();
16066 isolate1->Enter();
16067 v8::Persistent<v8::Context> context1 = v8::Context::New();
16068
16069 {
16070 v8::Context::Scope cscope(context1);
16071 v8::HandleScope scope;
16072 // Run something in new isolate.
16073 CompileRun("var foo = 'isolate 1';");
16074 ExpectString("function f() { return foo; }; f()", "isolate 1");
16075 }
16076
16077 // Run isolate 2.
16078 v8::Isolate* isolate2 = v8::Isolate::New();
16079 v8::Persistent<v8::Context> context2;
16080
16081 {
16082 v8::Isolate::Scope iscope(isolate2);
16083 context2 = v8::Context::New();
16084 v8::Context::Scope cscope(context2);
16085 v8::HandleScope scope;
16086
16087 // Run something in new isolate.
16088 CompileRun("var foo = 'isolate 2';");
16089 ExpectString("function f() { return foo; }; f()", "isolate 2");
16090 }
16091
16092 {
16093 v8::Context::Scope cscope(context1);
16094 v8::HandleScope scope;
16095 // Now again in isolate 1
16096 ExpectString("function f() { return foo; }; f()", "isolate 1");
16097 }
16098
16099 isolate1->Exit();
16100
16101 // Run some stuff in default isolate.
16102 v8::Persistent<v8::Context> context_default = v8::Context::New();
16103
16104 {
16105 v8::Context::Scope cscope(context_default);
16106 v8::HandleScope scope;
16107 // Variables in other isolates should be not available, verify there
16108 // is an exception.
16109 ExpectTrue("function f() {"
16110 " try {"
16111 " foo;"
16112 " return false;"
16113 " } catch(e) {"
16114 " return true;"
16115 " }"
16116 "};"
16117 "var isDefaultIsolate = true;"
16118 "f()");
16119 }
16120
16121 isolate1->Enter();
16122
16123 {
16124 v8::Isolate::Scope iscope(isolate2);
16125 v8::Context::Scope cscope(context2);
16126 v8::HandleScope scope;
16127 ExpectString("function f() { return foo; }; f()", "isolate 2");
16128 }
16129
16130 {
16131 v8::Context::Scope cscope(context1);
16132 v8::HandleScope scope;
16133 ExpectString("function f() { return foo; }; f()", "isolate 1");
16134 }
16135
16136 {
16137 v8::Isolate::Scope iscope(isolate2);
16138 context2.Dispose();
16139 }
16140
16141 context1.Dispose();
16142 isolate1->Exit();
16143
16144 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16145 last_location = last_message = NULL;
16146
16147 isolate1->Dispose();
16148 CHECK_EQ(last_location, NULL);
16149 CHECK_EQ(last_message, NULL);
16150
16151 isolate2->Dispose();
16152 CHECK_EQ(last_location, NULL);
16153 CHECK_EQ(last_message, NULL);
16154
16155 // Check that default isolate still runs.
16156 {
16157 v8::Context::Scope cscope(context_default);
16158 v8::HandleScope scope;
16159 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
16160 }
16161}
16162
16163static int CalcFibonacci(v8::Isolate* isolate, int limit) {
16164 v8::Isolate::Scope isolate_scope(isolate);
16165 v8::HandleScope scope;
16166 LocalContext context;
16167 i::ScopedVector<char> code(1024);
16168 i::OS::SNPrintF(code, "function fib(n) {"
16169 " if (n <= 2) return 1;"
16170 " return fib(n-1) + fib(n-2);"
16171 "}"
16172 "fib(%d)", limit);
16173 Local<Value> value = CompileRun(code.start());
16174 CHECK(value->IsNumber());
16175 return static_cast<int>(value->NumberValue());
16176}
16177
16178class IsolateThread : public v8::internal::Thread {
16179 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016180 IsolateThread(v8::Isolate* isolate, int fib_limit)
16181 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016182 isolate_(isolate),
16183 fib_limit_(fib_limit),
16184 result_(0) { }
16185
16186 void Run() {
16187 result_ = CalcFibonacci(isolate_, fib_limit_);
16188 }
16189
16190 int result() { return result_; }
16191
16192 private:
16193 v8::Isolate* isolate_;
16194 int fib_limit_;
16195 int result_;
16196};
16197
16198TEST(MultipleIsolatesOnIndividualThreads) {
16199 v8::Isolate* isolate1 = v8::Isolate::New();
16200 v8::Isolate* isolate2 = v8::Isolate::New();
16201
16202 IsolateThread thread1(isolate1, 21);
16203 IsolateThread thread2(isolate2, 12);
16204
16205 // Compute some fibonacci numbers on 3 threads in 3 isolates.
16206 thread1.Start();
16207 thread2.Start();
16208
16209 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
16210 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
16211
16212 thread1.Join();
16213 thread2.Join();
16214
16215 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
16216 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
16217 CHECK_EQ(result1, 10946);
16218 CHECK_EQ(result2, 144);
16219 CHECK_EQ(result1, thread1.result());
16220 CHECK_EQ(result2, thread2.result());
16221
16222 isolate1->Dispose();
16223 isolate2->Dispose();
16224}
16225
lrn@chromium.org1c092762011-05-09 09:42:16 +000016226TEST(IsolateDifferentContexts) {
16227 v8::Isolate* isolate = v8::Isolate::New();
16228 Persistent<v8::Context> context;
16229 {
16230 v8::Isolate::Scope isolate_scope(isolate);
16231 v8::HandleScope handle_scope;
16232 context = v8::Context::New();
16233 v8::Context::Scope context_scope(context);
16234 Local<Value> v = CompileRun("2");
16235 CHECK(v->IsNumber());
16236 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16237 }
16238 {
16239 v8::Isolate::Scope isolate_scope(isolate);
16240 v8::HandleScope handle_scope;
16241 context = v8::Context::New();
16242 v8::Context::Scope context_scope(context);
16243 Local<Value> v = CompileRun("22");
16244 CHECK(v->IsNumber());
16245 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16246 }
16247}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016248
16249class InitDefaultIsolateThread : public v8::internal::Thread {
16250 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016251 enum TestCase {
16252 IgnoreOOM,
16253 SetResourceConstraints,
16254 SetFatalHandler,
16255 SetCounterFunction,
16256 SetCreateHistogramFunction,
16257 SetAddHistogramSampleFunction
16258 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016259
16260 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016261 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016262 testCase_(testCase),
16263 result_(false) { }
16264
16265 void Run() {
16266 switch (testCase_) {
16267 case IgnoreOOM:
16268 v8::V8::IgnoreOutOfMemoryException();
16269 break;
16270
16271 case SetResourceConstraints: {
16272 static const int K = 1024;
16273 v8::ResourceConstraints constraints;
16274 constraints.set_max_young_space_size(256 * K);
16275 constraints.set_max_old_space_size(4 * K * K);
16276 v8::SetResourceConstraints(&constraints);
16277 break;
16278 }
16279
16280 case SetFatalHandler:
16281 v8::V8::SetFatalErrorHandler(NULL);
16282 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016283
16284 case SetCounterFunction:
16285 v8::V8::SetCounterFunction(NULL);
16286 break;
16287
16288 case SetCreateHistogramFunction:
16289 v8::V8::SetCreateHistogramFunction(NULL);
16290 break;
16291
16292 case SetAddHistogramSampleFunction:
16293 v8::V8::SetAddHistogramSampleFunction(NULL);
16294 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016295 }
16296 result_ = true;
16297 }
16298
16299 bool result() { return result_; }
16300
16301 private:
16302 TestCase testCase_;
16303 bool result_;
16304};
16305
16306
16307static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16308 InitDefaultIsolateThread thread(testCase);
16309 thread.Start();
16310 thread.Join();
16311 CHECK_EQ(thread.result(), true);
16312}
16313
16314TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16315 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16316}
16317
16318TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16319 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16320}
16321
16322TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16323 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16324}
16325
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016326TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16327 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16328}
16329
16330TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16331 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16332}
16333
16334TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16335 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16336}
16337
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016338
16339TEST(StringCheckMultipleContexts) {
16340 const char* code =
16341 "(function() { return \"a\".charAt(0); })()";
16342
16343 {
16344 // Run the code twice in the first context to initialize the call IC.
16345 v8::HandleScope scope;
16346 LocalContext context1;
16347 ExpectString(code, "a");
16348 ExpectString(code, "a");
16349 }
16350
16351 {
16352 // Change the String.prototype in the second context and check
16353 // that the right function gets called.
16354 v8::HandleScope scope;
16355 LocalContext context2;
16356 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16357 ExpectString(code, "not a");
16358 }
16359}
16360
16361
16362TEST(NumberCheckMultipleContexts) {
16363 const char* code =
16364 "(function() { return (42).toString(); })()";
16365
16366 {
16367 // Run the code twice in the first context to initialize the call IC.
16368 v8::HandleScope scope;
16369 LocalContext context1;
16370 ExpectString(code, "42");
16371 ExpectString(code, "42");
16372 }
16373
16374 {
16375 // Change the Number.prototype in the second context and check
16376 // that the right function gets called.
16377 v8::HandleScope scope;
16378 LocalContext context2;
16379 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16380 ExpectString(code, "not 42");
16381 }
16382}
16383
16384
16385TEST(BooleanCheckMultipleContexts) {
16386 const char* code =
16387 "(function() { return true.toString(); })()";
16388
16389 {
16390 // Run the code twice in the first context to initialize the call IC.
16391 v8::HandleScope scope;
16392 LocalContext context1;
16393 ExpectString(code, "true");
16394 ExpectString(code, "true");
16395 }
16396
16397 {
16398 // Change the Boolean.prototype in the second context and check
16399 // that the right function gets called.
16400 v8::HandleScope scope;
16401 LocalContext context2;
16402 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16403 ExpectString(code, "");
16404 }
16405}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016406
16407
16408TEST(DontDeleteCellLoadIC) {
16409 const char* function_code =
16410 "function readCell() { while (true) { return cell; } }";
16411
16412 {
16413 // Run the code twice in the first context to initialize the load
16414 // IC for a don't delete cell.
16415 v8::HandleScope scope;
16416 LocalContext context1;
16417 CompileRun("var cell = \"first\";");
16418 ExpectBoolean("delete cell", false);
16419 CompileRun(function_code);
16420 ExpectString("readCell()", "first");
16421 ExpectString("readCell()", "first");
16422 }
16423
16424 {
16425 // Use a deletable cell in the second context.
16426 v8::HandleScope scope;
16427 LocalContext context2;
16428 CompileRun("cell = \"second\";");
16429 CompileRun(function_code);
16430 ExpectString("readCell()", "second");
16431 ExpectBoolean("delete cell", true);
16432 ExpectString("(function() {"
16433 " try {"
16434 " return readCell();"
16435 " } catch(e) {"
16436 " return e.toString();"
16437 " }"
16438 "})()",
16439 "ReferenceError: cell is not defined");
16440 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016441 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016442 ExpectString("readCell()", "new_second");
16443 ExpectString("readCell()", "new_second");
16444 }
16445}
16446
16447
16448TEST(DontDeleteCellLoadICForceDelete) {
16449 const char* function_code =
16450 "function readCell() { while (true) { return cell; } }";
16451
16452 // Run the code twice to initialize the load IC for a don't delete
16453 // cell.
16454 v8::HandleScope scope;
16455 LocalContext context;
16456 CompileRun("var cell = \"value\";");
16457 ExpectBoolean("delete cell", false);
16458 CompileRun(function_code);
16459 ExpectString("readCell()", "value");
16460 ExpectString("readCell()", "value");
16461
16462 // Delete the cell using the API and check the inlined code works
16463 // correctly.
16464 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16465 ExpectString("(function() {"
16466 " try {"
16467 " return readCell();"
16468 " } catch(e) {"
16469 " return e.toString();"
16470 " }"
16471 "})()",
16472 "ReferenceError: cell is not defined");
16473}
16474
16475
16476TEST(DontDeleteCellLoadICAPI) {
16477 const char* function_code =
16478 "function readCell() { while (true) { return cell; } }";
16479
16480 // Run the code twice to initialize the load IC for a don't delete
16481 // cell created using the API.
16482 v8::HandleScope scope;
16483 LocalContext context;
16484 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16485 ExpectBoolean("delete cell", false);
16486 CompileRun(function_code);
16487 ExpectString("readCell()", "value");
16488 ExpectString("readCell()", "value");
16489
16490 // Delete the cell using the API and check the inlined code works
16491 // correctly.
16492 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16493 ExpectString("(function() {"
16494 " try {"
16495 " return readCell();"
16496 " } catch(e) {"
16497 " return e.toString();"
16498 " }"
16499 "})()",
16500 "ReferenceError: cell is not defined");
16501}
16502
16503
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016504class Visitor42 : public v8::PersistentHandleVisitor {
16505 public:
16506 explicit Visitor42(v8::Persistent<v8::Object> object)
16507 : counter_(0), object_(object) { }
16508
16509 virtual void VisitPersistentHandle(Persistent<Value> value,
16510 uint16_t class_id) {
16511 if (class_id == 42) {
16512 CHECK(value->IsObject());
16513 v8::Persistent<v8::Object> visited =
16514 v8::Persistent<v8::Object>::Cast(value);
16515 CHECK_EQ(42, visited.WrapperClassId());
16516 CHECK_EQ(object_, visited);
16517 ++counter_;
16518 }
16519 }
16520
16521 int counter_;
16522 v8::Persistent<v8::Object> object_;
16523};
16524
16525
16526TEST(PersistentHandleVisitor) {
16527 v8::HandleScope scope;
16528 LocalContext context;
16529 v8::Persistent<v8::Object> object =
16530 v8::Persistent<v8::Object>::New(v8::Object::New());
16531 CHECK_EQ(0, object.WrapperClassId());
16532 object.SetWrapperClassId(42);
16533 CHECK_EQ(42, object.WrapperClassId());
16534
16535 Visitor42 visitor(object);
16536 v8::V8::VisitHandlesWithClassIds(&visitor);
16537 CHECK_EQ(1, visitor.counter_);
16538
16539 object.Dispose();
16540}
16541
16542
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016543TEST(RegExp) {
16544 v8::HandleScope scope;
16545 LocalContext context;
16546
16547 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16548 CHECK(re->IsRegExp());
16549 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016550 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016551
16552 re = v8::RegExp::New(v8_str("bar"),
16553 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16554 v8::RegExp::kGlobal));
16555 CHECK(re->IsRegExp());
16556 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016557 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16558 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016559
16560 re = v8::RegExp::New(v8_str("baz"),
16561 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16562 v8::RegExp::kMultiline));
16563 CHECK(re->IsRegExp());
16564 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016565 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16566 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016567
16568 re = CompileRun("/quux/").As<v8::RegExp>();
16569 CHECK(re->IsRegExp());
16570 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016571 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016572
16573 re = CompileRun("/quux/gm").As<v8::RegExp>();
16574 CHECK(re->IsRegExp());
16575 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016576 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16577 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016578
16579 // Override the RegExp constructor and check the API constructor
16580 // still works.
16581 CompileRun("RegExp = function() {}");
16582
16583 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16584 CHECK(re->IsRegExp());
16585 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016586 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016587
16588 re = v8::RegExp::New(v8_str("foobarbaz"),
16589 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16590 v8::RegExp::kMultiline));
16591 CHECK(re->IsRegExp());
16592 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016593 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16594 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016595
16596 context->Global()->Set(v8_str("re"), re);
16597 ExpectTrue("re.test('FoobarbaZ')");
16598
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016599 // RegExps are objects on which you can set properties.
16600 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016601 v8::Handle<v8::Value> value(CompileRun("re.property"));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000016602 CHECK_EQ(32, value->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016603
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016604 v8::TryCatch try_catch;
16605 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16606 CHECK(re.IsEmpty());
16607 CHECK(try_catch.HasCaught());
16608 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16609 ExpectTrue("ex instanceof SyntaxError");
16610}
16611
16612
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016613THREADED_TEST(Equals) {
16614 v8::HandleScope handleScope;
16615 LocalContext localContext;
16616
16617 v8::Handle<v8::Object> globalProxy = localContext->Global();
16618 v8::Handle<Value> global = globalProxy->GetPrototype();
16619
16620 CHECK(global->StrictEquals(global));
16621 CHECK(!global->StrictEquals(globalProxy));
16622 CHECK(!globalProxy->StrictEquals(global));
16623 CHECK(globalProxy->StrictEquals(globalProxy));
16624
16625 CHECK(global->Equals(global));
16626 CHECK(!global->Equals(globalProxy));
16627 CHECK(!globalProxy->Equals(global));
16628 CHECK(globalProxy->Equals(globalProxy));
16629}
16630
16631
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016632static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16633 const v8::AccessorInfo& info ) {
16634 return v8_str("42!");
16635}
16636
16637
16638static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16639 v8::Handle<v8::Array> result = v8::Array::New();
16640 result->Set(0, v8_str("universalAnswer"));
16641 return result;
16642}
16643
16644
16645TEST(NamedEnumeratorAndForIn) {
16646 v8::HandleScope handle_scope;
16647 LocalContext context;
16648 v8::Context::Scope context_scope(context.local());
16649
16650 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16651 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16652 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16653 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16654 "var result = []; for (var k in o) result.push(k); result"));
16655 CHECK_EQ(1, result->Length());
16656 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16657}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016658
16659
16660TEST(DefinePropertyPostDetach) {
16661 v8::HandleScope scope;
16662 LocalContext context;
16663 v8::Handle<v8::Object> proxy = context->Global();
16664 v8::Handle<v8::Function> define_property =
16665 CompileRun("(function() {"
16666 " Object.defineProperty("
16667 " this,"
16668 " 1,"
16669 " { configurable: true, enumerable: true, value: 3 });"
16670 "})").As<Function>();
16671 context->DetachGlobal();
16672 define_property->Call(proxy, 0, NULL);
16673}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016674
16675
16676static void InstallContextId(v8::Handle<Context> context, int id) {
16677 Context::Scope scope(context);
16678 CompileRun("Object.prototype").As<Object>()->
16679 Set(v8_str("context_id"), v8::Integer::New(id));
16680}
16681
16682
16683static void CheckContextId(v8::Handle<Object> object, int expected) {
16684 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16685}
16686
16687
16688THREADED_TEST(CreationContext) {
16689 HandleScope handle_scope;
16690 Persistent<Context> context1 = Context::New();
16691 InstallContextId(context1, 1);
16692 Persistent<Context> context2 = Context::New();
16693 InstallContextId(context2, 2);
16694 Persistent<Context> context3 = Context::New();
16695 InstallContextId(context3, 3);
16696
16697 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16698
16699 Local<Object> object1;
16700 Local<Function> func1;
16701 {
16702 Context::Scope scope(context1);
16703 object1 = Object::New();
16704 func1 = tmpl->GetFunction();
16705 }
16706
16707 Local<Object> object2;
16708 Local<Function> func2;
16709 {
16710 Context::Scope scope(context2);
16711 object2 = Object::New();
16712 func2 = tmpl->GetFunction();
16713 }
16714
16715 Local<Object> instance1;
16716 Local<Object> instance2;
16717
16718 {
16719 Context::Scope scope(context3);
16720 instance1 = func1->NewInstance();
16721 instance2 = func2->NewInstance();
16722 }
16723
16724 CHECK(object1->CreationContext() == context1);
16725 CheckContextId(object1, 1);
16726 CHECK(func1->CreationContext() == context1);
16727 CheckContextId(func1, 1);
16728 CHECK(instance1->CreationContext() == context1);
16729 CheckContextId(instance1, 1);
16730 CHECK(object2->CreationContext() == context2);
16731 CheckContextId(object2, 2);
16732 CHECK(func2->CreationContext() == context2);
16733 CheckContextId(func2, 2);
16734 CHECK(instance2->CreationContext() == context2);
16735 CheckContextId(instance2, 2);
16736
16737 {
16738 Context::Scope scope(context1);
16739 CHECK(object1->CreationContext() == context1);
16740 CheckContextId(object1, 1);
16741 CHECK(func1->CreationContext() == context1);
16742 CheckContextId(func1, 1);
16743 CHECK(instance1->CreationContext() == context1);
16744 CheckContextId(instance1, 1);
16745 CHECK(object2->CreationContext() == context2);
16746 CheckContextId(object2, 2);
16747 CHECK(func2->CreationContext() == context2);
16748 CheckContextId(func2, 2);
16749 CHECK(instance2->CreationContext() == context2);
16750 CheckContextId(instance2, 2);
16751 }
16752
16753 {
16754 Context::Scope scope(context2);
16755 CHECK(object1->CreationContext() == context1);
16756 CheckContextId(object1, 1);
16757 CHECK(func1->CreationContext() == context1);
16758 CheckContextId(func1, 1);
16759 CHECK(instance1->CreationContext() == context1);
16760 CheckContextId(instance1, 1);
16761 CHECK(object2->CreationContext() == context2);
16762 CheckContextId(object2, 2);
16763 CHECK(func2->CreationContext() == context2);
16764 CheckContextId(func2, 2);
16765 CHECK(instance2->CreationContext() == context2);
16766 CheckContextId(instance2, 2);
16767 }
16768
16769 context1.Dispose();
16770 context2.Dispose();
16771 context3.Dispose();
16772}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016773
16774
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000016775THREADED_TEST(CreationContextOfJsFunction) {
16776 HandleScope handle_scope;
16777 Persistent<Context> context = Context::New();
16778 InstallContextId(context, 1);
16779
16780 Local<Object> function;
16781 {
16782 Context::Scope scope(context);
16783 function = CompileRun("function foo() {}; foo").As<Object>();
16784 }
16785
16786 CHECK(function->CreationContext() == context);
16787 CheckContextId(function, 1);
16788
16789 context.Dispose();
16790}
16791
16792
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016793Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16794 const AccessorInfo& info) {
16795 if (index == 42) return v8_str("yes");
16796 return Handle<v8::Integer>();
16797}
16798
16799
16800Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16801 const AccessorInfo& info) {
16802 if (property->Equals(v8_str("foo"))) return v8_str("yes");
16803 return Handle<Value>();
16804}
16805
16806
16807Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
16808 uint32_t index, const AccessorInfo& info) {
16809 if (index == 42) return v8_num(1).As<v8::Integer>();
16810 return Handle<v8::Integer>();
16811}
16812
16813
16814Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
16815 Local<String> property, const AccessorInfo& info) {
16816 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
16817 return Handle<v8::Integer>();
16818}
16819
16820
16821Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
16822 Local<String> property, const AccessorInfo& info) {
16823 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
16824 return Handle<v8::Integer>();
16825}
16826
16827
16828Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16829 const AccessorInfo& info) {
16830 return v8_str("yes");
16831}
16832
16833
16834TEST(HasOwnProperty) {
16835 v8::HandleScope scope;
16836 LocalContext env;
16837 { // Check normal properties and defined getters.
16838 Handle<Value> value = CompileRun(
16839 "function Foo() {"
16840 " this.foo = 11;"
16841 " this.__defineGetter__('baz', function() { return 1; });"
16842 "};"
16843 "function Bar() { "
16844 " this.bar = 13;"
16845 " this.__defineGetter__('bla', function() { return 2; });"
16846 "};"
16847 "Bar.prototype = new Foo();"
16848 "new Bar();");
16849 CHECK(value->IsObject());
16850 Handle<Object> object = value->ToObject();
16851 CHECK(object->Has(v8_str("foo")));
16852 CHECK(!object->HasOwnProperty(v8_str("foo")));
16853 CHECK(object->HasOwnProperty(v8_str("bar")));
16854 CHECK(object->Has(v8_str("baz")));
16855 CHECK(!object->HasOwnProperty(v8_str("baz")));
16856 CHECK(object->HasOwnProperty(v8_str("bla")));
16857 }
16858 { // Check named getter interceptors.
16859 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16860 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
16861 Handle<Object> instance = templ->NewInstance();
16862 CHECK(!instance->HasOwnProperty(v8_str("42")));
16863 CHECK(instance->HasOwnProperty(v8_str("foo")));
16864 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16865 }
16866 { // Check indexed getter interceptors.
16867 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16868 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
16869 Handle<Object> instance = templ->NewInstance();
16870 CHECK(instance->HasOwnProperty(v8_str("42")));
16871 CHECK(!instance->HasOwnProperty(v8_str("43")));
16872 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16873 }
16874 { // Check named query interceptors.
16875 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16876 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
16877 Handle<Object> instance = templ->NewInstance();
16878 CHECK(instance->HasOwnProperty(v8_str("foo")));
16879 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16880 }
16881 { // Check indexed query interceptors.
16882 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16883 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
16884 Handle<Object> instance = templ->NewInstance();
16885 CHECK(instance->HasOwnProperty(v8_str("42")));
16886 CHECK(!instance->HasOwnProperty(v8_str("41")));
16887 }
16888 { // Check callbacks.
16889 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16890 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
16891 Handle<Object> instance = templ->NewInstance();
16892 CHECK(instance->HasOwnProperty(v8_str("foo")));
16893 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16894 }
16895 { // Check that query wins on disagreement.
16896 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16897 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16898 0,
16899 HasOwnPropertyNamedPropertyQuery2);
16900 Handle<Object> instance = templ->NewInstance();
16901 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16902 CHECK(instance->HasOwnProperty(v8_str("bar")));
16903 }
16904}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016905
16906
16907void CheckCodeGenerationAllowed() {
16908 Handle<Value> result = CompileRun("eval('42')");
16909 CHECK_EQ(42, result->Int32Value());
16910 result = CompileRun("(function(e) { return e('42'); })(eval)");
16911 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016912 result = CompileRun("var f = new Function('return 42'); f()");
16913 CHECK_EQ(42, result->Int32Value());
16914}
16915
16916
16917void CheckCodeGenerationDisallowed() {
16918 TryCatch try_catch;
16919
16920 Handle<Value> result = CompileRun("eval('42')");
16921 CHECK(result.IsEmpty());
16922 CHECK(try_catch.HasCaught());
16923 try_catch.Reset();
16924
16925 result = CompileRun("(function(e) { return e('42'); })(eval)");
16926 CHECK(result.IsEmpty());
16927 CHECK(try_catch.HasCaught());
16928 try_catch.Reset();
16929
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016930 result = CompileRun("var f = new Function('return 42'); f()");
16931 CHECK(result.IsEmpty());
16932 CHECK(try_catch.HasCaught());
16933}
16934
16935
16936bool CodeGenerationAllowed(Local<Context> context) {
16937 ApiTestFuzzer::Fuzz();
16938 return true;
16939}
16940
16941
16942bool CodeGenerationDisallowed(Local<Context> context) {
16943 ApiTestFuzzer::Fuzz();
16944 return false;
16945}
16946
16947
16948THREADED_TEST(AllowCodeGenFromStrings) {
16949 v8::HandleScope scope;
16950 LocalContext context;
16951
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016952 // eval and the Function constructor allowed by default.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016953 CHECK(context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016954 CheckCodeGenerationAllowed();
16955
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016956 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016957 context->AllowCodeGenerationFromStrings(false);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016958 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016959 CheckCodeGenerationDisallowed();
16960
16961 // Allow again.
16962 context->AllowCodeGenerationFromStrings(true);
16963 CheckCodeGenerationAllowed();
16964
16965 // Disallow but setting a global callback that will allow the calls.
16966 context->AllowCodeGenerationFromStrings(false);
16967 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016968 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016969 CheckCodeGenerationAllowed();
16970
16971 // Set a callback that disallows the code generation.
16972 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016973 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016974 CheckCodeGenerationDisallowed();
16975}
lrn@chromium.org1c092762011-05-09 09:42:16 +000016976
16977
ulan@chromium.org56c14af2012-09-20 12:51:09 +000016978TEST(SetErrorMessageForCodeGenFromStrings) {
16979 v8::HandleScope scope;
16980 LocalContext context;
16981 TryCatch try_catch;
16982
16983 Handle<String> message = v8_str("Message") ;
16984 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
16985 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16986 context->AllowCodeGenerationFromStrings(false);
16987 context->SetErrorMessageForCodeGenerationFromStrings(message);
16988 Handle<Value> result = CompileRun("eval('42')");
16989 CHECK(result.IsEmpty());
16990 CHECK(try_catch.HasCaught());
16991 Handle<String> actual_message = try_catch.Message()->Get();
16992 CHECK(expected_message->Equals(actual_message));
16993}
16994
16995
lrn@chromium.org1c092762011-05-09 09:42:16 +000016996static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16997 return v8::Undefined();
16998}
16999
17000
17001THREADED_TEST(CallAPIFunctionOnNonObject) {
17002 v8::HandleScope scope;
17003 LocalContext context;
17004 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
17005 Handle<Function> function = templ->GetFunction();
17006 context->Global()->Set(v8_str("f"), function);
17007 TryCatch try_catch;
17008 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000017009}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000017010
17011
17012// Regression test for issue 1470.
17013THREADED_TEST(ReadOnlyIndexedProperties) {
17014 v8::HandleScope scope;
17015 Local<ObjectTemplate> templ = ObjectTemplate::New();
17016
17017 LocalContext context;
17018 Local<v8::Object> obj = templ->NewInstance();
17019 context->Global()->Set(v8_str("obj"), obj);
17020 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17021 obj->Set(v8_str("1"), v8_str("foobar"));
17022 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
17023 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
17024 obj->Set(v8_num(2), v8_str("foobar"));
17025 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
17026
17027 // Test non-smi case.
17028 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17029 obj->Set(v8_str("2000000000"), v8_str("foobar"));
17030 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
17031}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017032
17033
17034THREADED_TEST(Regress1516) {
17035 v8::HandleScope scope;
17036
17037 LocalContext context;
17038 { v8::HandleScope temp_scope;
17039 CompileRun("({'a': 0})");
17040 }
17041
17042 int elements;
17043 { i::MapCache* map_cache =
17044 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
17045 elements = map_cache->NumberOfElements();
17046 CHECK_LE(1, elements);
17047 }
17048
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +000017049 i::Isolate::Current()->heap()->CollectAllGarbage(
17050 i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017051 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
17052 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
17053 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
17054 CHECK_GT(elements, map_cache->NumberOfElements());
17055 }
17056 }
17057}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017058
17059
17060static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
17061 Local<Value> name,
17062 v8::AccessType type,
17063 Local<Value> data) {
17064 // Only block read access to __proto__.
17065 if (type == v8::ACCESS_GET &&
17066 name->IsString() &&
17067 name->ToString()->Length() == 9 &&
17068 name->ToString()->Utf8Length() == 9) {
17069 char buffer[10];
17070 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
17071 return strncmp(buffer, "__proto__", 9) != 0;
17072 }
17073
17074 return true;
17075}
17076
17077
17078THREADED_TEST(Regress93759) {
17079 HandleScope scope;
17080
17081 // Template for object with security check.
17082 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
17083 // We don't do indexing, so any callback can be used for that.
17084 no_proto_template->SetAccessCheckCallbacks(
17085 BlockProtoNamedSecurityTestCallback,
17086 IndexedSecurityTestCallback);
17087
17088 // Templates for objects with hidden prototypes and possibly security check.
17089 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
17090 hidden_proto_template->SetHiddenPrototype(true);
17091
17092 Local<FunctionTemplate> protected_hidden_proto_template =
17093 v8::FunctionTemplate::New();
17094 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
17095 BlockProtoNamedSecurityTestCallback,
17096 IndexedSecurityTestCallback);
17097 protected_hidden_proto_template->SetHiddenPrototype(true);
17098
17099 // Context for "foreign" objects used in test.
17100 Persistent<Context> context = v8::Context::New();
17101 context->Enter();
17102
17103 // Plain object, no security check.
17104 Local<Object> simple_object = Object::New();
17105
17106 // Object with explicit security check.
17107 Local<Object> protected_object =
17108 no_proto_template->NewInstance();
17109
17110 // JSGlobalProxy object, always have security check.
17111 Local<Object> proxy_object =
17112 context->Global();
17113
17114 // Global object, the prototype of proxy_object. No security checks.
17115 Local<Object> global_object =
17116 proxy_object->GetPrototype()->ToObject();
17117
17118 // Hidden prototype without security check.
17119 Local<Object> hidden_prototype =
17120 hidden_proto_template->GetFunction()->NewInstance();
17121 Local<Object> object_with_hidden =
17122 Object::New();
17123 object_with_hidden->SetPrototype(hidden_prototype);
17124
17125 // Hidden prototype with security check on the hidden prototype.
17126 Local<Object> protected_hidden_prototype =
17127 protected_hidden_proto_template->GetFunction()->NewInstance();
17128 Local<Object> object_with_protected_hidden =
17129 Object::New();
17130 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
17131
17132 context->Exit();
17133
17134 // Template for object for second context. Values to test are put on it as
17135 // properties.
17136 Local<ObjectTemplate> global_template = ObjectTemplate::New();
17137 global_template->Set(v8_str("simple"), simple_object);
17138 global_template->Set(v8_str("protected"), protected_object);
17139 global_template->Set(v8_str("global"), global_object);
17140 global_template->Set(v8_str("proxy"), proxy_object);
17141 global_template->Set(v8_str("hidden"), object_with_hidden);
17142 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
17143
17144 LocalContext context2(NULL, global_template);
17145
17146 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
17147 CHECK(result1->Equals(simple_object->GetPrototype()));
17148
17149 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
17150 CHECK(result2->Equals(Undefined()));
17151
17152 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
17153 CHECK(result3->Equals(global_object->GetPrototype()));
17154
17155 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
17156 CHECK(result4->Equals(Undefined()));
17157
17158 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
17159 CHECK(result5->Equals(
17160 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
17161
17162 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
17163 CHECK(result6->Equals(Undefined()));
17164
17165 context.Dispose();
17166}
17167
17168
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017169THREADED_TEST(Regress125988) {
17170 v8::HandleScope scope;
17171 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
17172 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
17173 LocalContext env;
17174 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
17175 CompileRun("var a = new Object();"
17176 "var b = new Intercept();"
17177 "var c = new Object();"
17178 "c.__proto__ = b;"
17179 "b.__proto__ = a;"
17180 "a.x = 23;"
17181 "for (var i = 0; i < 3; i++) c.x;");
17182 ExpectBoolean("c.hasOwnProperty('x')", false);
17183 ExpectInt32("c.x", 23);
17184 CompileRun("a.y = 42;"
17185 "for (var i = 0; i < 3; i++) c.x;");
17186 ExpectBoolean("c.hasOwnProperty('x')", false);
17187 ExpectInt32("c.x", 23);
17188 ExpectBoolean("c.hasOwnProperty('y')", false);
17189 ExpectInt32("c.y", 42);
17190}
17191
17192
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017193static void TestReceiver(Local<Value> expected_result,
17194 Local<Value> expected_receiver,
17195 const char* code) {
17196 Local<Value> result = CompileRun(code);
17197 CHECK(result->IsObject());
17198 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
17199 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
17200}
17201
17202
17203THREADED_TEST(ForeignFunctionReceiver) {
17204 HandleScope scope;
17205
17206 // Create two contexts with different "id" properties ('i' and 'o').
17207 // Call a function both from its own context and from a the foreign
17208 // context, and see what "this" is bound to (returning both "this"
17209 // and "this.id" for comparison).
17210
17211 Persistent<Context> foreign_context = v8::Context::New();
17212 foreign_context->Enter();
17213 Local<Value> foreign_function =
17214 CompileRun("function func() { return { 0: this.id, "
17215 " 1: this, "
17216 " toString: function() { "
17217 " return this[0];"
17218 " }"
17219 " };"
17220 "}"
17221 "var id = 'i';"
17222 "func;");
17223 CHECK(foreign_function->IsFunction());
17224 foreign_context->Exit();
17225
17226 LocalContext context;
17227
17228 Local<String> password = v8_str("Password");
17229 // Don't get hit by security checks when accessing foreign_context's
17230 // global receiver (aka. global proxy).
17231 context->SetSecurityToken(password);
17232 foreign_context->SetSecurityToken(password);
17233
17234 Local<String> i = v8_str("i");
17235 Local<String> o = v8_str("o");
17236 Local<String> id = v8_str("id");
17237
17238 CompileRun("function ownfunc() { return { 0: this.id, "
17239 " 1: this, "
17240 " toString: function() { "
17241 " return this[0];"
17242 " }"
17243 " };"
17244 "}"
17245 "var id = 'o';"
17246 "ownfunc");
17247 context->Global()->Set(v8_str("func"), foreign_function);
17248
17249 // Sanity check the contexts.
17250 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17251 CHECK(o->Equals(context->Global()->Get(id)));
17252
17253 // Checking local function's receiver.
17254 // Calling function using its call/apply methods.
17255 TestReceiver(o, context->Global(), "ownfunc.call()");
17256 TestReceiver(o, context->Global(), "ownfunc.apply()");
17257 // Making calls through built-in functions.
17258 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17259 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17260 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17261 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17262 // Calling with environment record as base.
17263 TestReceiver(o, context->Global(), "ownfunc()");
17264 // Calling with no base.
17265 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17266
17267 // Checking foreign function return value.
17268 // Calling function using its call/apply methods.
17269 TestReceiver(i, foreign_context->Global(), "func.call()");
17270 TestReceiver(i, foreign_context->Global(), "func.apply()");
17271 // Calling function using another context's call/apply methods.
17272 TestReceiver(i, foreign_context->Global(),
17273 "Function.prototype.call.call(func)");
17274 TestReceiver(i, foreign_context->Global(),
17275 "Function.prototype.call.apply(func)");
17276 TestReceiver(i, foreign_context->Global(),
17277 "Function.prototype.apply.call(func)");
17278 TestReceiver(i, foreign_context->Global(),
17279 "Function.prototype.apply.apply(func)");
17280 // Making calls through built-in functions.
17281 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17282 // ToString(func()) is func()[0], i.e., the returned this.id.
17283 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17284 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17285 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17286
17287 // TODO(1547): Make the following also return "i".
17288 // Calling with environment record as base.
17289 TestReceiver(o, context->Global(), "func()");
17290 // Calling with no base.
17291 TestReceiver(o, context->Global(), "(1,func)()");
17292
17293 foreign_context.Dispose();
17294}
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017295
17296
17297uint8_t callback_fired = 0;
17298
17299
17300void CallCompletedCallback1() {
17301 i::OS::Print("Firing callback 1.\n");
17302 callback_fired ^= 1; // Toggle first bit.
17303}
17304
17305
17306void CallCompletedCallback2() {
17307 i::OS::Print("Firing callback 2.\n");
17308 callback_fired ^= 2; // Toggle second bit.
17309}
17310
17311
17312Handle<Value> RecursiveCall(const Arguments& args) {
17313 int32_t level = args[0]->Int32Value();
17314 if (level < 3) {
17315 level++;
17316 i::OS::Print("Entering recursion level %d.\n", level);
17317 char script[64];
17318 i::Vector<char> script_vector(script, sizeof(script));
17319 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17320 CompileRun(script_vector.start());
17321 i::OS::Print("Leaving recursion level %d.\n", level);
17322 CHECK_EQ(0, callback_fired);
17323 } else {
17324 i::OS::Print("Recursion ends.\n");
17325 CHECK_EQ(0, callback_fired);
17326 }
17327 return Undefined();
17328}
17329
17330
17331TEST(CallCompletedCallback) {
17332 v8::HandleScope scope;
17333 LocalContext env;
17334 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17335 v8::FunctionTemplate::New(RecursiveCall);
17336 env->Global()->Set(v8_str("recursion"),
17337 recursive_runtime->GetFunction());
17338 // Adding the same callback a second time has no effect.
17339 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17340 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17341 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17342 i::OS::Print("--- Script (1) ---\n");
17343 Local<Script> script =
17344 v8::Script::Compile(v8::String::New("recursion(0)"));
17345 script->Run();
17346 CHECK_EQ(3, callback_fired);
17347
17348 i::OS::Print("\n--- Script (2) ---\n");
17349 callback_fired = 0;
17350 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17351 script->Run();
17352 CHECK_EQ(2, callback_fired);
17353
17354 i::OS::Print("\n--- Function ---\n");
17355 callback_fired = 0;
17356 Local<Function> recursive_function =
17357 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17358 v8::Handle<Value> args[] = { v8_num(0) };
17359 recursive_function->Call(env->Global(), 1, args);
17360 CHECK_EQ(2, callback_fired);
17361}
17362
17363
17364void CallCompletedCallbackNoException() {
17365 v8::HandleScope scope;
17366 CompileRun("1+1;");
17367}
17368
17369
17370void CallCompletedCallbackException() {
17371 v8::HandleScope scope;
17372 CompileRun("throw 'second exception';");
17373}
17374
17375
17376TEST(CallCompletedCallbackOneException) {
17377 v8::HandleScope scope;
17378 LocalContext env;
17379 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17380 CompileRun("throw 'exception';");
17381}
17382
17383
17384TEST(CallCompletedCallbackTwoExceptions) {
17385 v8::HandleScope scope;
17386 LocalContext env;
17387 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17388 CompileRun("throw 'first exception';");
17389}
ulan@chromium.org812308e2012-02-29 15:58:45 +000017390
17391
17392static int probes_counter = 0;
17393static int misses_counter = 0;
17394static int updates_counter = 0;
17395
17396
17397static int* LookupCounter(const char* name) {
17398 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17399 return &probes_counter;
17400 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17401 return &misses_counter;
17402 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17403 return &updates_counter;
17404 }
17405 return NULL;
17406}
17407
17408
17409static const char* kMegamorphicTestProgram =
17410 "function ClassA() { };"
17411 "function ClassB() { };"
17412 "ClassA.prototype.foo = function() { };"
17413 "ClassB.prototype.foo = function() { };"
17414 "function fooify(obj) { obj.foo(); };"
17415 "var a = new ClassA();"
17416 "var b = new ClassB();"
17417 "for (var i = 0; i < 10000; i++) {"
17418 " fooify(a);"
17419 " fooify(b);"
17420 "}";
17421
17422
17423static void StubCacheHelper(bool primary) {
17424 V8::SetCounterFunction(LookupCounter);
17425 USE(kMegamorphicTestProgram);
17426#ifdef DEBUG
17427 i::FLAG_native_code_counters = true;
17428 if (primary) {
17429 i::FLAG_test_primary_stub_cache = true;
17430 } else {
17431 i::FLAG_test_secondary_stub_cache = true;
17432 }
17433 i::FLAG_crankshaft = false;
17434 v8::HandleScope scope;
17435 LocalContext env;
17436 int initial_probes = probes_counter;
17437 int initial_misses = misses_counter;
17438 int initial_updates = updates_counter;
17439 CompileRun(kMegamorphicTestProgram);
17440 int probes = probes_counter - initial_probes;
17441 int misses = misses_counter - initial_misses;
17442 int updates = updates_counter - initial_updates;
17443 CHECK_LT(updates, 10);
17444 CHECK_LT(misses, 10);
17445 CHECK_GE(probes, 10000);
17446#endif
17447}
17448
17449
17450TEST(SecondaryStubCache) {
17451 StubCacheHelper(true);
17452}
17453
17454
17455TEST(PrimaryStubCache) {
17456 StubCacheHelper(false);
17457}
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017458
17459
17460static int fatal_error_callback_counter = 0;
17461static void CountingErrorCallback(const char* location, const char* message) {
17462 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17463 fatal_error_callback_counter++;
17464}
17465
17466
17467TEST(StaticGetters) {
17468 v8::HandleScope scope;
17469 LocalContext context;
17470 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17471 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17472 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17473 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17474 i::Handle<i::Object> null_value = FACTORY->null_value();
17475 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17476 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17477 i::Handle<i::Object> true_value = FACTORY->true_value();
17478 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17479 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17480 i::Handle<i::Object> false_value = FACTORY->false_value();
17481 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17482 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17483
17484 // Test after-death behavior.
17485 CHECK(i::Internals::IsInitialized(isolate));
17486 CHECK_EQ(0, fatal_error_callback_counter);
17487 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17488 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17489 i::Isolate::Current()->TearDown();
17490 CHECK(!i::Internals::IsInitialized(isolate));
17491 CHECK_EQ(1, fatal_error_callback_counter);
17492 CHECK(v8::Undefined().IsEmpty());
17493 CHECK_EQ(2, fatal_error_callback_counter);
17494 CHECK(v8::Undefined(isolate).IsEmpty());
17495 CHECK_EQ(3, fatal_error_callback_counter);
17496 CHECK(v8::Null().IsEmpty());
17497 CHECK_EQ(4, fatal_error_callback_counter);
17498 CHECK(v8::Null(isolate).IsEmpty());
17499 CHECK_EQ(5, fatal_error_callback_counter);
17500 CHECK(v8::True().IsEmpty());
17501 CHECK_EQ(6, fatal_error_callback_counter);
17502 CHECK(v8::True(isolate).IsEmpty());
17503 CHECK_EQ(7, fatal_error_callback_counter);
17504 CHECK(v8::False().IsEmpty());
17505 CHECK_EQ(8, fatal_error_callback_counter);
17506 CHECK(v8::False(isolate).IsEmpty());
17507 CHECK_EQ(9, fatal_error_callback_counter);
17508}
17509
17510
17511TEST(IsolateEmbedderData) {
17512 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17513 CHECK_EQ(NULL, isolate->GetData());
17514 CHECK_EQ(NULL, ISOLATE->GetData());
17515 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17516 isolate->SetData(data1);
17517 CHECK_EQ(data1, isolate->GetData());
17518 CHECK_EQ(data1, ISOLATE->GetData());
17519 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17520 ISOLATE->SetData(data2);
17521 CHECK_EQ(data2, isolate->GetData());
17522 CHECK_EQ(data2, ISOLATE->GetData());
17523 ISOLATE->TearDown();
17524 CHECK_EQ(data2, isolate->GetData());
17525 CHECK_EQ(data2, ISOLATE->GetData());
17526}
17527
17528
17529TEST(StringEmpty) {
17530 v8::HandleScope scope;
17531 LocalContext context;
17532 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17533 i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17534 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17535 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17536
17537 // Test after-death behavior.
17538 CHECK(i::Internals::IsInitialized(isolate));
17539 CHECK_EQ(0, fatal_error_callback_counter);
17540 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17541 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17542 i::Isolate::Current()->TearDown();
17543 CHECK(!i::Internals::IsInitialized(isolate));
17544 CHECK_EQ(1, fatal_error_callback_counter);
17545 CHECK(v8::String::Empty().IsEmpty());
17546 CHECK_EQ(2, fatal_error_callback_counter);
17547 CHECK(v8::String::Empty(isolate).IsEmpty());
17548 CHECK_EQ(3, fatal_error_callback_counter);
17549}
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017550
17551
17552static int instance_checked_getter_count = 0;
17553static Handle<Value> InstanceCheckedGetter(Local<String> name,
17554 const AccessorInfo& info) {
17555 CHECK_EQ(name, v8_str("foo"));
17556 instance_checked_getter_count++;
17557 return v8_num(11);
17558}
17559
17560
17561static int instance_checked_setter_count = 0;
17562static void InstanceCheckedSetter(Local<String> name,
17563 Local<Value> value,
17564 const AccessorInfo& info) {
17565 CHECK_EQ(name, v8_str("foo"));
17566 CHECK_EQ(value, v8_num(23));
17567 instance_checked_setter_count++;
17568}
17569
17570
17571static void CheckInstanceCheckedResult(int getters,
17572 int setters,
17573 bool expects_callbacks,
17574 TryCatch* try_catch) {
17575 if (expects_callbacks) {
17576 CHECK(!try_catch->HasCaught());
17577 CHECK_EQ(getters, instance_checked_getter_count);
17578 CHECK_EQ(setters, instance_checked_setter_count);
17579 } else {
17580 CHECK(try_catch->HasCaught());
17581 CHECK_EQ(0, instance_checked_getter_count);
17582 CHECK_EQ(0, instance_checked_setter_count);
17583 }
17584 try_catch->Reset();
17585}
17586
17587
17588static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17589 instance_checked_getter_count = 0;
17590 instance_checked_setter_count = 0;
17591 TryCatch try_catch;
17592
17593 // Test path through generic runtime code.
17594 CompileRun("obj.foo");
17595 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17596 CompileRun("obj.foo = 23");
17597 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17598
17599 // Test path through generated LoadIC and StoredIC.
17600 CompileRun("function test_get(o) { o.foo; }"
17601 "test_get(obj);");
17602 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17603 CompileRun("test_get(obj);");
17604 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17605 CompileRun("test_get(obj);");
17606 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17607 CompileRun("function test_set(o) { o.foo = 23; }"
17608 "test_set(obj);");
17609 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17610 CompileRun("test_set(obj);");
17611 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17612 CompileRun("test_set(obj);");
17613 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17614
17615 // Test path through optimized code.
17616 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17617 "test_get(obj);");
17618 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17619 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17620 "test_set(obj);");
17621 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17622
17623 // Cleanup so that closures start out fresh in next check.
17624 CompileRun("%DeoptimizeFunction(test_get);"
17625 "%ClearFunctionTypeFeedback(test_get);"
17626 "%DeoptimizeFunction(test_set);"
17627 "%ClearFunctionTypeFeedback(test_set);");
17628}
17629
17630
17631THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17632 v8::internal::FLAG_allow_natives_syntax = true;
17633 v8::HandleScope scope;
17634 LocalContext context;
17635
17636 Local<FunctionTemplate> templ = FunctionTemplate::New();
17637 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17638 inst->SetAccessor(v8_str("foo"),
17639 InstanceCheckedGetter, InstanceCheckedSetter,
17640 Handle<Value>(),
17641 v8::DEFAULT,
17642 v8::None,
17643 v8::AccessorSignature::New(templ));
17644 context->Global()->Set(v8_str("f"), templ->GetFunction());
17645
17646 printf("Testing positive ...\n");
17647 CompileRun("var obj = new f();");
17648 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17649 CheckInstanceCheckedAccessors(true);
17650
17651 printf("Testing negative ...\n");
17652 CompileRun("var obj = {};"
17653 "obj.__proto__ = new f();");
17654 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17655 CheckInstanceCheckedAccessors(false);
17656}
17657
17658
17659THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17660 v8::internal::FLAG_allow_natives_syntax = true;
17661 v8::HandleScope scope;
17662 LocalContext context;
17663
17664 Local<FunctionTemplate> templ = FunctionTemplate::New();
17665 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17666 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17667 inst->SetAccessor(v8_str("foo"),
17668 InstanceCheckedGetter, InstanceCheckedSetter,
17669 Handle<Value>(),
17670 v8::DEFAULT,
17671 v8::None,
17672 v8::AccessorSignature::New(templ));
17673 context->Global()->Set(v8_str("f"), templ->GetFunction());
17674
17675 printf("Testing positive ...\n");
17676 CompileRun("var obj = new f();");
17677 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17678 CheckInstanceCheckedAccessors(true);
17679
17680 printf("Testing negative ...\n");
17681 CompileRun("var obj = {};"
17682 "obj.__proto__ = new f();");
17683 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17684 CheckInstanceCheckedAccessors(false);
17685}
17686
17687
17688THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17689 v8::internal::FLAG_allow_natives_syntax = true;
17690 v8::HandleScope scope;
17691 LocalContext context;
17692
17693 Local<FunctionTemplate> templ = FunctionTemplate::New();
17694 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17695 proto->SetAccessor(v8_str("foo"),
17696 InstanceCheckedGetter, InstanceCheckedSetter,
17697 Handle<Value>(),
17698 v8::DEFAULT,
17699 v8::None,
17700 v8::AccessorSignature::New(templ));
17701 context->Global()->Set(v8_str("f"), templ->GetFunction());
17702
17703 printf("Testing positive ...\n");
17704 CompileRun("var obj = new f();");
17705 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17706 CheckInstanceCheckedAccessors(true);
17707
17708 printf("Testing negative ...\n");
17709 CompileRun("var obj = {};"
17710 "obj.__proto__ = new f();");
17711 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17712 CheckInstanceCheckedAccessors(false);
17713
17714 printf("Testing positive with modified prototype chain ...\n");
17715 CompileRun("var obj = new f();"
17716 "var pro = {};"
17717 "pro.__proto__ = obj.__proto__;"
17718 "obj.__proto__ = pro;");
17719 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17720 CheckInstanceCheckedAccessors(true);
17721}
17722
17723
17724TEST(TryFinallyMessage) {
17725 v8::HandleScope scope;
17726 LocalContext context;
17727 {
17728 // Test that the original error message is not lost if there is a
17729 // recursive call into Javascript is done in the finally block, e.g. to
17730 // initialize an IC. (crbug.com/129171)
17731 TryCatch try_catch;
17732 const char* trigger_ic =
17733 "try { \n"
17734 " throw new Error('test'); \n"
17735 "} finally { \n"
17736 " var x = 0; \n"
17737 " x++; \n" // Trigger an IC initialization here.
17738 "} \n";
17739 CompileRun(trigger_ic);
17740 CHECK(try_catch.HasCaught());
17741 Local<Message> message = try_catch.Message();
17742 CHECK(!message.IsEmpty());
17743 CHECK_EQ(2, message->GetLineNumber());
17744 }
17745
17746 {
17747 // Test that the original exception message is indeed overwritten if
17748 // a new error is thrown in the finally block.
17749 TryCatch try_catch;
17750 const char* throw_again =
17751 "try { \n"
17752 " throw new Error('test'); \n"
17753 "} finally { \n"
17754 " var x = 0; \n"
17755 " x++; \n"
17756 " throw new Error('again'); \n" // This is the new uncaught error.
17757 "} \n";
17758 CompileRun(throw_again);
17759 CHECK(try_catch.HasCaught());
17760 Local<Message> message = try_catch.Message();
17761 CHECK(!message.IsEmpty());
17762 CHECK_EQ(6, message->GetLineNumber());
17763 }
17764}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017765
17766
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017767static void Helper137002(bool do_store,
17768 bool polymorphic,
17769 bool remove_accessor,
17770 bool interceptor) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017771 LocalContext context;
17772 Local<ObjectTemplate> templ = ObjectTemplate::New();
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017773 if (interceptor) {
17774 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17775 } else {
17776 templ->SetAccessor(v8_str("foo"),
17777 GetterWhichReturns42,
17778 SetterWhichSetsYOnThisTo23);
17779 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017780 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17781
17782 // Turn monomorphic on slow object with native accessor, then turn
17783 // polymorphic, finally optimize to create negative lookup and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017784 CompileRun(do_store ?
17785 "function f(x) { x.foo = void 0; }" :
17786 "function f(x) { return x.foo; }");
17787 CompileRun("obj.y = void 0;");
17788 if (!interceptor) {
17789 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17790 }
17791 CompileRun("obj.__proto__ = null;"
17792 "f(obj); f(obj); f(obj);");
17793 if (polymorphic) {
17794 CompileRun("f({});");
17795 }
17796 CompileRun("obj.y = void 0;"
17797 "%OptimizeFunctionOnNextCall(f);");
17798 if (remove_accessor) {
17799 CompileRun("delete obj.foo;");
17800 }
17801 CompileRun("var result = f(obj);");
17802 if (do_store) {
17803 CompileRun("result = obj.y;");
17804 }
17805 if (remove_accessor && !interceptor) {
17806 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17807 } else {
17808 CHECK_EQ(do_store ? 23 : 42,
17809 context->Global()->Get(v8_str("result"))->Int32Value());
17810 }
17811}
17812
17813
17814THREADED_TEST(Regress137002a) {
17815 i::FLAG_allow_natives_syntax = true;
17816 i::FLAG_compilation_cache = false;
17817 v8::HandleScope scope;
17818 for (int i = 0; i < 16; i++) {
17819 Helper137002(i & 8, i & 4, i & 2, i & 1);
17820 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017821}
17822
17823
17824THREADED_TEST(Regress137002b) {
17825 i::FLAG_allow_natives_syntax = true;
17826 v8::HandleScope scope;
17827 LocalContext context;
17828 Local<ObjectTemplate> templ = ObjectTemplate::New();
17829 templ->SetAccessor(v8_str("foo"),
17830 GetterWhichReturns42,
17831 SetterWhichSetsYOnThisTo23);
17832 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17833
17834 // Turn monomorphic on slow object with native accessor, then just
17835 // delete the property and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017836 CompileRun("function load(x) { return x.foo; }"
17837 "function store(x) { x.foo = void 0; }"
17838 "function keyed_load(x, key) { return x[key]; }"
17839 // Second version of function has a different source (add void 0)
17840 // so that it does not share code with the first version. This
17841 // ensures that the ICs are monomorphic.
17842 "function load2(x) { void 0; return x.foo; }"
17843 "function store2(x) { void 0; x.foo = void 0; }"
17844 "function keyed_load2(x, key) { void 0; return x[key]; }"
17845
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017846 "obj.y = void 0;"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017847 "obj.__proto__ = null;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017848 "var subobj = {};"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017849 "subobj.y = void 0;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017850 "subobj.__proto__ = obj;"
17851 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17852
17853 // Make the ICs monomorphic.
17854 "load(obj); load(obj);"
17855 "load2(subobj); load2(subobj);"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017856 "store(obj); store(obj);"
17857 "store2(subobj); store2(subobj);"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017858 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
17859 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
17860
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017861 // Actually test the shiny new ICs and better not crash. This
17862 // serves as a regression test for issue 142088 as well.
17863 "load(obj);"
17864 "load2(subobj);"
17865 "store(obj);"
17866 "store2(subobj);"
17867 "keyed_load(obj, 'foo');"
17868 "keyed_load2(subobj, 'foo');"
17869
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017870 // Delete the accessor. It better not be called any more now.
17871 "delete obj.foo;"
17872 "obj.y = void 0;"
17873 "subobj.y = void 0;"
17874
17875 "var load_result = load(obj);"
17876 "var load_result2 = load2(subobj);"
17877 "var keyed_load_result = keyed_load(obj, 'foo');"
17878 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
17879 "store(obj);"
17880 "store2(subobj);"
17881 "var y_from_obj = obj.y;"
17882 "var y_from_subobj = subobj.y;");
17883 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
17884 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
17885 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
17886 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
17887 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
17888 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017889}
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017890
17891
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017892THREADED_TEST(Regress142088) {
17893 i::FLAG_allow_natives_syntax = true;
17894 v8::HandleScope scope;
17895 LocalContext context;
17896 Local<ObjectTemplate> templ = ObjectTemplate::New();
17897 templ->SetAccessor(v8_str("foo"),
17898 GetterWhichReturns42,
17899 SetterWhichSetsYOnThisTo23);
17900 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17901
17902 CompileRun("function load(x) { return x.foo; }"
17903 "var o = Object.create(obj);"
17904 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17905 "load(o); load(o); load(o); load(o);");
17906}
17907
17908
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017909THREADED_TEST(Regress137496) {
17910 i::FLAG_expose_gc = true;
17911 v8::HandleScope scope;
17912 LocalContext context;
17913
17914 // Compile a try-finally clause where the finally block causes a GC
17915 // while there still is a message pending for external reporting.
17916 TryCatch try_catch;
17917 try_catch.SetVerbose(true);
17918 CompileRun("try { throw new Error(); } finally { gc(); }");
17919 CHECK(try_catch.HasCaught());
17920}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017921
17922
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000017923THREADED_TEST(Regress149912) {
17924 v8::HandleScope scope;
17925 LocalContext context;
17926 Handle<FunctionTemplate> templ = FunctionTemplate::New();
17927 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17928 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
17929 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
17930}
17931
17932
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000017933THREADED_TEST(Regress157124) {
17934 v8::HandleScope scope;
17935 LocalContext context;
17936 Local<ObjectTemplate> templ = ObjectTemplate::New();
17937 Local<Object> obj = templ->NewInstance();
17938 obj->GetIdentityHash();
17939 obj->DeleteHiddenValue(v8_str("Bug"));
17940}
17941
17942
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017943#ifndef WIN32
17944class ThreadInterruptTest {
17945 public:
17946 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17947 ~ThreadInterruptTest() { delete sem_; }
17948
17949 void RunTest() {
17950 sem_ = i::OS::CreateSemaphore(0);
17951
17952 InterruptThread i_thread(this);
17953 i_thread.Start();
17954
17955 sem_->Wait();
17956 CHECK_EQ(kExpectedValue, sem_value_);
17957 }
17958
17959 private:
17960 static const int kExpectedValue = 1;
17961
17962 class InterruptThread : public i::Thread {
17963 public:
17964 explicit InterruptThread(ThreadInterruptTest* test)
17965 : Thread("InterruptThread"), test_(test) {}
17966
17967 virtual void Run() {
17968 struct sigaction action;
17969
17970 // Ensure that we'll enter waiting condition
17971 i::OS::Sleep(100);
17972
17973 // Setup signal handler
17974 memset(&action, 0, sizeof(action));
17975 action.sa_handler = SignalHandler;
17976 sigaction(SIGCHLD, &action, NULL);
17977
17978 // Send signal
17979 kill(getpid(), SIGCHLD);
17980
17981 // Ensure that if wait has returned because of error
17982 i::OS::Sleep(100);
17983
17984 // Set value and signal semaphore
17985 test_->sem_value_ = 1;
17986 test_->sem_->Signal();
17987 }
17988
17989 static void SignalHandler(int signal) {
17990 }
17991
17992 private:
17993 ThreadInterruptTest* test_;
17994 struct sigaction sa_;
17995 };
17996
17997 i::Semaphore* sem_;
17998 volatile int sem_value_;
17999};
18000
18001
18002THREADED_TEST(SemaphoreInterruption) {
18003 ThreadInterruptTest().RunTest();
18004}
18005#endif // WIN32