blob: aa85e2a899e35f6bd0d2e201816f48d1af7956db [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) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000629 i::FLAG_stress_compaction = false;
630 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000631 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000632 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 {
634 v8::HandleScope scope;
635 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
636 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000637 String::NewExternal(new TestResource(two_byte_string,
638 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HEAP->CollectGarbage(i::NEW_SPACE);
641 in_new_space = HEAP->InNewSpace(*istring);
642 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000643 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000646 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000647}
648
649
650THREADED_TEST(ScavengeExternalAsciiString) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000651 i::FLAG_stress_compaction = false;
652 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000653 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000654 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000655 {
656 v8::HandleScope scope;
657 const char* one_byte_string = "test string";
658 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000659 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 HEAP->CollectGarbage(i::NEW_SPACE);
662 in_new_space = HEAP->InNewSpace(*istring);
663 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000664 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000665 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000666 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000667 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000668}
669
670
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000671class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
672 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000673 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000674 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000675 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000676
677 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000678 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000679 dispose_(dispose) { }
680
681 void Dispose() {
682 ++dispose_calls;
683 if (dispose_) delete this;
684 }
685 private:
686 bool dispose_;
687};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688
689
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000690int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000691int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000692
693
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000694TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000695 const char* c_source = "1 + 2 * 3";
696
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000697 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000698 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000699 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
700 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000701 {
702 v8::HandleScope scope;
703 LocalContext env;
704 Local<String> source = String::NewExternal(&res_stack);
705 Local<Script> script = Script::Compile(source);
706 Local<Value> value = script->Run();
707 CHECK(value->IsNumber());
708 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000710 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000713 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000714 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000715 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000716
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000717 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000718 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000719 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
720 TestAsciiResource* res_heap =
721 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000722 {
723 v8::HandleScope scope;
724 LocalContext env;
725 Local<String> source = String::NewExternal(res_heap);
726 Local<Script> script = Script::Compile(source);
727 Local<Value> value = script->Run();
728 CHECK(value->IsNumber());
729 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000731 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000732 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000734 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000735 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000736 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000737}
738
739
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000740THREADED_TEST(StringConcat) {
741 {
742 v8::HandleScope scope;
743 LocalContext env;
744 const char* one_byte_string_1 = "function a_times_t";
745 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
746 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
747 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
748 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
749 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
750 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
751 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000752
753 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
754 Local<String> right = String::New(two_byte_source);
755 i::DeleteArray(two_byte_source);
756
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000757 Local<String> source = String::Concat(left, right);
758 right = String::NewExternal(
759 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
760 source = String::Concat(source, right);
761 right = String::NewExternal(
762 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
763 source = String::Concat(source, right);
764 right = v8_str(one_byte_string_2);
765 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000766
767 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
768 right = String::New(two_byte_source);
769 i::DeleteArray(two_byte_source);
770
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000771 source = String::Concat(source, right);
772 right = String::NewExternal(
773 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
774 source = String::Concat(source, right);
775 Local<Script> script = Script::Compile(source);
776 Local<Value> value = script->Run();
777 CHECK(value->IsNumber());
778 CHECK_EQ(68, value->Int32Value());
779 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000781 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
782 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000783}
784
785
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000786THREADED_TEST(GlobalProperties) {
787 v8::HandleScope scope;
788 LocalContext env;
789 v8::Handle<v8::Object> global = env->Global();
790 global->Set(v8_str("pi"), v8_num(3.1415926));
791 Local<Value> pi = global->Get(v8_str("pi"));
792 CHECK_EQ(3.1415926, pi->NumberValue());
793}
794
795
796static v8::Handle<Value> handle_call(const v8::Arguments& args) {
797 ApiTestFuzzer::Fuzz();
798 return v8_num(102);
799}
800
801
802static v8::Handle<Value> construct_call(const v8::Arguments& args) {
803 ApiTestFuzzer::Fuzz();
804 args.This()->Set(v8_str("x"), v8_num(1));
805 args.This()->Set(v8_str("y"), v8_num(2));
806 return args.This();
807}
808
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000809static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
810 ApiTestFuzzer::Fuzz();
811 return v8_num(239);
812}
813
814
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000815THREADED_TEST(FunctionTemplate) {
816 v8::HandleScope scope;
817 LocalContext env;
818 {
819 Local<v8::FunctionTemplate> fun_templ =
820 v8::FunctionTemplate::New(handle_call);
821 Local<Function> fun = fun_templ->GetFunction();
822 env->Global()->Set(v8_str("obj"), fun);
823 Local<Script> script = v8_compile("obj()");
824 CHECK_EQ(102, script->Run()->Int32Value());
825 }
826 // Use SetCallHandler to initialize a function template, should work like the
827 // previous one.
828 {
829 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
830 fun_templ->SetCallHandler(handle_call);
831 Local<Function> fun = fun_templ->GetFunction();
832 env->Global()->Set(v8_str("obj"), fun);
833 Local<Script> script = v8_compile("obj()");
834 CHECK_EQ(102, script->Run()->Int32Value());
835 }
836 // Test constructor calls.
837 {
838 Local<v8::FunctionTemplate> fun_templ =
839 v8::FunctionTemplate::New(construct_call);
840 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000841 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000842 Local<Function> fun = fun_templ->GetFunction();
843 env->Global()->Set(v8_str("obj"), fun);
844 Local<Script> script = v8_compile("var s = new obj(); s.x");
845 CHECK_EQ(1, script->Run()->Int32Value());
846
847 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
848 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000849
850 result = v8_compile("(new obj()).m")->Run();
851 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000852 }
853}
854
855
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000856static void* expected_ptr;
857static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
858 void* ptr = v8::External::Unwrap(args.Data());
859 CHECK_EQ(expected_ptr, ptr);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000860 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000861}
862
863
864static void TestExternalPointerWrapping() {
865 v8::HandleScope scope;
866 LocalContext env;
867
868 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
869
870 v8::Handle<v8::Object> obj = v8::Object::New();
871 obj->Set(v8_str("func"),
872 v8::FunctionTemplate::New(callback, data)->GetFunction());
873 env->Global()->Set(v8_str("obj"), obj);
874
875 CHECK(CompileRun(
876 "function foo() {\n"
877 " for (var i = 0; i < 13; i++) obj.func();\n"
878 "}\n"
879 "foo(), true")->BooleanValue());
880}
881
882
883THREADED_TEST(ExternalWrap) {
884 // Check heap allocated object.
885 int* ptr = new int;
886 expected_ptr = ptr;
887 TestExternalPointerWrapping();
888 delete ptr;
889
890 // Check stack allocated object.
891 int foo;
892 expected_ptr = &foo;
893 TestExternalPointerWrapping();
894
895 // Check not aligned addresses.
896 const int n = 100;
897 char* s = new char[n];
898 for (int i = 0; i < n; i++) {
899 expected_ptr = s + i;
900 TestExternalPointerWrapping();
901 }
902
903 delete[] s;
904
905 // Check several invalid addresses.
906 expected_ptr = reinterpret_cast<void*>(1);
907 TestExternalPointerWrapping();
908
909 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
910 TestExternalPointerWrapping();
911
912 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
913 TestExternalPointerWrapping();
914
915#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000916 // Check a value with a leading 1 bit in x64 Smi encoding.
917 expected_ptr = reinterpret_cast<void*>(0x400000000);
918 TestExternalPointerWrapping();
919
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000920 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
921 TestExternalPointerWrapping();
922
923 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
924 TestExternalPointerWrapping();
925#endif
926}
927
928
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000929THREADED_TEST(FindInstanceInPrototypeChain) {
930 v8::HandleScope scope;
931 LocalContext env;
932
933 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
934 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
935 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
936 derived->Inherit(base);
937
938 Local<v8::Function> base_function = base->GetFunction();
939 Local<v8::Function> derived_function = derived->GetFunction();
940 Local<v8::Function> other_function = other->GetFunction();
941
942 Local<v8::Object> base_instance = base_function->NewInstance();
943 Local<v8::Object> derived_instance = derived_function->NewInstance();
944 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
945 Local<v8::Object> other_instance = other_function->NewInstance();
946 derived_instance2->Set(v8_str("__proto__"), derived_instance);
947 other_instance->Set(v8_str("__proto__"), derived_instance2);
948
949 // base_instance is only an instance of base.
950 CHECK_EQ(base_instance,
951 base_instance->FindInstanceInPrototypeChain(base));
952 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
953 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
954
955 // derived_instance is an instance of base and derived.
956 CHECK_EQ(derived_instance,
957 derived_instance->FindInstanceInPrototypeChain(base));
958 CHECK_EQ(derived_instance,
959 derived_instance->FindInstanceInPrototypeChain(derived));
960 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
961
962 // other_instance is an instance of other and its immediate
963 // prototype derived_instance2 is an instance of base and derived.
964 // Note, derived_instance is an instance of base and derived too,
965 // but it comes after derived_instance2 in the prototype chain of
966 // other_instance.
967 CHECK_EQ(derived_instance2,
968 other_instance->FindInstanceInPrototypeChain(base));
969 CHECK_EQ(derived_instance2,
970 other_instance->FindInstanceInPrototypeChain(derived));
971 CHECK_EQ(other_instance,
972 other_instance->FindInstanceInPrototypeChain(other));
973}
974
975
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000976THREADED_TEST(TinyInteger) {
977 v8::HandleScope scope;
978 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000979 v8::Isolate* isolate = v8::Isolate::GetCurrent();
980
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000981 int32_t value = 239;
982 Local<v8::Integer> value_obj = v8::Integer::New(value);
983 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000984
985 value_obj = v8::Integer::New(value, isolate);
986 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000987}
988
989
990THREADED_TEST(BigSmiInteger) {
991 v8::HandleScope scope;
992 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000993 v8::Isolate* isolate = v8::Isolate::GetCurrent();
994
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000995 int32_t value = i::Smi::kMaxValue;
996 // We cannot add one to a Smi::kMaxValue without wrapping.
997 if (i::kSmiValueSize < 32) {
998 CHECK(i::Smi::IsValid(value));
999 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001000
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001001 Local<v8::Integer> value_obj = v8::Integer::New(value);
1002 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001003
1004 value_obj = v8::Integer::New(value, isolate);
1005 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001006 }
1007}
1008
1009
1010THREADED_TEST(BigInteger) {
1011 v8::HandleScope scope;
1012 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001013 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1014
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001015 // We cannot add one to a Smi::kMaxValue without wrapping.
1016 if (i::kSmiValueSize < 32) {
1017 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1018 // The code will not be run in that case, due to the "if" guard.
1019 int32_t value =
1020 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1021 CHECK(value > i::Smi::kMaxValue);
1022 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001023
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001024 Local<v8::Integer> value_obj = v8::Integer::New(value);
1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001026
1027 value_obj = v8::Integer::New(value, isolate);
1028 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001029 }
1030}
1031
1032
1033THREADED_TEST(TinyUnsignedInteger) {
1034 v8::HandleScope scope;
1035 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001036 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1037
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001038 uint32_t value = 239;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001039
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001040 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1041 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001042
1043 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1044 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001045}
1046
1047
1048THREADED_TEST(BigUnsignedSmiInteger) {
1049 v8::HandleScope scope;
1050 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001051 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1052
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001053 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1054 CHECK(i::Smi::IsValid(value));
1055 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001056
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001057 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1058 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001059
1060 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1061 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001062}
1063
1064
1065THREADED_TEST(BigUnsignedInteger) {
1066 v8::HandleScope scope;
1067 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001068 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1069
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001070 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1071 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1072 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001073
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001074 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1075 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001076
1077 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1078 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001079}
1080
1081
1082THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1083 v8::HandleScope scope;
1084 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001085 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1086
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001087 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1088 uint32_t value = INT32_MAX_AS_UINT + 1;
1089 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001090
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001091 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1092 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001093
1094 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1095 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001096}
1097
1098
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001099THREADED_TEST(IsNativeError) {
1100 v8::HandleScope scope;
1101 LocalContext env;
1102 v8::Handle<Value> syntax_error = CompileRun(
1103 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1104 CHECK(syntax_error->IsNativeError());
1105 v8::Handle<Value> not_error = CompileRun("{a:42}");
1106 CHECK(!not_error->IsNativeError());
1107 v8::Handle<Value> not_object = CompileRun("42");
1108 CHECK(!not_object->IsNativeError());
1109}
1110
1111
1112THREADED_TEST(StringObject) {
1113 v8::HandleScope scope;
1114 LocalContext env;
1115 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1116 CHECK(boxed_string->IsStringObject());
1117 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1118 CHECK(!unboxed_string->IsStringObject());
1119 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1120 CHECK(!boxed_not_string->IsStringObject());
1121 v8::Handle<Value> not_object = CompileRun("0");
1122 CHECK(!not_object->IsStringObject());
1123 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1124 CHECK(!as_boxed.IsEmpty());
1125 Local<v8::String> the_string = as_boxed->StringValue();
1126 CHECK(!the_string.IsEmpty());
1127 ExpectObject("\"test\"", the_string);
1128 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1129 CHECK(new_boxed_string->IsStringObject());
1130 as_boxed = new_boxed_string.As<v8::StringObject>();
1131 the_string = as_boxed->StringValue();
1132 CHECK(!the_string.IsEmpty());
1133 ExpectObject("\"test\"", the_string);
1134}
1135
1136
1137THREADED_TEST(NumberObject) {
1138 v8::HandleScope scope;
1139 LocalContext env;
1140 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1141 CHECK(boxed_number->IsNumberObject());
1142 v8::Handle<Value> unboxed_number = CompileRun("42");
1143 CHECK(!unboxed_number->IsNumberObject());
1144 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1145 CHECK(!boxed_not_number->IsNumberObject());
1146 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1147 CHECK(!as_boxed.IsEmpty());
1148 double the_number = as_boxed->NumberValue();
1149 CHECK_EQ(42.0, the_number);
1150 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1151 CHECK(new_boxed_number->IsNumberObject());
1152 as_boxed = new_boxed_number.As<v8::NumberObject>();
1153 the_number = as_boxed->NumberValue();
1154 CHECK_EQ(43.0, the_number);
1155}
1156
1157
1158THREADED_TEST(BooleanObject) {
1159 v8::HandleScope scope;
1160 LocalContext env;
1161 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1162 CHECK(boxed_boolean->IsBooleanObject());
1163 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1164 CHECK(!unboxed_boolean->IsBooleanObject());
1165 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1166 CHECK(!boxed_not_boolean->IsBooleanObject());
1167 v8::Handle<v8::BooleanObject> as_boxed =
1168 boxed_boolean.As<v8::BooleanObject>();
1169 CHECK(!as_boxed.IsEmpty());
1170 bool the_boolean = as_boxed->BooleanValue();
1171 CHECK_EQ(true, the_boolean);
1172 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1173 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1174 CHECK(boxed_true->IsBooleanObject());
1175 CHECK(boxed_false->IsBooleanObject());
1176 as_boxed = boxed_true.As<v8::BooleanObject>();
1177 CHECK_EQ(true, as_boxed->BooleanValue());
1178 as_boxed = boxed_false.As<v8::BooleanObject>();
1179 CHECK_EQ(false, as_boxed->BooleanValue());
1180}
1181
1182
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001183THREADED_TEST(Number) {
1184 v8::HandleScope scope;
1185 LocalContext env;
1186 double PI = 3.1415926;
1187 Local<v8::Number> pi_obj = v8::Number::New(PI);
1188 CHECK_EQ(PI, pi_obj->NumberValue());
1189}
1190
1191
1192THREADED_TEST(ToNumber) {
1193 v8::HandleScope scope;
1194 LocalContext env;
1195 Local<String> str = v8_str("3.1415926");
1196 CHECK_EQ(3.1415926, str->NumberValue());
1197 v8::Handle<v8::Boolean> t = v8::True();
1198 CHECK_EQ(1.0, t->NumberValue());
1199 v8::Handle<v8::Boolean> f = v8::False();
1200 CHECK_EQ(0.0, f->NumberValue());
1201}
1202
1203
1204THREADED_TEST(Date) {
1205 v8::HandleScope scope;
1206 LocalContext env;
1207 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001208 Local<Value> date = v8::Date::New(PI);
1209 CHECK_EQ(3.0, date->NumberValue());
1210 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1211 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001212}
1213
1214
1215THREADED_TEST(Boolean) {
1216 v8::HandleScope scope;
1217 LocalContext env;
1218 v8::Handle<v8::Boolean> t = v8::True();
1219 CHECK(t->Value());
1220 v8::Handle<v8::Boolean> f = v8::False();
1221 CHECK(!f->Value());
1222 v8::Handle<v8::Primitive> u = v8::Undefined();
1223 CHECK(!u->BooleanValue());
1224 v8::Handle<v8::Primitive> n = v8::Null();
1225 CHECK(!n->BooleanValue());
1226 v8::Handle<String> str1 = v8_str("");
1227 CHECK(!str1->BooleanValue());
1228 v8::Handle<String> str2 = v8_str("x");
1229 CHECK(str2->BooleanValue());
1230 CHECK(!v8::Number::New(0)->BooleanValue());
1231 CHECK(v8::Number::New(-1)->BooleanValue());
1232 CHECK(v8::Number::New(1)->BooleanValue());
1233 CHECK(v8::Number::New(42)->BooleanValue());
1234 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1235}
1236
1237
1238static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1239 ApiTestFuzzer::Fuzz();
1240 return v8_num(13.4);
1241}
1242
1243
1244static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1245 ApiTestFuzzer::Fuzz();
1246 return v8_num(876);
1247}
1248
1249
1250THREADED_TEST(GlobalPrototype) {
1251 v8::HandleScope scope;
1252 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1253 func_templ->PrototypeTemplate()->Set(
1254 "dummy",
1255 v8::FunctionTemplate::New(DummyCallHandler));
1256 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1257 templ->Set("x", v8_num(200));
1258 templ->SetAccessor(v8_str("m"), GetM);
1259 LocalContext env(0, templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001260 v8::Handle<Script> script(v8_compile("dummy()"));
1261 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001262 CHECK_EQ(13.4, result->NumberValue());
1263 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1264 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1265}
1266
1267
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001268THREADED_TEST(ObjectTemplate) {
1269 v8::HandleScope scope;
1270 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1271 templ1->Set("x", v8_num(10));
1272 templ1->Set("y", v8_num(13));
1273 LocalContext env;
1274 Local<v8::Object> instance1 = templ1->NewInstance();
1275 env->Global()->Set(v8_str("p"), instance1);
1276 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1277 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1278 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1279 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1280 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1281 templ2->Set("a", v8_num(12));
1282 templ2->Set("b", templ1);
1283 Local<v8::Object> instance2 = templ2->NewInstance();
1284 env->Global()->Set(v8_str("q"), instance2);
1285 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1286 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1287 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1288 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1289}
1290
1291
1292static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1293 ApiTestFuzzer::Fuzz();
1294 return v8_num(17.2);
1295}
1296
1297
1298static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1299 ApiTestFuzzer::Fuzz();
1300 return v8_num(15.2);
1301}
1302
1303
1304THREADED_TEST(DescriptorInheritance) {
1305 v8::HandleScope scope;
1306 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1307 super->PrototypeTemplate()->Set("flabby",
1308 v8::FunctionTemplate::New(GetFlabby));
1309 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1310
1311 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1312
1313 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1314 base1->Inherit(super);
1315 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1316
1317 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1318 base2->Inherit(super);
1319 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1320
1321 LocalContext env;
1322
1323 env->Global()->Set(v8_str("s"), super->GetFunction());
1324 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1325 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1326
1327 // Checks right __proto__ chain.
1328 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1329 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1330
1331 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1332
1333 // Instance accessor should not be visible on function object or its prototype
1334 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1335 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1336 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1337
1338 env->Global()->Set(v8_str("obj"),
1339 base1->GetFunction()->NewInstance());
1340 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1341 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1342 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1343 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1344 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1345
1346 env->Global()->Set(v8_str("obj2"),
1347 base2->GetFunction()->NewInstance());
1348 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1349 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1350 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1351 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1352 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1353
1354 // base1 and base2 cannot cross reference to each's prototype
1355 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1356 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1357}
1358
1359
1360int echo_named_call_count;
1361
1362
1363static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1364 const AccessorInfo& info) {
1365 ApiTestFuzzer::Fuzz();
1366 CHECK_EQ(v8_str("data"), info.Data());
1367 echo_named_call_count++;
1368 return name;
1369}
1370
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371// Helper functions for Interceptor/Accessor interaction tests
1372
1373Handle<Value> SimpleAccessorGetter(Local<String> name,
1374 const AccessorInfo& info) {
1375 Handle<Object> self = info.This();
1376 return self->Get(String::Concat(v8_str("accessor_"), name));
1377}
1378
1379void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1380 const AccessorInfo& info) {
1381 Handle<Object> self = info.This();
1382 self->Set(String::Concat(v8_str("accessor_"), name), value);
1383}
1384
1385Handle<Value> EmptyInterceptorGetter(Local<String> name,
1386 const AccessorInfo& info) {
1387 return Handle<Value>();
1388}
1389
1390Handle<Value> EmptyInterceptorSetter(Local<String> name,
1391 Local<Value> value,
1392 const AccessorInfo& info) {
1393 return Handle<Value>();
1394}
1395
1396Handle<Value> InterceptorGetter(Local<String> name,
1397 const AccessorInfo& info) {
1398 // Intercept names that start with 'interceptor_'.
1399 String::AsciiValue ascii(name);
1400 char* name_str = *ascii;
1401 char prefix[] = "interceptor_";
1402 int i;
1403 for (i = 0; name_str[i] && prefix[i]; ++i) {
1404 if (name_str[i] != prefix[i]) return Handle<Value>();
1405 }
1406 Handle<Object> self = info.This();
1407 return self->GetHiddenValue(v8_str(name_str + i));
1408}
1409
1410Handle<Value> InterceptorSetter(Local<String> name,
1411 Local<Value> value,
1412 const AccessorInfo& info) {
1413 // Intercept accesses that set certain integer values.
1414 if (value->IsInt32() && value->Int32Value() < 10000) {
1415 Handle<Object> self = info.This();
1416 self->SetHiddenValue(name, value);
1417 return value;
1418 }
1419 return Handle<Value>();
1420}
1421
1422void AddAccessor(Handle<FunctionTemplate> templ,
1423 Handle<String> name,
1424 v8::AccessorGetter getter,
1425 v8::AccessorSetter setter) {
1426 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1427}
1428
1429void AddInterceptor(Handle<FunctionTemplate> templ,
1430 v8::NamedPropertyGetter getter,
1431 v8::NamedPropertySetter setter) {
1432 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1433}
1434
1435THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1436 v8::HandleScope scope;
1437 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1438 Handle<FunctionTemplate> child = FunctionTemplate::New();
1439 child->Inherit(parent);
1440 AddAccessor(parent, v8_str("age"),
1441 SimpleAccessorGetter, SimpleAccessorSetter);
1442 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1443 LocalContext env;
1444 env->Global()->Set(v8_str("Child"), child->GetFunction());
1445 CompileRun("var child = new Child;"
1446 "child.age = 10;");
1447 ExpectBoolean("child.hasOwnProperty('age')", false);
1448 ExpectInt32("child.age", 10);
1449 ExpectInt32("child.accessor_age", 10);
1450}
1451
1452THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1453 v8::HandleScope scope;
1454 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1455 Handle<FunctionTemplate> child = FunctionTemplate::New();
1456 child->Inherit(parent);
1457 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1458 LocalContext env;
1459 env->Global()->Set(v8_str("Child"), child->GetFunction());
1460 CompileRun("var child = new Child;"
1461 "var parent = child.__proto__;"
1462 "Object.defineProperty(parent, 'age', "
1463 " {get: function(){ return this.accessor_age; }, "
1464 " set: function(v){ this.accessor_age = v; }, "
1465 " enumerable: true, configurable: true});"
1466 "child.age = 10;");
1467 ExpectBoolean("child.hasOwnProperty('age')", false);
1468 ExpectInt32("child.age", 10);
1469 ExpectInt32("child.accessor_age", 10);
1470}
1471
1472THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1473 v8::HandleScope scope;
1474 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1475 Handle<FunctionTemplate> child = FunctionTemplate::New();
1476 child->Inherit(parent);
1477 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1478 LocalContext env;
1479 env->Global()->Set(v8_str("Child"), child->GetFunction());
1480 CompileRun("var child = new Child;"
1481 "var parent = child.__proto__;"
1482 "parent.name = 'Alice';");
1483 ExpectBoolean("child.hasOwnProperty('name')", false);
1484 ExpectString("child.name", "Alice");
1485 CompileRun("child.name = 'Bob';");
1486 ExpectString("child.name", "Bob");
1487 ExpectBoolean("child.hasOwnProperty('name')", true);
1488 ExpectString("parent.name", "Alice");
1489}
1490
1491THREADED_TEST(SwitchFromInterceptorToAccessor) {
1492 v8::HandleScope scope;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001493 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1494 AddAccessor(templ, v8_str("age"),
1495 SimpleAccessorGetter, SimpleAccessorSetter);
1496 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1497 LocalContext env;
1498 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1499 CompileRun("var obj = new Obj;"
1500 "function setAge(i){ obj.age = i; };"
1501 "for(var i = 0; i <= 10000; i++) setAge(i);");
1502 // All i < 10000 go to the interceptor.
1503 ExpectInt32("obj.interceptor_age", 9999);
1504 // The last i goes to the accessor.
1505 ExpectInt32("obj.accessor_age", 10000);
1506}
1507
1508THREADED_TEST(SwitchFromAccessorToInterceptor) {
1509 v8::HandleScope scope;
1510 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1511 AddAccessor(templ, v8_str("age"),
1512 SimpleAccessorGetter, SimpleAccessorSetter);
1513 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1514 LocalContext env;
1515 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1516 CompileRun("var obj = new Obj;"
1517 "function setAge(i){ obj.age = i; };"
1518 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1519 // All i >= 10000 go to the accessor.
1520 ExpectInt32("obj.accessor_age", 10000);
1521 // The last i goes to the interceptor.
1522 ExpectInt32("obj.interceptor_age", 9999);
1523}
1524
1525THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1526 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1528 Handle<FunctionTemplate> child = FunctionTemplate::New();
1529 child->Inherit(parent);
1530 AddAccessor(parent, v8_str("age"),
1531 SimpleAccessorGetter, SimpleAccessorSetter);
1532 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1533 LocalContext env;
1534 env->Global()->Set(v8_str("Child"), child->GetFunction());
1535 CompileRun("var child = new Child;"
1536 "function setAge(i){ child.age = i; };"
1537 "for(var i = 0; i <= 10000; i++) setAge(i);");
1538 // All i < 10000 go to the interceptor.
1539 ExpectInt32("child.interceptor_age", 9999);
1540 // The last i goes to the accessor.
1541 ExpectInt32("child.accessor_age", 10000);
1542}
1543
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001544THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001545 v8::HandleScope scope;
1546 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1547 Handle<FunctionTemplate> child = FunctionTemplate::New();
1548 child->Inherit(parent);
1549 AddAccessor(parent, v8_str("age"),
1550 SimpleAccessorGetter, SimpleAccessorSetter);
1551 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1552 LocalContext env;
1553 env->Global()->Set(v8_str("Child"), child->GetFunction());
1554 CompileRun("var child = new Child;"
1555 "function setAge(i){ child.age = i; };"
1556 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1557 // All i >= 10000 go to the accessor.
1558 ExpectInt32("child.accessor_age", 10000);
1559 // The last i goes to the interceptor.
1560 ExpectInt32("child.interceptor_age", 9999);
1561}
1562
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001563THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1564 v8::HandleScope scope;
1565 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1566 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1567 LocalContext env;
1568 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1569 CompileRun("var obj = new Obj;"
1570 "function setter(i) { this.accessor_age = i; };"
1571 "function getter() { return this.accessor_age; };"
1572 "function setAge(i) { obj.age = i; };"
1573 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1574 "for(var i = 0; i <= 10000; i++) setAge(i);");
1575 // All i < 10000 go to the interceptor.
1576 ExpectInt32("obj.interceptor_age", 9999);
1577 // The last i goes to the JavaScript accessor.
1578 ExpectInt32("obj.accessor_age", 10000);
1579 // The installed JavaScript getter is still intact.
1580 // This last part is a regression test for issue 1651 and relies on the fact
1581 // that both interceptor and accessor are being installed on the same object.
1582 ExpectInt32("obj.age", 10000);
1583 ExpectBoolean("obj.hasOwnProperty('age')", true);
1584 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1585}
1586
1587THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1588 v8::HandleScope scope;
1589 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1590 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1591 LocalContext env;
1592 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1593 CompileRun("var obj = new Obj;"
1594 "function setter(i) { this.accessor_age = i; };"
1595 "function getter() { return this.accessor_age; };"
1596 "function setAge(i) { obj.age = i; };"
1597 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1598 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1599 // All i >= 10000 go to the accessor.
1600 ExpectInt32("obj.accessor_age", 10000);
1601 // The last i goes to the interceptor.
1602 ExpectInt32("obj.interceptor_age", 9999);
1603 // The installed JavaScript getter is still intact.
1604 // This last part is a regression test for issue 1651 and relies on the fact
1605 // that both interceptor and accessor are being installed on the same object.
1606 ExpectInt32("obj.age", 10000);
1607 ExpectBoolean("obj.hasOwnProperty('age')", true);
1608 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1609}
1610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001611THREADED_TEST(SwitchFromInterceptorToProperty) {
1612 v8::HandleScope scope;
1613 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1614 Handle<FunctionTemplate> child = FunctionTemplate::New();
1615 child->Inherit(parent);
1616 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1617 LocalContext env;
1618 env->Global()->Set(v8_str("Child"), child->GetFunction());
1619 CompileRun("var child = new Child;"
1620 "function setAge(i){ child.age = i; };"
1621 "for(var i = 0; i <= 10000; i++) setAge(i);");
1622 // All i < 10000 go to the interceptor.
1623 ExpectInt32("child.interceptor_age", 9999);
1624 // The last i goes to child's own property.
1625 ExpectInt32("child.age", 10000);
1626}
1627
1628THREADED_TEST(SwitchFromPropertyToInterceptor) {
1629 v8::HandleScope scope;
1630 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1631 Handle<FunctionTemplate> child = FunctionTemplate::New();
1632 child->Inherit(parent);
1633 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1634 LocalContext env;
1635 env->Global()->Set(v8_str("Child"), child->GetFunction());
1636 CompileRun("var child = new Child;"
1637 "function setAge(i){ child.age = i; };"
1638 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1639 // All i >= 10000 go to child's own property.
1640 ExpectInt32("child.age", 10000);
1641 // The last i goes to the interceptor.
1642 ExpectInt32("child.interceptor_age", 9999);
1643}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001644
1645THREADED_TEST(NamedPropertyHandlerGetter) {
1646 echo_named_call_count = 0;
1647 v8::HandleScope scope;
1648 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1649 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1650 0, 0, 0, 0,
1651 v8_str("data"));
1652 LocalContext env;
1653 env->Global()->Set(v8_str("obj"),
1654 templ->GetFunction()->NewInstance());
1655 CHECK_EQ(echo_named_call_count, 0);
1656 v8_compile("obj.x")->Run();
1657 CHECK_EQ(echo_named_call_count, 1);
1658 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1659 v8::Handle<Value> str = CompileRun(code);
1660 String::AsciiValue value(str);
1661 CHECK_EQ(*value, "oddlepoddle");
1662 // Check default behavior
1663 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1664 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1665 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1666}
1667
1668
1669int echo_indexed_call_count = 0;
1670
1671
1672static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1673 const AccessorInfo& info) {
1674 ApiTestFuzzer::Fuzz();
1675 CHECK_EQ(v8_num(637), info.Data());
1676 echo_indexed_call_count++;
1677 return v8_num(index);
1678}
1679
1680
1681THREADED_TEST(IndexedPropertyHandlerGetter) {
1682 v8::HandleScope scope;
1683 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1684 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1685 0, 0, 0, 0,
1686 v8_num(637));
1687 LocalContext env;
1688 env->Global()->Set(v8_str("obj"),
1689 templ->GetFunction()->NewInstance());
1690 Local<Script> script = v8_compile("obj[900]");
1691 CHECK_EQ(script->Run()->Int32Value(), 900);
1692}
1693
1694
1695v8::Handle<v8::Object> bottom;
1696
1697static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1698 uint32_t index,
1699 const AccessorInfo& info) {
1700 ApiTestFuzzer::Fuzz();
1701 CHECK(info.This()->Equals(bottom));
1702 return v8::Handle<Value>();
1703}
1704
1705static v8::Handle<Value> CheckThisNamedPropertyHandler(
1706 Local<String> name,
1707 const AccessorInfo& info) {
1708 ApiTestFuzzer::Fuzz();
1709 CHECK(info.This()->Equals(bottom));
1710 return v8::Handle<Value>();
1711}
1712
1713
1714v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1715 Local<Value> value,
1716 const AccessorInfo& info) {
1717 ApiTestFuzzer::Fuzz();
1718 CHECK(info.This()->Equals(bottom));
1719 return v8::Handle<Value>();
1720}
1721
1722
1723v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1724 Local<Value> value,
1725 const AccessorInfo& info) {
1726 ApiTestFuzzer::Fuzz();
1727 CHECK(info.This()->Equals(bottom));
1728 return v8::Handle<Value>();
1729}
1730
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001731v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001732 uint32_t index,
1733 const AccessorInfo& info) {
1734 ApiTestFuzzer::Fuzz();
1735 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001736 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001737}
1738
1739
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001740v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001741 const AccessorInfo& info) {
1742 ApiTestFuzzer::Fuzz();
1743 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001744 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001745}
1746
1747
1748v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1749 uint32_t index,
1750 const AccessorInfo& info) {
1751 ApiTestFuzzer::Fuzz();
1752 CHECK(info.This()->Equals(bottom));
1753 return v8::Handle<v8::Boolean>();
1754}
1755
1756
1757v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1758 Local<String> property,
1759 const AccessorInfo& info) {
1760 ApiTestFuzzer::Fuzz();
1761 CHECK(info.This()->Equals(bottom));
1762 return v8::Handle<v8::Boolean>();
1763}
1764
1765
1766v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1767 const AccessorInfo& info) {
1768 ApiTestFuzzer::Fuzz();
1769 CHECK(info.This()->Equals(bottom));
1770 return v8::Handle<v8::Array>();
1771}
1772
1773
1774v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1775 const AccessorInfo& info) {
1776 ApiTestFuzzer::Fuzz();
1777 CHECK(info.This()->Equals(bottom));
1778 return v8::Handle<v8::Array>();
1779}
1780
1781
1782THREADED_TEST(PropertyHandlerInPrototype) {
1783 v8::HandleScope scope;
1784 LocalContext env;
1785
1786 // Set up a prototype chain with three interceptors.
1787 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1788 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1789 CheckThisIndexedPropertyHandler,
1790 CheckThisIndexedPropertySetter,
1791 CheckThisIndexedPropertyQuery,
1792 CheckThisIndexedPropertyDeleter,
1793 CheckThisIndexedPropertyEnumerator);
1794
1795 templ->InstanceTemplate()->SetNamedPropertyHandler(
1796 CheckThisNamedPropertyHandler,
1797 CheckThisNamedPropertySetter,
1798 CheckThisNamedPropertyQuery,
1799 CheckThisNamedPropertyDeleter,
1800 CheckThisNamedPropertyEnumerator);
1801
1802 bottom = templ->GetFunction()->NewInstance();
1803 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1804 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1805
1806 bottom->Set(v8_str("__proto__"), middle);
1807 middle->Set(v8_str("__proto__"), top);
1808 env->Global()->Set(v8_str("obj"), bottom);
1809
1810 // Indexed and named get.
1811 Script::Compile(v8_str("obj[0]"))->Run();
1812 Script::Compile(v8_str("obj.x"))->Run();
1813
1814 // Indexed and named set.
1815 Script::Compile(v8_str("obj[1] = 42"))->Run();
1816 Script::Compile(v8_str("obj.y = 42"))->Run();
1817
1818 // Indexed and named query.
1819 Script::Compile(v8_str("0 in obj"))->Run();
1820 Script::Compile(v8_str("'x' in obj"))->Run();
1821
1822 // Indexed and named deleter.
1823 Script::Compile(v8_str("delete obj[0]"))->Run();
1824 Script::Compile(v8_str("delete obj.x"))->Run();
1825
1826 // Enumerators.
1827 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1828}
1829
1830
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001831static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1832 const AccessorInfo& info) {
1833 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001834 if (v8_str("pre")->Equals(key)) {
1835 return v8_str("PrePropertyHandler: pre");
1836 }
1837 return v8::Handle<String>();
1838}
1839
1840
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001841static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1842 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001843 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001844 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001845 }
1846
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001847 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001848}
1849
1850
1851THREADED_TEST(PrePropertyHandler) {
1852 v8::HandleScope scope;
1853 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1854 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1855 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001856 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001857 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001858 Script::Compile(v8_str(
1859 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1860 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1861 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1862 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1863 CHECK_EQ(v8_str("Object: on"), result_on);
1864 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1865 CHECK(result_post.IsEmpty());
1866}
1867
1868
ager@chromium.org870a0b62008-11-04 11:43:05 +00001869THREADED_TEST(UndefinedIsNotEnumerable) {
1870 v8::HandleScope scope;
1871 LocalContext env;
1872 v8::Handle<Value> result = Script::Compile(v8_str(
1873 "this.propertyIsEnumerable(undefined)"))->Run();
1874 CHECK(result->IsFalse());
1875}
1876
1877
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001878v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001879static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880
1881
1882static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1883 ApiTestFuzzer::Fuzz();
1884 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1885 if (depth == kTargetRecursionDepth) return v8::Undefined();
1886 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1887 return call_recursively_script->Run();
1888}
1889
1890
1891static v8::Handle<Value> CallFunctionRecursivelyCall(
1892 const v8::Arguments& args) {
1893 ApiTestFuzzer::Fuzz();
1894 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1895 if (depth == kTargetRecursionDepth) {
1896 printf("[depth = %d]\n", depth);
1897 return v8::Undefined();
1898 }
1899 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1900 v8::Handle<Value> function =
1901 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001902 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001903}
1904
1905
1906THREADED_TEST(DeepCrossLanguageRecursion) {
1907 v8::HandleScope scope;
1908 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1909 global->Set(v8_str("callScriptRecursively"),
1910 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1911 global->Set(v8_str("callFunctionRecursively"),
1912 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1913 LocalContext env(NULL, global);
1914
1915 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1916 call_recursively_script = v8_compile("callScriptRecursively()");
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001917 call_recursively_script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001918 call_recursively_script = v8::Handle<Script>();
1919
1920 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1921 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1922}
1923
1924
1925static v8::Handle<Value>
1926 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1927 ApiTestFuzzer::Fuzz();
1928 return v8::ThrowException(key);
1929}
1930
1931
1932static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1933 Local<Value>,
1934 const AccessorInfo&) {
1935 v8::ThrowException(key);
1936 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1937}
1938
1939
1940THREADED_TEST(CallbackExceptionRegression) {
1941 v8::HandleScope scope;
1942 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1943 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1944 ThrowingPropertyHandlerSet);
1945 LocalContext env;
1946 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1947 v8::Handle<Value> otto = Script::Compile(v8_str(
1948 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1949 CHECK_EQ(v8_str("otto"), otto);
1950 v8::Handle<Value> netto = Script::Compile(v8_str(
1951 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1952 CHECK_EQ(v8_str("netto"), netto);
1953}
1954
1955
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001956THREADED_TEST(FunctionPrototype) {
1957 v8::HandleScope scope;
1958 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1959 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1960 LocalContext env;
1961 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1962 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1963 CHECK_EQ(script->Run()->Int32Value(), 321);
1964}
1965
1966
1967THREADED_TEST(InternalFields) {
1968 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001969 LocalContext env;
1970
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001971 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1972 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1973 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001974 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1975 CHECK_EQ(1, obj->InternalFieldCount());
1976 CHECK(obj->GetInternalField(0)->IsUndefined());
1977 obj->SetInternalField(0, v8_num(17));
1978 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1979}
1980
1981
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001982THREADED_TEST(GlobalObjectInternalFields) {
1983 v8::HandleScope scope;
1984 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1985 global_template->SetInternalFieldCount(1);
1986 LocalContext env(NULL, global_template);
1987 v8::Handle<v8::Object> global_proxy = env->Global();
1988 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1989 CHECK_EQ(1, global->InternalFieldCount());
1990 CHECK(global->GetInternalField(0)->IsUndefined());
1991 global->SetInternalField(0, v8_num(17));
1992 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1993}
1994
1995
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001996THREADED_TEST(InternalFieldsNativePointers) {
1997 v8::HandleScope scope;
1998 LocalContext env;
1999
2000 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2001 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2002 instance_templ->SetInternalFieldCount(1);
2003 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2004 CHECK_EQ(1, obj->InternalFieldCount());
2005 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2006
2007 char* data = new char[100];
2008
2009 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002010 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002011 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002012 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002013
2014 // Check reading and writing aligned pointers.
2015 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002016 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002017 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2018
2019 // Check reading and writing unaligned pointers.
2020 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002021 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002022 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2023
2024 delete[] data;
2025}
2026
2027
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002028THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2029 v8::HandleScope scope;
2030 LocalContext env;
2031
2032 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2033 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2034 instance_templ->SetInternalFieldCount(1);
2035 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2036 CHECK_EQ(1, obj->InternalFieldCount());
2037 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2038
2039 char* data = new char[100];
2040
2041 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002042 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002043 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002044 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002045
2046 obj->SetPointerInInternalField(0, aligned);
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(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2049
2050 obj->SetPointerInInternalField(0, unaligned);
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(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2053
2054 obj->SetInternalField(0, v8::External::Wrap(aligned));
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(aligned, obj->GetPointerFromInternalField(0));
2057
2058 obj->SetInternalField(0, v8::External::Wrap(unaligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002059 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002060 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2061
2062 delete[] data;
2063}
2064
2065
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002066static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2067 void* value) {
2068 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2069 obj->SetPointerInInternalField(0, value);
2070 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2071 CHECK_EQ(value, obj->GetPointerFromInternalField(0));
2072}
2073
2074
2075THREADED_TEST(InternalFieldsAlignedPointers) {
2076 v8::HandleScope scope;
2077 LocalContext env;
2078
2079 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2080 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2081 instance_templ->SetInternalFieldCount(1);
2082 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2083 CHECK_EQ(1, obj->InternalFieldCount());
2084
2085 CheckAlignedPointerInInternalField(obj, NULL);
2086
2087 int* heap_allocated = new int[100];
2088 CheckAlignedPointerInInternalField(obj, heap_allocated);
2089 delete[] heap_allocated;
2090
2091 int stack_allocated[100];
2092 CheckAlignedPointerInInternalField(obj, stack_allocated);
2093
2094 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2095 CheckAlignedPointerInInternalField(obj, huge);
2096}
2097
2098
2099static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2100 int index,
2101 void* value) {
2102 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2103 (*env)->SetAlignedPointerInEmbedderData(index, value);
2104 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2105 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2106}
2107
2108
2109static void* AlignedTestPointer(int i) {
2110 return reinterpret_cast<void*>(i * 1234);
2111}
2112
2113
2114THREADED_TEST(EmbedderDataAlignedPointers) {
2115 v8::HandleScope scope;
2116 LocalContext env;
2117
2118 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2119
2120 int* heap_allocated = new int[100];
2121 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2122 delete[] heap_allocated;
2123
2124 int stack_allocated[100];
2125 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2126
2127 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2128 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2129
2130 // Test growing of the embedder data's backing store.
2131 for (int i = 0; i < 100; i++) {
2132 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2133 }
2134 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2135 for (int i = 0; i < 100; i++) {
2136 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2137 }
2138}
2139
2140
2141static void CheckEmbedderData(LocalContext* env,
2142 int index,
2143 v8::Handle<Value> data) {
2144 (*env)->SetEmbedderData(index, data);
2145 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2146}
2147
2148THREADED_TEST(EmbedderData) {
2149 v8::HandleScope scope;
2150 LocalContext env;
2151
2152 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2153 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2154 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2155 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2156}
2157
2158
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002159THREADED_TEST(IdentityHash) {
2160 v8::HandleScope scope;
2161 LocalContext env;
2162
2163 // Ensure that the test starts with an fresh heap to test whether the hash
2164 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002165 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002166 Local<v8::Object> obj = v8::Object::New();
2167 int hash = obj->GetIdentityHash();
2168 int hash1 = obj->GetIdentityHash();
2169 CHECK_EQ(hash, hash1);
2170 int hash2 = v8::Object::New()->GetIdentityHash();
2171 // Since the identity hash is essentially a random number two consecutive
2172 // objects should not be assigned the same hash code. If the test below fails
2173 // the random number generator should be evaluated.
2174 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002175 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002176 int hash3 = v8::Object::New()->GetIdentityHash();
2177 // Make sure that the identity hash is not based on the initial address of
2178 // the object alone. If the test below fails the random number generator
2179 // should be evaluated.
2180 CHECK_NE(hash, hash3);
2181 int hash4 = obj->GetIdentityHash();
2182 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002183
2184 // Check identity hashes behaviour in the presence of JS accessors.
2185 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2186 {
2187 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2188 Local<v8::Object> o1 = v8::Object::New();
2189 Local<v8::Object> o2 = v8::Object::New();
2190 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2191 }
2192 {
2193 CompileRun(
2194 "function cnst() { return 42; };\n"
2195 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2196 Local<v8::Object> o1 = v8::Object::New();
2197 Local<v8::Object> o2 = v8::Object::New();
2198 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2199 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002200}
2201
2202
2203THREADED_TEST(HiddenProperties) {
2204 v8::HandleScope scope;
2205 LocalContext env;
2206
2207 v8::Local<v8::Object> obj = v8::Object::New();
2208 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2209 v8::Local<v8::String> empty = v8_str("");
2210 v8::Local<v8::String> prop_name = v8_str("prop_name");
2211
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002212 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002213
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002214 // Make sure delete of a non-existent hidden value works
2215 CHECK(obj->DeleteHiddenValue(key));
2216
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002217 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2218 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2219 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2220 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2221
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002222 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002223
2224 // Make sure we do not find the hidden property.
2225 CHECK(!obj->Has(empty));
2226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2227 CHECK(obj->Get(empty)->IsUndefined());
2228 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2229 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2230 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2231 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2232
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002233 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002234
2235 // Add another property and delete it afterwards to force the object in
2236 // slow case.
2237 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2239 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2240 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2241 CHECK(obj->Delete(prop_name));
2242 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2243
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002244 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002245
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002246 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2247 CHECK(obj->GetHiddenValue(key).IsEmpty());
2248
2249 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002250 CHECK(obj->DeleteHiddenValue(key));
2251 CHECK(obj->GetHiddenValue(key).IsEmpty());
2252}
2253
2254
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002255THREADED_TEST(Regress97784) {
2256 // Regression test for crbug.com/97784
2257 // Messing with the Object.prototype should not have effect on
2258 // hidden properties.
2259 v8::HandleScope scope;
2260 LocalContext env;
2261
2262 v8::Local<v8::Object> obj = v8::Object::New();
2263 v8::Local<v8::String> key = v8_str("hidden");
2264
2265 CompileRun(
2266 "set_called = false;"
2267 "Object.defineProperty("
2268 " Object.prototype,"
2269 " 'hidden',"
2270 " {get: function() { return 45; },"
2271 " set: function() { set_called = true; }})");
2272
2273 CHECK(obj->GetHiddenValue(key).IsEmpty());
2274 // Make sure that the getter and setter from Object.prototype is not invoked.
2275 // If it did we would have full access to the hidden properties in
2276 // the accessor.
2277 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2278 ExpectFalse("set_called");
2279 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2280}
2281
2282
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002283static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002284static v8::Handle<Value> InterceptorForHiddenProperties(
2285 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002286 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002287 return v8::Handle<Value>();
2288}
2289
2290
2291THREADED_TEST(HiddenPropertiesWithInterceptors) {
2292 v8::HandleScope scope;
2293 LocalContext context;
2294
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002295 interceptor_for_hidden_properties_called = false;
2296
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002297 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2298
2299 // Associate an interceptor with an object and start setting hidden values.
2300 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2301 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2302 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2303 Local<v8::Function> function = fun_templ->GetFunction();
2304 Local<v8::Object> obj = function->NewInstance();
2305 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2306 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002307 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002308}
2309
2310
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002311THREADED_TEST(External) {
2312 v8::HandleScope scope;
2313 int x = 3;
2314 Local<v8::External> ext = v8::External::New(&x);
2315 LocalContext env;
2316 env->Global()->Set(v8_str("ext"), ext);
2317 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002318 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002319 int* ptr = static_cast<int*>(reext->Value());
2320 CHECK_EQ(x, 3);
2321 *ptr = 10;
2322 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323
2324 // Make sure unaligned pointers are wrapped properly.
2325 char* data = i::StrDup("0123456789");
2326 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2327 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2328 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2329 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2330
2331 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2332 CHECK_EQ('0', *char_ptr);
2333 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2334 CHECK_EQ('1', *char_ptr);
2335 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2336 CHECK_EQ('2', *char_ptr);
2337 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2338 CHECK_EQ('3', *char_ptr);
2339 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002340}
2341
2342
2343THREADED_TEST(GlobalHandle) {
2344 v8::Persistent<String> global;
2345 {
2346 v8::HandleScope scope;
2347 Local<String> str = v8_str("str");
2348 global = v8::Persistent<String>::New(str);
2349 }
2350 CHECK_EQ(global->Length(), 3);
2351 global.Dispose();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002352
2353 {
2354 v8::HandleScope scope;
2355 Local<String> str = v8_str("str");
2356 global = v8::Persistent<String>::New(str);
2357 }
2358 CHECK_EQ(global->Length(), 3);
2359 global.Dispose(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002360}
2361
2362
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002363class WeakCallCounter {
2364 public:
2365 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2366 int id() { return id_; }
2367 void increment() { number_of_weak_calls_++; }
2368 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2369 private:
2370 int id_;
2371 int number_of_weak_calls_;
2372};
2373
2374
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002375static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2377 CHECK_EQ(1234, counter->id());
2378 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002379 handle.Dispose();
2380}
2381
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002382
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002383THREADED_TEST(ApiObjectGroups) {
2384 HandleScope scope;
2385 LocalContext env;
2386
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002387 Persistent<Object> g1s1;
2388 Persistent<Object> g1s2;
2389 Persistent<Object> g1c1;
2390 Persistent<Object> g2s1;
2391 Persistent<Object> g2s2;
2392 Persistent<Object> g2c1;
2393
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002394 WeakCallCounter counter(1234);
2395
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002396 {
2397 HandleScope scope;
2398 g1s1 = Persistent<Object>::New(Object::New());
2399 g1s2 = Persistent<Object>::New(Object::New());
2400 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002401 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2402 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2403 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002404
2405 g2s1 = Persistent<Object>::New(Object::New());
2406 g2s2 = Persistent<Object>::New(Object::New());
2407 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002408 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2409 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2410 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002411 }
2412
2413 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2414
2415 // Connect group 1 and 2, make a cycle.
2416 CHECK(g1s2->Set(0, g2s2));
2417 CHECK(g2s1->Set(0, g1s1));
2418
2419 {
2420 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2421 Persistent<Value> g1_children[] = { g1c1 };
2422 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2423 Persistent<Value> g2_children[] = { g2c1 };
2424 V8::AddObjectGroup(g1_objects, 2);
2425 V8::AddImplicitReferences(g1s1, g1_children, 1);
2426 V8::AddObjectGroup(g2_objects, 2);
2427 V8::AddImplicitReferences(g2s2, g2_children, 1);
2428 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002429 // Do a single full GC, ensure incremental marking is stopped.
2430 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002431
2432 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002433 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002434
2435 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002436 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002437 // But make children strong roots---all the objects (except for children)
2438 // should be collectable now.
2439 g1c1.ClearWeak();
2440 g2c1.ClearWeak();
2441
2442 // Groups are deleted, rebuild groups.
2443 {
2444 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2445 Persistent<Value> g1_children[] = { g1c1 };
2446 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2447 Persistent<Value> g2_children[] = { g2c1 };
2448 V8::AddObjectGroup(g1_objects, 2);
2449 V8::AddImplicitReferences(g1s1, g1_children, 1);
2450 V8::AddObjectGroup(g2_objects, 2);
2451 V8::AddImplicitReferences(g2s2, g2_children, 1);
2452 }
2453
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002454 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002455
2456 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002457 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002458
2459 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002460 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2461 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002462
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002463 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002464 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002465}
2466
2467
2468THREADED_TEST(ApiObjectGroupsCycle) {
2469 HandleScope scope;
2470 LocalContext env;
2471
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002472 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002473
2474 Persistent<Object> g1s1;
2475 Persistent<Object> g1s2;
2476 Persistent<Object> g2s1;
2477 Persistent<Object> g2s2;
2478 Persistent<Object> g3s1;
2479 Persistent<Object> g3s2;
2480
2481 {
2482 HandleScope scope;
2483 g1s1 = Persistent<Object>::New(Object::New());
2484 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002485 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2486 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002487
2488 g2s1 = Persistent<Object>::New(Object::New());
2489 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002490 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2491 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002492
2493 g3s1 = Persistent<Object>::New(Object::New());
2494 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002495 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2496 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002497 }
2498
2499 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2500
2501 // Connect groups. We're building the following cycle:
2502 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2503 // groups.
2504 {
2505 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2506 Persistent<Value> g1_children[] = { g2s1 };
2507 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2508 Persistent<Value> g2_children[] = { g3s1 };
2509 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2510 Persistent<Value> g3_children[] = { g1s1 };
2511 V8::AddObjectGroup(g1_objects, 2);
2512 V8::AddImplicitReferences(g1s1, g1_children, 1);
2513 V8::AddObjectGroup(g2_objects, 2);
2514 V8::AddImplicitReferences(g2s1, g2_children, 1);
2515 V8::AddObjectGroup(g3_objects, 2);
2516 V8::AddImplicitReferences(g3s1, g3_children, 1);
2517 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002518 // Do a single full GC
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002519 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002520
2521 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002522 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002523
2524 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002525 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002526
2527 // Groups are deleted, rebuild groups.
2528 {
2529 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2530 Persistent<Value> g1_children[] = { g2s1 };
2531 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2532 Persistent<Value> g2_children[] = { g3s1 };
2533 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2534 Persistent<Value> g3_children[] = { g1s1 };
2535 V8::AddObjectGroup(g1_objects, 2);
2536 V8::AddImplicitReferences(g1s1, g1_children, 1);
2537 V8::AddObjectGroup(g2_objects, 2);
2538 V8::AddImplicitReferences(g2s1, g2_children, 1);
2539 V8::AddObjectGroup(g3_objects, 2);
2540 V8::AddImplicitReferences(g3s1, g3_children, 1);
2541 }
2542
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002543 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002544
2545 // All objects should be gone. 7 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002546 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002547}
2548
2549
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002550// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
2551// on the buildbots, so was made non-threaded for the time being.
2552TEST(ApiObjectGroupsCycleForScavenger) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002553 i::FLAG_stress_compaction = false;
2554 i::FLAG_gc_global = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002555 HandleScope scope;
2556 LocalContext env;
2557
2558 WeakCallCounter counter(1234);
2559
2560 Persistent<Object> g1s1;
2561 Persistent<Object> g1s2;
2562 Persistent<Object> g2s1;
2563 Persistent<Object> g2s2;
2564 Persistent<Object> g3s1;
2565 Persistent<Object> g3s2;
2566
2567 {
2568 HandleScope scope;
2569 g1s1 = Persistent<Object>::New(Object::New());
2570 g1s2 = Persistent<Object>::New(Object::New());
2571 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2572 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2573
2574 g2s1 = Persistent<Object>::New(Object::New());
2575 g2s2 = Persistent<Object>::New(Object::New());
2576 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2577 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2578
2579 g3s1 = Persistent<Object>::New(Object::New());
2580 g3s2 = Persistent<Object>::New(Object::New());
2581 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2582 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2583 }
2584
2585 // Make a root.
2586 Persistent<Object> root = Persistent<Object>::New(g1s1);
2587 root.MarkPartiallyDependent();
2588
2589 // Connect groups. We're building the following cycle:
2590 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2591 // groups.
2592 {
2593 g1s1.MarkPartiallyDependent();
2594 g1s2.MarkPartiallyDependent();
2595 g2s1.MarkPartiallyDependent();
2596 g2s2.MarkPartiallyDependent();
2597 g3s1.MarkPartiallyDependent();
2598 g3s2.MarkPartiallyDependent();
2599 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2600 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2601 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2602 V8::AddObjectGroup(g1_objects, 2);
2603 g1s1->Set(v8_str("x"), g2s1);
2604 V8::AddObjectGroup(g2_objects, 2);
2605 g2s1->Set(v8_str("x"), g3s1);
2606 V8::AddObjectGroup(g3_objects, 2);
2607 g3s1->Set(v8_str("x"), g1s1);
2608 }
2609
2610 HEAP->CollectGarbage(i::NEW_SPACE);
2611
2612 // All objects should be alive.
2613 CHECK_EQ(0, counter.NumberOfWeakCalls());
2614
2615 // Weaken the root.
2616 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2617 root.MarkPartiallyDependent();
2618
2619 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2620 // Groups are deleted, rebuild groups.
2621 {
2622 g1s1.MarkPartiallyDependent(isolate);
2623 g1s2.MarkPartiallyDependent(isolate);
2624 g2s1.MarkPartiallyDependent(isolate);
2625 g2s2.MarkPartiallyDependent(isolate);
2626 g3s1.MarkPartiallyDependent(isolate);
2627 g3s2.MarkPartiallyDependent(isolate);
2628 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2629 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2630 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2631 V8::AddObjectGroup(g1_objects, 2);
2632 g1s1->Set(v8_str("x"), g2s1);
2633 V8::AddObjectGroup(g2_objects, 2);
2634 g2s1->Set(v8_str("x"), g3s1);
2635 V8::AddObjectGroup(g3_objects, 2);
2636 g3s1->Set(v8_str("x"), g1s1);
2637 }
2638
2639 HEAP->CollectGarbage(i::NEW_SPACE);
2640
2641 // All objects should be gone. 7 global handles in total.
2642 CHECK_EQ(7, counter.NumberOfWeakCalls());
2643}
2644
2645
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002646THREADED_TEST(ScriptException) {
2647 v8::HandleScope scope;
2648 LocalContext env;
2649 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2650 v8::TryCatch try_catch;
2651 Local<Value> result = script->Run();
2652 CHECK(result.IsEmpty());
2653 CHECK(try_catch.HasCaught());
2654 String::AsciiValue exception_value(try_catch.Exception());
2655 CHECK_EQ(*exception_value, "panama!");
2656}
2657
2658
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002659TEST(TryCatchCustomException) {
2660 v8::HandleScope scope;
2661 LocalContext env;
2662 v8::TryCatch try_catch;
2663 CompileRun("function CustomError() { this.a = 'b'; }"
2664 "(function f() { throw new CustomError(); })();");
2665 CHECK(try_catch.HasCaught());
2666 CHECK(try_catch.Exception()->ToObject()->
2667 Get(v8_str("a"))->Equals(v8_str("b")));
2668}
2669
2670
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002671bool message_received;
2672
2673
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002674static void check_message_0(v8::Handle<v8::Message> message,
2675 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002676 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002677 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002678 message_received = true;
2679}
2680
2681
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002682THREADED_TEST(MessageHandler0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002683 message_received = false;
2684 v8::HandleScope scope;
2685 CHECK(!message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002686 v8::V8::AddMessageListener(check_message_0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002687 LocalContext context;
2688 v8::ScriptOrigin origin =
2689 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002690 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2691 &origin);
2692 script->SetData(v8_str("7.56"));
2693 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002694 CHECK(message_received);
2695 // clear out the message listener
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002696 v8::V8::RemoveMessageListeners(check_message_0);
2697}
2698
2699
2700static void check_message_1(v8::Handle<v8::Message> message,
2701 v8::Handle<Value> data) {
2702 CHECK(data->IsNumber());
2703 CHECK_EQ(1337, data->Int32Value());
2704 message_received = true;
2705}
2706
2707
2708TEST(MessageHandler1) {
2709 message_received = false;
2710 v8::HandleScope scope;
2711 CHECK(!message_received);
2712 v8::V8::AddMessageListener(check_message_1);
2713 LocalContext context;
2714 CompileRun("throw 1337;");
2715 CHECK(message_received);
2716 // clear out the message listener
2717 v8::V8::RemoveMessageListeners(check_message_1);
2718}
2719
2720
2721static void check_message_2(v8::Handle<v8::Message> message,
2722 v8::Handle<Value> data) {
2723 LocalContext context;
2724 CHECK(data->IsObject());
2725 v8::Local<v8::Value> hidden_property =
2726 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2727 CHECK(v8_str("hidden value")->Equals(hidden_property));
2728 message_received = true;
2729}
2730
2731
2732TEST(MessageHandler2) {
2733 message_received = false;
2734 v8::HandleScope scope;
2735 CHECK(!message_received);
2736 v8::V8::AddMessageListener(check_message_2);
2737 LocalContext context;
2738 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2739 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2740 v8_str("hidden value"));
2741 context->Global()->Set(v8_str("error"), error);
2742 CompileRun("throw error;");
2743 CHECK(message_received);
2744 // clear out the message listener
2745 v8::V8::RemoveMessageListeners(check_message_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002746}
2747
2748
2749THREADED_TEST(GetSetProperty) {
2750 v8::HandleScope scope;
2751 LocalContext context;
2752 context->Global()->Set(v8_str("foo"), v8_num(14));
2753 context->Global()->Set(v8_str("12"), v8_num(92));
2754 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2755 context->Global()->Set(v8_num(13), v8_num(56));
2756 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2757 CHECK_EQ(14, foo->Int32Value());
2758 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2759 CHECK_EQ(92, twelve->Int32Value());
2760 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2761 CHECK_EQ(32, sixteen->Int32Value());
2762 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2763 CHECK_EQ(56, thirteen->Int32Value());
2764 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2765 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2766 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2767 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2768 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2769 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2770 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2771 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2772 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2773}
2774
2775
2776THREADED_TEST(PropertyAttributes) {
2777 v8::HandleScope scope;
2778 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002779 // none
2780 Local<String> prop = v8_str("none");
2781 context->Global()->Set(prop, v8_num(7));
2782 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002783 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002784 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002785 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2786 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002787 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002788 Script::Compile(v8_str("read_only = 9"))->Run();
2789 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2790 context->Global()->Set(prop, v8_num(10));
2791 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2792 // dont-delete
2793 prop = v8_str("dont_delete");
2794 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2795 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2796 Script::Compile(v8_str("delete dont_delete"))->Run();
2797 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002798 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2799 // dont-enum
2800 prop = v8_str("dont_enum");
2801 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2802 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2803 // absent
2804 prop = v8_str("absent");
2805 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2806 Local<Value> fake_prop = v8_num(1);
2807 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2808 // exception
2809 TryCatch try_catch;
2810 Local<Value> exception =
2811 CompileRun("({ toString: function() { throw 'exception';} })");
2812 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2813 CHECK(try_catch.HasCaught());
2814 String::AsciiValue exception_value(try_catch.Exception());
2815 CHECK_EQ("exception", *exception_value);
2816 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002817}
2818
2819
2820THREADED_TEST(Array) {
2821 v8::HandleScope scope;
2822 LocalContext context;
2823 Local<v8::Array> array = v8::Array::New();
2824 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002825 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002826 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002827 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002828 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002829 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002830 CHECK_EQ(3, array->Length());
2831 CHECK(!array->Has(0));
2832 CHECK(!array->Has(1));
2833 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002834 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002835 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002836 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002837 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002838 CHECK_EQ(1, arr->Get(0)->Int32Value());
2839 CHECK_EQ(2, arr->Get(1)->Int32Value());
2840 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002841 array = v8::Array::New(27);
2842 CHECK_EQ(27, array->Length());
2843 array = v8::Array::New(-27);
2844 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002845}
2846
2847
2848v8::Handle<Value> HandleF(const v8::Arguments& args) {
2849 v8::HandleScope scope;
2850 ApiTestFuzzer::Fuzz();
2851 Local<v8::Array> result = v8::Array::New(args.Length());
2852 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002853 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002854 return scope.Close(result);
2855}
2856
2857
2858THREADED_TEST(Vector) {
2859 v8::HandleScope scope;
2860 Local<ObjectTemplate> global = ObjectTemplate::New();
2861 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2862 LocalContext context(0, global);
2863
2864 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002865 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002866 CHECK_EQ(0, a0->Length());
2867
2868 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002869 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002870 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002871 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002872
2873 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002874 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002875 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002876 CHECK_EQ(12, a2->Get(0)->Int32Value());
2877 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002878
2879 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002880 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002881 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002882 CHECK_EQ(14, a3->Get(0)->Int32Value());
2883 CHECK_EQ(15, a3->Get(1)->Int32Value());
2884 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002885
2886 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002887 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002888 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002889 CHECK_EQ(17, a4->Get(0)->Int32Value());
2890 CHECK_EQ(18, a4->Get(1)->Int32Value());
2891 CHECK_EQ(19, a4->Get(2)->Int32Value());
2892 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002893}
2894
2895
2896THREADED_TEST(FunctionCall) {
2897 v8::HandleScope scope;
2898 LocalContext context;
2899 CompileRun(
2900 "function Foo() {"
2901 " var result = [];"
2902 " for (var i = 0; i < arguments.length; i++) {"
2903 " result.push(arguments[i]);"
2904 " }"
2905 " return result;"
2906 "}");
2907 Local<Function> Foo =
2908 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2909
2910 v8::Handle<Value>* args0 = NULL;
2911 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2912 CHECK_EQ(0, a0->Length());
2913
2914 v8::Handle<Value> args1[] = { v8_num(1.1) };
2915 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2916 CHECK_EQ(1, a1->Length());
2917 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2918
2919 v8::Handle<Value> args2[] = { v8_num(2.2),
2920 v8_num(3.3) };
2921 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2922 CHECK_EQ(2, a2->Length());
2923 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2924 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2925
2926 v8::Handle<Value> args3[] = { v8_num(4.4),
2927 v8_num(5.5),
2928 v8_num(6.6) };
2929 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2930 CHECK_EQ(3, a3->Length());
2931 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2932 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2933 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2934
2935 v8::Handle<Value> args4[] = { v8_num(7.7),
2936 v8_num(8.8),
2937 v8_num(9.9),
2938 v8_num(10.11) };
2939 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2940 CHECK_EQ(4, a4->Length());
2941 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2942 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2943 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2944 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2945}
2946
2947
2948static const char* js_code_causing_out_of_memory =
2949 "var a = new Array(); while(true) a.push(a);";
2950
2951
2952// These tests run for a long time and prevent us from running tests
2953// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002954TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002955 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002956 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002957 // Set heap limits.
2958 static const int K = 1024;
2959 v8::ResourceConstraints constraints;
2960 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002961 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002962 v8::SetResourceConstraints(&constraints);
2963
2964 // Execute a script that causes out of memory.
2965 v8::HandleScope scope;
2966 LocalContext context;
2967 v8::V8::IgnoreOutOfMemoryException();
2968 Local<Script> script =
2969 Script::Compile(String::New(js_code_causing_out_of_memory));
2970 Local<Value> result = script->Run();
2971
2972 // Check for out of memory state.
2973 CHECK(result.IsEmpty());
2974 CHECK(context->HasOutOfMemoryException());
2975}
2976
2977
2978v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2979 ApiTestFuzzer::Fuzz();
2980
2981 v8::HandleScope scope;
2982 LocalContext context;
2983 Local<Script> script =
2984 Script::Compile(String::New(js_code_causing_out_of_memory));
2985 Local<Value> result = script->Run();
2986
2987 // Check for out of memory state.
2988 CHECK(result.IsEmpty());
2989 CHECK(context->HasOutOfMemoryException());
2990
2991 return result;
2992}
2993
2994
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002995TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002996 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002997 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002998 // Set heap limits.
2999 static const int K = 1024;
3000 v8::ResourceConstraints constraints;
3001 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003002 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003003 v8::SetResourceConstraints(&constraints);
3004
3005 v8::HandleScope scope;
3006 Local<ObjectTemplate> templ = ObjectTemplate::New();
3007 templ->Set(v8_str("ProvokeOutOfMemory"),
3008 v8::FunctionTemplate::New(ProvokeOutOfMemory));
3009 LocalContext context(0, templ);
3010 v8::V8::IgnoreOutOfMemoryException();
3011 Local<Value> result = CompileRun(
3012 "var thrown = false;"
3013 "try {"
3014 " ProvokeOutOfMemory();"
3015 "} catch (e) {"
3016 " thrown = true;"
3017 "}");
3018 // Check for out of memory state.
3019 CHECK(result.IsEmpty());
3020 CHECK(context->HasOutOfMemoryException());
3021}
3022
3023
3024TEST(HugeConsStringOutOfMemory) {
3025 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003026 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003027 // Set heap limits.
3028 static const int K = 1024;
3029 v8::ResourceConstraints constraints;
3030 constraints.set_max_young_space_size(256 * K);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003031 constraints.set_max_old_space_size(3 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003032 v8::SetResourceConstraints(&constraints);
3033
3034 // Execute a script that causes out of memory.
3035 v8::V8::IgnoreOutOfMemoryException();
3036
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003037 v8::HandleScope scope;
3038 LocalContext context;
3039
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003040 // Build huge string. This should fail with out of memory exception.
3041 Local<Value> result = CompileRun(
3042 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003043 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003044
3045 // Check for out of memory state.
3046 CHECK(result.IsEmpty());
3047 CHECK(context->HasOutOfMemoryException());
3048}
3049
3050
3051THREADED_TEST(ConstructCall) {
3052 v8::HandleScope scope;
3053 LocalContext context;
3054 CompileRun(
3055 "function Foo() {"
3056 " var result = [];"
3057 " for (var i = 0; i < arguments.length; i++) {"
3058 " result.push(arguments[i]);"
3059 " }"
3060 " return result;"
3061 "}");
3062 Local<Function> Foo =
3063 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3064
3065 v8::Handle<Value>* args0 = NULL;
3066 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3067 CHECK_EQ(0, a0->Length());
3068
3069 v8::Handle<Value> args1[] = { v8_num(1.1) };
3070 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3071 CHECK_EQ(1, a1->Length());
3072 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3073
3074 v8::Handle<Value> args2[] = { v8_num(2.2),
3075 v8_num(3.3) };
3076 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3077 CHECK_EQ(2, a2->Length());
3078 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3079 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3080
3081 v8::Handle<Value> args3[] = { v8_num(4.4),
3082 v8_num(5.5),
3083 v8_num(6.6) };
3084 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3085 CHECK_EQ(3, a3->Length());
3086 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3087 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3088 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3089
3090 v8::Handle<Value> args4[] = { v8_num(7.7),
3091 v8_num(8.8),
3092 v8_num(9.9),
3093 v8_num(10.11) };
3094 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3095 CHECK_EQ(4, a4->Length());
3096 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3097 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3098 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3099 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3100}
3101
3102
3103static void CheckUncle(v8::TryCatch* try_catch) {
3104 CHECK(try_catch->HasCaught());
3105 String::AsciiValue str_value(try_catch->Exception());
3106 CHECK_EQ(*str_value, "uncle?");
3107 try_catch->Reset();
3108}
3109
3110
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003111THREADED_TEST(ConversionNumber) {
3112 v8::HandleScope scope;
3113 LocalContext env;
3114 // Very large number.
3115 CompileRun("var obj = Math.pow(2,32) * 1237;");
3116 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3117 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
3118 CHECK_EQ(0, obj->ToInt32()->Value());
3119 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
3120 // Large number.
3121 CompileRun("var obj = -1234567890123;");
3122 obj = env->Global()->Get(v8_str("obj"));
3123 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
3124 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
3125 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
3126 // Small positive integer.
3127 CompileRun("var obj = 42;");
3128 obj = env->Global()->Get(v8_str("obj"));
3129 CHECK_EQ(42.0, obj->ToNumber()->Value());
3130 CHECK_EQ(42, obj->ToInt32()->Value());
3131 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3132 // Negative integer.
3133 CompileRun("var obj = -37;");
3134 obj = env->Global()->Get(v8_str("obj"));
3135 CHECK_EQ(-37.0, obj->ToNumber()->Value());
3136 CHECK_EQ(-37, obj->ToInt32()->Value());
3137 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
3138 // Positive non-int32 integer.
3139 CompileRun("var obj = 0x81234567;");
3140 obj = env->Global()->Get(v8_str("obj"));
3141 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
3142 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
3143 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
3144 // Fraction.
3145 CompileRun("var obj = 42.3;");
3146 obj = env->Global()->Get(v8_str("obj"));
3147 CHECK_EQ(42.3, obj->ToNumber()->Value());
3148 CHECK_EQ(42, obj->ToInt32()->Value());
3149 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3150 // Large negative fraction.
3151 CompileRun("var obj = -5726623061.75;");
3152 obj = env->Global()->Get(v8_str("obj"));
3153 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
3154 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
3155 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
3156}
3157
3158
3159THREADED_TEST(isNumberType) {
3160 v8::HandleScope scope;
3161 LocalContext env;
3162 // Very large number.
3163 CompileRun("var obj = Math.pow(2,32) * 1237;");
3164 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3165 CHECK(!obj->IsInt32());
3166 CHECK(!obj->IsUint32());
3167 // Large negative number.
3168 CompileRun("var obj = -1234567890123;");
3169 obj = env->Global()->Get(v8_str("obj"));
3170 CHECK(!obj->IsInt32());
3171 CHECK(!obj->IsUint32());
3172 // Small positive integer.
3173 CompileRun("var obj = 42;");
3174 obj = env->Global()->Get(v8_str("obj"));
3175 CHECK(obj->IsInt32());
3176 CHECK(obj->IsUint32());
3177 // Negative integer.
3178 CompileRun("var obj = -37;");
3179 obj = env->Global()->Get(v8_str("obj"));
3180 CHECK(obj->IsInt32());
3181 CHECK(!obj->IsUint32());
3182 // Positive non-int32 integer.
3183 CompileRun("var obj = 0x81234567;");
3184 obj = env->Global()->Get(v8_str("obj"));
3185 CHECK(!obj->IsInt32());
3186 CHECK(obj->IsUint32());
3187 // Fraction.
3188 CompileRun("var obj = 42.3;");
3189 obj = env->Global()->Get(v8_str("obj"));
3190 CHECK(!obj->IsInt32());
3191 CHECK(!obj->IsUint32());
3192 // Large negative fraction.
3193 CompileRun("var obj = -5726623061.75;");
3194 obj = env->Global()->Get(v8_str("obj"));
3195 CHECK(!obj->IsInt32());
3196 CHECK(!obj->IsUint32());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003197 // Positive zero
3198 CompileRun("var obj = 0.0;");
3199 obj = env->Global()->Get(v8_str("obj"));
3200 CHECK(obj->IsInt32());
3201 CHECK(obj->IsUint32());
3202 // Positive zero
3203 CompileRun("var obj = -0.0;");
3204 obj = env->Global()->Get(v8_str("obj"));
3205 CHECK(!obj->IsInt32());
3206 CHECK(!obj->IsUint32());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003207}
3208
3209
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003210THREADED_TEST(ConversionException) {
3211 v8::HandleScope scope;
3212 LocalContext env;
3213 CompileRun(
3214 "function TestClass() { };"
3215 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3216 "var obj = new TestClass();");
3217 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3218
3219 v8::TryCatch try_catch;
3220
3221 Local<Value> to_string_result = obj->ToString();
3222 CHECK(to_string_result.IsEmpty());
3223 CheckUncle(&try_catch);
3224
3225 Local<Value> to_number_result = obj->ToNumber();
3226 CHECK(to_number_result.IsEmpty());
3227 CheckUncle(&try_catch);
3228
3229 Local<Value> to_integer_result = obj->ToInteger();
3230 CHECK(to_integer_result.IsEmpty());
3231 CheckUncle(&try_catch);
3232
3233 Local<Value> to_uint32_result = obj->ToUint32();
3234 CHECK(to_uint32_result.IsEmpty());
3235 CheckUncle(&try_catch);
3236
3237 Local<Value> to_int32_result = obj->ToInt32();
3238 CHECK(to_int32_result.IsEmpty());
3239 CheckUncle(&try_catch);
3240
3241 Local<Value> to_object_result = v8::Undefined()->ToObject();
3242 CHECK(to_object_result.IsEmpty());
3243 CHECK(try_catch.HasCaught());
3244 try_catch.Reset();
3245
3246 int32_t int32_value = obj->Int32Value();
3247 CHECK_EQ(0, int32_value);
3248 CheckUncle(&try_catch);
3249
3250 uint32_t uint32_value = obj->Uint32Value();
3251 CHECK_EQ(0, uint32_value);
3252 CheckUncle(&try_catch);
3253
3254 double number_value = obj->NumberValue();
3255 CHECK_NE(0, IsNaN(number_value));
3256 CheckUncle(&try_catch);
3257
3258 int64_t integer_value = obj->IntegerValue();
3259 CHECK_EQ(0.0, static_cast<double>(integer_value));
3260 CheckUncle(&try_catch);
3261}
3262
3263
3264v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3265 ApiTestFuzzer::Fuzz();
3266 return v8::ThrowException(v8_str("konto"));
3267}
3268
3269
ager@chromium.org8bb60582008-12-11 12:02:20 +00003270v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003271 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003272 v8::HandleScope scope;
3273 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003274 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3275 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003276 return v8::Boolean::New(try_catch.HasCaught());
3277}
3278
3279
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003280THREADED_TEST(APICatch) {
3281 v8::HandleScope scope;
3282 Local<ObjectTemplate> templ = ObjectTemplate::New();
3283 templ->Set(v8_str("ThrowFromC"),
3284 v8::FunctionTemplate::New(ThrowFromC));
3285 LocalContext context(0, templ);
3286 CompileRun(
3287 "var thrown = false;"
3288 "try {"
3289 " ThrowFromC();"
3290 "} catch (e) {"
3291 " thrown = true;"
3292 "}");
3293 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3294 CHECK(thrown->BooleanValue());
3295}
3296
3297
ager@chromium.org8bb60582008-12-11 12:02:20 +00003298THREADED_TEST(APIThrowTryCatch) {
3299 v8::HandleScope scope;
3300 Local<ObjectTemplate> templ = ObjectTemplate::New();
3301 templ->Set(v8_str("ThrowFromC"),
3302 v8::FunctionTemplate::New(ThrowFromC));
3303 LocalContext context(0, templ);
3304 v8::TryCatch try_catch;
3305 CompileRun("ThrowFromC();");
3306 CHECK(try_catch.HasCaught());
3307}
3308
3309
3310// Test that a try-finally block doesn't shadow a try-catch block
3311// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003312//
3313// BUG(271): Some of the exception propagation does not work on the
3314// ARM simulator because the simulator separates the C++ stack and the
3315// JS stack. This test therefore fails on the simulator. The test is
3316// not threaded to allow the threading tests to run on the simulator.
3317TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003318 v8::HandleScope scope;
3319 Local<ObjectTemplate> templ = ObjectTemplate::New();
3320 templ->Set(v8_str("CCatcher"),
3321 v8::FunctionTemplate::New(CCatcher));
3322 LocalContext context(0, templ);
3323 Local<Value> result = CompileRun("try {"
3324 " try {"
3325 " CCatcher('throw 7;');"
3326 " } finally {"
3327 " }"
3328 "} catch (e) {"
3329 "}");
3330 CHECK(result->IsTrue());
3331}
3332
3333
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003334static void check_reference_error_message(
3335 v8::Handle<v8::Message> message,
3336 v8::Handle<v8::Value> data) {
3337 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3338 CHECK(message->Get()->Equals(v8_str(reference_error)));
3339}
3340
3341
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003342static v8::Handle<Value> Fail(const v8::Arguments& args) {
3343 ApiTestFuzzer::Fuzz();
3344 CHECK(false);
3345 return v8::Undefined();
3346}
3347
3348
3349// Test that overwritten methods are not invoked on uncaught exception
3350// formatting. However, they are invoked when performing normal error
3351// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003352TEST(APIThrowMessageOverwrittenToString) {
3353 v8::HandleScope scope;
3354 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003355 Local<ObjectTemplate> templ = ObjectTemplate::New();
3356 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3357 LocalContext context(NULL, templ);
3358 CompileRun("asdf;");
3359 CompileRun("var limit = {};"
3360 "limit.valueOf = fail;"
3361 "Error.stackTraceLimit = limit;");
3362 CompileRun("asdf");
3363 CompileRun("Array.prototype.pop = fail;");
3364 CompileRun("Object.prototype.hasOwnProperty = fail;");
3365 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003366 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3367 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003368 CompileRun("ReferenceError.prototype.toString ="
3369 " function() { return 'Whoops' }");
3370 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003371 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3372 CompileRun("asdf;");
3373 CompileRun("ReferenceError.prototype.constructor = void 0;");
3374 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003375 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3376 CompileRun("asdf;");
3377 CompileRun("ReferenceError.prototype = new Object();");
3378 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003379 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3380 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003381 CompileRun("ReferenceError.prototype.constructor = new Object();"
3382 "ReferenceError.prototype.constructor.name = 1;"
3383 "Number.prototype.toString = function() { return 'Whoops'; };"
3384 "ReferenceError.prototype.toString = Object.prototype.toString;");
3385 CompileRun("asdf;");
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003386 v8::V8::RemoveMessageListeners(check_reference_error_message);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003387}
3388
3389
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003390static void check_custom_error_message(
3391 v8::Handle<v8::Message> message,
3392 v8::Handle<v8::Value> data) {
3393 const char* uncaught_error = "Uncaught MyError toString";
3394 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3395}
3396
3397
3398TEST(CustomErrorToString) {
3399 v8::HandleScope scope;
3400 v8::V8::AddMessageListener(check_custom_error_message);
3401 LocalContext context;
3402 CompileRun(
3403 "function MyError(name, message) { "
3404 " this.name = name; "
3405 " this.message = message; "
3406 "} "
3407 "MyError.prototype = Object.create(Error.prototype); "
3408 "MyError.prototype.toString = function() { "
3409 " return 'MyError toString'; "
3410 "}; "
3411 "throw new MyError('my name', 'my message'); ");
3412 v8::V8::RemoveMessageListeners(check_custom_error_message);
3413}
3414
3415
ager@chromium.org8bb60582008-12-11 12:02:20 +00003416static void receive_message(v8::Handle<v8::Message> message,
3417 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003418 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003419 message_received = true;
3420}
3421
3422
3423TEST(APIThrowMessage) {
3424 message_received = false;
3425 v8::HandleScope scope;
3426 v8::V8::AddMessageListener(receive_message);
3427 Local<ObjectTemplate> templ = ObjectTemplate::New();
3428 templ->Set(v8_str("ThrowFromC"),
3429 v8::FunctionTemplate::New(ThrowFromC));
3430 LocalContext context(0, templ);
3431 CompileRun("ThrowFromC();");
3432 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003433 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003434}
3435
3436
3437TEST(APIThrowMessageAndVerboseTryCatch) {
3438 message_received = false;
3439 v8::HandleScope scope;
3440 v8::V8::AddMessageListener(receive_message);
3441 Local<ObjectTemplate> templ = ObjectTemplate::New();
3442 templ->Set(v8_str("ThrowFromC"),
3443 v8::FunctionTemplate::New(ThrowFromC));
3444 LocalContext context(0, templ);
3445 v8::TryCatch try_catch;
3446 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003447 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003448 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003449 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003450 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003451 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003452}
3453
3454
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003455TEST(APIStackOverflowAndVerboseTryCatch) {
3456 message_received = false;
3457 v8::HandleScope scope;
3458 v8::V8::AddMessageListener(receive_message);
3459 LocalContext context;
3460 v8::TryCatch try_catch;
3461 try_catch.SetVerbose(true);
3462 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3463 CHECK(try_catch.HasCaught());
3464 CHECK(result.IsEmpty());
3465 CHECK(message_received);
3466 v8::V8::RemoveMessageListeners(receive_message);
3467}
3468
3469
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003470THREADED_TEST(ExternalScriptException) {
3471 v8::HandleScope scope;
3472 Local<ObjectTemplate> templ = ObjectTemplate::New();
3473 templ->Set(v8_str("ThrowFromC"),
3474 v8::FunctionTemplate::New(ThrowFromC));
3475 LocalContext context(0, templ);
3476
3477 v8::TryCatch try_catch;
3478 Local<Script> script
3479 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3480 Local<Value> result = script->Run();
3481 CHECK(result.IsEmpty());
3482 CHECK(try_catch.HasCaught());
3483 String::AsciiValue exception_value(try_catch.Exception());
3484 CHECK_EQ("konto", *exception_value);
3485}
3486
3487
3488
3489v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3490 ApiTestFuzzer::Fuzz();
3491 CHECK_EQ(4, args.Length());
3492 int count = args[0]->Int32Value();
3493 int cInterval = args[2]->Int32Value();
3494 if (count == 0) {
3495 return v8::ThrowException(v8_str("FromC"));
3496 } else {
3497 Local<v8::Object> global = Context::GetCurrent()->Global();
3498 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3499 v8::Handle<Value> argv[] = { v8_num(count - 1),
3500 args[1],
3501 args[2],
3502 args[3] };
3503 if (count % cInterval == 0) {
3504 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003505 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003506 int expected = args[3]->Int32Value();
3507 if (try_catch.HasCaught()) {
3508 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003509 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003510 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003511 } else {
3512 CHECK_NE(expected, count);
3513 }
3514 return result;
3515 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003516 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003517 }
3518 }
3519}
3520
3521
3522v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3523 ApiTestFuzzer::Fuzz();
3524 CHECK_EQ(3, args.Length());
3525 bool equality = args[0]->BooleanValue();
3526 int count = args[1]->Int32Value();
3527 int expected = args[2]->Int32Value();
3528 if (equality) {
3529 CHECK_EQ(count, expected);
3530 } else {
3531 CHECK_NE(count, expected);
3532 }
3533 return v8::Undefined();
3534}
3535
3536
ager@chromium.org8bb60582008-12-11 12:02:20 +00003537THREADED_TEST(EvalInTryFinally) {
3538 v8::HandleScope scope;
3539 LocalContext context;
3540 v8::TryCatch try_catch;
3541 CompileRun("(function() {"
3542 " try {"
3543 " eval('asldkf (*&^&*^');"
3544 " } finally {"
3545 " return;"
3546 " }"
3547 "})()");
3548 CHECK(!try_catch.HasCaught());
3549}
3550
3551
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003552// This test works by making a stack of alternating JavaScript and C
3553// activations. These activations set up exception handlers with regular
3554// intervals, one interval for C activations and another for JavaScript
3555// activations. When enough activations have been created an exception is
3556// thrown and we check that the right activation catches the exception and that
3557// no other activations do. The right activation is always the topmost one with
3558// a handler, regardless of whether it is in JavaScript or C.
3559//
3560// The notation used to describe a test case looks like this:
3561//
3562// *JS[4] *C[3] @JS[2] C[1] JS[0]
3563//
3564// Each entry is an activation, either JS or C. The index is the count at that
3565// level. Stars identify activations with exception handlers, the @ identifies
3566// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003567//
3568// BUG(271): Some of the exception propagation does not work on the
3569// ARM simulator because the simulator separates the C++ stack and the
3570// JS stack. This test therefore fails on the simulator. The test is
3571// not threaded to allow the threading tests to run on the simulator.
3572TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003573 v8::HandleScope scope;
3574 Local<ObjectTemplate> templ = ObjectTemplate::New();
3575 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3576 templ->Set(v8_str("CThrowCountDown"),
3577 v8::FunctionTemplate::New(CThrowCountDown));
3578 LocalContext context(0, templ);
3579 CompileRun(
3580 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3581 " if (count == 0) throw 'FromJS';"
3582 " if (count % jsInterval == 0) {"
3583 " try {"
3584 " var value = CThrowCountDown(count - 1,"
3585 " jsInterval,"
3586 " cInterval,"
3587 " expected);"
3588 " check(false, count, expected);"
3589 " return value;"
3590 " } catch (e) {"
3591 " check(true, count, expected);"
3592 " }"
3593 " } else {"
3594 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3595 " }"
3596 "}");
3597 Local<Function> fun =
3598 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3599
3600 const int argc = 4;
3601 // count jsInterval cInterval expected
3602
3603 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3604 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3605 fun->Call(fun, argc, a0);
3606
3607 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3608 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3609 fun->Call(fun, argc, a1);
3610
3611 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3612 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3613 fun->Call(fun, argc, a2);
3614
3615 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3616 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3617 fun->Call(fun, argc, a3);
3618
3619 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3620 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3621 fun->Call(fun, argc, a4);
3622
3623 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3624 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3625 fun->Call(fun, argc, a5);
3626}
3627
3628
3629v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3630 ApiTestFuzzer::Fuzz();
3631 CHECK_EQ(1, args.Length());
3632 return v8::ThrowException(args[0]);
3633}
3634
3635
3636THREADED_TEST(ThrowValues) {
3637 v8::HandleScope scope;
3638 Local<ObjectTemplate> templ = ObjectTemplate::New();
3639 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3640 LocalContext context(0, templ);
3641 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3642 "function Run(obj) {"
3643 " try {"
3644 " Throw(obj);"
3645 " } catch (e) {"
3646 " return e;"
3647 " }"
3648 " return 'no exception';"
3649 "}"
3650 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3651 CHECK_EQ(5, result->Length());
3652 CHECK(result->Get(v8::Integer::New(0))->IsString());
3653 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3654 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3655 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3656 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3657 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3658 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3659}
3660
3661
3662THREADED_TEST(CatchZero) {
3663 v8::HandleScope scope;
3664 LocalContext context;
3665 v8::TryCatch try_catch;
3666 CHECK(!try_catch.HasCaught());
3667 Script::Compile(v8_str("throw 10"))->Run();
3668 CHECK(try_catch.HasCaught());
3669 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3670 try_catch.Reset();
3671 CHECK(!try_catch.HasCaught());
3672 Script::Compile(v8_str("throw 0"))->Run();
3673 CHECK(try_catch.HasCaught());
3674 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3675}
3676
3677
3678THREADED_TEST(CatchExceptionFromWith) {
3679 v8::HandleScope scope;
3680 LocalContext context;
3681 v8::TryCatch try_catch;
3682 CHECK(!try_catch.HasCaught());
3683 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3684 CHECK(try_catch.HasCaught());
3685}
3686
3687
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003688THREADED_TEST(TryCatchAndFinallyHidingException) {
3689 v8::HandleScope scope;
3690 LocalContext context;
3691 v8::TryCatch try_catch;
3692 CHECK(!try_catch.HasCaught());
3693 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3694 CompileRun("f({toString: function() { throw 42; }});");
3695 CHECK(!try_catch.HasCaught());
3696}
3697
3698
3699v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3700 v8::TryCatch try_catch;
3701 return v8::Undefined();
3702}
3703
3704
3705THREADED_TEST(TryCatchAndFinally) {
3706 v8::HandleScope scope;
3707 LocalContext context;
3708 context->Global()->Set(
3709 v8_str("native_with_try_catch"),
3710 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3711 v8::TryCatch try_catch;
3712 CHECK(!try_catch.HasCaught());
3713 CompileRun(
3714 "try {\n"
3715 " throw new Error('a');\n"
3716 "} finally {\n"
3717 " native_with_try_catch();\n"
3718 "}\n");
3719 CHECK(try_catch.HasCaught());
3720}
3721
3722
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003723THREADED_TEST(Equality) {
3724 v8::HandleScope scope;
3725 LocalContext context;
3726 // Check that equality works at all before relying on CHECK_EQ
3727 CHECK(v8_str("a")->Equals(v8_str("a")));
3728 CHECK(!v8_str("a")->Equals(v8_str("b")));
3729
3730 CHECK_EQ(v8_str("a"), v8_str("a"));
3731 CHECK_NE(v8_str("a"), v8_str("b"));
3732 CHECK_EQ(v8_num(1), v8_num(1));
3733 CHECK_EQ(v8_num(1.00), v8_num(1));
3734 CHECK_NE(v8_num(1), v8_num(2));
3735
3736 // Assume String is not symbol.
3737 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3738 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3739 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3740 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3741 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3742 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3743 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3744 CHECK(!not_a_number->StrictEquals(not_a_number));
3745 CHECK(v8::False()->StrictEquals(v8::False()));
3746 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3747
3748 v8::Handle<v8::Object> obj = v8::Object::New();
3749 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3750 CHECK(alias->StrictEquals(obj));
3751 alias.Dispose();
3752}
3753
3754
3755THREADED_TEST(MultiRun) {
3756 v8::HandleScope scope;
3757 LocalContext context;
3758 Local<Script> script = Script::Compile(v8_str("x"));
3759 for (int i = 0; i < 10; i++)
3760 script->Run();
3761}
3762
3763
3764static v8::Handle<Value> GetXValue(Local<String> name,
3765 const AccessorInfo& info) {
3766 ApiTestFuzzer::Fuzz();
3767 CHECK_EQ(info.Data(), v8_str("donut"));
3768 CHECK_EQ(name, v8_str("x"));
3769 return name;
3770}
3771
3772
3773THREADED_TEST(SimplePropertyRead) {
3774 v8::HandleScope scope;
3775 Local<ObjectTemplate> templ = ObjectTemplate::New();
3776 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3777 LocalContext context;
3778 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3779 Local<Script> script = Script::Compile(v8_str("obj.x"));
3780 for (int i = 0; i < 10; i++) {
3781 Local<Value> result = script->Run();
3782 CHECK_EQ(result, v8_str("x"));
3783 }
3784}
3785
ager@chromium.org5c838252010-02-19 08:53:10 +00003786THREADED_TEST(DefinePropertyOnAPIAccessor) {
3787 v8::HandleScope scope;
3788 Local<ObjectTemplate> templ = ObjectTemplate::New();
3789 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3790 LocalContext context;
3791 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3792
3793 // Uses getOwnPropertyDescriptor to check the configurable status
3794 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003795 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003796 "obj, 'x');"
3797 "prop.configurable;"));
3798 Local<Value> result = script_desc->Run();
3799 CHECK_EQ(result->BooleanValue(), true);
3800
3801 // Redefine get - but still configurable
3802 Local<Script> script_define
3803 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3804 " configurable: true };"
3805 "Object.defineProperty(obj, 'x', desc);"
3806 "obj.x"));
3807 result = script_define->Run();
3808 CHECK_EQ(result, v8_num(42));
3809
3810 // Check that the accessor is still configurable
3811 result = script_desc->Run();
3812 CHECK_EQ(result->BooleanValue(), true);
3813
3814 // Redefine to a non-configurable
3815 script_define
3816 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3817 " configurable: false };"
3818 "Object.defineProperty(obj, 'x', desc);"
3819 "obj.x"));
3820 result = script_define->Run();
3821 CHECK_EQ(result, v8_num(43));
3822 result = script_desc->Run();
3823 CHECK_EQ(result->BooleanValue(), false);
3824
3825 // Make sure that it is not possible to redefine again
3826 v8::TryCatch try_catch;
3827 result = script_define->Run();
3828 CHECK(try_catch.HasCaught());
3829 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003830 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003831}
3832
3833THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3834 v8::HandleScope scope;
3835 Local<ObjectTemplate> templ = ObjectTemplate::New();
3836 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3837 LocalContext context;
3838 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3839
3840 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3841 "Object.getOwnPropertyDescriptor( "
3842 "obj, 'x');"
3843 "prop.configurable;"));
3844 Local<Value> result = script_desc->Run();
3845 CHECK_EQ(result->BooleanValue(), true);
3846
3847 Local<Script> script_define =
3848 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3849 " configurable: true };"
3850 "Object.defineProperty(obj, 'x', desc);"
3851 "obj.x"));
3852 result = script_define->Run();
3853 CHECK_EQ(result, v8_num(42));
3854
3855
3856 result = script_desc->Run();
3857 CHECK_EQ(result->BooleanValue(), true);
3858
3859
3860 script_define =
3861 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3862 " configurable: false };"
3863 "Object.defineProperty(obj, 'x', desc);"
3864 "obj.x"));
3865 result = script_define->Run();
3866 CHECK_EQ(result, v8_num(43));
3867 result = script_desc->Run();
3868
3869 CHECK_EQ(result->BooleanValue(), false);
3870
3871 v8::TryCatch try_catch;
3872 result = script_define->Run();
3873 CHECK(try_catch.HasCaught());
3874 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003875 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003876}
3877
3878
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003879static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3880 char const* name) {
3881 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3882}
ager@chromium.org5c838252010-02-19 08:53:10 +00003883
3884
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003885THREADED_TEST(DefineAPIAccessorOnObject) {
3886 v8::HandleScope scope;
3887 Local<ObjectTemplate> templ = ObjectTemplate::New();
3888 LocalContext context;
3889
3890 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3891 CompileRun("var obj2 = {};");
3892
3893 CHECK(CompileRun("obj1.x")->IsUndefined());
3894 CHECK(CompileRun("obj2.x")->IsUndefined());
3895
3896 CHECK(GetGlobalProperty(&context, "obj1")->
3897 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3898
3899 ExpectString("obj1.x", "x");
3900 CHECK(CompileRun("obj2.x")->IsUndefined());
3901
3902 CHECK(GetGlobalProperty(&context, "obj2")->
3903 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3904
3905 ExpectString("obj1.x", "x");
3906 ExpectString("obj2.x", "x");
3907
3908 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3909 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3910
3911 CompileRun("Object.defineProperty(obj1, 'x',"
3912 "{ get: function() { return 'y'; }, configurable: true })");
3913
3914 ExpectString("obj1.x", "y");
3915 ExpectString("obj2.x", "x");
3916
3917 CompileRun("Object.defineProperty(obj2, 'x',"
3918 "{ get: function() { return 'y'; }, configurable: true })");
3919
3920 ExpectString("obj1.x", "y");
3921 ExpectString("obj2.x", "y");
3922
3923 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3924 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3925
3926 CHECK(GetGlobalProperty(&context, "obj1")->
3927 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3928 CHECK(GetGlobalProperty(&context, "obj2")->
3929 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3930
3931 ExpectString("obj1.x", "x");
3932 ExpectString("obj2.x", "x");
3933
3934 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3935 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3936
3937 // Define getters/setters, but now make them not configurable.
3938 CompileRun("Object.defineProperty(obj1, 'x',"
3939 "{ get: function() { return 'z'; }, configurable: false })");
3940 CompileRun("Object.defineProperty(obj2, 'x',"
3941 "{ get: function() { return 'z'; }, configurable: false })");
3942
3943 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3944 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3945
3946 ExpectString("obj1.x", "z");
3947 ExpectString("obj2.x", "z");
3948
3949 CHECK(!GetGlobalProperty(&context, "obj1")->
3950 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3951 CHECK(!GetGlobalProperty(&context, "obj2")->
3952 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3953
3954 ExpectString("obj1.x", "z");
3955 ExpectString("obj2.x", "z");
3956}
3957
3958
3959THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3960 v8::HandleScope scope;
3961 Local<ObjectTemplate> templ = ObjectTemplate::New();
3962 LocalContext context;
3963
3964 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3965 CompileRun("var obj2 = {};");
3966
3967 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3968 v8_str("x"),
3969 GetXValue, NULL,
3970 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3971 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3972 v8_str("x"),
3973 GetXValue, NULL,
3974 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3975
3976 ExpectString("obj1.x", "x");
3977 ExpectString("obj2.x", "x");
3978
3979 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3980 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3981
3982 CHECK(!GetGlobalProperty(&context, "obj1")->
3983 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3984 CHECK(!GetGlobalProperty(&context, "obj2")->
3985 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3986
3987 {
3988 v8::TryCatch try_catch;
3989 CompileRun("Object.defineProperty(obj1, 'x',"
3990 "{get: function() { return 'func'; }})");
3991 CHECK(try_catch.HasCaught());
3992 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003993 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003994 }
3995 {
3996 v8::TryCatch try_catch;
3997 CompileRun("Object.defineProperty(obj2, 'x',"
3998 "{get: function() { return 'func'; }})");
3999 CHECK(try_catch.HasCaught());
4000 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004001 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004002 }
4003}
4004
4005
4006static v8::Handle<Value> Get239Value(Local<String> name,
4007 const AccessorInfo& info) {
4008 ApiTestFuzzer::Fuzz();
4009 CHECK_EQ(info.Data(), v8_str("donut"));
4010 CHECK_EQ(name, v8_str("239"));
4011 return name;
4012}
4013
4014
4015THREADED_TEST(ElementAPIAccessor) {
4016 v8::HandleScope scope;
4017 Local<ObjectTemplate> templ = ObjectTemplate::New();
4018 LocalContext context;
4019
4020 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4021 CompileRun("var obj2 = {};");
4022
4023 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4024 v8_str("239"),
4025 Get239Value, NULL,
4026 v8_str("donut")));
4027 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4028 v8_str("239"),
4029 Get239Value, NULL,
4030 v8_str("donut")));
4031
4032 ExpectString("obj1[239]", "239");
4033 ExpectString("obj2[239]", "239");
4034 ExpectString("obj1['239']", "239");
4035 ExpectString("obj2['239']", "239");
4036}
4037
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004038
4039v8::Persistent<Value> xValue;
4040
4041
4042static void SetXValue(Local<String> name,
4043 Local<Value> value,
4044 const AccessorInfo& info) {
4045 CHECK_EQ(value, v8_num(4));
4046 CHECK_EQ(info.Data(), v8_str("donut"));
4047 CHECK_EQ(name, v8_str("x"));
4048 CHECK(xValue.IsEmpty());
4049 xValue = v8::Persistent<Value>::New(value);
4050}
4051
4052
4053THREADED_TEST(SimplePropertyWrite) {
4054 v8::HandleScope scope;
4055 Local<ObjectTemplate> templ = ObjectTemplate::New();
4056 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
4057 LocalContext context;
4058 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4059 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
4060 for (int i = 0; i < 10; i++) {
4061 CHECK(xValue.IsEmpty());
4062 script->Run();
4063 CHECK_EQ(v8_num(4), xValue);
4064 xValue.Dispose();
4065 xValue = v8::Persistent<Value>();
4066 }
4067}
4068
4069
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004070THREADED_TEST(SetterOnly) {
4071 v8::HandleScope scope;
4072 Local<ObjectTemplate> templ = ObjectTemplate::New();
4073 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
4074 LocalContext context;
4075 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4076 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4077 for (int i = 0; i < 10; i++) {
4078 CHECK(xValue.IsEmpty());
4079 script->Run();
4080 CHECK_EQ(v8_num(4), xValue);
4081 xValue.Dispose();
4082 xValue = v8::Persistent<Value>();
4083 }
4084}
4085
4086
4087THREADED_TEST(NoAccessors) {
4088 v8::HandleScope scope;
4089 Local<ObjectTemplate> templ = ObjectTemplate::New();
4090 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
4091 LocalContext context;
4092 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4093 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4094 for (int i = 0; i < 10; i++) {
4095 script->Run();
4096 }
4097}
4098
4099
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004100static v8::Handle<Value> XPropertyGetter(Local<String> property,
4101 const AccessorInfo& info) {
4102 ApiTestFuzzer::Fuzz();
4103 CHECK(info.Data()->IsUndefined());
4104 return property;
4105}
4106
4107
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004108THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004109 v8::HandleScope scope;
4110 Local<ObjectTemplate> templ = ObjectTemplate::New();
4111 templ->SetNamedPropertyHandler(XPropertyGetter);
4112 LocalContext context;
4113 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4114 Local<Script> script = Script::Compile(v8_str("obj.x"));
4115 for (int i = 0; i < 10; i++) {
4116 Local<Value> result = script->Run();
4117 CHECK_EQ(result, v8_str("x"));
4118 }
4119}
4120
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004121
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004122THREADED_TEST(NamedInterceptorDictionaryIC) {
4123 v8::HandleScope scope;
4124 Local<ObjectTemplate> templ = ObjectTemplate::New();
4125 templ->SetNamedPropertyHandler(XPropertyGetter);
4126 LocalContext context;
4127 // Create an object with a named interceptor.
4128 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
4129 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
4130 for (int i = 0; i < 10; i++) {
4131 Local<Value> result = script->Run();
4132 CHECK_EQ(result, v8_str("x"));
4133 }
4134 // Create a slow case object and a function accessing a property in
4135 // that slow case object (with dictionary probing in generated
4136 // code). Then force object with a named interceptor into slow-case,
4137 // pass it to the function, and check that the interceptor is called
4138 // instead of accessing the local property.
4139 Local<Value> result =
4140 CompileRun("function get_x(o) { return o.x; };"
4141 "var obj = { x : 42, y : 0 };"
4142 "delete obj.y;"
4143 "for (var i = 0; i < 10; i++) get_x(obj);"
4144 "interceptor_obj.x = 42;"
4145 "interceptor_obj.y = 10;"
4146 "delete interceptor_obj.y;"
4147 "get_x(interceptor_obj)");
4148 CHECK_EQ(result, v8_str("x"));
4149}
4150
4151
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004152THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
4153 v8::HandleScope scope;
4154
4155 v8::Persistent<Context> context1 = Context::New();
4156
4157 context1->Enter();
4158 Local<ObjectTemplate> templ = ObjectTemplate::New();
4159 templ->SetNamedPropertyHandler(XPropertyGetter);
4160 // Create an object with a named interceptor.
4161 v8::Local<v8::Object> object = templ->NewInstance();
4162 context1->Global()->Set(v8_str("interceptor_obj"), object);
4163
4164 // Force the object into the slow case.
4165 CompileRun("interceptor_obj.y = 0;"
4166 "delete interceptor_obj.y;");
4167 context1->Exit();
4168
4169 {
4170 // Introduce the object into a different context.
4171 // Repeat named loads to exercise ICs.
4172 LocalContext context2;
4173 context2->Global()->Set(v8_str("interceptor_obj"), object);
4174 Local<Value> result =
4175 CompileRun("function get_x(o) { return o.x; }"
4176 "interceptor_obj.x = 42;"
4177 "for (var i=0; i != 10; i++) {"
4178 " get_x(interceptor_obj);"
4179 "}"
4180 "get_x(interceptor_obj)");
4181 // Check that the interceptor was actually invoked.
4182 CHECK_EQ(result, v8_str("x"));
4183 }
4184
4185 // Return to the original context and force some object to the slow case
4186 // to cause the NormalizedMapCache to verify.
4187 context1->Enter();
4188 CompileRun("var obj = { x : 0 }; delete obj.x;");
4189 context1->Exit();
4190
4191 context1.Dispose();
4192}
4193
4194
ager@chromium.org5c838252010-02-19 08:53:10 +00004195static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
4196 const AccessorInfo& info) {
4197 // Set x on the prototype object and do not handle the get request.
4198 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004199 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00004200 return v8::Handle<Value>();
4201}
4202
4203
4204// This is a regression test for http://crbug.com/20104. Map
4205// transitions should not interfere with post interceptor lookup.
4206THREADED_TEST(NamedInterceptorMapTransitionRead) {
4207 v8::HandleScope scope;
4208 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
4209 Local<v8::ObjectTemplate> instance_template
4210 = function_template->InstanceTemplate();
4211 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
4212 LocalContext context;
4213 context->Global()->Set(v8_str("F"), function_template->GetFunction());
4214 // Create an instance of F and introduce a map transition for x.
4215 CompileRun("var o = new F(); o.x = 23;");
4216 // Create an instance of F and invoke the getter. The result should be 23.
4217 Local<Value> result = CompileRun("o = new F(); o.x");
4218 CHECK_EQ(result->Int32Value(), 23);
4219}
4220
4221
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004222static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4223 const AccessorInfo& info) {
4224 ApiTestFuzzer::Fuzz();
4225 if (index == 37) {
4226 return v8::Handle<Value>(v8_num(625));
4227 }
4228 return v8::Handle<Value>();
4229}
4230
4231
4232static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4233 Local<Value> value,
4234 const AccessorInfo& info) {
4235 ApiTestFuzzer::Fuzz();
4236 if (index == 39) {
4237 return value;
4238 }
4239 return v8::Handle<Value>();
4240}
4241
4242
4243THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4244 v8::HandleScope scope;
4245 Local<ObjectTemplate> templ = ObjectTemplate::New();
4246 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4247 IndexedPropertySetter);
4248 LocalContext context;
4249 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4250 Local<Script> getter_script = Script::Compile(v8_str(
4251 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4252 Local<Script> setter_script = Script::Compile(v8_str(
4253 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4254 "obj[17] = 23;"
4255 "obj.foo;"));
4256 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4257 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4258 "obj[39] = 47;"
4259 "obj.foo;")); // This setter should not run, due to the interceptor.
4260 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4261 "obj[37];"));
4262 Local<Value> result = getter_script->Run();
4263 CHECK_EQ(v8_num(5), result);
4264 result = setter_script->Run();
4265 CHECK_EQ(v8_num(23), result);
4266 result = interceptor_setter_script->Run();
4267 CHECK_EQ(v8_num(23), result);
4268 result = interceptor_getter_script->Run();
4269 CHECK_EQ(v8_num(625), result);
4270}
4271
4272
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004273static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4274 uint32_t index,
4275 const AccessorInfo& info) {
4276 ApiTestFuzzer::Fuzz();
4277 if (index < 25) {
4278 return v8::Handle<Value>(v8_num(index));
4279 }
4280 return v8::Handle<Value>();
4281}
4282
4283
4284static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4285 uint32_t index,
4286 Local<Value> value,
4287 const AccessorInfo& info) {
4288 ApiTestFuzzer::Fuzz();
4289 if (index < 25) {
4290 return v8::Handle<Value>(v8_num(index));
4291 }
4292 return v8::Handle<Value>();
4293}
4294
4295
4296Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4297 const AccessorInfo& info) {
4298 // Force the list of returned keys to be stored in a FastDoubleArray.
4299 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4300 "keys = new Array(); keys[125000] = 1;"
4301 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4302 "keys.length = 25; keys;"));
4303 Local<Value> result = indexed_property_names_script->Run();
4304 return Local<v8::Array>(::v8::Array::Cast(*result));
4305}
4306
4307
4308// Make sure that the the interceptor code in the runtime properly handles
4309// merging property name lists for double-array-backed arrays.
4310THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4311 v8::HandleScope scope;
4312 Local<ObjectTemplate> templ = ObjectTemplate::New();
4313 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4314 UnboxedDoubleIndexedPropertySetter,
4315 0,
4316 0,
4317 UnboxedDoubleIndexedPropertyEnumerator);
4318 LocalContext context;
4319 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4320 // When obj is created, force it to be Stored in a FastDoubleArray.
4321 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4322 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4323 "key_count = 0; "
4324 "for (x in obj) {key_count++;};"
4325 "obj;"));
4326 Local<Value> result = create_unboxed_double_script->Run();
4327 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4328 Local<Script> key_count_check = Script::Compile(v8_str(
4329 "key_count;"));
4330 result = key_count_check->Run();
4331 CHECK_EQ(v8_num(40013), result);
4332}
4333
4334
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004335Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4336 const AccessorInfo& info) {
4337 // Force the list of returned keys to be stored in a Arguments object.
4338 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4339 "function f(w,x) {"
4340 " return arguments;"
4341 "}"
4342 "keys = f(0, 1, 2, 3);"
4343 "keys;"));
4344 Local<Value> result = indexed_property_names_script->Run();
4345 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4346}
4347
4348
4349static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4350 uint32_t index,
4351 const AccessorInfo& info) {
4352 ApiTestFuzzer::Fuzz();
4353 if (index < 4) {
4354 return v8::Handle<Value>(v8_num(index));
4355 }
4356 return v8::Handle<Value>();
4357}
4358
4359
4360// Make sure that the the interceptor code in the runtime properly handles
4361// merging property name lists for non-string arguments arrays.
4362THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4363 v8::HandleScope scope;
4364 Local<ObjectTemplate> templ = ObjectTemplate::New();
4365 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4366 0,
4367 0,
4368 0,
4369 NonStrictArgsIndexedPropertyEnumerator);
4370 LocalContext context;
4371 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4372 Local<Script> create_args_script =
4373 Script::Compile(v8_str(
4374 "var key_count = 0;"
4375 "for (x in obj) {key_count++;} key_count;"));
4376 Local<Value> result = create_args_script->Run();
4377 CHECK_EQ(v8_num(4), result);
4378}
4379
4380
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004381static v8::Handle<Value> IdentityIndexedPropertyGetter(
4382 uint32_t index,
4383 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004384 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004385}
4386
4387
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004388THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4389 v8::HandleScope scope;
4390 Local<ObjectTemplate> templ = ObjectTemplate::New();
4391 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4392
4393 LocalContext context;
4394 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4395
4396 // Check fast object case.
4397 const char* fast_case_code =
4398 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4399 ExpectString(fast_case_code, "0");
4400
4401 // Check slow case.
4402 const char* slow_case_code =
4403 "obj.x = 1; delete obj.x;"
4404 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4405 ExpectString(slow_case_code, "1");
4406}
4407
4408
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004409THREADED_TEST(IndexedInterceptorWithNoSetter) {
4410 v8::HandleScope scope;
4411 Local<ObjectTemplate> templ = ObjectTemplate::New();
4412 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4413
4414 LocalContext context;
4415 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4416
4417 const char* code =
4418 "try {"
4419 " obj[0] = 239;"
4420 " for (var i = 0; i < 100; i++) {"
4421 " var v = obj[0];"
4422 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4423 " }"
4424 " 'PASSED'"
4425 "} catch(e) {"
4426 " e"
4427 "}";
4428 ExpectString(code, "PASSED");
4429}
4430
4431
ager@chromium.org5c838252010-02-19 08:53:10 +00004432THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4433 v8::HandleScope scope;
4434 Local<ObjectTemplate> templ = ObjectTemplate::New();
4435 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4436
4437 LocalContext context;
4438 Local<v8::Object> obj = templ->NewInstance();
4439 obj->TurnOnAccessCheck();
4440 context->Global()->Set(v8_str("obj"), obj);
4441
4442 const char* code =
4443 "try {"
4444 " for (var i = 0; i < 100; i++) {"
4445 " var v = obj[0];"
4446 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4447 " }"
4448 " 'PASSED'"
4449 "} catch(e) {"
4450 " e"
4451 "}";
4452 ExpectString(code, "PASSED");
4453}
4454
4455
4456THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4457 i::FLAG_allow_natives_syntax = true;
4458 v8::HandleScope scope;
4459 Local<ObjectTemplate> templ = ObjectTemplate::New();
4460 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4461
4462 LocalContext context;
4463 Local<v8::Object> obj = templ->NewInstance();
4464 context->Global()->Set(v8_str("obj"), obj);
4465
4466 const char* code =
4467 "try {"
4468 " for (var i = 0; i < 100; i++) {"
4469 " var expected = i;"
4470 " if (i == 5) {"
4471 " %EnableAccessChecks(obj);"
4472 " expected = undefined;"
4473 " }"
4474 " var v = obj[i];"
4475 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4476 " if (i == 5) %DisableAccessChecks(obj);"
4477 " }"
4478 " 'PASSED'"
4479 "} catch(e) {"
4480 " e"
4481 "}";
4482 ExpectString(code, "PASSED");
4483}
4484
4485
4486THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4487 v8::HandleScope scope;
4488 Local<ObjectTemplate> templ = ObjectTemplate::New();
4489 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4490
4491 LocalContext context;
4492 Local<v8::Object> obj = templ->NewInstance();
4493 context->Global()->Set(v8_str("obj"), obj);
4494
4495 const char* code =
4496 "try {"
4497 " for (var i = 0; i < 100; i++) {"
4498 " var v = obj[i];"
4499 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4500 " }"
4501 " 'PASSED'"
4502 "} catch(e) {"
4503 " e"
4504 "}";
4505 ExpectString(code, "PASSED");
4506}
4507
4508
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004509THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4510 v8::HandleScope scope;
4511 Local<ObjectTemplate> templ = ObjectTemplate::New();
4512 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4513
4514 LocalContext context;
4515 Local<v8::Object> obj = templ->NewInstance();
4516 context->Global()->Set(v8_str("obj"), obj);
4517
4518 const char* code =
4519 "try {"
4520 " for (var i = 0; i < 100; i++) {"
4521 " var expected = i;"
4522 " var key = i;"
4523 " if (i == 25) {"
4524 " key = -1;"
4525 " expected = undefined;"
4526 " }"
4527 " if (i == 50) {"
4528 " /* probe minimal Smi number on 32-bit platforms */"
4529 " key = -(1 << 30);"
4530 " expected = undefined;"
4531 " }"
4532 " if (i == 75) {"
4533 " /* probe minimal Smi number on 64-bit platforms */"
4534 " key = 1 << 31;"
4535 " expected = undefined;"
4536 " }"
4537 " var v = obj[key];"
4538 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4539 " }"
4540 " 'PASSED'"
4541 "} catch(e) {"
4542 " e"
4543 "}";
4544 ExpectString(code, "PASSED");
4545}
4546
4547
ager@chromium.org5c838252010-02-19 08:53:10 +00004548THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4549 v8::HandleScope scope;
4550 Local<ObjectTemplate> templ = ObjectTemplate::New();
4551 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4552
4553 LocalContext context;
4554 Local<v8::Object> obj = templ->NewInstance();
4555 context->Global()->Set(v8_str("obj"), obj);
4556
4557 const char* code =
4558 "try {"
4559 " for (var i = 0; i < 100; i++) {"
4560 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004561 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004562 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004563 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004564 " expected = undefined;"
4565 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004566 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004567 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4568 " }"
4569 " 'PASSED'"
4570 "} catch(e) {"
4571 " e"
4572 "}";
4573 ExpectString(code, "PASSED");
4574}
4575
4576
4577THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4578 v8::HandleScope scope;
4579 Local<ObjectTemplate> templ = ObjectTemplate::New();
4580 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4581
4582 LocalContext context;
4583 Local<v8::Object> obj = templ->NewInstance();
4584 context->Global()->Set(v8_str("obj"), obj);
4585
4586 const char* code =
4587 "var original = obj;"
4588 "try {"
4589 " for (var i = 0; i < 100; i++) {"
4590 " var expected = i;"
4591 " if (i == 50) {"
4592 " obj = {50: 'foobar'};"
4593 " expected = 'foobar';"
4594 " }"
4595 " var v = obj[i];"
4596 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4597 " if (i == 50) obj = original;"
4598 " }"
4599 " 'PASSED'"
4600 "} catch(e) {"
4601 " e"
4602 "}";
4603 ExpectString(code, "PASSED");
4604}
4605
4606
4607THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4608 v8::HandleScope scope;
4609 Local<ObjectTemplate> templ = ObjectTemplate::New();
4610 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4611
4612 LocalContext context;
4613 Local<v8::Object> obj = templ->NewInstance();
4614 context->Global()->Set(v8_str("obj"), obj);
4615
4616 const char* code =
4617 "var original = obj;"
4618 "try {"
4619 " for (var i = 0; i < 100; i++) {"
4620 " var expected = i;"
4621 " if (i == 5) {"
4622 " obj = 239;"
4623 " expected = undefined;"
4624 " }"
4625 " var v = obj[i];"
4626 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4627 " if (i == 5) obj = original;"
4628 " }"
4629 " 'PASSED'"
4630 "} catch(e) {"
4631 " e"
4632 "}";
4633 ExpectString(code, "PASSED");
4634}
4635
4636
4637THREADED_TEST(IndexedInterceptorOnProto) {
4638 v8::HandleScope scope;
4639 Local<ObjectTemplate> templ = ObjectTemplate::New();
4640 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4641
4642 LocalContext context;
4643 Local<v8::Object> obj = templ->NewInstance();
4644 context->Global()->Set(v8_str("obj"), obj);
4645
4646 const char* code =
4647 "var o = {__proto__: obj};"
4648 "try {"
4649 " for (var i = 0; i < 100; i++) {"
4650 " var v = o[i];"
4651 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4652 " }"
4653 " 'PASSED'"
4654 "} catch(e) {"
4655 " e"
4656 "}";
4657 ExpectString(code, "PASSED");
4658}
4659
4660
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004661THREADED_TEST(MultiContexts) {
4662 v8::HandleScope scope;
4663 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4664 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4665
4666 Local<String> password = v8_str("Password");
4667
4668 // Create an environment
4669 LocalContext context0(0, templ);
4670 context0->SetSecurityToken(password);
4671 v8::Handle<v8::Object> global0 = context0->Global();
4672 global0->Set(v8_str("custom"), v8_num(1234));
4673 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4674
4675 // Create an independent environment
4676 LocalContext context1(0, templ);
4677 context1->SetSecurityToken(password);
4678 v8::Handle<v8::Object> global1 = context1->Global();
4679 global1->Set(v8_str("custom"), v8_num(1234));
4680 CHECK_NE(global0, global1);
4681 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4682 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4683
4684 // Now create a new context with the old global
4685 LocalContext context2(0, templ, global1);
4686 context2->SetSecurityToken(password);
4687 v8::Handle<v8::Object> global2 = context2->Global();
4688 CHECK_EQ(global1, global2);
4689 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4690 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4691}
4692
4693
4694THREADED_TEST(FunctionPrototypeAcrossContexts) {
4695 // Make sure that functions created by cloning boilerplates cannot
4696 // communicate through their __proto__ field.
4697
4698 v8::HandleScope scope;
4699
4700 LocalContext env0;
4701 v8::Handle<v8::Object> global0 =
4702 env0->Global();
4703 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004704 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004705 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004706 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004707 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004708 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004709 proto0->Set(v8_str("custom"), v8_num(1234));
4710
4711 LocalContext env1;
4712 v8::Handle<v8::Object> global1 =
4713 env1->Global();
4714 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004715 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004716 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004717 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004718 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004719 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004720 CHECK(!proto1->Has(v8_str("custom")));
4721}
4722
4723
4724THREADED_TEST(Regress892105) {
4725 // Make sure that object and array literals created by cloning
4726 // boilerplates cannot communicate through their __proto__
4727 // field. This is rather difficult to check, but we try to add stuff
4728 // to Object.prototype and Array.prototype and create a new
4729 // environment. This should succeed.
4730
4731 v8::HandleScope scope;
4732
4733 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4734 "Array.prototype.arr = 4567;"
4735 "8901");
4736
4737 LocalContext env0;
4738 Local<Script> script0 = Script::Compile(source);
4739 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4740
4741 LocalContext env1;
4742 Local<Script> script1 = Script::Compile(source);
4743 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4744}
4745
4746
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004747THREADED_TEST(UndetectableObject) {
4748 v8::HandleScope scope;
4749 LocalContext env;
4750
4751 Local<v8::FunctionTemplate> desc =
4752 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4753 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4754
4755 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4756 env->Global()->Set(v8_str("undetectable"), obj);
4757
4758 ExpectString("undetectable.toString()", "[object Object]");
4759 ExpectString("typeof undetectable", "undefined");
4760 ExpectString("typeof(undetectable)", "undefined");
4761 ExpectBoolean("typeof undetectable == 'undefined'", true);
4762 ExpectBoolean("typeof undetectable == 'object'", false);
4763 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4764 ExpectBoolean("!undetectable", true);
4765
4766 ExpectObject("true&&undetectable", obj);
4767 ExpectBoolean("false&&undetectable", false);
4768 ExpectBoolean("true||undetectable", true);
4769 ExpectObject("false||undetectable", obj);
4770
4771 ExpectObject("undetectable&&true", obj);
4772 ExpectObject("undetectable&&false", obj);
4773 ExpectBoolean("undetectable||true", true);
4774 ExpectBoolean("undetectable||false", false);
4775
4776 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004777 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004778 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004779 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004780 ExpectBoolean("undetectable==undetectable", true);
4781
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004782
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004783 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004784 ExpectBoolean("null===undetectable", false);
4785 ExpectBoolean("undetectable===undefined", false);
4786 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004787 ExpectBoolean("undetectable===undetectable", true);
4788}
4789
4790
ager@chromium.org04921a82011-06-27 13:21:41 +00004791THREADED_TEST(VoidLiteral) {
4792 v8::HandleScope scope;
4793 LocalContext env;
4794
4795 Local<v8::FunctionTemplate> desc =
4796 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4797 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4798
4799 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4800 env->Global()->Set(v8_str("undetectable"), obj);
4801
4802 ExpectBoolean("undefined == void 0", true);
4803 ExpectBoolean("undetectable == void 0", true);
4804 ExpectBoolean("null == void 0", true);
4805 ExpectBoolean("undefined === void 0", true);
4806 ExpectBoolean("undetectable === void 0", false);
4807 ExpectBoolean("null === void 0", false);
4808
4809 ExpectBoolean("void 0 == undefined", true);
4810 ExpectBoolean("void 0 == undetectable", true);
4811 ExpectBoolean("void 0 == null", true);
4812 ExpectBoolean("void 0 === undefined", true);
4813 ExpectBoolean("void 0 === undetectable", false);
4814 ExpectBoolean("void 0 === null", false);
4815
4816 ExpectString("(function() {"
4817 " try {"
4818 " return x === void 0;"
4819 " } catch(e) {"
4820 " return e.toString();"
4821 " }"
4822 "})()",
4823 "ReferenceError: x is not defined");
4824 ExpectString("(function() {"
4825 " try {"
4826 " return void 0 === x;"
4827 " } catch(e) {"
4828 " return e.toString();"
4829 " }"
4830 "})()",
4831 "ReferenceError: x is not defined");
4832}
4833
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004834
4835THREADED_TEST(ExtensibleOnUndetectable) {
4836 v8::HandleScope scope;
4837 LocalContext env;
4838
4839 Local<v8::FunctionTemplate> desc =
4840 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4841 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4842
4843 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4844 env->Global()->Set(v8_str("undetectable"), obj);
4845
4846 Local<String> source = v8_str("undetectable.x = 42;"
4847 "undetectable.x");
4848
4849 Local<Script> script = Script::Compile(source);
4850
4851 CHECK_EQ(v8::Integer::New(42), script->Run());
4852
4853 ExpectBoolean("Object.isExtensible(undetectable)", true);
4854
4855 source = v8_str("Object.preventExtensions(undetectable);");
4856 script = Script::Compile(source);
4857 script->Run();
4858 ExpectBoolean("Object.isExtensible(undetectable)", false);
4859
4860 source = v8_str("undetectable.y = 2000;");
4861 script = Script::Compile(source);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004862 script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004863 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004864}
4865
4866
4867
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004868THREADED_TEST(UndetectableString) {
4869 v8::HandleScope scope;
4870 LocalContext env;
4871
4872 Local<String> obj = String::NewUndetectable("foo");
4873 env->Global()->Set(v8_str("undetectable"), obj);
4874
4875 ExpectString("undetectable", "foo");
4876 ExpectString("typeof undetectable", "undefined");
4877 ExpectString("typeof(undetectable)", "undefined");
4878 ExpectBoolean("typeof undetectable == 'undefined'", true);
4879 ExpectBoolean("typeof undetectable == 'string'", false);
4880 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4881 ExpectBoolean("!undetectable", true);
4882
4883 ExpectObject("true&&undetectable", obj);
4884 ExpectBoolean("false&&undetectable", false);
4885 ExpectBoolean("true||undetectable", true);
4886 ExpectObject("false||undetectable", obj);
4887
4888 ExpectObject("undetectable&&true", obj);
4889 ExpectObject("undetectable&&false", obj);
4890 ExpectBoolean("undetectable||true", true);
4891 ExpectBoolean("undetectable||false", false);
4892
4893 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004894 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004895 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004896 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004897 ExpectBoolean("undetectable==undetectable", true);
4898
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004899
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004900 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004901 ExpectBoolean("null===undetectable", false);
4902 ExpectBoolean("undetectable===undefined", false);
4903 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004904 ExpectBoolean("undetectable===undetectable", true);
4905}
4906
4907
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004908TEST(UndetectableOptimized) {
4909 i::FLAG_allow_natives_syntax = true;
4910 v8::HandleScope scope;
4911 LocalContext env;
4912
4913 Local<String> obj = String::NewUndetectable("foo");
4914 env->Global()->Set(v8_str("undetectable"), obj);
4915 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4916
4917 ExpectString(
4918 "function testBranch() {"
4919 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4920 " if (%_IsUndetectableObject(detectable)) throw 2;"
4921 "}\n"
4922 "function testBool() {"
4923 " var b1 = !%_IsUndetectableObject(undetectable);"
4924 " var b2 = %_IsUndetectableObject(detectable);"
4925 " if (b1) throw 3;"
4926 " if (b2) throw 4;"
4927 " return b1 == b2;"
4928 "}\n"
4929 "%OptimizeFunctionOnNextCall(testBranch);"
4930 "%OptimizeFunctionOnNextCall(testBool);"
4931 "for (var i = 0; i < 10; i++) {"
4932 " testBranch();"
4933 " testBool();"
4934 "}\n"
4935 "\"PASS\"",
4936 "PASS");
4937}
4938
4939
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004940template <typename T> static void USE(T) { }
4941
4942
4943// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004944static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004945 USE(PersistentHandles);
4946 Local<String> str = v8_str("foo");
4947 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4948 USE(p_str);
4949 Local<Script> scr = Script::Compile(v8_str(""));
4950 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4951 USE(p_scr);
4952 Local<ObjectTemplate> templ = ObjectTemplate::New();
4953 v8::Persistent<ObjectTemplate> p_templ =
4954 v8::Persistent<ObjectTemplate>::New(templ);
4955 USE(p_templ);
4956}
4957
4958
4959static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4960 ApiTestFuzzer::Fuzz();
4961 return v8::Undefined();
4962}
4963
4964
4965THREADED_TEST(GlobalObjectTemplate) {
4966 v8::HandleScope handle_scope;
4967 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4968 global_template->Set(v8_str("JSNI_Log"),
4969 v8::FunctionTemplate::New(HandleLogDelegator));
4970 v8::Persistent<Context> context = Context::New(0, global_template);
4971 Context::Scope context_scope(context);
4972 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4973 context.Dispose();
4974}
4975
4976
4977static const char* kSimpleExtensionSource =
4978 "function Foo() {"
4979 " return 4;"
4980 "}";
4981
4982
4983THREADED_TEST(SimpleExtensions) {
4984 v8::HandleScope handle_scope;
4985 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4986 const char* extension_names[] = { "simpletest" };
4987 v8::ExtensionConfiguration extensions(1, extension_names);
4988 v8::Handle<Context> context = Context::New(&extensions);
4989 Context::Scope lock(context);
4990 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4991 CHECK_EQ(result, v8::Integer::New(4));
4992}
4993
4994
danno@chromium.org412fa512012-09-14 13:28:26 +00004995THREADED_TEST(NullExtensions) {
4996 v8::HandleScope handle_scope;
4997 v8::RegisterExtension(new Extension("nulltest", NULL));
4998 const char* extension_names[] = { "nulltest" };
4999 v8::ExtensionConfiguration extensions(1, extension_names);
5000 v8::Handle<Context> context = Context::New(&extensions);
5001 Context::Scope lock(context);
5002 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
5003 CHECK_EQ(result, v8::Integer::New(4));
5004}
5005
5006
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005007static const char* kEmbeddedExtensionSource =
5008 "function Ret54321(){return 54321;}~~@@$"
5009 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5010static const int kEmbeddedExtensionSourceValidLen = 34;
5011
5012
5013THREADED_TEST(ExtensionMissingSourceLength) {
5014 v8::HandleScope handle_scope;
5015 v8::RegisterExtension(new Extension("srclentest_fail",
5016 kEmbeddedExtensionSource));
5017 const char* extension_names[] = { "srclentest_fail" };
5018 v8::ExtensionConfiguration extensions(1, extension_names);
5019 v8::Handle<Context> context = Context::New(&extensions);
5020 CHECK_EQ(0, *context);
5021}
5022
5023
5024THREADED_TEST(ExtensionWithSourceLength) {
5025 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5026 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5027 v8::HandleScope handle_scope;
5028 i::ScopedVector<char> extension_name(32);
5029 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5030 v8::RegisterExtension(new Extension(extension_name.start(),
5031 kEmbeddedExtensionSource, 0, 0,
5032 source_len));
5033 const char* extension_names[1] = { extension_name.start() };
5034 v8::ExtensionConfiguration extensions(1, extension_names);
5035 v8::Handle<Context> context = Context::New(&extensions);
5036 if (source_len == kEmbeddedExtensionSourceValidLen) {
5037 Context::Scope lock(context);
5038 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
5039 CHECK_EQ(v8::Integer::New(54321), result);
5040 } else {
5041 // Anything but exactly the right length should fail to compile.
5042 CHECK_EQ(0, *context);
5043 }
5044 }
5045}
5046
5047
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005048static const char* kEvalExtensionSource1 =
5049 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005050 " var x = 42;"
5051 " return eval('x');"
5052 "}";
5053
5054
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005055static const char* kEvalExtensionSource2 =
5056 "(function() {"
5057 " var x = 42;"
5058 " function e() {"
5059 " return eval('x');"
5060 " }"
5061 " this.UseEval2 = e;"
5062 "})()";
5063
5064
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005065THREADED_TEST(UseEvalFromExtension) {
5066 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005067 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
5068 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
5069 const char* extension_names[] = { "evaltest1", "evaltest2" };
5070 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005071 v8::Handle<Context> context = Context::New(&extensions);
5072 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005073 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
5074 CHECK_EQ(result, v8::Integer::New(42));
5075 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005076 CHECK_EQ(result, v8::Integer::New(42));
5077}
5078
5079
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005080static const char* kWithExtensionSource1 =
5081 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005082 " var x = 42;"
5083 " with({x:87}) { return x; }"
5084 "}";
5085
5086
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005087
5088static const char* kWithExtensionSource2 =
5089 "(function() {"
5090 " var x = 42;"
5091 " function e() {"
5092 " with ({x:87}) { return x; }"
5093 " }"
5094 " this.UseWith2 = e;"
5095 "})()";
5096
5097
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005098THREADED_TEST(UseWithFromExtension) {
5099 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005100 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
5101 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
5102 const char* extension_names[] = { "withtest1", "withtest2" };
5103 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005104 v8::Handle<Context> context = Context::New(&extensions);
5105 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005106 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
5107 CHECK_EQ(result, v8::Integer::New(87));
5108 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005109 CHECK_EQ(result, v8::Integer::New(87));
5110}
5111
5112
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005113THREADED_TEST(AutoExtensions) {
5114 v8::HandleScope handle_scope;
5115 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5116 extension->set_auto_enable(true);
5117 v8::RegisterExtension(extension);
5118 v8::Handle<Context> context = Context::New();
5119 Context::Scope lock(context);
5120 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5121 CHECK_EQ(result, v8::Integer::New(4));
5122}
5123
5124
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005125static const char* kSyntaxErrorInExtensionSource =
5126 "[";
5127
5128
5129// Test that a syntax error in an extension does not cause a fatal
5130// error but results in an empty context.
5131THREADED_TEST(SyntaxErrorExtensions) {
5132 v8::HandleScope handle_scope;
5133 v8::RegisterExtension(new Extension("syntaxerror",
5134 kSyntaxErrorInExtensionSource));
5135 const char* extension_names[] = { "syntaxerror" };
5136 v8::ExtensionConfiguration extensions(1, extension_names);
5137 v8::Handle<Context> context = Context::New(&extensions);
5138 CHECK(context.IsEmpty());
5139}
5140
5141
5142static const char* kExceptionInExtensionSource =
5143 "throw 42";
5144
5145
5146// Test that an exception when installing an extension does not cause
5147// a fatal error but results in an empty context.
5148THREADED_TEST(ExceptionExtensions) {
5149 v8::HandleScope handle_scope;
5150 v8::RegisterExtension(new Extension("exception",
5151 kExceptionInExtensionSource));
5152 const char* extension_names[] = { "exception" };
5153 v8::ExtensionConfiguration extensions(1, extension_names);
5154 v8::Handle<Context> context = Context::New(&extensions);
5155 CHECK(context.IsEmpty());
5156}
5157
5158
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005159static const char* kNativeCallInExtensionSource =
5160 "function call_runtime_last_index_of(x) {"
5161 " return %StringLastIndexOf(x, 'bob', 10);"
5162 "}";
5163
5164
5165static const char* kNativeCallTest =
5166 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
5167
5168// Test that a native runtime calls are supported in extensions.
5169THREADED_TEST(NativeCallInExtensions) {
5170 v8::HandleScope handle_scope;
5171 v8::RegisterExtension(new Extension("nativecall",
5172 kNativeCallInExtensionSource));
5173 const char* extension_names[] = { "nativecall" };
5174 v8::ExtensionConfiguration extensions(1, extension_names);
5175 v8::Handle<Context> context = Context::New(&extensions);
5176 Context::Scope lock(context);
5177 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
5178 CHECK_EQ(result, v8::Integer::New(3));
5179}
5180
5181
whesse@chromium.org7b260152011-06-20 15:33:18 +00005182class NativeFunctionExtension : public Extension {
5183 public:
5184 NativeFunctionExtension(const char* name,
5185 const char* source,
5186 v8::InvocationCallback fun = &Echo)
5187 : Extension(name, source),
5188 function_(fun) { }
5189
5190 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5191 v8::Handle<v8::String> name) {
5192 return v8::FunctionTemplate::New(function_);
5193 }
5194
5195 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
5196 if (args.Length() >= 1) return (args[0]);
5197 return v8::Undefined();
5198 }
5199 private:
5200 v8::InvocationCallback function_;
5201};
5202
5203
5204THREADED_TEST(NativeFunctionDeclaration) {
5205 v8::HandleScope handle_scope;
5206 const char* name = "nativedecl";
5207 v8::RegisterExtension(new NativeFunctionExtension(name,
5208 "native function foo();"));
5209 const char* extension_names[] = { name };
5210 v8::ExtensionConfiguration extensions(1, extension_names);
5211 v8::Handle<Context> context = Context::New(&extensions);
5212 Context::Scope lock(context);
5213 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
5214 CHECK_EQ(result, v8::Integer::New(42));
5215}
5216
5217
5218THREADED_TEST(NativeFunctionDeclarationError) {
5219 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005220 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005221 // Syntax error in extension code.
5222 v8::RegisterExtension(new NativeFunctionExtension(name,
5223 "native\nfunction foo();"));
5224 const char* extension_names[] = { name };
5225 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005226 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005227 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005228}
5229
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005230
whesse@chromium.org7b260152011-06-20 15:33:18 +00005231THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5232 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005233 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005234 // Syntax error in extension code - escape code in "native" means that
5235 // it's not treated as a keyword.
5236 v8::RegisterExtension(new NativeFunctionExtension(
5237 name,
5238 "nativ\\u0065 function foo();"));
5239 const char* extension_names[] = { name };
5240 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005241 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005242 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005243}
5244
5245
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005246static void CheckDependencies(const char* name, const char* expected) {
5247 v8::HandleScope handle_scope;
5248 v8::ExtensionConfiguration config(1, &name);
5249 LocalContext context(&config);
5250 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5251}
5252
5253
5254/*
5255 * Configuration:
5256 *
5257 * /-- B <--\
5258 * A <- -- D <-- E
5259 * \-- C <--/
5260 */
5261THREADED_TEST(ExtensionDependency) {
5262 static const char* kEDeps[] = { "D" };
5263 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5264 static const char* kDDeps[] = { "B", "C" };
5265 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5266 static const char* kBCDeps[] = { "A" };
5267 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5268 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5269 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5270 CheckDependencies("A", "undefinedA");
5271 CheckDependencies("B", "undefinedAB");
5272 CheckDependencies("C", "undefinedAC");
5273 CheckDependencies("D", "undefinedABCD");
5274 CheckDependencies("E", "undefinedABCDE");
5275 v8::HandleScope handle_scope;
5276 static const char* exts[2] = { "C", "E" };
5277 v8::ExtensionConfiguration config(2, exts);
5278 LocalContext context(&config);
5279 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5280}
5281
5282
5283static const char* kExtensionTestScript =
5284 "native function A();"
5285 "native function B();"
5286 "native function C();"
5287 "function Foo(i) {"
5288 " if (i == 0) return A();"
5289 " if (i == 1) return B();"
5290 " if (i == 2) return C();"
5291 "}";
5292
5293
5294static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5295 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005296 if (args.IsConstructCall()) {
5297 args.This()->Set(v8_str("data"), args.Data());
5298 return v8::Null();
5299 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005300 return args.Data();
5301}
5302
5303
5304class FunctionExtension : public Extension {
5305 public:
5306 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5307 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5308 v8::Handle<String> name);
5309};
5310
5311
5312static int lookup_count = 0;
5313v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5314 v8::Handle<String> name) {
5315 lookup_count++;
5316 if (name->Equals(v8_str("A"))) {
5317 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5318 } else if (name->Equals(v8_str("B"))) {
5319 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5320 } else if (name->Equals(v8_str("C"))) {
5321 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5322 } else {
5323 return v8::Handle<v8::FunctionTemplate>();
5324 }
5325}
5326
5327
5328THREADED_TEST(FunctionLookup) {
5329 v8::RegisterExtension(new FunctionExtension());
5330 v8::HandleScope handle_scope;
5331 static const char* exts[1] = { "functiontest" };
5332 v8::ExtensionConfiguration config(1, exts);
5333 LocalContext context(&config);
5334 CHECK_EQ(3, lookup_count);
5335 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5336 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5337 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5338}
5339
5340
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005341THREADED_TEST(NativeFunctionConstructCall) {
5342 v8::RegisterExtension(new FunctionExtension());
5343 v8::HandleScope handle_scope;
5344 static const char* exts[1] = { "functiontest" };
5345 v8::ExtensionConfiguration config(1, exts);
5346 LocalContext context(&config);
5347 for (int i = 0; i < 10; i++) {
5348 // Run a few times to ensure that allocation of objects doesn't
5349 // change behavior of a constructor function.
5350 CHECK_EQ(v8::Integer::New(8),
5351 Script::Compile(v8_str("(new A()).data"))->Run());
5352 CHECK_EQ(v8::Integer::New(7),
5353 Script::Compile(v8_str("(new B()).data"))->Run());
5354 CHECK_EQ(v8::Integer::New(6),
5355 Script::Compile(v8_str("(new C()).data"))->Run());
5356 }
5357}
5358
5359
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005360static const char* last_location;
5361static const char* last_message;
5362void StoringErrorCallback(const char* location, const char* message) {
5363 if (last_location == NULL) {
5364 last_location = location;
5365 last_message = message;
5366 }
5367}
5368
5369
5370// ErrorReporting creates a circular extensions configuration and
5371// tests that the fatal error handler gets called. This renders V8
5372// unusable and therefore this test cannot be run in parallel.
5373TEST(ErrorReporting) {
5374 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5375 static const char* aDeps[] = { "B" };
5376 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5377 static const char* bDeps[] = { "A" };
5378 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5379 last_location = NULL;
5380 v8::ExtensionConfiguration config(1, bDeps);
5381 v8::Handle<Context> context = Context::New(&config);
5382 CHECK(context.IsEmpty());
5383 CHECK_NE(last_location, NULL);
5384}
5385
5386
ager@chromium.org7c537e22008-10-16 08:43:32 +00005387static const char* js_code_causing_huge_string_flattening =
5388 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00005389 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00005390 " str = str + str;"
5391 "}"
5392 "str.match(/X/);";
5393
5394
5395void OOMCallback(const char* location, const char* message) {
5396 exit(0);
5397}
5398
5399
5400TEST(RegexpOutOfMemory) {
5401 // Execute a script that causes out of memory when flattening a string.
5402 v8::HandleScope scope;
5403 v8::V8::SetFatalErrorHandler(OOMCallback);
5404 LocalContext context;
5405 Local<Script> script =
5406 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5407 last_location = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005408 script->Run();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005409
5410 CHECK(false); // Should not return.
5411}
5412
5413
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005414static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5415 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005416 CHECK(message->GetScriptResourceName()->IsUndefined());
5417 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005418 message->GetLineNumber();
5419 message->GetSourceLine();
5420}
5421
5422
5423THREADED_TEST(ErrorWithMissingScriptInfo) {
5424 v8::HandleScope scope;
5425 LocalContext context;
5426 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5427 Script::Compile(v8_str("throw Error()"))->Run();
5428 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5429}
5430
5431
5432int global_index = 0;
5433
5434class Snorkel {
5435 public:
5436 Snorkel() { index_ = global_index++; }
5437 int index_;
5438};
5439
5440class Whammy {
5441 public:
5442 Whammy() {
5443 cursor_ = 0;
5444 }
5445 ~Whammy() {
5446 script_.Dispose();
5447 }
5448 v8::Handle<Script> getScript() {
5449 if (script_.IsEmpty())
5450 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5451 return Local<Script>(*script_);
5452 }
5453
5454 public:
5455 static const int kObjectCount = 256;
5456 int cursor_;
5457 v8::Persistent<v8::Object> objects_[kObjectCount];
5458 v8::Persistent<Script> script_;
5459};
5460
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005461static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005462 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5463 delete snorkel;
5464 obj.ClearWeak();
5465}
5466
5467v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5468 const AccessorInfo& info) {
5469 Whammy* whammy =
5470 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5471
5472 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5473
5474 v8::Handle<v8::Object> obj = v8::Object::New();
5475 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5476 if (!prev.IsEmpty()) {
5477 prev->Set(v8_str("next"), obj);
5478 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5479 whammy->objects_[whammy->cursor_].Clear();
5480 }
5481 whammy->objects_[whammy->cursor_] = global;
5482 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5483 return whammy->getScript()->Run();
5484}
5485
5486THREADED_TEST(WeakReference) {
5487 v8::HandleScope handle_scope;
5488 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005489 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005490 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5491 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005492 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005493 const char* extension_list[] = { "v8/gc" };
5494 v8::ExtensionConfiguration extensions(1, extension_list);
5495 v8::Persistent<Context> context = Context::New(&extensions);
5496 Context::Scope context_scope(context);
5497
5498 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5499 context->Global()->Set(v8_str("whammy"), interceptor);
5500 const char* code =
5501 "var last;"
5502 "for (var i = 0; i < 10000; i++) {"
5503 " var obj = whammy.length;"
5504 " if (last) last.next = obj;"
5505 " last = obj;"
5506 "}"
5507 "gc();"
5508 "4";
5509 v8::Handle<Value> result = CompileRun(code);
5510 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005511 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005512 context.Dispose();
5513}
5514
5515
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005516static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005517 obj.Dispose();
5518 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005519 *(reinterpret_cast<bool*>(data)) = true;
5520}
5521
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005522
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005523THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005524 v8::Persistent<Context> context = Context::New();
5525 Context::Scope context_scope(context);
5526
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005527 v8::Persistent<v8::Object> object_a, object_b;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005528
5529 {
5530 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005531 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005532 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005533 }
5534
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005535 v8::Isolate* isolate = v8::Isolate::GetCurrent();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005536 bool object_a_disposed = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005537 bool object_b_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005538 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005539 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005540 CHECK(!object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005541 CHECK(!object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005542 object_a.MarkIndependent();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005543 object_b.MarkIndependent(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005544 CHECK(object_a.IsIndependent());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005545 CHECK(object_b.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005546 HEAP->PerformScavenge();
5547 CHECK(object_a_disposed);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005548 CHECK(object_b_disposed);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005549}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005550
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005551
5552static void InvokeScavenge() {
5553 HEAP->PerformScavenge();
5554}
5555
5556
5557static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005558 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005559}
5560
5561
5562static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5563 obj.Dispose();
5564 obj.Clear();
5565 *(reinterpret_cast<bool*>(data)) = true;
5566 InvokeScavenge();
5567}
5568
5569
5570static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5571 obj.Dispose();
5572 obj.Clear();
5573 *(reinterpret_cast<bool*>(data)) = true;
5574 InvokeMarkSweep();
5575}
5576
5577
5578THREADED_TEST(GCFromWeakCallbacks) {
5579 v8::Persistent<Context> context = Context::New();
5580 Context::Scope context_scope(context);
5581
5582 static const int kNumberOfGCTypes = 2;
5583 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5584 {&ForceScavenge, &ForceMarkSweep};
5585
5586 typedef void (*GCInvoker)();
5587 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5588
5589 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5590 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5591 v8::Persistent<v8::Object> object;
5592 {
5593 v8::HandleScope handle_scope;
5594 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5595 }
5596 bool disposed = false;
5597 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5598 object.MarkIndependent();
5599 invoke_gc[outer_gc]();
5600 CHECK(disposed);
5601 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005602 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005603}
5604
5605
5606static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5607 obj.ClearWeak();
5608 *(reinterpret_cast<bool*>(data)) = true;
5609}
5610
5611
5612THREADED_TEST(IndependentHandleRevival) {
5613 v8::Persistent<Context> context = Context::New();
5614 Context::Scope context_scope(context);
5615
5616 v8::Persistent<v8::Object> object;
5617 {
5618 v8::HandleScope handle_scope;
5619 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5620 object->Set(v8_str("x"), v8::Integer::New(1));
5621 v8::Local<String> y_str = v8_str("y");
5622 object->Set(y_str, y_str);
5623 }
5624 bool revived = false;
5625 object.MakeWeak(&revived, &RevivingCallback);
5626 object.MarkIndependent();
5627 HEAP->PerformScavenge();
5628 CHECK(revived);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00005629 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005630 {
5631 v8::HandleScope handle_scope;
5632 v8::Local<String> y_str = v8_str("y");
5633 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5634 CHECK(object->Get(y_str)->Equals(y_str));
5635 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005636}
5637
5638
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005639v8::Handle<Function> args_fun;
5640
5641
5642static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5643 ApiTestFuzzer::Fuzz();
5644 CHECK_EQ(args_fun, args.Callee());
5645 CHECK_EQ(3, args.Length());
5646 CHECK_EQ(v8::Integer::New(1), args[0]);
5647 CHECK_EQ(v8::Integer::New(2), args[1]);
5648 CHECK_EQ(v8::Integer::New(3), args[2]);
5649 CHECK_EQ(v8::Undefined(), args[3]);
5650 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005651 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005652 return v8::Undefined();
5653}
5654
5655
5656THREADED_TEST(Arguments) {
5657 v8::HandleScope scope;
5658 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5659 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5660 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005661 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005662 v8_compile("f(1, 2, 3)")->Run();
5663}
5664
5665
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005666static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5667 const AccessorInfo&) {
5668 return v8::Handle<Value>();
5669}
5670
5671
5672static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5673 const AccessorInfo&) {
5674 return v8::Handle<Value>();
5675}
5676
5677
5678static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5679 const AccessorInfo&) {
5680 if (!name->Equals(v8_str("foo"))) {
5681 return v8::Handle<v8::Boolean>(); // not intercepted
5682 }
5683
5684 return v8::False(); // intercepted, and don't delete the property
5685}
5686
5687
5688static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5689 if (index != 2) {
5690 return v8::Handle<v8::Boolean>(); // not intercepted
5691 }
5692
5693 return v8::False(); // intercepted, and don't delete the property
5694}
5695
5696
5697THREADED_TEST(Deleter) {
5698 v8::HandleScope scope;
5699 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5700 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5701 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5702 LocalContext context;
5703 context->Global()->Set(v8_str("k"), obj->NewInstance());
5704 CompileRun(
5705 "k.foo = 'foo';"
5706 "k.bar = 'bar';"
5707 "k[2] = 2;"
5708 "k[4] = 4;");
5709 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5710 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5711
5712 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5713 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5714
5715 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5716 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5717
5718 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5719 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5720}
5721
5722
5723static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5724 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005725 if (name->Equals(v8_str("foo")) ||
5726 name->Equals(v8_str("bar")) ||
5727 name->Equals(v8_str("baz"))) {
5728 return v8::Undefined();
5729 }
5730 return v8::Handle<Value>();
5731}
5732
5733
5734static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5735 ApiTestFuzzer::Fuzz();
5736 if (index == 0 || index == 1) return v8::Undefined();
5737 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005738}
5739
5740
5741static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5742 ApiTestFuzzer::Fuzz();
5743 v8::Handle<v8::Array> result = v8::Array::New(3);
5744 result->Set(v8::Integer::New(0), v8_str("foo"));
5745 result->Set(v8::Integer::New(1), v8_str("bar"));
5746 result->Set(v8::Integer::New(2), v8_str("baz"));
5747 return result;
5748}
5749
5750
5751static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5752 ApiTestFuzzer::Fuzz();
5753 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005754 result->Set(v8::Integer::New(0), v8_str("0"));
5755 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005756 return result;
5757}
5758
5759
5760THREADED_TEST(Enumerators) {
5761 v8::HandleScope scope;
5762 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5763 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005764 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005765 LocalContext context;
5766 context->Global()->Set(v8_str("k"), obj->NewInstance());
5767 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005768 "k[10] = 0;"
5769 "k.a = 0;"
5770 "k[5] = 0;"
5771 "k.b = 0;"
5772 "k[4294967295] = 0;"
5773 "k.c = 0;"
5774 "k[4294967296] = 0;"
5775 "k.d = 0;"
5776 "k[140000] = 0;"
5777 "k.e = 0;"
5778 "k[30000000000] = 0;"
5779 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005780 "var result = [];"
5781 "for (var prop in k) {"
5782 " result.push(prop);"
5783 "}"
5784 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005785 // Check that we get all the property names returned including the
5786 // ones from the enumerators in the right order: indexed properties
5787 // in numerical order, indexed interceptor properties, named
5788 // properties in insertion order, named interceptor properties.
5789 // This order is not mandated by the spec, so this test is just
5790 // documenting our behavior.
5791 CHECK_EQ(17, result->Length());
5792 // Indexed properties in numerical order.
5793 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5794 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5795 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5796 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5797 // Indexed interceptor properties in the order they are returned
5798 // from the enumerator interceptor.
5799 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5800 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5801 // Named properties in insertion order.
5802 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5803 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5804 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5805 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5806 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5807 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5808 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5809 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5810 // Named interceptor properties.
5811 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5812 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5813 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005814}
5815
5816
5817int p_getter_count;
5818int p_getter_count2;
5819
5820
5821static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5822 ApiTestFuzzer::Fuzz();
5823 p_getter_count++;
5824 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5825 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5826 if (name->Equals(v8_str("p1"))) {
5827 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5828 } else if (name->Equals(v8_str("p2"))) {
5829 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5830 } else if (name->Equals(v8_str("p3"))) {
5831 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5832 } else if (name->Equals(v8_str("p4"))) {
5833 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5834 }
5835 return v8::Undefined();
5836}
5837
5838
5839static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5840 ApiTestFuzzer::Fuzz();
5841 LocalContext context;
5842 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5843 CompileRun(
5844 "o1.__proto__ = { };"
5845 "var o2 = { __proto__: o1 };"
5846 "var o3 = { __proto__: o2 };"
5847 "var o4 = { __proto__: o3 };"
5848 "for (var i = 0; i < 10; i++) o4.p4;"
5849 "for (var i = 0; i < 10; i++) o3.p3;"
5850 "for (var i = 0; i < 10; i++) o2.p2;"
5851 "for (var i = 0; i < 10; i++) o1.p1;");
5852}
5853
5854
5855static v8::Handle<Value> PGetter2(Local<String> name,
5856 const AccessorInfo& info) {
5857 ApiTestFuzzer::Fuzz();
5858 p_getter_count2++;
5859 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5860 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5861 if (name->Equals(v8_str("p1"))) {
5862 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5863 } else if (name->Equals(v8_str("p2"))) {
5864 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5865 } else if (name->Equals(v8_str("p3"))) {
5866 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5867 } else if (name->Equals(v8_str("p4"))) {
5868 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5869 }
5870 return v8::Undefined();
5871}
5872
5873
5874THREADED_TEST(GetterHolders) {
5875 v8::HandleScope scope;
5876 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5877 obj->SetAccessor(v8_str("p1"), PGetter);
5878 obj->SetAccessor(v8_str("p2"), PGetter);
5879 obj->SetAccessor(v8_str("p3"), PGetter);
5880 obj->SetAccessor(v8_str("p4"), PGetter);
5881 p_getter_count = 0;
5882 RunHolderTest(obj);
5883 CHECK_EQ(40, p_getter_count);
5884}
5885
5886
5887THREADED_TEST(PreInterceptorHolders) {
5888 v8::HandleScope scope;
5889 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5890 obj->SetNamedPropertyHandler(PGetter2);
5891 p_getter_count2 = 0;
5892 RunHolderTest(obj);
5893 CHECK_EQ(40, p_getter_count2);
5894}
5895
5896
5897THREADED_TEST(ObjectInstantiation) {
5898 v8::HandleScope scope;
5899 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5900 templ->SetAccessor(v8_str("t"), PGetter2);
5901 LocalContext context;
5902 context->Global()->Set(v8_str("o"), templ->NewInstance());
5903 for (int i = 0; i < 100; i++) {
5904 v8::HandleScope inner_scope;
5905 v8::Handle<v8::Object> obj = templ->NewInstance();
5906 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5907 context->Global()->Set(v8_str("o2"), obj);
5908 v8::Handle<Value> value =
5909 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5910 CHECK_EQ(v8::True(), value);
5911 context->Global()->Set(v8_str("o"), obj);
5912 }
5913}
5914
5915
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005916static int StrCmp16(uint16_t* a, uint16_t* b) {
5917 while (true) {
5918 if (*a == 0 && *b == 0) return 0;
5919 if (*a != *b) return 0 + *a - *b;
5920 a++;
5921 b++;
5922 }
5923}
5924
5925
5926static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5927 while (true) {
5928 if (n-- == 0) return 0;
5929 if (*a == 0 && *b == 0) return 0;
5930 if (*a != *b) return 0 + *a - *b;
5931 a++;
5932 b++;
5933 }
5934}
5935
5936
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005937int GetUtf8Length(Handle<String> str) {
5938 int len = str->Utf8Length();
5939 if (len < 0) {
5940 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5941 i::FlattenString(istr);
5942 len = str->Utf8Length();
5943 }
5944 return len;
5945}
5946
5947
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005948THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005949 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005950 v8::HandleScope scope;
5951 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005952 // abc<Icelandic eth><Unicode snowman>.
5953 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005954 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005955 const int kStride = 4; // Must match stride in for loops in JS below.
5956 CompileRun(
5957 "var left = '';"
5958 "for (var i = 0; i < 0xd800; i += 4) {"
5959 " left = left + String.fromCharCode(i);"
5960 "}");
5961 CompileRun(
5962 "var right = '';"
5963 "for (var i = 0; i < 0xd800; i += 4) {"
5964 " right = String.fromCharCode(i) + right;"
5965 "}");
5966 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5967 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5968 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005969
5970 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005971 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5972 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005973
5974 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005975 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005976 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005977 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005978 int charlen;
5979
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, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005982 CHECK_EQ(9, len);
5983 CHECK_EQ(5, charlen);
5984 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
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, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005988 CHECK_EQ(8, len);
5989 CHECK_EQ(5, charlen);
5990 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
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, 7, &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, 6, &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, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006006 CHECK_EQ(5, len);
6007 CHECK_EQ(4, charlen);
6008 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
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, 4, &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, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006018 CHECK_EQ(3, len);
6019 CHECK_EQ(3, charlen);
6020 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006021
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006022 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006023 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006024 CHECK_EQ(2, len);
6025 CHECK_EQ(2, charlen);
6026 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006027
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006028 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006029 len = GetUtf8Length(left_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006030 int utf8_expected =
6031 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
6032 CHECK_EQ(utf8_expected, len);
6033 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6034 CHECK_EQ(utf8_expected, len);
6035 CHECK_EQ(0xd800 / kStride, charlen);
6036 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
6037 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
6038 CHECK_EQ(0xc0 - kStride,
6039 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
6040 CHECK_EQ(1, utf8buf[utf8_expected]);
6041
6042 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006043 len = GetUtf8Length(right_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006044 CHECK_EQ(utf8_expected, len);
6045 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6046 CHECK_EQ(utf8_expected, len);
6047 CHECK_EQ(0xd800 / kStride, charlen);
6048 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
6049 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
6050 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
6051 CHECK_EQ(1, utf8buf[utf8_expected]);
6052
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006053 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006054 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006055 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006056 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006058 CHECK_EQ(5, len);
6059 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006060 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006061 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006062
6063 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006064 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006065 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006066 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006067 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006068 CHECK_EQ(4, len);
6069 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006070 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006071 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006072
6073 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006074 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006075 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006076 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006077 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006078 CHECK_EQ(5, len);
6079 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006080 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006081 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006082
6083 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006084 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006085 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006086 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006087 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006088 CHECK_EQ(5, len);
6089 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006090 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006091 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006092
6093 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006094 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006095 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006096 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006097 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006098 CHECK_EQ(1, len);
6099 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006100 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006101 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006102
6103 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006104 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006105 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006106 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006107 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006108 CHECK_EQ(1, len);
6109 CHECK_EQ(0, strcmp("e", buf));
6110 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006111
6112 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006113 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006114 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006115 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006116 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006117 CHECK_EQ(1, len);
6118 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006119 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006120 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006121
6122 memset(buf, 0x1, sizeof(buf));
6123 memset(wbuf, 0x1, sizeof(wbuf));
6124 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006125 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006126 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006127 CHECK_EQ(1, len);
6128 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006129 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006130 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006131
6132 memset(wbuf, 0x1, sizeof(wbuf));
6133 wbuf[5] = 'X';
6134 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
6135 CHECK_EQ(5, len);
6136 CHECK_EQ('X', wbuf[5]);
6137 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
6138 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6139 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
6140 CHECK_NE(0, StrCmp16(answer8b, wbuf));
6141 wbuf[5] = '\0';
6142 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
6143
6144 memset(buf, 0x1, sizeof(buf));
6145 buf[5] = 'X';
6146 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
6147 CHECK_EQ(5, len);
6148 CHECK_EQ('X', buf[5]);
6149 CHECK_EQ(0, strncmp("abcde", buf, 5));
6150 CHECK_NE(0, strcmp("abcde", buf));
6151 buf[5] = '\0';
6152 CHECK_EQ(0, strcmp("abcde", buf));
6153
6154 memset(utf8buf, 0x1, sizeof(utf8buf));
6155 utf8buf[8] = 'X';
6156 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6157 String::NO_NULL_TERMINATION);
6158 CHECK_EQ(8, len);
6159 CHECK_EQ('X', utf8buf[8]);
6160 CHECK_EQ(5, charlen);
6161 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
6162 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6163 utf8buf[8] = '\0';
6164 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006165
6166 memset(utf8buf, 0x1, sizeof(utf8buf));
6167 utf8buf[5] = 'X';
6168 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6169 String::NO_NULL_TERMINATION);
6170 CHECK_EQ(5, len);
6171 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
6172 CHECK_EQ(5, charlen);
6173 utf8buf[5] = '\0';
6174 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
6175
6176 memset(buf, 0x1, sizeof(buf));
6177 len = str3->WriteAscii(buf);
6178 CHECK_EQ(7, len);
6179 CHECK_EQ(0, strcmp("abc def", buf));
6180
6181 memset(buf, 0x1, sizeof(buf));
6182 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
6183 CHECK_EQ(7, len);
6184 CHECK_EQ(0, strcmp("abc", buf));
6185 CHECK_EQ(0, buf[3]);
6186 CHECK_EQ(0, strcmp("def", buf + 4));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006187}
6188
6189
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006190static void Utf16Helper(
6191 LocalContext& context,
6192 const char* name,
6193 const char* lengths_name,
6194 int len) {
6195 Local<v8::Array> a =
6196 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6197 Local<v8::Array> alens =
6198 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6199 for (int i = 0; i < len; i++) {
6200 Local<v8::String> string =
6201 Local<v8::String>::Cast(a->Get(i));
6202 Local<v8::Number> expected_len =
6203 Local<v8::Number>::Cast(alens->Get(i));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006204 CHECK_EQ(expected_len->Value() != string->Length(),
6205 string->MayContainNonAscii());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006206 int length = GetUtf8Length(string);
6207 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
6208 }
6209}
6210
6211
6212static uint16_t StringGet(Handle<String> str, int index) {
6213 i::Handle<i::String> istring =
6214 v8::Utils::OpenHandle(String::Cast(*str));
6215 return istring->Get(index);
6216}
6217
6218
6219static void WriteUtf8Helper(
6220 LocalContext& context,
6221 const char* name,
6222 const char* lengths_name,
6223 int len) {
6224 Local<v8::Array> b =
6225 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6226 Local<v8::Array> alens =
6227 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6228 char buffer[1000];
6229 char buffer2[1000];
6230 for (int i = 0; i < len; i++) {
6231 Local<v8::String> string =
6232 Local<v8::String>::Cast(b->Get(i));
6233 Local<v8::Number> expected_len =
6234 Local<v8::Number>::Cast(alens->Get(i));
6235 int utf8_length = static_cast<int>(expected_len->Value());
6236 for (int j = utf8_length + 1; j >= 0; j--) {
6237 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6238 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6239 int nchars;
6240 int utf8_written =
6241 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6242 int utf8_written2 =
6243 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6244 CHECK_GE(utf8_length + 1, utf8_written);
6245 CHECK_GE(utf8_length, utf8_written2);
6246 for (int k = 0; k < utf8_written2; k++) {
6247 CHECK_EQ(buffer[k], buffer2[k]);
6248 }
6249 CHECK(nchars * 3 >= utf8_written - 1);
6250 CHECK(nchars <= utf8_written);
6251 if (j == utf8_length + 1) {
6252 CHECK_EQ(utf8_written2, utf8_length);
6253 CHECK_EQ(utf8_written2 + 1, utf8_written);
6254 }
6255 CHECK_EQ(buffer[utf8_written], 42);
6256 if (j > utf8_length) {
6257 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6258 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6259 Handle<String> roundtrip = v8_str(buffer);
6260 CHECK(roundtrip->Equals(string));
6261 } else {
6262 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6263 }
6264 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6265 if (nchars >= 2) {
6266 uint16_t trail = StringGet(string, nchars - 1);
6267 uint16_t lead = StringGet(string, nchars - 2);
6268 if (((lead & 0xfc00) == 0xd800) &&
6269 ((trail & 0xfc00) == 0xdc00)) {
6270 unsigned char u1 = buffer2[utf8_written2 - 4];
6271 unsigned char u2 = buffer2[utf8_written2 - 3];
6272 unsigned char u3 = buffer2[utf8_written2 - 2];
6273 unsigned char u4 = buffer2[utf8_written2 - 1];
6274 CHECK_EQ((u1 & 0xf8), 0xf0);
6275 CHECK_EQ((u2 & 0xc0), 0x80);
6276 CHECK_EQ((u3 & 0xc0), 0x80);
6277 CHECK_EQ((u4 & 0xc0), 0x80);
6278 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6279 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6280 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6281 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6282 CHECK_EQ((u1 & 0x3), c >> 18);
6283 }
6284 }
6285 }
6286 }
6287}
6288
6289
6290THREADED_TEST(Utf16) {
6291 LocalContext context;
6292 v8::HandleScope scope;
6293 CompileRun(
6294 "var pad = '01234567890123456789';"
6295 "var p = [];"
6296 "var plens = [20, 3, 3];"
6297 "p.push('01234567890123456789');"
6298 "var lead = 0xd800;"
6299 "var trail = 0xdc00;"
6300 "p.push(String.fromCharCode(0xd800));"
6301 "p.push(String.fromCharCode(0xdc00));"
6302 "var a = [];"
6303 "var b = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006304 "var c = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006305 "var alens = [];"
6306 "for (var i = 0; i < 3; i++) {"
6307 " p[1] = String.fromCharCode(lead++);"
6308 " for (var j = 0; j < 3; j++) {"
6309 " p[2] = String.fromCharCode(trail++);"
6310 " a.push(p[i] + p[j]);"
6311 " b.push(p[i] + p[j]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006312 " c.push(p[i] + p[j]);"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006313 " alens.push(plens[i] + plens[j]);"
6314 " }"
6315 "}"
6316 "alens[5] -= 2;" // Here the surrogate pairs match up.
6317 "var a2 = [];"
6318 "var b2 = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006319 "var c2 = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006320 "var a2lens = [];"
6321 "for (var m = 0; m < 9; m++) {"
6322 " for (var n = 0; n < 9; n++) {"
6323 " a2.push(a[m] + a[n]);"
6324 " b2.push(b[m] + b[n]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006325 " var newc = 'x' + c[m] + c[n] + 'y';"
6326 " c2.push(newc.substring(1, newc.length - 1));"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006327 " var utf = alens[m] + alens[n];" // And here.
6328 // The 'n's that start with 0xdc.. are 6-8
6329 // The 'm's that end with 0xd8.. are 1, 4 and 7
6330 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6331 " a2lens.push(utf);"
6332 " }"
6333 "}");
6334 Utf16Helper(context, "a", "alens", 9);
6335 Utf16Helper(context, "a2", "a2lens", 81);
6336 WriteUtf8Helper(context, "b", "alens", 9);
6337 WriteUtf8Helper(context, "b2", "a2lens", 81);
danno@chromium.org88aa0582012-03-23 15:11:57 +00006338 WriteUtf8Helper(context, "c2", "a2lens", 81);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006339}
6340
6341
6342static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6343 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6344 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6345 return *is1 == *is2;
6346}
6347
6348
6349static void SameSymbolHelper(const char* a, const char* b) {
6350 Handle<String> symbol1 = v8::String::NewSymbol(a);
6351 Handle<String> symbol2 = v8::String::NewSymbol(b);
6352 CHECK(SameSymbol(symbol1, symbol2));
6353}
6354
6355
6356THREADED_TEST(Utf16Symbol) {
6357 LocalContext context;
6358 v8::HandleScope scope;
6359
6360 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6361 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6362 CHECK(SameSymbol(symbol1, symbol2));
6363
6364 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6365 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6366 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6367 "\360\220\220\206"); // 4 byte encoding.
6368 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6369 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6370 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6371 "x\360\220\220\206"); // 4 byte encoding.
6372 CompileRun(
6373 "var sym0 = 'benedictus';"
6374 "var sym0b = 'S\303\270ren';"
6375 "var sym1 = '\355\240\201\355\260\207';"
6376 "var sym2 = '\360\220\220\210';"
6377 "var sym3 = 'x\355\240\201\355\260\207';"
6378 "var sym4 = 'x\360\220\220\210';"
6379 "if (sym1.length != 2) throw sym1;"
6380 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6381 "if (sym2.length != 2) throw sym2;"
6382 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6383 "if (sym3.length != 3) throw sym3;"
6384 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6385 "if (sym4.length != 3) throw sym4;"
6386 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6387 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6388 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6389 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6390 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6391 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6392 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6393 v8::Local<v8::Object> global = context->Global();
6394 Local<Value> s0 = global->Get(v8_str("sym0"));
6395 Local<Value> s0b = global->Get(v8_str("sym0b"));
6396 Local<Value> s1 = global->Get(v8_str("sym1"));
6397 Local<Value> s2 = global->Get(v8_str("sym2"));
6398 Local<Value> s3 = global->Get(v8_str("sym3"));
6399 Local<Value> s4 = global->Get(v8_str("sym4"));
6400 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6401 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6402 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6403 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6404 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6405 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6406}
6407
6408
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006409THREADED_TEST(ToArrayIndex) {
6410 v8::HandleScope scope;
6411 LocalContext context;
6412
6413 v8::Handle<String> str = v8_str("42");
6414 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6415 CHECK(!index.IsEmpty());
6416 CHECK_EQ(42.0, index->Uint32Value());
6417 str = v8_str("42asdf");
6418 index = str->ToArrayIndex();
6419 CHECK(index.IsEmpty());
6420 str = v8_str("-42");
6421 index = str->ToArrayIndex();
6422 CHECK(index.IsEmpty());
6423 str = v8_str("4294967295");
6424 index = str->ToArrayIndex();
6425 CHECK(!index.IsEmpty());
6426 CHECK_EQ(4294967295.0, index->Uint32Value());
6427 v8::Handle<v8::Number> num = v8::Number::New(1);
6428 index = num->ToArrayIndex();
6429 CHECK(!index.IsEmpty());
6430 CHECK_EQ(1.0, index->Uint32Value());
6431 num = v8::Number::New(-1);
6432 index = num->ToArrayIndex();
6433 CHECK(index.IsEmpty());
6434 v8::Handle<v8::Object> obj = v8::Object::New();
6435 index = obj->ToArrayIndex();
6436 CHECK(index.IsEmpty());
6437}
6438
6439
6440THREADED_TEST(ErrorConstruction) {
6441 v8::HandleScope scope;
6442 LocalContext context;
6443
6444 v8::Handle<String> foo = v8_str("foo");
6445 v8::Handle<String> message = v8_str("message");
6446 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6447 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006448 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006449 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6450 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006451 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006452 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6453 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006454 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006455 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6456 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006457 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006458 v8::Handle<Value> error = v8::Exception::Error(foo);
6459 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006460 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006461}
6462
6463
6464static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6465 ApiTestFuzzer::Fuzz();
6466 return v8_num(10);
6467}
6468
6469
6470static void YSetter(Local<String> name,
6471 Local<Value> value,
6472 const AccessorInfo& info) {
6473 if (info.This()->Has(name)) {
6474 info.This()->Delete(name);
6475 }
6476 info.This()->Set(name, value);
6477}
6478
6479
6480THREADED_TEST(DeleteAccessor) {
6481 v8::HandleScope scope;
6482 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6483 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6484 LocalContext context;
6485 v8::Handle<v8::Object> holder = obj->NewInstance();
6486 context->Global()->Set(v8_str("holder"), holder);
6487 v8::Handle<Value> result = CompileRun(
6488 "holder.y = 11; holder.y = 12; holder.y");
6489 CHECK_EQ(12, result->Uint32Value());
6490}
6491
6492
6493THREADED_TEST(TypeSwitch) {
6494 v8::HandleScope scope;
6495 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6496 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6497 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6498 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6499 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6500 LocalContext context;
6501 v8::Handle<v8::Object> obj0 = v8::Object::New();
6502 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6503 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6504 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6505 for (int i = 0; i < 10; i++) {
6506 CHECK_EQ(0, type_switch->match(obj0));
6507 CHECK_EQ(1, type_switch->match(obj1));
6508 CHECK_EQ(2, type_switch->match(obj2));
6509 CHECK_EQ(3, type_switch->match(obj3));
6510 CHECK_EQ(3, type_switch->match(obj3));
6511 CHECK_EQ(2, type_switch->match(obj2));
6512 CHECK_EQ(1, type_switch->match(obj1));
6513 CHECK_EQ(0, type_switch->match(obj0));
6514 }
6515}
6516
6517
6518// For use within the TestSecurityHandler() test.
6519static bool g_security_callback_result = false;
6520static bool NamedSecurityTestCallback(Local<v8::Object> global,
6521 Local<Value> name,
6522 v8::AccessType type,
6523 Local<Value> data) {
6524 // Always allow read access.
6525 if (type == v8::ACCESS_GET)
6526 return true;
6527
6528 // Sometimes allow other access.
6529 return g_security_callback_result;
6530}
6531
6532
6533static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6534 uint32_t key,
6535 v8::AccessType type,
6536 Local<Value> data) {
6537 // Always allow read access.
6538 if (type == v8::ACCESS_GET)
6539 return true;
6540
6541 // Sometimes allow other access.
6542 return g_security_callback_result;
6543}
6544
6545
6546static int trouble_nesting = 0;
6547static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6548 ApiTestFuzzer::Fuzz();
6549 trouble_nesting++;
6550
6551 // Call a JS function that throws an uncaught exception.
6552 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6553 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6554 arg_this->Get(v8_str("trouble_callee")) :
6555 arg_this->Get(v8_str("trouble_caller"));
6556 CHECK(trouble_callee->IsFunction());
6557 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6558}
6559
6560
6561static int report_count = 0;
6562static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6563 v8::Handle<Value>) {
6564 report_count++;
6565}
6566
6567
6568// Counts uncaught exceptions, but other tests running in parallel
6569// also have uncaught exceptions.
6570TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006571 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006572 v8::HandleScope scope;
6573 LocalContext env;
6574 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6575
6576 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6577 v8::Local<v8::Object> global = env->Global();
6578 global->Set(v8_str("trouble"), fun->GetFunction());
6579
6580 Script::Compile(v8_str("function trouble_callee() {"
6581 " var x = null;"
6582 " return x.foo;"
6583 "};"
6584 "function trouble_caller() {"
6585 " trouble();"
6586 "};"))->Run();
6587 Local<Value> trouble = global->Get(v8_str("trouble"));
6588 CHECK(trouble->IsFunction());
6589 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6590 CHECK(trouble_callee->IsFunction());
6591 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6592 CHECK(trouble_caller->IsFunction());
6593 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6594 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006595 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6596}
6597
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006598static const char* script_resource_name = "ExceptionInNativeScript.js";
6599static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6600 v8::Handle<Value>) {
6601 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6602 CHECK(!name_val.IsEmpty() && name_val->IsString());
6603 v8::String::AsciiValue name(message->GetScriptResourceName());
6604 CHECK_EQ(script_resource_name, *name);
6605 CHECK_EQ(3, message->GetLineNumber());
6606 v8::String::AsciiValue source_line(message->GetSourceLine());
6607 CHECK_EQ(" new o.foo();", *source_line);
6608}
6609
6610TEST(ExceptionInNativeScript) {
6611 v8::HandleScope scope;
6612 LocalContext env;
6613 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6614
6615 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6616 v8::Local<v8::Object> global = env->Global();
6617 global->Set(v8_str("trouble"), fun->GetFunction());
6618
6619 Script::Compile(v8_str("function trouble() {\n"
6620 " var o = {};\n"
6621 " new o.foo();\n"
6622 "};"), v8::String::New(script_resource_name))->Run();
6623 Local<Value> trouble = global->Get(v8_str("trouble"));
6624 CHECK(trouble->IsFunction());
6625 Function::Cast(*trouble)->Call(global, 0, NULL);
6626 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6627}
6628
ager@chromium.org8bb60582008-12-11 12:02:20 +00006629
6630TEST(CompilationErrorUsingTryCatchHandler) {
6631 v8::HandleScope scope;
6632 LocalContext env;
6633 v8::TryCatch try_catch;
6634 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6635 CHECK_NE(NULL, *try_catch.Exception());
6636 CHECK(try_catch.HasCaught());
6637}
6638
6639
6640TEST(TryCatchFinallyUsingTryCatchHandler) {
6641 v8::HandleScope scope;
6642 LocalContext env;
6643 v8::TryCatch try_catch;
6644 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6645 CHECK(!try_catch.HasCaught());
6646 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6647 CHECK(try_catch.HasCaught());
6648 try_catch.Reset();
6649 Script::Compile(v8_str("(function() {"
6650 "try { throw ''; } finally { return; }"
6651 "})()"))->Run();
6652 CHECK(!try_catch.HasCaught());
6653 Script::Compile(v8_str("(function()"
6654 " { try { throw ''; } finally { throw 0; }"
6655 "})()"))->Run();
6656 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006657}
6658
6659
6660// SecurityHandler can't be run twice
6661TEST(SecurityHandler) {
6662 v8::HandleScope scope0;
6663 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6664 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6665 IndexedSecurityTestCallback);
6666 // Create an environment
6667 v8::Persistent<Context> context0 =
6668 Context::New(NULL, global_template);
6669 context0->Enter();
6670
6671 v8::Handle<v8::Object> global0 = context0->Global();
6672 v8::Handle<Script> script0 = v8_compile("foo = 111");
6673 script0->Run();
6674 global0->Set(v8_str("0"), v8_num(999));
6675 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6676 CHECK_EQ(111, foo0->Int32Value());
6677 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6678 CHECK_EQ(999, z0->Int32Value());
6679
6680 // Create another environment, should fail security checks.
6681 v8::HandleScope scope1;
6682
6683 v8::Persistent<Context> context1 =
6684 Context::New(NULL, global_template);
6685 context1->Enter();
6686
6687 v8::Handle<v8::Object> global1 = context1->Global();
6688 global1->Set(v8_str("othercontext"), global0);
6689 // This set will fail the security check.
6690 v8::Handle<Script> script1 =
6691 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6692 script1->Run();
6693 // This read will pass the security check.
6694 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6695 CHECK_EQ(111, foo1->Int32Value());
6696 // This read will pass the security check.
6697 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6698 CHECK_EQ(999, z1->Int32Value());
6699
6700 // Create another environment, should pass security checks.
6701 { g_security_callback_result = true; // allow security handler to pass.
6702 v8::HandleScope scope2;
6703 LocalContext context2;
6704 v8::Handle<v8::Object> global2 = context2->Global();
6705 global2->Set(v8_str("othercontext"), global0);
6706 v8::Handle<Script> script2 =
6707 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6708 script2->Run();
6709 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6710 CHECK_EQ(333, foo2->Int32Value());
6711 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6712 CHECK_EQ(888, z2->Int32Value());
6713 }
6714
6715 context1->Exit();
6716 context1.Dispose();
6717
6718 context0->Exit();
6719 context0.Dispose();
6720}
6721
6722
6723THREADED_TEST(SecurityChecks) {
6724 v8::HandleScope handle_scope;
6725 LocalContext env1;
6726 v8::Persistent<Context> env2 = Context::New();
6727
6728 Local<Value> foo = v8_str("foo");
6729 Local<Value> bar = v8_str("bar");
6730
6731 // Set to the same domain.
6732 env1->SetSecurityToken(foo);
6733
6734 // Create a function in env1.
6735 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6736 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6737 CHECK(spy->IsFunction());
6738
6739 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006740 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6742 CHECK(spy2->IsFunction());
6743
6744 // Switch to env2 in the same domain and invoke spy on env2.
6745 {
6746 env2->SetSecurityToken(foo);
6747 // Enter env2
6748 Context::Scope scope_env2(env2);
6749 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6750 CHECK(result->IsFunction());
6751 }
6752
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006753 {
6754 env2->SetSecurityToken(bar);
6755 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006756
6757 // Call cross_domain_call, it should throw an exception
6758 v8::TryCatch try_catch;
6759 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6760 CHECK(try_catch.HasCaught());
6761 }
6762
6763 env2.Dispose();
6764}
6765
6766
6767// Regression test case for issue 1183439.
6768THREADED_TEST(SecurityChecksForPrototypeChain) {
6769 v8::HandleScope scope;
6770 LocalContext current;
6771 v8::Persistent<Context> other = Context::New();
6772
6773 // Change context to be able to get to the Object function in the
6774 // other context without hitting the security checks.
6775 v8::Local<Value> other_object;
6776 { Context::Scope scope(other);
6777 other_object = other->Global()->Get(v8_str("Object"));
6778 other->Global()->Set(v8_num(42), v8_num(87));
6779 }
6780
6781 current->Global()->Set(v8_str("other"), other->Global());
6782 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6783
6784 // Make sure the security check fails here and we get an undefined
6785 // result instead of getting the Object function. Repeat in a loop
6786 // to make sure to exercise the IC code.
6787 v8::Local<Script> access_other0 = v8_compile("other.Object");
6788 v8::Local<Script> access_other1 = v8_compile("other[42]");
6789 for (int i = 0; i < 5; i++) {
6790 CHECK(!access_other0->Run()->Equals(other_object));
6791 CHECK(access_other0->Run()->IsUndefined());
6792 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6793 CHECK(access_other1->Run()->IsUndefined());
6794 }
6795
6796 // Create an object that has 'other' in its prototype chain and make
6797 // sure we cannot access the Object function indirectly through
6798 // that. Repeat in a loop to make sure to exercise the IC code.
6799 v8_compile("function F() { };"
6800 "F.prototype = other;"
6801 "var f = new F();")->Run();
6802 v8::Local<Script> access_f0 = v8_compile("f.Object");
6803 v8::Local<Script> access_f1 = v8_compile("f[42]");
6804 for (int j = 0; j < 5; j++) {
6805 CHECK(!access_f0->Run()->Equals(other_object));
6806 CHECK(access_f0->Run()->IsUndefined());
6807 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6808 CHECK(access_f1->Run()->IsUndefined());
6809 }
6810
6811 // Now it gets hairy: Set the prototype for the other global object
6812 // to be the current global object. The prototype chain for 'f' now
6813 // goes through 'other' but ends up in the current global object.
6814 { Context::Scope scope(other);
6815 other->Global()->Set(v8_str("__proto__"), current->Global());
6816 }
6817 // Set a named and an index property on the current global
6818 // object. To force the lookup to go through the other global object,
6819 // the properties must not exist in the other global object.
6820 current->Global()->Set(v8_str("foo"), v8_num(100));
6821 current->Global()->Set(v8_num(99), v8_num(101));
6822 // Try to read the properties from f and make sure that the access
6823 // gets stopped by the security checks on the other global object.
6824 Local<Script> access_f2 = v8_compile("f.foo");
6825 Local<Script> access_f3 = v8_compile("f[99]");
6826 for (int k = 0; k < 5; k++) {
6827 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6828 CHECK(access_f2->Run()->IsUndefined());
6829 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6830 CHECK(access_f3->Run()->IsUndefined());
6831 }
6832 other.Dispose();
6833}
6834
6835
6836THREADED_TEST(CrossDomainDelete) {
6837 v8::HandleScope handle_scope;
6838 LocalContext env1;
6839 v8::Persistent<Context> env2 = Context::New();
6840
6841 Local<Value> foo = v8_str("foo");
6842 Local<Value> bar = v8_str("bar");
6843
6844 // Set to the same domain.
6845 env1->SetSecurityToken(foo);
6846 env2->SetSecurityToken(foo);
6847
6848 env1->Global()->Set(v8_str("prop"), v8_num(3));
6849 env2->Global()->Set(v8_str("env1"), env1->Global());
6850
6851 // Change env2 to a different domain and delete env1.prop.
6852 env2->SetSecurityToken(bar);
6853 {
6854 Context::Scope scope_env2(env2);
6855 Local<Value> result =
6856 Script::Compile(v8_str("delete env1.prop"))->Run();
6857 CHECK(result->IsFalse());
6858 }
6859
6860 // Check that env1.prop still exists.
6861 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6862 CHECK(v->IsNumber());
6863 CHECK_EQ(3, v->Int32Value());
6864
6865 env2.Dispose();
6866}
6867
6868
ager@chromium.org870a0b62008-11-04 11:43:05 +00006869THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6870 v8::HandleScope handle_scope;
6871 LocalContext env1;
6872 v8::Persistent<Context> env2 = Context::New();
6873
6874 Local<Value> foo = v8_str("foo");
6875 Local<Value> bar = v8_str("bar");
6876
6877 // Set to the same domain.
6878 env1->SetSecurityToken(foo);
6879 env2->SetSecurityToken(foo);
6880
6881 env1->Global()->Set(v8_str("prop"), v8_num(3));
6882 env2->Global()->Set(v8_str("env1"), env1->Global());
6883
6884 // env1.prop is enumerable in env2.
6885 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6886 {
6887 Context::Scope scope_env2(env2);
6888 Local<Value> result = Script::Compile(test)->Run();
6889 CHECK(result->IsTrue());
6890 }
6891
6892 // Change env2 to a different domain and test again.
6893 env2->SetSecurityToken(bar);
6894 {
6895 Context::Scope scope_env2(env2);
6896 Local<Value> result = Script::Compile(test)->Run();
6897 CHECK(result->IsFalse());
6898 }
6899
6900 env2.Dispose();
6901}
6902
6903
ager@chromium.org236ad962008-09-25 09:45:57 +00006904THREADED_TEST(CrossDomainForIn) {
6905 v8::HandleScope handle_scope;
6906 LocalContext env1;
6907 v8::Persistent<Context> env2 = Context::New();
6908
6909 Local<Value> foo = v8_str("foo");
6910 Local<Value> bar = v8_str("bar");
6911
6912 // Set to the same domain.
6913 env1->SetSecurityToken(foo);
6914 env2->SetSecurityToken(foo);
6915
6916 env1->Global()->Set(v8_str("prop"), v8_num(3));
6917 env2->Global()->Set(v8_str("env1"), env1->Global());
6918
6919 // Change env2 to a different domain and set env1's global object
6920 // as the __proto__ of an object in env2 and enumerate properties
6921 // in for-in. It shouldn't enumerate properties on env1's global
6922 // object.
6923 env2->SetSecurityToken(bar);
6924 {
6925 Context::Scope scope_env2(env2);
6926 Local<Value> result =
6927 CompileRun("(function(){var obj = {'__proto__':env1};"
6928 "for (var p in obj)"
6929 " if (p == 'prop') return false;"
6930 "return true;})()");
6931 CHECK(result->IsTrue());
6932 }
6933 env2.Dispose();
6934}
6935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006936
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006937TEST(ContextDetachGlobal) {
6938 v8::HandleScope handle_scope;
6939 LocalContext env1;
6940 v8::Persistent<Context> env2 = Context::New();
6941
6942 Local<v8::Object> global1 = env1->Global();
6943
6944 Local<Value> foo = v8_str("foo");
6945
6946 // Set to the same domain.
6947 env1->SetSecurityToken(foo);
6948 env2->SetSecurityToken(foo);
6949
6950 // Enter env2
6951 env2->Enter();
6952
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006953 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006954 Local<v8::Object> global2 = env2->Global();
6955 global2->Set(v8_str("prop"), v8::Integer::New(1));
6956 CompileRun("function getProp() {return prop;}");
6957
6958 env1->Global()->Set(v8_str("getProp"),
6959 global2->Get(v8_str("getProp")));
6960
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006961 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006962 env2->Exit();
6963 env2->DetachGlobal();
6964 // env2 has a new global object.
6965 CHECK(!env2->Global()->Equals(global2));
6966
6967 v8::Persistent<Context> env3 =
6968 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6969 env3->SetSecurityToken(v8_str("bar"));
6970 env3->Enter();
6971
6972 Local<v8::Object> global3 = env3->Global();
6973 CHECK_EQ(global2, global3);
6974 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6975 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6976 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6977 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6978 env3->Exit();
6979
6980 // Call getProp in env1, and it should return the value 1
6981 {
6982 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6983 CHECK(get_prop->IsFunction());
6984 v8::TryCatch try_catch;
6985 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6986 CHECK(!try_catch.HasCaught());
6987 CHECK_EQ(1, r->Int32Value());
6988 }
6989
6990 // Check that env3 is not accessible from env1
6991 {
6992 Local<Value> r = global3->Get(v8_str("prop2"));
6993 CHECK(r->IsUndefined());
6994 }
6995
6996 env2.Dispose();
6997 env3.Dispose();
6998}
6999
7000
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007001TEST(DetachAndReattachGlobal) {
7002 v8::HandleScope scope;
7003 LocalContext env1;
7004
7005 // Create second environment.
7006 v8::Persistent<Context> env2 = Context::New();
7007
7008 Local<Value> foo = v8_str("foo");
7009
7010 // Set same security token for env1 and env2.
7011 env1->SetSecurityToken(foo);
7012 env2->SetSecurityToken(foo);
7013
7014 // Create a property on the global object in env2.
7015 {
7016 v8::Context::Scope scope(env2);
7017 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7018 }
7019
7020 // Create a reference to env2 global from env1 global.
7021 env1->Global()->Set(v8_str("other"), env2->Global());
7022
7023 // Check that we have access to other.p in env2 from env1.
7024 Local<Value> result = CompileRun("other.p");
7025 CHECK(result->IsInt32());
7026 CHECK_EQ(42, result->Int32Value());
7027
7028 // Hold on to global from env2 and detach global from env2.
7029 Local<v8::Object> global2 = env2->Global();
7030 env2->DetachGlobal();
7031
7032 // Check that the global has been detached. No other.p property can
7033 // be found.
7034 result = CompileRun("other.p");
7035 CHECK(result->IsUndefined());
7036
7037 // Reuse global2 for env3.
7038 v8::Persistent<Context> env3 =
7039 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7040 CHECK_EQ(global2, env3->Global());
7041
7042 // Start by using the same security token for env3 as for env1 and env2.
7043 env3->SetSecurityToken(foo);
7044
7045 // Create a property on the global object in env3.
7046 {
7047 v8::Context::Scope scope(env3);
7048 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
7049 }
7050
7051 // Check that other.p is now the property in env3 and that we have access.
7052 result = CompileRun("other.p");
7053 CHECK(result->IsInt32());
7054 CHECK_EQ(24, result->Int32Value());
7055
7056 // Change security token for env3 to something different from env1 and env2.
7057 env3->SetSecurityToken(v8_str("bar"));
7058
7059 // Check that we do not have access to other.p in env1. |other| is now
7060 // the global object for env3 which has a different security token,
7061 // so access should be blocked.
7062 result = CompileRun("other.p");
7063 CHECK(result->IsUndefined());
7064
7065 // Detach the global for env3 and reattach it to env2.
7066 env3->DetachGlobal();
7067 env2->ReattachGlobal(global2);
7068
7069 // Check that we have access to other.p again in env1. |other| is now
7070 // the global object for env2 which has the same security token as env1.
7071 result = CompileRun("other.p");
7072 CHECK(result->IsInt32());
7073 CHECK_EQ(42, result->Int32Value());
7074
7075 env2.Dispose();
7076 env3.Dispose();
7077}
7078
7079
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007080static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007081static bool NamedAccessBlocker(Local<v8::Object> global,
7082 Local<Value> name,
7083 v8::AccessType type,
7084 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007085 return Context::GetCurrent()->Global()->Equals(global) ||
7086 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007087}
7088
7089
7090static bool IndexedAccessBlocker(Local<v8::Object> global,
7091 uint32_t key,
7092 v8::AccessType type,
7093 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007094 return Context::GetCurrent()->Global()->Equals(global) ||
7095 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007096}
7097
7098
7099static int g_echo_value = -1;
7100static v8::Handle<Value> EchoGetter(Local<String> name,
7101 const AccessorInfo& info) {
7102 return v8_num(g_echo_value);
7103}
7104
7105
7106static void EchoSetter(Local<String> name,
7107 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007108 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007109 if (value->IsNumber())
7110 g_echo_value = value->Int32Value();
7111}
7112
7113
7114static v8::Handle<Value> UnreachableGetter(Local<String> name,
7115 const AccessorInfo& info) {
7116 CHECK(false); // This function should not be called..
7117 return v8::Undefined();
7118}
7119
7120
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007121static void UnreachableSetter(Local<String>, Local<Value>,
7122 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007123 CHECK(false); // This function should nto be called.
7124}
7125
7126
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007127TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007128 v8::HandleScope handle_scope;
7129 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7130
7131 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7132 IndexedAccessBlocker);
7133
7134 // Add an accessor accessible by cross-domain JS code.
7135 global_template->SetAccessor(
7136 v8_str("accessible_prop"),
7137 EchoGetter, EchoSetter,
7138 v8::Handle<Value>(),
7139 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7140
7141 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00007142 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007143 UnreachableGetter, UnreachableSetter,
7144 v8::Handle<Value>(),
7145 v8::DEFAULT);
7146
7147 // Create an environment
7148 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7149 context0->Enter();
7150
7151 v8::Handle<v8::Object> global0 = context0->Global();
7152
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007153 // Define a property with JS getter and setter.
7154 CompileRun(
7155 "function getter() { return 'getter'; };\n"
7156 "function setter() { return 'setter'; }\n"
7157 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
7158
7159 Local<Value> getter = global0->Get(v8_str("getter"));
7160 Local<Value> setter = global0->Get(v8_str("setter"));
7161
7162 // And define normal element.
7163 global0->Set(239, v8_str("239"));
7164
7165 // Define an element with JS getter and setter.
7166 CompileRun(
7167 "function el_getter() { return 'el_getter'; };\n"
7168 "function el_setter() { return 'el_setter'; };\n"
7169 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
7170
7171 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
7172 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
7173
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007174 v8::HandleScope scope1;
7175
7176 v8::Persistent<Context> context1 = Context::New();
7177 context1->Enter();
7178
7179 v8::Handle<v8::Object> global1 = context1->Global();
7180 global1->Set(v8_str("other"), global0);
7181
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007182 // Access blocked property.
7183 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007184
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007185 ExpectUndefined("other.blocked_prop");
7186 ExpectUndefined(
7187 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7188 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007189
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007190 // Enable ACCESS_HAS
7191 allowed_access_type[v8::ACCESS_HAS] = true;
7192 ExpectUndefined("other.blocked_prop");
7193 // ... and now we can get the descriptor...
7194 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007195 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007196 // ... and enumerate the property.
7197 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
7198 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007199
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007200 // Access blocked element.
7201 CompileRun("other[239] = 1");
7202
7203 ExpectUndefined("other[239]");
7204 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
7205 ExpectFalse("propertyIsEnumerable.call(other, '239')");
7206
7207 // Enable ACCESS_HAS
7208 allowed_access_type[v8::ACCESS_HAS] = true;
7209 ExpectUndefined("other[239]");
7210 // ... and now we can get the descriptor...
7211 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
7212 // ... and enumerate the property.
7213 ExpectTrue("propertyIsEnumerable.call(other, '239')");
7214 allowed_access_type[v8::ACCESS_HAS] = false;
7215
7216 // Access a property with JS accessor.
7217 CompileRun("other.js_accessor_p = 2");
7218
7219 ExpectUndefined("other.js_accessor_p");
7220 ExpectUndefined(
7221 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7222
7223 // Enable ACCESS_HAS.
7224 allowed_access_type[v8::ACCESS_HAS] = true;
7225 ExpectUndefined("other.js_accessor_p");
7226 ExpectUndefined(
7227 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7228 ExpectUndefined(
7229 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7230 ExpectUndefined(
7231 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7232 allowed_access_type[v8::ACCESS_HAS] = false;
7233
7234 // Enable both ACCESS_HAS and ACCESS_GET.
7235 allowed_access_type[v8::ACCESS_HAS] = true;
7236 allowed_access_type[v8::ACCESS_GET] = true;
7237
7238 ExpectString("other.js_accessor_p", "getter");
7239 ExpectObject(
7240 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7241 ExpectUndefined(
7242 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7243 ExpectUndefined(
7244 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7245
7246 allowed_access_type[v8::ACCESS_GET] = false;
7247 allowed_access_type[v8::ACCESS_HAS] = false;
7248
7249 // Enable both ACCESS_HAS and ACCESS_SET.
7250 allowed_access_type[v8::ACCESS_HAS] = true;
7251 allowed_access_type[v8::ACCESS_SET] = true;
7252
7253 ExpectUndefined("other.js_accessor_p");
7254 ExpectUndefined(
7255 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7256 ExpectObject(
7257 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7258 ExpectUndefined(
7259 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7260
7261 allowed_access_type[v8::ACCESS_SET] = false;
7262 allowed_access_type[v8::ACCESS_HAS] = false;
7263
7264 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7265 allowed_access_type[v8::ACCESS_HAS] = true;
7266 allowed_access_type[v8::ACCESS_GET] = true;
7267 allowed_access_type[v8::ACCESS_SET] = true;
7268
7269 ExpectString("other.js_accessor_p", "getter");
7270 ExpectObject(
7271 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7272 ExpectObject(
7273 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7274 ExpectUndefined(
7275 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7276
7277 allowed_access_type[v8::ACCESS_SET] = false;
7278 allowed_access_type[v8::ACCESS_GET] = false;
7279 allowed_access_type[v8::ACCESS_HAS] = false;
7280
7281 // Access an element with JS accessor.
7282 CompileRun("other[42] = 2");
7283
7284 ExpectUndefined("other[42]");
7285 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7286
7287 // Enable ACCESS_HAS.
7288 allowed_access_type[v8::ACCESS_HAS] = true;
7289 ExpectUndefined("other[42]");
7290 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7291 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7292 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7293 allowed_access_type[v8::ACCESS_HAS] = false;
7294
7295 // Enable both ACCESS_HAS and ACCESS_GET.
7296 allowed_access_type[v8::ACCESS_HAS] = true;
7297 allowed_access_type[v8::ACCESS_GET] = true;
7298
7299 ExpectString("other[42]", "el_getter");
7300 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7301 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7302 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7303
7304 allowed_access_type[v8::ACCESS_GET] = false;
7305 allowed_access_type[v8::ACCESS_HAS] = false;
7306
7307 // Enable both ACCESS_HAS and ACCESS_SET.
7308 allowed_access_type[v8::ACCESS_HAS] = true;
7309 allowed_access_type[v8::ACCESS_SET] = true;
7310
7311 ExpectUndefined("other[42]");
7312 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7313 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7314 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7315
7316 allowed_access_type[v8::ACCESS_SET] = false;
7317 allowed_access_type[v8::ACCESS_HAS] = false;
7318
7319 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7320 allowed_access_type[v8::ACCESS_HAS] = true;
7321 allowed_access_type[v8::ACCESS_GET] = true;
7322 allowed_access_type[v8::ACCESS_SET] = true;
7323
7324 ExpectString("other[42]", "el_getter");
7325 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7326 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7327 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7328
7329 allowed_access_type[v8::ACCESS_SET] = false;
7330 allowed_access_type[v8::ACCESS_GET] = false;
7331 allowed_access_type[v8::ACCESS_HAS] = false;
7332
7333 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007334
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007335 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007336 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007337 CHECK(value->IsNumber());
7338 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007339 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007340
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007341 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007342 CHECK(value->IsNumber());
7343 CHECK_EQ(3, value->Int32Value());
7344
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007345 value = CompileRun(
7346 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7347 CHECK(value->IsNumber());
7348 CHECK_EQ(3, value->Int32Value());
7349
7350 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00007351 CHECK(value->IsTrue());
7352
7353 // Enumeration doesn't enumerate accessors from inaccessible objects in
7354 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007355 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00007356 CompileRun("(function(){var obj = {'__proto__':other};"
7357 "for (var p in obj)"
7358 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7359 " return false;"
7360 " }"
7361 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007362 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00007363
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007364 context1->Exit();
7365 context0->Exit();
7366 context1.Dispose();
7367 context0.Dispose();
7368}
7369
7370
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007371TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00007372 v8::HandleScope handle_scope;
7373 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7374
7375 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7376 IndexedAccessBlocker);
7377
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007378 // Add accessible accessor.
7379 global_template->SetAccessor(
7380 v8_str("accessible_prop"),
7381 EchoGetter, EchoSetter,
7382 v8::Handle<Value>(),
7383 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7384
7385
ricow@chromium.org65001782011-02-15 13:36:41 +00007386 // Add an accessor that is not accessible by cross-domain JS code.
7387 global_template->SetAccessor(v8_str("blocked_prop"),
7388 UnreachableGetter, UnreachableSetter,
7389 v8::Handle<Value>(),
7390 v8::DEFAULT);
7391
7392 // Create an environment
7393 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7394 context0->Enter();
7395
7396 v8::Handle<v8::Object> global0 = context0->Global();
7397
7398 v8::Persistent<Context> context1 = Context::New();
7399 context1->Enter();
7400 v8::Handle<v8::Object> global1 = context1->Global();
7401 global1->Set(v8_str("other"), global0);
7402
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007403 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00007404 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007405
7406 ExpectUndefined("other.blocked_prop");
7407
7408 // Regression test for issue 1027.
7409 CompileRun("Object.defineProperty(\n"
7410 " other, 'blocked_prop', {configurable: false})");
7411 ExpectUndefined("other.blocked_prop");
7412 ExpectUndefined(
7413 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7414
7415 // Regression test for issue 1171.
7416 ExpectTrue("Object.isExtensible(other)");
7417 CompileRun("Object.preventExtensions(other)");
7418 ExpectTrue("Object.isExtensible(other)");
7419
7420 // Object.seal and Object.freeze.
7421 CompileRun("Object.freeze(other)");
7422 ExpectTrue("Object.isExtensible(other)");
7423
7424 CompileRun("Object.seal(other)");
7425 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007426
7427 // Regression test for issue 1250.
7428 // Make sure that we can set the accessible accessors value using normal
7429 // assignment.
7430 CompileRun("other.accessible_prop = 42");
7431 CHECK_EQ(42, g_echo_value);
7432
7433 v8::Handle<Value> value;
7434 // We follow Safari in ignoring assignments to host object accessors.
7435 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7436 value = CompileRun("other.accessible_prop == 42");
7437 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00007438}
7439
7440
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007441static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7442 Local<Value> name,
7443 v8::AccessType type,
7444 Local<Value> data) {
7445 return false;
7446}
7447
7448
7449static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7450 uint32_t key,
7451 v8::AccessType type,
7452 Local<Value> data) {
7453 return false;
7454}
7455
7456
7457THREADED_TEST(AccessControlGetOwnPropertyNames) {
7458 v8::HandleScope handle_scope;
7459 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7460
7461 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7462 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7463 GetOwnPropertyNamesIndexedBlocker);
7464
7465 // Create an environment
7466 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7467 context0->Enter();
7468
7469 v8::Handle<v8::Object> global0 = context0->Global();
7470
7471 v8::HandleScope scope1;
7472
7473 v8::Persistent<Context> context1 = Context::New();
7474 context1->Enter();
7475
7476 v8::Handle<v8::Object> global1 = context1->Global();
7477 global1->Set(v8_str("other"), global0);
7478 global1->Set(v8_str("object"), obj_template->NewInstance());
7479
7480 v8::Handle<Value> value;
7481
7482 // Attempt to get the property names of the other global object and
7483 // of an object that requires access checks. Accessing the other
7484 // global object should be blocked by access checks on the global
7485 // proxy object. Accessing the object that requires access checks
7486 // is blocked by the access checks on the object itself.
7487 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7488 CHECK(value->IsTrue());
7489
7490 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7491 CHECK(value->IsTrue());
7492
7493 context1->Exit();
7494 context0->Exit();
7495 context1.Dispose();
7496 context0.Dispose();
7497}
7498
7499
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007500static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7501 v8::Handle<v8::Array> result = v8::Array::New(1);
7502 result->Set(0, v8_str("x"));
7503 return result;
7504}
7505
7506
7507THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7508 v8::HandleScope handle_scope;
7509 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7510
7511 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7512 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7513 NamedPropertyEnumerator);
7514
7515 LocalContext context;
7516 v8::Handle<v8::Object> global = context->Global();
7517 global->Set(v8_str("object"), obj_template->NewInstance());
7518
7519 v8::Handle<Value> value =
7520 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7521 CHECK_EQ(v8_str("x"), value);
7522}
7523
7524
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007525static v8::Handle<Value> ConstTenGetter(Local<String> name,
7526 const AccessorInfo& info) {
7527 return v8_num(10);
7528}
7529
7530
7531THREADED_TEST(CrossDomainAccessors) {
7532 v8::HandleScope handle_scope;
7533
7534 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7535
7536 v8::Handle<v8::ObjectTemplate> global_template =
7537 func_template->InstanceTemplate();
7538
7539 v8::Handle<v8::ObjectTemplate> proto_template =
7540 func_template->PrototypeTemplate();
7541
7542 // Add an accessor to proto that's accessible by cross-domain JS code.
7543 proto_template->SetAccessor(v8_str("accessible"),
7544 ConstTenGetter, 0,
7545 v8::Handle<Value>(),
7546 v8::ALL_CAN_READ);
7547
7548 // Add an accessor that is not accessible by cross-domain JS code.
7549 global_template->SetAccessor(v8_str("unreachable"),
7550 UnreachableGetter, 0,
7551 v8::Handle<Value>(),
7552 v8::DEFAULT);
7553
7554 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7555 context0->Enter();
7556
7557 Local<v8::Object> global = context0->Global();
7558 // Add a normal property that shadows 'accessible'
7559 global->Set(v8_str("accessible"), v8_num(11));
7560
7561 // Enter a new context.
7562 v8::HandleScope scope1;
7563 v8::Persistent<Context> context1 = Context::New();
7564 context1->Enter();
7565
7566 v8::Handle<v8::Object> global1 = context1->Global();
7567 global1->Set(v8_str("other"), global);
7568
7569 // Should return 10, instead of 11
7570 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7571 CHECK(value->IsNumber());
7572 CHECK_EQ(10, value->Int32Value());
7573
7574 value = v8_compile("other.unreachable")->Run();
7575 CHECK(value->IsUndefined());
7576
7577 context1->Exit();
7578 context0->Exit();
7579 context1.Dispose();
7580 context0.Dispose();
7581}
7582
7583
7584static int named_access_count = 0;
7585static int indexed_access_count = 0;
7586
7587static bool NamedAccessCounter(Local<v8::Object> global,
7588 Local<Value> name,
7589 v8::AccessType type,
7590 Local<Value> data) {
7591 named_access_count++;
7592 return true;
7593}
7594
7595
7596static bool IndexedAccessCounter(Local<v8::Object> global,
7597 uint32_t key,
7598 v8::AccessType type,
7599 Local<Value> data) {
7600 indexed_access_count++;
7601 return true;
7602}
7603
7604
7605// This one is too easily disturbed by other tests.
7606TEST(AccessControlIC) {
7607 named_access_count = 0;
7608 indexed_access_count = 0;
7609
7610 v8::HandleScope handle_scope;
7611
7612 // Create an environment.
7613 v8::Persistent<Context> context0 = Context::New();
7614 context0->Enter();
7615
7616 // Create an object that requires access-check functions to be
7617 // called for cross-domain access.
7618 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7619 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7620 IndexedAccessCounter);
7621 Local<v8::Object> object = object_template->NewInstance();
7622
7623 v8::HandleScope scope1;
7624
7625 // Create another environment.
7626 v8::Persistent<Context> context1 = Context::New();
7627 context1->Enter();
7628
7629 // Make easy access to the object from the other environment.
7630 v8::Handle<v8::Object> global1 = context1->Global();
7631 global1->Set(v8_str("obj"), object);
7632
7633 v8::Handle<Value> value;
7634
7635 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007636 CompileRun("function testProp(obj) {"
7637 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7638 " for (var j = 0; j < 10; j++) obj.prop;"
7639 " return obj.prop"
7640 "}");
7641 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007642 CHECK(value->IsNumber());
7643 CHECK_EQ(1, value->Int32Value());
7644 CHECK_EQ(21, named_access_count);
7645
7646 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007647 CompileRun("var p = 'prop';"
7648 "function testKeyed(obj) {"
7649 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7650 " for (var j = 0; j < 10; j++) obj[p];"
7651 " return obj[p];"
7652 "}");
7653 // Use obj which requires access checks. No inline caching is used
7654 // in that case.
7655 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007656 CHECK(value->IsNumber());
7657 CHECK_EQ(1, value->Int32Value());
7658 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007659 // Force the inline caches into generic state and try again.
7660 CompileRun("testKeyed({ a: 0 })");
7661 CompileRun("testKeyed({ b: 0 })");
7662 value = CompileRun("testKeyed(obj)");
7663 CHECK(value->IsNumber());
7664 CHECK_EQ(1, value->Int32Value());
7665 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007666
7667 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007668 CompileRun("function testIndexed(obj) {"
7669 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7670 " for (var j = 0; j < 10; j++) obj[0];"
7671 " return obj[0]"
7672 "}");
7673 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007674 CHECK(value->IsNumber());
7675 CHECK_EQ(1, value->Int32Value());
7676 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007677 // Force the inline caches into generic state.
7678 CompileRun("testIndexed(new Array(1))");
7679 // Test that the indexed access check is called.
7680 value = CompileRun("testIndexed(obj)");
7681 CHECK(value->IsNumber());
7682 CHECK_EQ(1, value->Int32Value());
7683 CHECK_EQ(42, indexed_access_count);
7684
7685 // Check that the named access check is called when invoking
7686 // functions on an object that requires access checks.
7687 CompileRun("obj.f = function() {}");
7688 CompileRun("function testCallNormal(obj) {"
7689 " for (var i = 0; i < 10; i++) obj.f();"
7690 "}");
7691 CompileRun("testCallNormal(obj)");
7692 CHECK_EQ(74, named_access_count);
7693
7694 // Force obj into slow case.
7695 value = CompileRun("delete obj.prop");
7696 CHECK(value->BooleanValue());
7697 // Force inline caches into dictionary probing mode.
7698 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7699 // Test that the named access check is called.
7700 value = CompileRun("testProp(obj);");
7701 CHECK(value->IsNumber());
7702 CHECK_EQ(1, value->Int32Value());
7703 CHECK_EQ(96, named_access_count);
7704
7705 // Force the call inline cache into dictionary probing mode.
7706 CompileRun("o.f = function() {}; testCallNormal(o)");
7707 // Test that the named access check is still called for each
7708 // invocation of the function.
7709 value = CompileRun("testCallNormal(obj)");
7710 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007711
7712 context1->Exit();
7713 context0->Exit();
7714 context1.Dispose();
7715 context0.Dispose();
7716}
7717
7718
7719static bool NamedAccessFlatten(Local<v8::Object> global,
7720 Local<Value> name,
7721 v8::AccessType type,
7722 Local<Value> data) {
7723 char buf[100];
7724 int len;
7725
7726 CHECK(name->IsString());
7727
7728 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007729 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007730 CHECK_EQ(4, len);
7731
7732 uint16_t buf2[100];
7733
7734 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007735 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007736 CHECK_EQ(4, len);
7737
7738 return true;
7739}
7740
7741
7742static bool IndexedAccessFlatten(Local<v8::Object> global,
7743 uint32_t key,
7744 v8::AccessType type,
7745 Local<Value> data) {
7746 return true;
7747}
7748
7749
7750// Regression test. In access checks, operations that may cause
7751// garbage collection are not allowed. It used to be the case that
7752// using the Write operation on a string could cause a garbage
7753// collection due to flattening of the string. This is no longer the
7754// case.
7755THREADED_TEST(AccessControlFlatten) {
7756 named_access_count = 0;
7757 indexed_access_count = 0;
7758
7759 v8::HandleScope handle_scope;
7760
7761 // Create an environment.
7762 v8::Persistent<Context> context0 = Context::New();
7763 context0->Enter();
7764
7765 // Create an object that requires access-check functions to be
7766 // called for cross-domain access.
7767 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7768 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7769 IndexedAccessFlatten);
7770 Local<v8::Object> object = object_template->NewInstance();
7771
7772 v8::HandleScope scope1;
7773
7774 // Create another environment.
7775 v8::Persistent<Context> context1 = Context::New();
7776 context1->Enter();
7777
7778 // Make easy access to the object from the other environment.
7779 v8::Handle<v8::Object> global1 = context1->Global();
7780 global1->Set(v8_str("obj"), object);
7781
7782 v8::Handle<Value> value;
7783
7784 value = v8_compile("var p = 'as' + 'df';")->Run();
7785 value = v8_compile("obj[p];")->Run();
7786
7787 context1->Exit();
7788 context0->Exit();
7789 context1.Dispose();
7790 context0.Dispose();
7791}
7792
7793
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007794static v8::Handle<Value> AccessControlNamedGetter(
7795 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007796 return v8::Integer::New(42);
7797}
7798
7799
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007800static v8::Handle<Value> AccessControlNamedSetter(
7801 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007802 return value;
7803}
7804
7805
7806static v8::Handle<Value> AccessControlIndexedGetter(
7807 uint32_t index,
7808 const AccessorInfo& info) {
7809 return v8_num(42);
7810}
7811
7812
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007813static v8::Handle<Value> AccessControlIndexedSetter(
7814 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007815 return value;
7816}
7817
7818
7819THREADED_TEST(AccessControlInterceptorIC) {
7820 named_access_count = 0;
7821 indexed_access_count = 0;
7822
7823 v8::HandleScope handle_scope;
7824
7825 // Create an environment.
7826 v8::Persistent<Context> context0 = Context::New();
7827 context0->Enter();
7828
7829 // Create an object that requires access-check functions to be
7830 // called for cross-domain access. The object also has interceptors
7831 // interceptor.
7832 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7833 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7834 IndexedAccessCounter);
7835 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7836 AccessControlNamedSetter);
7837 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7838 AccessControlIndexedSetter);
7839 Local<v8::Object> object = object_template->NewInstance();
7840
7841 v8::HandleScope scope1;
7842
7843 // Create another environment.
7844 v8::Persistent<Context> context1 = Context::New();
7845 context1->Enter();
7846
7847 // Make easy access to the object from the other environment.
7848 v8::Handle<v8::Object> global1 = context1->Global();
7849 global1->Set(v8_str("obj"), object);
7850
7851 v8::Handle<Value> value;
7852
7853 // Check that the named access-control function is called every time
7854 // eventhough there is an interceptor on the object.
7855 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7856 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7857 "obj.x")->Run();
7858 CHECK(value->IsNumber());
7859 CHECK_EQ(42, value->Int32Value());
7860 CHECK_EQ(21, named_access_count);
7861
7862 value = v8_compile("var p = 'x';")->Run();
7863 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7864 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7865 "obj[p]")->Run();
7866 CHECK(value->IsNumber());
7867 CHECK_EQ(42, value->Int32Value());
7868 CHECK_EQ(42, named_access_count);
7869
7870 // Check that the indexed access-control function is called every
7871 // time eventhough there is an interceptor on the object.
7872 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7873 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7874 "obj[0]")->Run();
7875 CHECK(value->IsNumber());
7876 CHECK_EQ(42, value->Int32Value());
7877 CHECK_EQ(21, indexed_access_count);
7878
7879 context1->Exit();
7880 context0->Exit();
7881 context1.Dispose();
7882 context0.Dispose();
7883}
7884
7885
7886THREADED_TEST(Version) {
7887 v8::V8::GetVersion();
7888}
7889
7890
7891static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7892 ApiTestFuzzer::Fuzz();
7893 return v8_num(12);
7894}
7895
7896
7897THREADED_TEST(InstanceProperties) {
7898 v8::HandleScope handle_scope;
7899 LocalContext context;
7900
7901 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7902 Local<ObjectTemplate> instance = t->InstanceTemplate();
7903
7904 instance->Set(v8_str("x"), v8_num(42));
7905 instance->Set(v8_str("f"),
7906 v8::FunctionTemplate::New(InstanceFunctionCallback));
7907
7908 Local<Value> o = t->GetFunction()->NewInstance();
7909
7910 context->Global()->Set(v8_str("i"), o);
7911 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7912 CHECK_EQ(42, value->Int32Value());
7913
7914 value = Script::Compile(v8_str("i.f()"))->Run();
7915 CHECK_EQ(12, value->Int32Value());
7916}
7917
7918
7919static v8::Handle<Value>
7920GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7921 ApiTestFuzzer::Fuzz();
7922 return v8::Handle<Value>();
7923}
7924
7925
7926THREADED_TEST(GlobalObjectInstanceProperties) {
7927 v8::HandleScope handle_scope;
7928
7929 Local<Value> global_object;
7930
7931 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7932 t->InstanceTemplate()->SetNamedPropertyHandler(
7933 GlobalObjectInstancePropertiesGet);
7934 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7935 instance_template->Set(v8_str("x"), v8_num(42));
7936 instance_template->Set(v8_str("f"),
7937 v8::FunctionTemplate::New(InstanceFunctionCallback));
7938
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007939 // The script to check how Crankshaft compiles missing global function
7940 // invocations. function g is not defined and should throw on call.
7941 const char* script =
7942 "function wrapper(call) {"
7943 " var x = 0, y = 1;"
7944 " for (var i = 0; i < 1000; i++) {"
7945 " x += i * 100;"
7946 " y += i * 100;"
7947 " }"
7948 " if (call) g();"
7949 "}"
7950 "for (var i = 0; i < 17; i++) wrapper(false);"
7951 "var thrown = 0;"
7952 "try { wrapper(true); } catch (e) { thrown = 1; };"
7953 "thrown";
7954
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007955 {
7956 LocalContext env(NULL, instance_template);
7957 // Hold on to the global object so it can be used again in another
7958 // environment initialization.
7959 global_object = env->Global();
7960
7961 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7962 CHECK_EQ(42, value->Int32Value());
7963 value = Script::Compile(v8_str("f()"))->Run();
7964 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007965 value = Script::Compile(v8_str(script))->Run();
7966 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007967 }
7968
7969 {
7970 // Create new environment reusing the global object.
7971 LocalContext env(NULL, instance_template, global_object);
7972 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7973 CHECK_EQ(42, value->Int32Value());
7974 value = Script::Compile(v8_str("f()"))->Run();
7975 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007976 value = Script::Compile(v8_str(script))->Run();
7977 CHECK_EQ(1, value->Int32Value());
7978 }
7979}
7980
7981
7982THREADED_TEST(CallKnownGlobalReceiver) {
7983 v8::HandleScope handle_scope;
7984
7985 Local<Value> global_object;
7986
7987 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7988 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7989
7990 // The script to check that we leave global object not
7991 // global object proxy on stack when we deoptimize from inside
7992 // arguments evaluation.
7993 // To provoke error we need to both force deoptimization
7994 // from arguments evaluation and to force CallIC to take
7995 // CallIC_Miss code path that can't cope with global proxy.
7996 const char* script =
7997 "function bar(x, y) { try { } finally { } }"
7998 "function baz(x) { try { } finally { } }"
7999 "function bom(x) { try { } finally { } }"
8000 "function foo(x) { bar([x], bom(2)); }"
8001 "for (var i = 0; i < 10000; i++) foo(1);"
8002 "foo";
8003
8004 Local<Value> foo;
8005 {
8006 LocalContext env(NULL, instance_template);
8007 // Hold on to the global object so it can be used again in another
8008 // environment initialization.
8009 global_object = env->Global();
8010 foo = Script::Compile(v8_str(script))->Run();
8011 }
8012
8013 {
8014 // Create new environment reusing the global object.
8015 LocalContext env(NULL, instance_template, global_object);
8016 env->Global()->Set(v8_str("foo"), foo);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008017 Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008018 }
8019}
8020
8021
8022static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
8023 ApiTestFuzzer::Fuzz();
8024 return v8_num(42);
8025}
8026
8027
8028static int shadow_y;
8029static int shadow_y_setter_call_count;
8030static int shadow_y_getter_call_count;
8031
8032
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008033static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008034 shadow_y_setter_call_count++;
8035 shadow_y = 42;
8036}
8037
8038
8039static v8::Handle<Value> ShadowYGetter(Local<String> name,
8040 const AccessorInfo& info) {
8041 ApiTestFuzzer::Fuzz();
8042 shadow_y_getter_call_count++;
8043 return v8_num(shadow_y);
8044}
8045
8046
8047static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
8048 const AccessorInfo& info) {
8049 return v8::Handle<Value>();
8050}
8051
8052
8053static v8::Handle<Value> ShadowNamedGet(Local<String> key,
8054 const AccessorInfo&) {
8055 return v8::Handle<Value>();
8056}
8057
8058
8059THREADED_TEST(ShadowObject) {
8060 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
8061 v8::HandleScope handle_scope;
8062
8063 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
8064 LocalContext context(NULL, global_template);
8065
8066 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8067 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
8068 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
8069 Local<ObjectTemplate> proto = t->PrototypeTemplate();
8070 Local<ObjectTemplate> instance = t->InstanceTemplate();
8071
8072 // Only allow calls of f on instances of t.
8073 Local<v8::Signature> signature = v8::Signature::New(t);
8074 proto->Set(v8_str("f"),
8075 v8::FunctionTemplate::New(ShadowFunctionCallback,
8076 Local<Value>(),
8077 signature));
8078 proto->Set(v8_str("x"), v8_num(12));
8079
8080 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
8081
8082 Local<Value> o = t->GetFunction()->NewInstance();
8083 context->Global()->Set(v8_str("__proto__"), o);
8084
8085 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008086 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008087 CHECK(value->IsBoolean());
8088 CHECK(!value->BooleanValue());
8089
8090 value = Script::Compile(v8_str("x"))->Run();
8091 CHECK_EQ(12, value->Int32Value());
8092
8093 value = Script::Compile(v8_str("f()"))->Run();
8094 CHECK_EQ(42, value->Int32Value());
8095
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008096 Script::Compile(v8_str("y = 43"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008097 CHECK_EQ(1, shadow_y_setter_call_count);
8098 value = Script::Compile(v8_str("y"))->Run();
8099 CHECK_EQ(1, shadow_y_getter_call_count);
8100 CHECK_EQ(42, value->Int32Value());
8101}
8102
8103
8104THREADED_TEST(HiddenPrototype) {
8105 v8::HandleScope handle_scope;
8106 LocalContext context;
8107
8108 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8109 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8110 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8111 t1->SetHiddenPrototype(true);
8112 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8113 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8114 t2->SetHiddenPrototype(true);
8115 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8116 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8117 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8118
8119 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8120 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8121 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8122 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8123
8124 // Setting the prototype on an object skips hidden prototypes.
8125 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8126 o0->Set(v8_str("__proto__"), o1);
8127 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8128 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8129 o0->Set(v8_str("__proto__"), o2);
8130 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8131 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8132 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8133 o0->Set(v8_str("__proto__"), o3);
8134 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8135 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8136 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8137 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8138
8139 // Getting the prototype of o0 should get the first visible one
8140 // which is o3. Therefore, z should not be defined on the prototype
8141 // object.
8142 Local<Value> proto = o0->Get(v8_str("__proto__"));
8143 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008144 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008145}
8146
8147
ager@chromium.org5c838252010-02-19 08:53:10 +00008148THREADED_TEST(SetPrototype) {
8149 v8::HandleScope handle_scope;
8150 LocalContext context;
8151
8152 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8153 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8154 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8155 t1->SetHiddenPrototype(true);
8156 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8157 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8158 t2->SetHiddenPrototype(true);
8159 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8160 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8161 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8162
8163 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8164 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8165 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8166 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8167
8168 // Setting the prototype on an object does not skip hidden prototypes.
8169 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8170 CHECK(o0->SetPrototype(o1));
8171 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8172 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8173 CHECK(o1->SetPrototype(o2));
8174 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8175 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8176 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8177 CHECK(o2->SetPrototype(o3));
8178 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8179 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8180 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8181 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8182
8183 // Getting the prototype of o0 should get the first visible one
8184 // which is o3. Therefore, z should not be defined on the prototype
8185 // object.
8186 Local<Value> proto = o0->Get(v8_str("__proto__"));
8187 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008188 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008189
8190 // However, Object::GetPrototype ignores hidden prototype.
8191 Local<Value> proto0 = o0->GetPrototype();
8192 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008193 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00008194
8195 Local<Value> proto1 = o1->GetPrototype();
8196 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008197 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00008198
8199 Local<Value> proto2 = o2->GetPrototype();
8200 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008201 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008202}
8203
8204
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008205// Getting property names of an object with a prototype chain that
8206// triggers dictionary elements in GetLocalPropertyNames() shouldn't
8207// crash the runtime.
8208THREADED_TEST(Regress91517) {
8209 i::FLAG_allow_natives_syntax = true;
8210 v8::HandleScope handle_scope;
8211 LocalContext context;
8212
8213 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8214 t1->SetHiddenPrototype(true);
8215 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
8216 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8217 t2->SetHiddenPrototype(true);
8218 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
8219 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
8220 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
8221 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8222 t3->SetHiddenPrototype(true);
8223 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8224 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8225 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8226
8227 // Force dictionary-based properties.
8228 i::ScopedVector<char> name_buf(1024);
8229 for (int i = 1; i <= 1000; i++) {
8230 i::OS::SNPrintF(name_buf, "sdf%d", i);
8231 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8232 }
8233
8234 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8235 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8236 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8237 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8238
8239 // Create prototype chain of hidden prototypes.
8240 CHECK(o4->SetPrototype(o3));
8241 CHECK(o3->SetPrototype(o2));
8242 CHECK(o2->SetPrototype(o1));
8243
8244 // Call the runtime version of GetLocalPropertyNames() on the natively
8245 // created object through JavaScript.
8246 context->Global()->Set(v8_str("obj"), o4);
8247 CompileRun("var names = %GetLocalPropertyNames(obj);");
8248
8249 ExpectInt32("names.length", 1006);
8250 ExpectTrue("names.indexOf(\"baz\") >= 0");
8251 ExpectTrue("names.indexOf(\"boo\") >= 0");
8252 ExpectTrue("names.indexOf(\"foo\") >= 0");
8253 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8254 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8255 ExpectFalse("names[1005] == undefined");
8256}
8257
8258
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008259THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00008260 v8::HandleScope handle_scope;
8261 LocalContext context;
8262
8263 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008264 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8265 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00008266 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008267 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008268 CHECK(CompileRun(
8269 "(function() {"
8270 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008271 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008272 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008273 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8274 CHECK_EQ(42,
8275 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008276
8277 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008278 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00008279 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008280 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008281 CHECK(CompileRun(
8282 "(function() {"
8283 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008284 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008285 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008286 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008287}
8288
8289
ager@chromium.org5c838252010-02-19 08:53:10 +00008290THREADED_TEST(SetPrototypeThrows) {
8291 v8::HandleScope handle_scope;
8292 LocalContext context;
8293
8294 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8295
8296 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8297 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8298
8299 CHECK(o0->SetPrototype(o1));
8300 // If setting the prototype leads to the cycle, SetPrototype should
8301 // return false and keep VM in sane state.
8302 v8::TryCatch try_catch;
8303 CHECK(!o1->SetPrototype(o0));
8304 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00008306
8307 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8308}
8309
8310
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008311THREADED_TEST(GetterSetterExceptions) {
8312 v8::HandleScope handle_scope;
8313 LocalContext context;
8314 CompileRun(
8315 "function Foo() { };"
8316 "function Throw() { throw 5; };"
8317 "var x = { };"
8318 "x.__defineSetter__('set', Throw);"
8319 "x.__defineGetter__('get', Throw);");
8320 Local<v8::Object> x =
8321 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8322 v8::TryCatch try_catch;
8323 x->Set(v8_str("set"), v8::Integer::New(8));
8324 x->Get(v8_str("get"));
8325 x->Set(v8_str("set"), v8::Integer::New(8));
8326 x->Get(v8_str("get"));
8327 x->Set(v8_str("set"), v8::Integer::New(8));
8328 x->Get(v8_str("get"));
8329 x->Set(v8_str("set"), v8::Integer::New(8));
8330 x->Get(v8_str("get"));
8331}
8332
8333
8334THREADED_TEST(Constructor) {
8335 v8::HandleScope handle_scope;
8336 LocalContext context;
8337 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8338 templ->SetClassName(v8_str("Fun"));
8339 Local<Function> cons = templ->GetFunction();
8340 context->Global()->Set(v8_str("Fun"), cons);
8341 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008342 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008343 CHECK(obj->IsJSObject());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008344 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8345 CHECK(value->BooleanValue());
8346}
8347
lrn@chromium.org1c092762011-05-09 09:42:16 +00008348
8349static Handle<Value> ConstructorCallback(const Arguments& args) {
8350 ApiTestFuzzer::Fuzz();
8351 Local<Object> This;
8352
8353 if (args.IsConstructCall()) {
8354 Local<Object> Holder = args.Holder();
8355 This = Object::New();
8356 Local<Value> proto = Holder->GetPrototype();
8357 if (proto->IsObject()) {
8358 This->SetPrototype(proto);
8359 }
8360 } else {
8361 This = args.This();
8362 }
8363
8364 This->Set(v8_str("a"), args[0]);
8365 return This;
8366}
8367
8368
8369static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8370 ApiTestFuzzer::Fuzz();
8371 return args[0];
8372}
8373
8374
8375THREADED_TEST(ConstructorForObject) {
8376 v8::HandleScope handle_scope;
8377 LocalContext context;
8378
8379 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8380 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8381 Local<Object> instance = instance_template->NewInstance();
8382 context->Global()->Set(v8_str("obj"), instance);
8383 v8::TryCatch try_catch;
8384 Local<Value> value;
8385 CHECK(!try_catch.HasCaught());
8386
8387 // Call the Object's constructor with a 32-bit signed integer.
8388 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8389 CHECK(!try_catch.HasCaught());
8390 CHECK(value->IsInt32());
8391 CHECK_EQ(28, value->Int32Value());
8392
8393 Local<Value> args1[] = { v8_num(28) };
8394 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8395 CHECK(value_obj1->IsObject());
8396 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8397 value = object1->Get(v8_str("a"));
8398 CHECK(value->IsInt32());
8399 CHECK(!try_catch.HasCaught());
8400 CHECK_EQ(28, value->Int32Value());
8401
8402 // Call the Object's constructor with a String.
8403 value = CompileRun(
8404 "(function() { var o = new obj('tipli'); return o.a; })()");
8405 CHECK(!try_catch.HasCaught());
8406 CHECK(value->IsString());
8407 String::AsciiValue string_value1(value->ToString());
8408 CHECK_EQ("tipli", *string_value1);
8409
8410 Local<Value> args2[] = { v8_str("tipli") };
8411 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8412 CHECK(value_obj2->IsObject());
8413 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8414 value = object2->Get(v8_str("a"));
8415 CHECK(!try_catch.HasCaught());
8416 CHECK(value->IsString());
8417 String::AsciiValue string_value2(value->ToString());
8418 CHECK_EQ("tipli", *string_value2);
8419
8420 // Call the Object's constructor with a Boolean.
8421 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8422 CHECK(!try_catch.HasCaught());
8423 CHECK(value->IsBoolean());
8424 CHECK_EQ(true, value->BooleanValue());
8425
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008426 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00008427 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8428 CHECK(value_obj3->IsObject());
8429 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8430 value = object3->Get(v8_str("a"));
8431 CHECK(!try_catch.HasCaught());
8432 CHECK(value->IsBoolean());
8433 CHECK_EQ(true, value->BooleanValue());
8434
8435 // Call the Object's constructor with undefined.
8436 Handle<Value> args4[] = { v8::Undefined() };
8437 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8438 CHECK(value_obj4->IsObject());
8439 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8440 value = object4->Get(v8_str("a"));
8441 CHECK(!try_catch.HasCaught());
8442 CHECK(value->IsUndefined());
8443
8444 // Call the Object's constructor with null.
8445 Handle<Value> args5[] = { v8::Null() };
8446 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8447 CHECK(value_obj5->IsObject());
8448 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8449 value = object5->Get(v8_str("a"));
8450 CHECK(!try_catch.HasCaught());
8451 CHECK(value->IsNull());
8452 }
8453
8454 // Check exception handling when there is no constructor set for the Object.
8455 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8456 Local<Object> instance = instance_template->NewInstance();
8457 context->Global()->Set(v8_str("obj2"), instance);
8458 v8::TryCatch try_catch;
8459 Local<Value> value;
8460 CHECK(!try_catch.HasCaught());
8461
8462 value = CompileRun("new obj2(28)");
8463 CHECK(try_catch.HasCaught());
8464 String::AsciiValue exception_value1(try_catch.Exception());
8465 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8466 try_catch.Reset();
8467
8468 Local<Value> args[] = { v8_num(29) };
8469 value = instance->CallAsConstructor(1, args);
8470 CHECK(try_catch.HasCaught());
8471 String::AsciiValue exception_value2(try_catch.Exception());
8472 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8473 try_catch.Reset();
8474 }
8475
8476 // Check the case when constructor throws exception.
8477 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8478 instance_template->SetCallAsFunctionHandler(ThrowValue);
8479 Local<Object> instance = instance_template->NewInstance();
8480 context->Global()->Set(v8_str("obj3"), instance);
8481 v8::TryCatch try_catch;
8482 Local<Value> value;
8483 CHECK(!try_catch.HasCaught());
8484
8485 value = CompileRun("new obj3(22)");
8486 CHECK(try_catch.HasCaught());
8487 String::AsciiValue exception_value1(try_catch.Exception());
8488 CHECK_EQ("22", *exception_value1);
8489 try_catch.Reset();
8490
8491 Local<Value> args[] = { v8_num(23) };
8492 value = instance->CallAsConstructor(1, args);
8493 CHECK(try_catch.HasCaught());
8494 String::AsciiValue exception_value2(try_catch.Exception());
8495 CHECK_EQ("23", *exception_value2);
8496 try_catch.Reset();
8497 }
8498
8499 // Check whether constructor returns with an object or non-object.
8500 { Local<FunctionTemplate> function_template =
8501 FunctionTemplate::New(FakeConstructorCallback);
8502 Local<Function> function = function_template->GetFunction();
8503 Local<Object> instance1 = function;
8504 context->Global()->Set(v8_str("obj4"), instance1);
8505 v8::TryCatch try_catch;
8506 Local<Value> value;
8507 CHECK(!try_catch.HasCaught());
8508
8509 CHECK(instance1->IsObject());
8510 CHECK(instance1->IsFunction());
8511
8512 value = CompileRun("new obj4(28)");
8513 CHECK(!try_catch.HasCaught());
8514 CHECK(value->IsObject());
8515
8516 Local<Value> args1[] = { v8_num(28) };
8517 value = instance1->CallAsConstructor(1, args1);
8518 CHECK(!try_catch.HasCaught());
8519 CHECK(value->IsObject());
8520
8521 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8522 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8523 Local<Object> instance2 = instance_template->NewInstance();
8524 context->Global()->Set(v8_str("obj5"), instance2);
8525 CHECK(!try_catch.HasCaught());
8526
8527 CHECK(instance2->IsObject());
8528 CHECK(!instance2->IsFunction());
8529
8530 value = CompileRun("new obj5(28)");
8531 CHECK(!try_catch.HasCaught());
8532 CHECK(!value->IsObject());
8533
8534 Local<Value> args2[] = { v8_num(28) };
8535 value = instance2->CallAsConstructor(1, args2);
8536 CHECK(!try_catch.HasCaught());
8537 CHECK(!value->IsObject());
8538 }
8539}
8540
8541
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008542THREADED_TEST(FunctionDescriptorException) {
8543 v8::HandleScope handle_scope;
8544 LocalContext context;
8545 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8546 templ->SetClassName(v8_str("Fun"));
8547 Local<Function> cons = templ->GetFunction();
8548 context->Global()->Set(v8_str("Fun"), cons);
8549 Local<Value> value = CompileRun(
8550 "function test() {"
8551 " try {"
8552 " (new Fun()).blah()"
8553 " } catch (e) {"
8554 " var str = String(e);"
8555 " if (str.indexOf('TypeError') == -1) return 1;"
8556 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00008557 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008558 " return 0;"
8559 " }"
8560 " return 4;"
8561 "}"
8562 "test();");
8563 CHECK_EQ(0, value->Int32Value());
8564}
8565
8566
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008567THREADED_TEST(EvalAliasedDynamic) {
8568 v8::HandleScope scope;
8569 LocalContext current;
8570
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008571 // Tests where aliased eval can only be resolved dynamically.
8572 Local<Script> script =
8573 Script::Compile(v8_str("function f(x) { "
8574 " var foo = 2;"
8575 " with (x) { return eval('foo'); }"
8576 "}"
8577 "foo = 0;"
8578 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008579 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008580 "var x = new Object();"
8581 "x.eval = function(x) { return 1; };"
8582 "result3 = f(x);"));
8583 script->Run();
8584 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8585 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8586 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8587
8588 v8::TryCatch try_catch;
8589 script =
8590 Script::Compile(v8_str("function f(x) { "
8591 " var bar = 2;"
8592 " with (x) { return eval('bar'); }"
8593 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008594 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008595 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008596 CHECK(!try_catch.HasCaught());
8597 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8598
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008599 try_catch.Reset();
8600}
8601
8602
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008603THREADED_TEST(CrossEval) {
8604 v8::HandleScope scope;
8605 LocalContext other;
8606 LocalContext current;
8607
8608 Local<String> token = v8_str("<security token>");
8609 other->SetSecurityToken(token);
8610 current->SetSecurityToken(token);
8611
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008612 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008613 current->Global()->Set(v8_str("other"), other->Global());
8614
8615 // Check that new variables are introduced in other context.
8616 Local<Script> script =
8617 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8618 script->Run();
8619 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8620 CHECK_EQ(1234, foo->Int32Value());
8621 CHECK(!current->Global()->Has(v8_str("foo")));
8622
8623 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008624 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008625 script =
8626 Script::Compile(v8_str("other.eval('na = 1234')"));
8627 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008628 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8629 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008630
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008631 // Check that global variables in current context are not visible in other
8632 // context.
8633 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008634 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008635 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008636 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008637 CHECK(try_catch.HasCaught());
8638 try_catch.Reset();
8639
8640 // Check that local variables in current context are not visible in other
8641 // context.
8642 script =
8643 Script::Compile(v8_str("(function() { "
8644 " var baz = 87;"
8645 " return other.eval('baz');"
8646 "})();"));
8647 result = script->Run();
8648 CHECK(try_catch.HasCaught());
8649 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008650
8651 // Check that global variables in the other environment are visible
8652 // when evaluting code.
8653 other->Global()->Set(v8_str("bis"), v8_num(1234));
8654 script = Script::Compile(v8_str("other.eval('bis')"));
8655 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008656 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008657
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008658 // Check that the 'this' pointer points to the global object evaluating
8659 // code.
8660 other->Global()->Set(v8_str("t"), other->Global());
8661 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008662 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008663 CHECK(result->IsTrue());
8664 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008665
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008666 // Check that variables introduced in with-statement are not visible in
8667 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008668 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008669 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008670 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008671 CHECK(try_catch.HasCaught());
8672 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008673
8674 // Check that you cannot use 'eval.call' with another object than the
8675 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008676 script =
8677 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8678 result = script->Run();
8679 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008680}
8681
8682
ager@chromium.orge2902be2009-06-08 12:21:35 +00008683// Test that calling eval in a context which has been detached from
8684// its global throws an exception. This behavior is consistent with
8685// other JavaScript implementations.
8686THREADED_TEST(EvalInDetachedGlobal) {
8687 v8::HandleScope scope;
8688
8689 v8::Persistent<Context> context0 = Context::New();
8690 v8::Persistent<Context> context1 = Context::New();
8691
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008692 // Set up function in context0 that uses eval from context0.
ager@chromium.orge2902be2009-06-08 12:21:35 +00008693 context0->Enter();
8694 v8::Handle<v8::Value> fun =
8695 CompileRun("var x = 42;"
8696 "(function() {"
8697 " var e = eval;"
8698 " return function(s) { return e(s); }"
8699 "})()");
8700 context0->Exit();
8701
8702 // Put the function into context1 and call it before and after
8703 // detaching the global. Before detaching, the call succeeds and
8704 // after detaching and exception is thrown.
8705 context1->Enter();
8706 context1->Global()->Set(v8_str("fun"), fun);
8707 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8708 CHECK_EQ(42, x_value->Int32Value());
8709 context0->DetachGlobal();
8710 v8::TryCatch catcher;
8711 x_value = CompileRun("fun('x')");
8712 CHECK(x_value.IsEmpty());
8713 CHECK(catcher.HasCaught());
8714 context1->Exit();
8715
8716 context1.Dispose();
8717 context0.Dispose();
8718}
8719
8720
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008721THREADED_TEST(CrossLazyLoad) {
8722 v8::HandleScope scope;
8723 LocalContext other;
8724 LocalContext current;
8725
8726 Local<String> token = v8_str("<security token>");
8727 other->SetSecurityToken(token);
8728 current->SetSecurityToken(token);
8729
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008730 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008731 current->Global()->Set(v8_str("other"), other->Global());
8732
8733 // Trigger lazy loading in other context.
8734 Local<Script> script =
8735 Script::Compile(v8_str("other.eval('new Date(42)')"));
8736 Local<Value> value = script->Run();
8737 CHECK_EQ(42.0, value->NumberValue());
8738}
8739
8740
8741static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8742 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008743 if (args.IsConstructCall()) {
8744 if (args[0]->IsInt32()) {
8745 return v8_num(-args[0]->Int32Value());
8746 }
8747 }
8748
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008749 return args[0];
8750}
8751
8752
8753// Test that a call handler can be set for objects which will allow
8754// non-function objects created through the API to be called as
8755// functions.
8756THREADED_TEST(CallAsFunction) {
8757 v8::HandleScope scope;
8758 LocalContext context;
8759
lrn@chromium.org1c092762011-05-09 09:42:16 +00008760 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8761 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8762 instance_template->SetCallAsFunctionHandler(call_as_function);
8763 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8764 context->Global()->Set(v8_str("obj"), instance);
8765 v8::TryCatch try_catch;
8766 Local<Value> value;
8767 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008768
lrn@chromium.org1c092762011-05-09 09:42:16 +00008769 value = CompileRun("obj(42)");
8770 CHECK(!try_catch.HasCaught());
8771 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008772
lrn@chromium.org1c092762011-05-09 09:42:16 +00008773 value = CompileRun("(function(o){return o(49)})(obj)");
8774 CHECK(!try_catch.HasCaught());
8775 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008776
lrn@chromium.org1c092762011-05-09 09:42:16 +00008777 // test special case of call as function
8778 value = CompileRun("[obj]['0'](45)");
8779 CHECK(!try_catch.HasCaught());
8780 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008781
lrn@chromium.org1c092762011-05-09 09:42:16 +00008782 value = CompileRun("obj.call = Function.prototype.call;"
8783 "obj.call(null, 87)");
8784 CHECK(!try_catch.HasCaught());
8785 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008786
lrn@chromium.org1c092762011-05-09 09:42:16 +00008787 // Regression tests for bug #1116356: Calling call through call/apply
8788 // must work for non-function receivers.
8789 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8790 value = CompileRun(apply_99);
8791 CHECK(!try_catch.HasCaught());
8792 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008793
lrn@chromium.org1c092762011-05-09 09:42:16 +00008794 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8795 value = CompileRun(call_17);
8796 CHECK(!try_catch.HasCaught());
8797 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008798
lrn@chromium.org1c092762011-05-09 09:42:16 +00008799 // Check that the call-as-function handler can be called through
8800 // new.
8801 value = CompileRun("new obj(43)");
8802 CHECK(!try_catch.HasCaught());
8803 CHECK_EQ(-43, value->Int32Value());
8804
8805 // Check that the call-as-function handler can be called through
8806 // the API.
8807 v8::Handle<Value> args[] = { v8_num(28) };
8808 value = instance->CallAsFunction(instance, 1, args);
8809 CHECK(!try_catch.HasCaught());
8810 CHECK_EQ(28, value->Int32Value());
8811 }
8812
8813 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008814 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008815 USE(instance_template);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008816 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8817 context->Global()->Set(v8_str("obj2"), instance);
8818 v8::TryCatch try_catch;
8819 Local<Value> value;
8820 CHECK(!try_catch.HasCaught());
8821
8822 // Call an object without call-as-function handler through the JS
8823 value = CompileRun("obj2(28)");
8824 CHECK(value.IsEmpty());
8825 CHECK(try_catch.HasCaught());
8826 String::AsciiValue exception_value1(try_catch.Exception());
8827 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8828 *exception_value1);
8829 try_catch.Reset();
8830
8831 // Call an object without call-as-function handler through the API
8832 value = CompileRun("obj2(28)");
8833 v8::Handle<Value> args[] = { v8_num(28) };
8834 value = instance->CallAsFunction(instance, 1, args);
8835 CHECK(value.IsEmpty());
8836 CHECK(try_catch.HasCaught());
8837 String::AsciiValue exception_value2(try_catch.Exception());
8838 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8839 try_catch.Reset();
8840 }
8841
8842 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8843 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8844 instance_template->SetCallAsFunctionHandler(ThrowValue);
8845 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8846 context->Global()->Set(v8_str("obj3"), instance);
8847 v8::TryCatch try_catch;
8848 Local<Value> value;
8849 CHECK(!try_catch.HasCaught());
8850
8851 // Catch the exception which is thrown by call-as-function handler
8852 value = CompileRun("obj3(22)");
8853 CHECK(try_catch.HasCaught());
8854 String::AsciiValue exception_value1(try_catch.Exception());
8855 CHECK_EQ("22", *exception_value1);
8856 try_catch.Reset();
8857
8858 v8::Handle<Value> args[] = { v8_num(23) };
8859 value = instance->CallAsFunction(instance, 1, args);
8860 CHECK(try_catch.HasCaught());
8861 String::AsciiValue exception_value2(try_catch.Exception());
8862 CHECK_EQ("23", *exception_value2);
8863 try_catch.Reset();
8864 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008865}
8866
8867
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008868// Check whether a non-function object is callable.
8869THREADED_TEST(CallableObject) {
8870 v8::HandleScope scope;
8871 LocalContext context;
8872
8873 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8874 instance_template->SetCallAsFunctionHandler(call_as_function);
8875 Local<Object> instance = instance_template->NewInstance();
8876 v8::TryCatch try_catch;
8877
8878 CHECK(instance->IsCallable());
8879 CHECK(!try_catch.HasCaught());
8880 }
8881
8882 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8883 Local<Object> instance = instance_template->NewInstance();
8884 v8::TryCatch try_catch;
8885
8886 CHECK(!instance->IsCallable());
8887 CHECK(!try_catch.HasCaught());
8888 }
8889
8890 { Local<FunctionTemplate> function_template =
8891 FunctionTemplate::New(call_as_function);
8892 Local<Function> function = function_template->GetFunction();
8893 Local<Object> instance = function;
8894 v8::TryCatch try_catch;
8895
8896 CHECK(instance->IsCallable());
8897 CHECK(!try_catch.HasCaught());
8898 }
8899
8900 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8901 Local<Function> function = function_template->GetFunction();
8902 Local<Object> instance = function;
8903 v8::TryCatch try_catch;
8904
8905 CHECK(instance->IsCallable());
8906 CHECK(!try_catch.HasCaught());
8907 }
8908}
8909
8910
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008911static int CountHandles() {
8912 return v8::HandleScope::NumberOfHandles();
8913}
8914
8915
8916static int Recurse(int depth, int iterations) {
8917 v8::HandleScope scope;
8918 if (depth == 0) return CountHandles();
8919 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008920 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008921 }
8922 return Recurse(depth - 1, iterations);
8923}
8924
8925
8926THREADED_TEST(HandleIteration) {
8927 static const int kIterations = 500;
8928 static const int kNesting = 200;
8929 CHECK_EQ(0, CountHandles());
8930 {
8931 v8::HandleScope scope1;
8932 CHECK_EQ(0, CountHandles());
8933 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008934 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008935 CHECK_EQ(i + 1, CountHandles());
8936 }
8937
8938 CHECK_EQ(kIterations, CountHandles());
8939 {
8940 v8::HandleScope scope2;
8941 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008942 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008943 CHECK_EQ(j + 1 + kIterations, CountHandles());
8944 }
8945 }
8946 CHECK_EQ(kIterations, CountHandles());
8947 }
8948 CHECK_EQ(0, CountHandles());
8949 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8950}
8951
8952
8953static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8954 Local<String> name,
8955 const AccessorInfo& info) {
8956 ApiTestFuzzer::Fuzz();
8957 return v8::Handle<Value>();
8958}
8959
8960
8961THREADED_TEST(InterceptorHasOwnProperty) {
8962 v8::HandleScope scope;
8963 LocalContext context;
8964 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8965 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8966 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8967 Local<Function> function = fun_templ->GetFunction();
8968 context->Global()->Set(v8_str("constructor"), function);
8969 v8::Handle<Value> value = CompileRun(
8970 "var o = new constructor();"
8971 "o.hasOwnProperty('ostehaps');");
8972 CHECK_EQ(false, value->BooleanValue());
8973 value = CompileRun(
8974 "o.ostehaps = 42;"
8975 "o.hasOwnProperty('ostehaps');");
8976 CHECK_EQ(true, value->BooleanValue());
8977 value = CompileRun(
8978 "var p = new constructor();"
8979 "p.hasOwnProperty('ostehaps');");
8980 CHECK_EQ(false, value->BooleanValue());
8981}
8982
8983
ager@chromium.org9085a012009-05-11 19:22:57 +00008984static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8985 Local<String> name,
8986 const AccessorInfo& info) {
8987 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008988 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00008989 return v8::Handle<Value>();
8990}
8991
8992
8993THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8994 v8::HandleScope scope;
8995 LocalContext context;
8996 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8997 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8998 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8999 Local<Function> function = fun_templ->GetFunction();
9000 context->Global()->Set(v8_str("constructor"), function);
9001 // Let's first make some stuff so we can be sure to get a good GC.
9002 CompileRun(
9003 "function makestr(size) {"
9004 " switch (size) {"
9005 " case 1: return 'f';"
9006 " case 2: return 'fo';"
9007 " case 3: return 'foo';"
9008 " }"
9009 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
9010 "}"
9011 "var x = makestr(12345);"
9012 "x = makestr(31415);"
9013 "x = makestr(23456);");
9014 v8::Handle<Value> value = CompileRun(
9015 "var o = new constructor();"
9016 "o.__proto__ = new String(x);"
9017 "o.hasOwnProperty('ostehaps');");
9018 CHECK_EQ(false, value->BooleanValue());
9019}
9020
9021
ager@chromium.orge2902be2009-06-08 12:21:35 +00009022typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
9023 const AccessorInfo& info);
9024
9025
9026static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
9027 const char* source,
9028 int expected) {
9029 v8::HandleScope scope;
9030 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009031 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00009032 LocalContext context;
9033 context->Global()->Set(v8_str("o"), templ->NewInstance());
9034 v8::Handle<Value> value = CompileRun(source);
9035 CHECK_EQ(expected, value->Int32Value());
9036}
9037
9038
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009039static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
9040 const AccessorInfo& info) {
9041 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009042 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9043 CHECK_EQ(isolate, info.GetIsolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009044 CHECK_EQ(v8_str("data"), info.Data());
9045 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009046 return v8::Integer::New(42);
9047}
9048
9049
9050// This test should hit the load IC for the interceptor case.
9051THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00009052 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009053 "var result = 0;"
9054 "for (var i = 0; i < 1000; i++) {"
9055 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00009056 "}",
9057 42);
9058}
9059
9060
9061// Below go several tests which verify that JITing for various
9062// configurations of interceptor and explicit fields works fine
9063// (those cases are special cased to get better performance).
9064
9065static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
9066 const AccessorInfo& info) {
9067 ApiTestFuzzer::Fuzz();
9068 return v8_str("x")->Equals(name)
9069 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
9070}
9071
9072
9073THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
9074 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9075 "var result = 0;"
9076 "o.y = 239;"
9077 "for (var i = 0; i < 1000; i++) {"
9078 " result = o.y;"
9079 "}",
9080 239);
9081}
9082
9083
9084THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
9085 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9086 "var result = 0;"
9087 "o.__proto__ = { 'y': 239 };"
9088 "for (var i = 0; i < 1000; i++) {"
9089 " result = o.y + o.x;"
9090 "}",
9091 239 + 42);
9092}
9093
9094
9095THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
9096 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9097 "var result = 0;"
9098 "o.__proto__.y = 239;"
9099 "for (var i = 0; i < 1000; i++) {"
9100 " result = o.y + o.x;"
9101 "}",
9102 239 + 42);
9103}
9104
9105
9106THREADED_TEST(InterceptorLoadICUndefined) {
9107 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9108 "var result = 0;"
9109 "for (var i = 0; i < 1000; i++) {"
9110 " result = (o.y == undefined) ? 239 : 42;"
9111 "}",
9112 239);
9113}
9114
9115
9116THREADED_TEST(InterceptorLoadICWithOverride) {
9117 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9118 "fst = new Object(); fst.__proto__ = o;"
9119 "snd = new Object(); snd.__proto__ = fst;"
9120 "var result1 = 0;"
9121 "for (var i = 0; i < 1000; i++) {"
9122 " result1 = snd.x;"
9123 "}"
9124 "fst.x = 239;"
9125 "var result = 0;"
9126 "for (var i = 0; i < 1000; i++) {"
9127 " result = snd.x;"
9128 "}"
9129 "result + result1",
9130 239 + 42);
9131}
9132
9133
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009134// Test the case when we stored field into
9135// a stub, but interceptor produced value on its own.
9136THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
9137 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9138 "proto = new Object();"
9139 "o.__proto__ = proto;"
9140 "proto.x = 239;"
9141 "for (var i = 0; i < 1000; i++) {"
9142 " o.x;"
9143 // Now it should be ICed and keep a reference to x defined on proto
9144 "}"
9145 "var result = 0;"
9146 "for (var i = 0; i < 1000; i++) {"
9147 " result += o.x;"
9148 "}"
9149 "result;",
9150 42 * 1000);
9151}
9152
9153
9154// Test the case when we stored field into
9155// a stub, but it got invalidated later on.
9156THREADED_TEST(InterceptorLoadICInvalidatedField) {
9157 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9158 "proto1 = new Object();"
9159 "proto2 = new Object();"
9160 "o.__proto__ = proto1;"
9161 "proto1.__proto__ = proto2;"
9162 "proto2.y = 239;"
9163 "for (var i = 0; i < 1000; i++) {"
9164 " o.y;"
9165 // Now it should be ICed and keep a reference to y defined on proto2
9166 "}"
9167 "proto1.y = 42;"
9168 "var result = 0;"
9169 "for (var i = 0; i < 1000; i++) {"
9170 " result += o.y;"
9171 "}"
9172 "result;",
9173 42 * 1000);
9174}
9175
9176
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00009177static int interceptor_load_not_handled_calls = 0;
9178static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
9179 const AccessorInfo& info) {
9180 ++interceptor_load_not_handled_calls;
9181 return v8::Handle<v8::Value>();
9182}
9183
9184
9185// Test how post-interceptor lookups are done in the non-cacheable
9186// case: the interceptor should not be invoked during this lookup.
9187THREADED_TEST(InterceptorLoadICPostInterceptor) {
9188 interceptor_load_not_handled_calls = 0;
9189 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
9190 "receiver = new Object();"
9191 "receiver.__proto__ = o;"
9192 "proto = new Object();"
9193 "/* Make proto a slow-case object. */"
9194 "for (var i = 0; i < 1000; i++) {"
9195 " proto[\"xxxxxxxx\" + i] = [];"
9196 "}"
9197 "proto.x = 17;"
9198 "o.__proto__ = proto;"
9199 "var result = 0;"
9200 "for (var i = 0; i < 1000; i++) {"
9201 " result += receiver.x;"
9202 "}"
9203 "result;",
9204 17 * 1000);
9205 CHECK_EQ(1000, interceptor_load_not_handled_calls);
9206}
9207
9208
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009209// Test the case when we stored field into
9210// a stub, but it got invalidated later on due to override on
9211// global object which is between interceptor and fields' holders.
9212THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
9213 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9214 "o.__proto__ = this;" // set a global to be a proto of o.
9215 "this.__proto__.y = 239;"
9216 "for (var i = 0; i < 10; i++) {"
9217 " if (o.y != 239) throw 'oops: ' + o.y;"
9218 // Now it should be ICed and keep a reference to y defined on field_holder.
9219 "}"
9220 "this.y = 42;" // Assign on a global.
9221 "var result = 0;"
9222 "for (var i = 0; i < 10; i++) {"
9223 " result += o.y;"
9224 "}"
9225 "result;",
9226 42 * 10);
9227}
9228
9229
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009230static void SetOnThis(Local<String> name,
9231 Local<Value> value,
9232 const AccessorInfo& info) {
9233 info.This()->ForceSet(name, value);
9234}
9235
9236
9237THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9238 v8::HandleScope scope;
9239 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9240 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9241 templ->SetAccessor(v8_str("y"), Return239);
9242 LocalContext context;
9243 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009244
9245 // Check the case when receiver and interceptor's holder
9246 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009247 v8::Handle<Value> value = CompileRun(
9248 "var result = 0;"
9249 "for (var i = 0; i < 7; i++) {"
9250 " result = o.y;"
9251 "}");
9252 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009253
9254 // Check the case when interceptor's holder is in proto chain
9255 // of receiver.
9256 value = CompileRun(
9257 "r = { __proto__: o };"
9258 "var result = 0;"
9259 "for (var i = 0; i < 7; i++) {"
9260 " result = r.y;"
9261 "}");
9262 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009263}
9264
9265
9266THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9267 v8::HandleScope scope;
9268 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9269 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9270 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9271 templ_p->SetAccessor(v8_str("y"), Return239);
9272
9273 LocalContext context;
9274 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9275 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9276
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009277 // Check the case when receiver and interceptor's holder
9278 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009279 v8::Handle<Value> value = CompileRun(
9280 "o.__proto__ = p;"
9281 "var result = 0;"
9282 "for (var i = 0; i < 7; i++) {"
9283 " result = o.x + o.y;"
9284 "}");
9285 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009286
9287 // Check the case when interceptor's holder is in proto chain
9288 // of receiver.
9289 value = CompileRun(
9290 "r = { __proto__: o };"
9291 "var result = 0;"
9292 "for (var i = 0; i < 7; i++) {"
9293 " result = r.x + r.y;"
9294 "}");
9295 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009296}
9297
9298
9299THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9300 v8::HandleScope scope;
9301 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9302 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9303 templ->SetAccessor(v8_str("y"), Return239);
9304
9305 LocalContext context;
9306 context->Global()->Set(v8_str("o"), templ->NewInstance());
9307
9308 v8::Handle<Value> value = CompileRun(
9309 "fst = new Object(); fst.__proto__ = o;"
9310 "snd = new Object(); snd.__proto__ = fst;"
9311 "var result1 = 0;"
9312 "for (var i = 0; i < 7; i++) {"
9313 " result1 = snd.x;"
9314 "}"
9315 "fst.x = 239;"
9316 "var result = 0;"
9317 "for (var i = 0; i < 7; i++) {"
9318 " result = snd.x;"
9319 "}"
9320 "result + result1");
9321 CHECK_EQ(239 + 42, value->Int32Value());
9322}
9323
9324
9325// Test the case when we stored callback into
9326// a stub, but interceptor produced value on its own.
9327THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9328 v8::HandleScope scope;
9329 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9330 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9331 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9332 templ_p->SetAccessor(v8_str("y"), Return239);
9333
9334 LocalContext context;
9335 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9336 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9337
9338 v8::Handle<Value> value = CompileRun(
9339 "o.__proto__ = p;"
9340 "for (var i = 0; i < 7; i++) {"
9341 " o.x;"
9342 // Now it should be ICed and keep a reference to x defined on p
9343 "}"
9344 "var result = 0;"
9345 "for (var i = 0; i < 7; i++) {"
9346 " result += o.x;"
9347 "}"
9348 "result");
9349 CHECK_EQ(42 * 7, value->Int32Value());
9350}
9351
9352
9353// Test the case when we stored callback into
9354// a stub, but it got invalidated later on.
9355THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9356 v8::HandleScope scope;
9357 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9358 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9359 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9360 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9361
9362 LocalContext context;
9363 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9364 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9365
9366 v8::Handle<Value> value = CompileRun(
9367 "inbetween = new Object();"
9368 "o.__proto__ = inbetween;"
9369 "inbetween.__proto__ = p;"
9370 "for (var i = 0; i < 10; i++) {"
9371 " o.y;"
9372 // Now it should be ICed and keep a reference to y defined on p
9373 "}"
9374 "inbetween.y = 42;"
9375 "var result = 0;"
9376 "for (var i = 0; i < 10; i++) {"
9377 " result += o.y;"
9378 "}"
9379 "result");
9380 CHECK_EQ(42 * 10, value->Int32Value());
9381}
9382
9383
9384// Test the case when we stored callback into
9385// a stub, but it got invalidated later on due to override on
9386// global object which is between interceptor and callbacks' holders.
9387THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9388 v8::HandleScope scope;
9389 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9390 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9391 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9392 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9393
9394 LocalContext context;
9395 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9396 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9397
9398 v8::Handle<Value> value = CompileRun(
9399 "o.__proto__ = this;"
9400 "this.__proto__ = p;"
9401 "for (var i = 0; i < 10; i++) {"
9402 " if (o.y != 239) throw 'oops: ' + o.y;"
9403 // Now it should be ICed and keep a reference to y defined on p
9404 "}"
9405 "this.y = 42;"
9406 "var result = 0;"
9407 "for (var i = 0; i < 10; i++) {"
9408 " result += o.y;"
9409 "}"
9410 "result");
9411 CHECK_EQ(42 * 10, value->Int32Value());
9412}
9413
9414
ager@chromium.orge2902be2009-06-08 12:21:35 +00009415static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9416 const AccessorInfo& info) {
9417 ApiTestFuzzer::Fuzz();
9418 CHECK(v8_str("x")->Equals(name));
9419 return v8::Integer::New(0);
9420}
9421
9422
9423THREADED_TEST(InterceptorReturningZero) {
9424 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9425 "o.x == undefined ? 1 : 0",
9426 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009427}
9428
9429
9430static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009431 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009432 CHECK(v8_str("x")->Equals(key));
9433 CHECK_EQ(42, value->Int32Value());
9434 return value;
9435}
9436
9437
9438// This test should hit the store IC for the interceptor case.
9439THREADED_TEST(InterceptorStoreIC) {
9440 v8::HandleScope scope;
9441 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9442 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009443 InterceptorStoreICSetter,
9444 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009445 LocalContext context;
9446 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009447 CompileRun(
9448 "for (var i = 0; i < 1000; i++) {"
9449 " o.x = 42;"
9450 "}");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009451}
9452
9453
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009454THREADED_TEST(InterceptorStoreICWithNoSetter) {
9455 v8::HandleScope scope;
9456 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9457 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9458 LocalContext context;
9459 context->Global()->Set(v8_str("o"), templ->NewInstance());
9460 v8::Handle<Value> value = CompileRun(
9461 "for (var i = 0; i < 1000; i++) {"
9462 " o.y = 239;"
9463 "}"
9464 "42 + o.y");
9465 CHECK_EQ(239 + 42, value->Int32Value());
9466}
9467
9468
9469
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009470
9471v8::Handle<Value> call_ic_function;
9472v8::Handle<Value> call_ic_function2;
9473v8::Handle<Value> call_ic_function3;
9474
9475static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9476 const AccessorInfo& info) {
9477 ApiTestFuzzer::Fuzz();
9478 CHECK(v8_str("x")->Equals(name));
9479 return call_ic_function;
9480}
9481
9482
9483// This test should hit the call IC for the interceptor case.
9484THREADED_TEST(InterceptorCallIC) {
9485 v8::HandleScope scope;
9486 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9487 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9488 LocalContext context;
9489 context->Global()->Set(v8_str("o"), templ->NewInstance());
9490 call_ic_function =
9491 v8_compile("function f(x) { return x + 1; }; f")->Run();
9492 v8::Handle<Value> value = CompileRun(
9493 "var result = 0;"
9494 "for (var i = 0; i < 1000; i++) {"
9495 " result = o.x(41);"
9496 "}");
9497 CHECK_EQ(42, value->Int32Value());
9498}
9499
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009500
9501// This test checks that if interceptor doesn't provide
9502// a value, we can fetch regular value.
9503THREADED_TEST(InterceptorCallICSeesOthers) {
9504 v8::HandleScope scope;
9505 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9506 templ->SetNamedPropertyHandler(NoBlockGetterX);
9507 LocalContext context;
9508 context->Global()->Set(v8_str("o"), templ->NewInstance());
9509 v8::Handle<Value> value = CompileRun(
9510 "o.x = function f(x) { return x + 1; };"
9511 "var result = 0;"
9512 "for (var i = 0; i < 7; i++) {"
9513 " result = o.x(41);"
9514 "}");
9515 CHECK_EQ(42, value->Int32Value());
9516}
9517
9518
9519static v8::Handle<Value> call_ic_function4;
9520static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9521 const AccessorInfo& info) {
9522 ApiTestFuzzer::Fuzz();
9523 CHECK(v8_str("x")->Equals(name));
9524 return call_ic_function4;
9525}
9526
9527
9528// This test checks that if interceptor provides a function,
9529// even if we cached shadowed variant, interceptor's function
9530// is invoked
9531THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9532 v8::HandleScope scope;
9533 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9534 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9535 LocalContext context;
9536 context->Global()->Set(v8_str("o"), templ->NewInstance());
9537 call_ic_function4 =
9538 v8_compile("function f(x) { return x - 1; }; f")->Run();
9539 v8::Handle<Value> value = CompileRun(
9540 "o.__proto__.x = function(x) { return x + 1; };"
9541 "var result = 0;"
9542 "for (var i = 0; i < 1000; i++) {"
9543 " result = o.x(42);"
9544 "}");
9545 CHECK_EQ(41, value->Int32Value());
9546}
9547
9548
9549// Test the case when we stored cacheable lookup into
9550// a stub, but it got invalidated later on
9551THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9552 v8::HandleScope scope;
9553 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9554 templ->SetNamedPropertyHandler(NoBlockGetterX);
9555 LocalContext context;
9556 context->Global()->Set(v8_str("o"), templ->NewInstance());
9557 v8::Handle<Value> value = CompileRun(
9558 "proto1 = new Object();"
9559 "proto2 = new Object();"
9560 "o.__proto__ = proto1;"
9561 "proto1.__proto__ = proto2;"
9562 "proto2.y = function(x) { return x + 1; };"
9563 // Invoke it many times to compile a stub
9564 "for (var i = 0; i < 7; i++) {"
9565 " o.y(42);"
9566 "}"
9567 "proto1.y = function(x) { return x - 1; };"
9568 "var result = 0;"
9569 "for (var i = 0; i < 7; i++) {"
9570 " result += o.y(42);"
9571 "}");
9572 CHECK_EQ(41 * 7, value->Int32Value());
9573}
9574
9575
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009576// This test checks that if interceptor doesn't provide a function,
9577// cached constant function is used
9578THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9579 v8::HandleScope scope;
9580 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9581 templ->SetNamedPropertyHandler(NoBlockGetterX);
9582 LocalContext context;
9583 context->Global()->Set(v8_str("o"), templ->NewInstance());
9584 v8::Handle<Value> value = CompileRun(
9585 "function inc(x) { return x + 1; };"
9586 "inc(1);"
9587 "o.x = inc;"
9588 "var result = 0;"
9589 "for (var i = 0; i < 1000; i++) {"
9590 " result = o.x(42);"
9591 "}");
9592 CHECK_EQ(43, value->Int32Value());
9593}
9594
9595
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009596static v8::Handle<Value> call_ic_function5;
9597static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9598 const AccessorInfo& info) {
9599 ApiTestFuzzer::Fuzz();
9600 if (v8_str("x")->Equals(name))
9601 return call_ic_function5;
9602 else
9603 return Local<Value>();
9604}
9605
9606
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009607// This test checks that if interceptor provides a function,
9608// even if we cached constant function, interceptor's function
9609// is invoked
9610THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9611 v8::HandleScope scope;
9612 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9613 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9614 LocalContext context;
9615 context->Global()->Set(v8_str("o"), templ->NewInstance());
9616 call_ic_function5 =
9617 v8_compile("function f(x) { return x - 1; }; f")->Run();
9618 v8::Handle<Value> value = CompileRun(
9619 "function inc(x) { return x + 1; };"
9620 "inc(1);"
9621 "o.x = inc;"
9622 "var result = 0;"
9623 "for (var i = 0; i < 1000; i++) {"
9624 " result = o.x(42);"
9625 "}");
9626 CHECK_EQ(41, value->Int32Value());
9627}
9628
9629
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009630static v8::Handle<Value> call_ic_function6;
9631static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9632 const AccessorInfo& info) {
9633 ApiTestFuzzer::Fuzz();
9634 if (v8_str("x")->Equals(name))
9635 return call_ic_function6;
9636 else
9637 return Local<Value>();
9638}
9639
9640
9641// Same test as above, except the code is wrapped in a function
9642// to test the optimized compiler.
9643THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9644 i::FLAG_allow_natives_syntax = true;
9645 v8::HandleScope scope;
9646 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9647 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9648 LocalContext context;
9649 context->Global()->Set(v8_str("o"), templ->NewInstance());
9650 call_ic_function6 =
9651 v8_compile("function f(x) { return x - 1; }; f")->Run();
9652 v8::Handle<Value> value = CompileRun(
9653 "function inc(x) { return x + 1; };"
9654 "inc(1);"
9655 "o.x = inc;"
9656 "function test() {"
9657 " var result = 0;"
9658 " for (var i = 0; i < 1000; i++) {"
9659 " result = o.x(42);"
9660 " }"
9661 " return result;"
9662 "};"
9663 "test();"
9664 "test();"
9665 "test();"
9666 "%OptimizeFunctionOnNextCall(test);"
9667 "test()");
9668 CHECK_EQ(41, value->Int32Value());
9669}
9670
9671
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009672// Test the case when we stored constant function into
9673// a stub, but it got invalidated later on
9674THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9675 v8::HandleScope scope;
9676 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9677 templ->SetNamedPropertyHandler(NoBlockGetterX);
9678 LocalContext context;
9679 context->Global()->Set(v8_str("o"), templ->NewInstance());
9680 v8::Handle<Value> value = CompileRun(
9681 "function inc(x) { return x + 1; };"
9682 "inc(1);"
9683 "proto1 = new Object();"
9684 "proto2 = new Object();"
9685 "o.__proto__ = proto1;"
9686 "proto1.__proto__ = proto2;"
9687 "proto2.y = inc;"
9688 // Invoke it many times to compile a stub
9689 "for (var i = 0; i < 7; i++) {"
9690 " o.y(42);"
9691 "}"
9692 "proto1.y = function(x) { return x - 1; };"
9693 "var result = 0;"
9694 "for (var i = 0; i < 7; i++) {"
9695 " result += o.y(42);"
9696 "}");
9697 CHECK_EQ(41 * 7, value->Int32Value());
9698}
9699
9700
9701// Test the case when we stored constant function into
9702// a stub, but it got invalidated later on due to override on
9703// global object which is between interceptor and constant function' holders.
9704THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9705 v8::HandleScope scope;
9706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9707 templ->SetNamedPropertyHandler(NoBlockGetterX);
9708 LocalContext context;
9709 context->Global()->Set(v8_str("o"), templ->NewInstance());
9710 v8::Handle<Value> value = CompileRun(
9711 "function inc(x) { return x + 1; };"
9712 "inc(1);"
9713 "o.__proto__ = this;"
9714 "this.__proto__.y = inc;"
9715 // Invoke it many times to compile a stub
9716 "for (var i = 0; i < 7; i++) {"
9717 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9718 "}"
9719 "this.y = function(x) { return x - 1; };"
9720 "var result = 0;"
9721 "for (var i = 0; i < 7; i++) {"
9722 " result += o.y(42);"
9723 "}");
9724 CHECK_EQ(41 * 7, value->Int32Value());
9725}
9726
9727
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009728// Test the case when actual function to call sits on global object.
9729THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9730 v8::HandleScope scope;
9731 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9732 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9733
9734 LocalContext context;
9735 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9736
9737 v8::Handle<Value> value = CompileRun(
9738 "try {"
9739 " o.__proto__ = this;"
9740 " for (var i = 0; i < 10; i++) {"
9741 " var v = o.parseFloat('239');"
9742 " if (v != 239) throw v;"
9743 // Now it should be ICed and keep a reference to parseFloat.
9744 " }"
9745 " var result = 0;"
9746 " for (var i = 0; i < 10; i++) {"
9747 " result += o.parseFloat('239');"
9748 " }"
9749 " result"
9750 "} catch(e) {"
9751 " e"
9752 "};");
9753 CHECK_EQ(239 * 10, value->Int32Value());
9754}
9755
ager@chromium.org5c838252010-02-19 08:53:10 +00009756static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9757 const AccessorInfo& info) {
9758 ApiTestFuzzer::Fuzz();
9759 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9760 ++(*call_count);
9761 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009762 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009763 }
9764 return v8::Handle<Value>();
9765}
9766
9767static v8::Handle<Value> FastApiCallback_TrivialSignature(
9768 const v8::Arguments& args) {
9769 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009770 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9771 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009772 CHECK_EQ(args.This(), args.Holder());
9773 CHECK(args.Data()->Equals(v8_str("method_data")));
9774 return v8::Integer::New(args[0]->Int32Value() + 1);
9775}
9776
9777static v8::Handle<Value> FastApiCallback_SimpleSignature(
9778 const v8::Arguments& args) {
9779 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009780 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9781 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009782 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9783 CHECK(args.Data()->Equals(v8_str("method_data")));
9784 // Note, we're using HasRealNamedProperty instead of Has to avoid
9785 // invoking the interceptor again.
9786 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9787 return v8::Integer::New(args[0]->Int32Value() + 1);
9788}
9789
9790// Helper to maximize the odds of object moving.
9791static void GenerateSomeGarbage() {
9792 CompileRun(
9793 "var garbage;"
9794 "for (var i = 0; i < 1000; i++) {"
9795 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9796 "}"
9797 "garbage = undefined;");
9798}
9799
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009800
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009801v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9802 static int count = 0;
9803 if (count++ % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009804 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9805 // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009806 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9807 }
9808 return v8::Handle<v8::Value>();
9809}
9810
9811
9812THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9813 v8::HandleScope scope;
9814 LocalContext context;
9815 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9816 nativeobject_templ->Set("callback",
9817 v8::FunctionTemplate::New(DirectApiCallback));
9818 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9819 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9820 // call the api function multiple times to ensure direct call stub creation.
9821 CompileRun(
9822 "function f() {"
9823 " for (var i = 1; i <= 30; i++) {"
9824 " nativeobject.callback();"
9825 " }"
9826 "}"
9827 "f();");
9828}
9829
9830
9831v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9832 return v8::ThrowException(v8_str("g"));
9833}
9834
9835
9836THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9837 v8::HandleScope scope;
9838 LocalContext context;
9839 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9840 nativeobject_templ->Set("callback",
9841 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9842 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9843 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9844 // call the api function multiple times to ensure direct call stub creation.
9845 v8::Handle<Value> result = CompileRun(
9846 "var result = '';"
9847 "function f() {"
9848 " for (var i = 1; i <= 5; i++) {"
9849 " try { nativeobject.callback(); } catch (e) { result += e; }"
9850 " }"
9851 "}"
9852 "f(); result;");
9853 CHECK_EQ(v8_str("ggggg"), result);
9854}
9855
9856
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009857v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9858 const v8::AccessorInfo& info) {
9859 if (++p_getter_count % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009860 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009861 GenerateSomeGarbage();
9862 }
9863 return v8::Handle<v8::Value>();
9864}
9865
9866
9867THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9868 v8::HandleScope scope;
9869 LocalContext context;
9870 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9871 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9872 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9873 p_getter_count = 0;
9874 CompileRun(
9875 "function f() {"
9876 " for (var i = 0; i < 30; i++) o1.p1;"
9877 "}"
9878 "f();");
9879 CHECK_EQ(30, p_getter_count);
9880}
9881
9882
9883v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9884 Local<String> name, const v8::AccessorInfo& info) {
9885 return v8::ThrowException(v8_str("g"));
9886}
9887
9888
9889THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9890 v8::HandleScope scope;
9891 LocalContext context;
9892 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9893 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9894 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9895 v8::Handle<Value> result = CompileRun(
9896 "var result = '';"
9897 "for (var i = 0; i < 5; i++) {"
9898 " try { o1.p1; } catch (e) { result += e; }"
9899 "}"
9900 "result;");
9901 CHECK_EQ(v8_str("ggggg"), result);
9902}
9903
9904
ager@chromium.org5c838252010-02-19 08:53:10 +00009905THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9906 int interceptor_call_count = 0;
9907 v8::HandleScope scope;
9908 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9909 v8::Handle<v8::FunctionTemplate> method_templ =
9910 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9911 v8_str("method_data"),
9912 v8::Handle<v8::Signature>());
9913 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9914 proto_templ->Set(v8_str("method"), method_templ);
9915 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9916 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9917 NULL, NULL, NULL, NULL,
9918 v8::External::Wrap(&interceptor_call_count));
9919 LocalContext context;
9920 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9921 GenerateSomeGarbage();
9922 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009923 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009924 "var result = 0;"
9925 "for (var i = 0; i < 100; i++) {"
9926 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009927 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009928 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9929 CHECK_EQ(100, interceptor_call_count);
9930}
9931
9932THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9933 int interceptor_call_count = 0;
9934 v8::HandleScope scope;
9935 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9936 v8::Handle<v8::FunctionTemplate> method_templ =
9937 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9938 v8_str("method_data"),
9939 v8::Signature::New(fun_templ));
9940 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9941 proto_templ->Set(v8_str("method"), method_templ);
9942 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9943 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9944 NULL, NULL, NULL, NULL,
9945 v8::External::Wrap(&interceptor_call_count));
9946 LocalContext context;
9947 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9948 GenerateSomeGarbage();
9949 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009950 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009951 "o.foo = 17;"
9952 "var receiver = {};"
9953 "receiver.__proto__ = o;"
9954 "var result = 0;"
9955 "for (var i = 0; i < 100; i++) {"
9956 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009957 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009958 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9959 CHECK_EQ(100, interceptor_call_count);
9960}
9961
9962THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9963 int interceptor_call_count = 0;
9964 v8::HandleScope scope;
9965 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9966 v8::Handle<v8::FunctionTemplate> method_templ =
9967 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9968 v8_str("method_data"),
9969 v8::Signature::New(fun_templ));
9970 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9971 proto_templ->Set(v8_str("method"), method_templ);
9972 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9973 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9974 NULL, NULL, NULL, NULL,
9975 v8::External::Wrap(&interceptor_call_count));
9976 LocalContext context;
9977 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9978 GenerateSomeGarbage();
9979 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009980 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009981 "o.foo = 17;"
9982 "var receiver = {};"
9983 "receiver.__proto__ = o;"
9984 "var result = 0;"
9985 "var saved_result = 0;"
9986 "for (var i = 0; i < 100; i++) {"
9987 " result = receiver.method(41);"
9988 " if (i == 50) {"
9989 " saved_result = result;"
9990 " receiver = {method: function(x) { return x - 1 }};"
9991 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009992 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009993 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9994 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9995 CHECK_GE(interceptor_call_count, 50);
9996}
9997
9998THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9999 int interceptor_call_count = 0;
10000 v8::HandleScope scope;
10001 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10002 v8::Handle<v8::FunctionTemplate> method_templ =
10003 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10004 v8_str("method_data"),
10005 v8::Signature::New(fun_templ));
10006 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10007 proto_templ->Set(v8_str("method"), method_templ);
10008 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10009 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10010 NULL, NULL, NULL, NULL,
10011 v8::External::Wrap(&interceptor_call_count));
10012 LocalContext context;
10013 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10014 GenerateSomeGarbage();
10015 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010016 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010017 "o.foo = 17;"
10018 "var receiver = {};"
10019 "receiver.__proto__ = o;"
10020 "var result = 0;"
10021 "var saved_result = 0;"
10022 "for (var i = 0; i < 100; i++) {"
10023 " result = receiver.method(41);"
10024 " if (i == 50) {"
10025 " saved_result = result;"
10026 " o.method = function(x) { return x - 1 };"
10027 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010028 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010029 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10030 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10031 CHECK_GE(interceptor_call_count, 50);
10032}
10033
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010034THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10035 int interceptor_call_count = 0;
10036 v8::HandleScope scope;
10037 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10038 v8::Handle<v8::FunctionTemplate> method_templ =
10039 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10040 v8_str("method_data"),
10041 v8::Signature::New(fun_templ));
10042 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10043 proto_templ->Set(v8_str("method"), method_templ);
10044 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10045 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10046 NULL, NULL, NULL, NULL,
10047 v8::External::Wrap(&interceptor_call_count));
10048 LocalContext context;
10049 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10050 GenerateSomeGarbage();
10051 context->Global()->Set(v8_str("o"), fun->NewInstance());
10052 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010053 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010054 "o.foo = 17;"
10055 "var receiver = {};"
10056 "receiver.__proto__ = o;"
10057 "var result = 0;"
10058 "var saved_result = 0;"
10059 "for (var i = 0; i < 100; i++) {"
10060 " result = receiver.method(41);"
10061 " if (i == 50) {"
10062 " saved_result = result;"
10063 " receiver = 333;"
10064 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010065 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010066 CHECK(try_catch.HasCaught());
10067 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10068 try_catch.Exception()->ToString());
10069 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10070 CHECK_GE(interceptor_call_count, 50);
10071}
10072
ager@chromium.org5c838252010-02-19 08:53:10 +000010073THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10074 int interceptor_call_count = 0;
10075 v8::HandleScope scope;
10076 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10077 v8::Handle<v8::FunctionTemplate> method_templ =
10078 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10079 v8_str("method_data"),
10080 v8::Signature::New(fun_templ));
10081 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10082 proto_templ->Set(v8_str("method"), method_templ);
10083 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10084 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10085 NULL, NULL, NULL, NULL,
10086 v8::External::Wrap(&interceptor_call_count));
10087 LocalContext context;
10088 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10089 GenerateSomeGarbage();
10090 context->Global()->Set(v8_str("o"), fun->NewInstance());
10091 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010092 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010093 "o.foo = 17;"
10094 "var receiver = {};"
10095 "receiver.__proto__ = o;"
10096 "var result = 0;"
10097 "var saved_result = 0;"
10098 "for (var i = 0; i < 100; i++) {"
10099 " result = receiver.method(41);"
10100 " if (i == 50) {"
10101 " saved_result = result;"
10102 " receiver = {method: receiver.method};"
10103 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010104 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010105 CHECK(try_catch.HasCaught());
10106 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10107 try_catch.Exception()->ToString());
10108 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10109 CHECK_GE(interceptor_call_count, 50);
10110}
10111
10112THREADED_TEST(CallICFastApi_TrivialSignature) {
10113 v8::HandleScope scope;
10114 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10115 v8::Handle<v8::FunctionTemplate> method_templ =
10116 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10117 v8_str("method_data"),
10118 v8::Handle<v8::Signature>());
10119 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10120 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010121 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010122 USE(templ);
ager@chromium.org5c838252010-02-19 08:53:10 +000010123 LocalContext context;
10124 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10125 GenerateSomeGarbage();
10126 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010127 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010128 "var result = 0;"
10129 "for (var i = 0; i < 100; i++) {"
10130 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010131 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010132
10133 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10134}
10135
10136THREADED_TEST(CallICFastApi_SimpleSignature) {
10137 v8::HandleScope scope;
10138 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10139 v8::Handle<v8::FunctionTemplate> method_templ =
10140 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10141 v8_str("method_data"),
10142 v8::Signature::New(fun_templ));
10143 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10144 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010145 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010146 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010147 LocalContext context;
10148 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10149 GenerateSomeGarbage();
10150 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010151 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010152 "o.foo = 17;"
10153 "var receiver = {};"
10154 "receiver.__proto__ = o;"
10155 "var result = 0;"
10156 "for (var i = 0; i < 100; i++) {"
10157 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010158 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010159
10160 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10161}
10162
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010163THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010164 v8::HandleScope scope;
10165 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10166 v8::Handle<v8::FunctionTemplate> method_templ =
10167 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10168 v8_str("method_data"),
10169 v8::Signature::New(fun_templ));
10170 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10171 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010172 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010173 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010174 LocalContext context;
10175 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10176 GenerateSomeGarbage();
10177 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010178 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010179 "o.foo = 17;"
10180 "var receiver = {};"
10181 "receiver.__proto__ = o;"
10182 "var result = 0;"
10183 "var saved_result = 0;"
10184 "for (var i = 0; i < 100; i++) {"
10185 " result = receiver.method(41);"
10186 " if (i == 50) {"
10187 " saved_result = result;"
10188 " receiver = {method: function(x) { return x - 1 }};"
10189 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010190 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010191 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10192 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10193}
10194
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010195THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10196 v8::HandleScope scope;
10197 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10198 v8::Handle<v8::FunctionTemplate> method_templ =
10199 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10200 v8_str("method_data"),
10201 v8::Signature::New(fun_templ));
10202 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10203 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010204 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010205 CHECK(!templ.IsEmpty());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010206 LocalContext context;
10207 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10208 GenerateSomeGarbage();
10209 context->Global()->Set(v8_str("o"), fun->NewInstance());
10210 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010211 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010212 "o.foo = 17;"
10213 "var receiver = {};"
10214 "receiver.__proto__ = o;"
10215 "var result = 0;"
10216 "var saved_result = 0;"
10217 "for (var i = 0; i < 100; i++) {"
10218 " result = receiver.method(41);"
10219 " if (i == 50) {"
10220 " saved_result = result;"
10221 " receiver = 333;"
10222 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010223 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010224 CHECK(try_catch.HasCaught());
10225 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10226 try_catch.Exception()->ToString());
10227 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10228}
10229
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010230
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010231v8::Handle<Value> keyed_call_ic_function;
10232
10233static v8::Handle<Value> InterceptorKeyedCallICGetter(
10234 Local<String> name, const AccessorInfo& info) {
10235 ApiTestFuzzer::Fuzz();
10236 if (v8_str("x")->Equals(name)) {
10237 return keyed_call_ic_function;
10238 }
10239 return v8::Handle<Value>();
10240}
10241
10242
10243// Test the case when we stored cacheable lookup into
10244// a stub, but the function name changed (to another cacheable function).
10245THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10246 v8::HandleScope scope;
10247 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10248 templ->SetNamedPropertyHandler(NoBlockGetterX);
10249 LocalContext context;
10250 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010251 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010252 "proto = new Object();"
10253 "proto.y = function(x) { return x + 1; };"
10254 "proto.z = function(x) { return x - 1; };"
10255 "o.__proto__ = proto;"
10256 "var result = 0;"
10257 "var method = 'y';"
10258 "for (var i = 0; i < 10; i++) {"
10259 " if (i == 5) { method = 'z'; };"
10260 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010261 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010262 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10263}
10264
10265
10266// Test the case when we stored cacheable lookup into
10267// a stub, but the function name changed (and the new function is present
10268// both before and after the interceptor in the prototype chain).
10269THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10270 v8::HandleScope scope;
10271 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10272 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10273 LocalContext context;
10274 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10275 keyed_call_ic_function =
10276 v8_compile("function f(x) { return x - 1; }; f")->Run();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010277 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010278 "o = new Object();"
10279 "proto2 = new Object();"
10280 "o.y = function(x) { return x + 1; };"
10281 "proto2.y = function(x) { return x + 2; };"
10282 "o.__proto__ = proto1;"
10283 "proto1.__proto__ = proto2;"
10284 "var result = 0;"
10285 "var method = 'x';"
10286 "for (var i = 0; i < 10; i++) {"
10287 " if (i == 5) { method = 'y'; };"
10288 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010289 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010290 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10291}
10292
10293
10294// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10295// on the global object.
10296THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10297 v8::HandleScope scope;
10298 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10299 templ->SetNamedPropertyHandler(NoBlockGetterX);
10300 LocalContext context;
10301 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010302 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010303 "function inc(x) { return x + 1; };"
10304 "inc(1);"
10305 "function dec(x) { return x - 1; };"
10306 "dec(1);"
10307 "o.__proto__ = this;"
10308 "this.__proto__.x = inc;"
10309 "this.__proto__.y = dec;"
10310 "var result = 0;"
10311 "var method = 'x';"
10312 "for (var i = 0; i < 10; i++) {"
10313 " if (i == 5) { method = 'y'; };"
10314 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010315 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010316 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10317}
10318
10319
10320// Test the case when actual function to call sits on global object.
10321THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10322 v8::HandleScope scope;
10323 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10324 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10325 LocalContext context;
10326 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10327
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010328 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010329 "function len(x) { return x.length; };"
10330 "o.__proto__ = this;"
10331 "var m = 'parseFloat';"
10332 "var result = 0;"
10333 "for (var i = 0; i < 10; i++) {"
10334 " if (i == 5) {"
10335 " m = 'len';"
10336 " saved_result = result;"
10337 " };"
10338 " result = o[m]('239');"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010339 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010340 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10341 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10342}
10343
10344// Test the map transition before the interceptor.
10345THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10346 v8::HandleScope scope;
10347 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10348 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10349 LocalContext context;
10350 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10351
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010352 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010353 "var o = new Object();"
10354 "o.__proto__ = proto;"
10355 "o.method = function(x) { return x + 1; };"
10356 "var m = 'method';"
10357 "var result = 0;"
10358 "for (var i = 0; i < 10; i++) {"
10359 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10360 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010361 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010362 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10363}
10364
10365
10366// Test the map transition after the interceptor.
10367THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10368 v8::HandleScope scope;
10369 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10370 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10371 LocalContext context;
10372 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10373
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010374 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010375 "var proto = new Object();"
10376 "o.__proto__ = proto;"
10377 "proto.method = function(x) { return x + 1; };"
10378 "var m = 'method';"
10379 "var result = 0;"
10380 "for (var i = 0; i < 10; i++) {"
10381 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10382 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010383 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010384 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10385}
10386
10387
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010388static int interceptor_call_count = 0;
10389
10390static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10391 const AccessorInfo& info) {
10392 ApiTestFuzzer::Fuzz();
10393 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10394 return call_ic_function2;
10395 }
10396 return v8::Handle<Value>();
10397}
10398
10399
10400// This test should hit load and call ICs for the interceptor case.
10401// Once in a while, the interceptor will reply that a property was not
10402// found in which case we should get a reference error.
10403THREADED_TEST(InterceptorICReferenceErrors) {
10404 v8::HandleScope scope;
10405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10406 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10407 LocalContext context(0, templ, v8::Handle<Value>());
10408 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10409 v8::Handle<Value> value = CompileRun(
10410 "function f() {"
10411 " for (var i = 0; i < 1000; i++) {"
10412 " try { x; } catch(e) { return true; }"
10413 " }"
10414 " return false;"
10415 "};"
10416 "f();");
10417 CHECK_EQ(true, value->BooleanValue());
10418 interceptor_call_count = 0;
10419 value = CompileRun(
10420 "function g() {"
10421 " for (var i = 0; i < 1000; i++) {"
10422 " try { x(42); } catch(e) { return true; }"
10423 " }"
10424 " return false;"
10425 "};"
10426 "g();");
10427 CHECK_EQ(true, value->BooleanValue());
10428}
10429
10430
10431static int interceptor_ic_exception_get_count = 0;
10432
10433static v8::Handle<Value> InterceptorICExceptionGetter(
10434 Local<String> name,
10435 const AccessorInfo& info) {
10436 ApiTestFuzzer::Fuzz();
10437 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10438 return call_ic_function3;
10439 }
10440 if (interceptor_ic_exception_get_count == 20) {
10441 return v8::ThrowException(v8_num(42));
10442 }
10443 // Do not handle get for properties other than x.
10444 return v8::Handle<Value>();
10445}
10446
10447// Test interceptor load/call IC where the interceptor throws an
10448// exception once in a while.
10449THREADED_TEST(InterceptorICGetterExceptions) {
10450 interceptor_ic_exception_get_count = 0;
10451 v8::HandleScope scope;
10452 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10453 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10454 LocalContext context(0, templ, v8::Handle<Value>());
10455 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10456 v8::Handle<Value> value = CompileRun(
10457 "function f() {"
10458 " for (var i = 0; i < 100; i++) {"
10459 " try { x; } catch(e) { return true; }"
10460 " }"
10461 " return false;"
10462 "};"
10463 "f();");
10464 CHECK_EQ(true, value->BooleanValue());
10465 interceptor_ic_exception_get_count = 0;
10466 value = CompileRun(
10467 "function f() {"
10468 " for (var i = 0; i < 100; i++) {"
10469 " try { x(42); } catch(e) { return true; }"
10470 " }"
10471 " return false;"
10472 "};"
10473 "f();");
10474 CHECK_EQ(true, value->BooleanValue());
10475}
10476
10477
10478static int interceptor_ic_exception_set_count = 0;
10479
10480static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010481 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010482 ApiTestFuzzer::Fuzz();
10483 if (++interceptor_ic_exception_set_count > 20) {
10484 return v8::ThrowException(v8_num(42));
10485 }
10486 // Do not actually handle setting.
10487 return v8::Handle<Value>();
10488}
10489
10490// Test interceptor store IC where the interceptor throws an exception
10491// once in a while.
10492THREADED_TEST(InterceptorICSetterExceptions) {
10493 interceptor_ic_exception_set_count = 0;
10494 v8::HandleScope scope;
10495 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10496 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10497 LocalContext context(0, templ, v8::Handle<Value>());
10498 v8::Handle<Value> value = CompileRun(
10499 "function f() {"
10500 " for (var i = 0; i < 100; i++) {"
10501 " try { x = 42; } catch(e) { return true; }"
10502 " }"
10503 " return false;"
10504 "};"
10505 "f();");
10506 CHECK_EQ(true, value->BooleanValue());
10507}
10508
10509
10510// Test that we ignore null interceptors.
10511THREADED_TEST(NullNamedInterceptor) {
10512 v8::HandleScope scope;
10513 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10514 templ->SetNamedPropertyHandler(0);
10515 LocalContext context;
10516 templ->Set("x", v8_num(42));
10517 v8::Handle<v8::Object> obj = templ->NewInstance();
10518 context->Global()->Set(v8_str("obj"), obj);
10519 v8::Handle<Value> value = CompileRun("obj.x");
10520 CHECK(value->IsInt32());
10521 CHECK_EQ(42, value->Int32Value());
10522}
10523
10524
10525// Test that we ignore null interceptors.
10526THREADED_TEST(NullIndexedInterceptor) {
10527 v8::HandleScope scope;
10528 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10529 templ->SetIndexedPropertyHandler(0);
10530 LocalContext context;
10531 templ->Set("42", v8_num(42));
10532 v8::Handle<v8::Object> obj = templ->NewInstance();
10533 context->Global()->Set(v8_str("obj"), obj);
10534 v8::Handle<Value> value = CompileRun("obj[42]");
10535 CHECK(value->IsInt32());
10536 CHECK_EQ(42, value->Int32Value());
10537}
10538
10539
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010540THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10541 v8::HandleScope scope;
10542 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10543 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10544 LocalContext env;
10545 env->Global()->Set(v8_str("obj"),
10546 templ->GetFunction()->NewInstance());
10547 ExpectTrue("obj.x === 42");
10548 ExpectTrue("!obj.propertyIsEnumerable('x')");
10549}
10550
10551
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010552static Handle<Value> ThrowingGetter(Local<String> name,
10553 const AccessorInfo& info) {
10554 ApiTestFuzzer::Fuzz();
10555 ThrowException(Handle<Value>());
10556 return Undefined();
10557}
10558
10559
10560THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10561 HandleScope scope;
10562 LocalContext context;
10563
10564 Local<FunctionTemplate> templ = FunctionTemplate::New();
10565 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10566 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10567
10568 Local<Object> instance = templ->GetFunction()->NewInstance();
10569
10570 Local<Object> another = Object::New();
10571 another->SetPrototype(instance);
10572
10573 Local<Object> with_js_getter = CompileRun(
10574 "o = {};\n"
10575 "o.__defineGetter__('f', function() { throw undefined; });\n"
10576 "o\n").As<Object>();
10577 CHECK(!with_js_getter.IsEmpty());
10578
10579 TryCatch try_catch;
10580
10581 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10582 CHECK(try_catch.HasCaught());
10583 try_catch.Reset();
10584 CHECK(result.IsEmpty());
10585
10586 result = another->GetRealNamedProperty(v8_str("f"));
10587 CHECK(try_catch.HasCaught());
10588 try_catch.Reset();
10589 CHECK(result.IsEmpty());
10590
10591 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10592 CHECK(try_catch.HasCaught());
10593 try_catch.Reset();
10594 CHECK(result.IsEmpty());
10595
10596 result = another->Get(v8_str("f"));
10597 CHECK(try_catch.HasCaught());
10598 try_catch.Reset();
10599 CHECK(result.IsEmpty());
10600
10601 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10602 CHECK(try_catch.HasCaught());
10603 try_catch.Reset();
10604 CHECK(result.IsEmpty());
10605
10606 result = with_js_getter->Get(v8_str("f"));
10607 CHECK(try_catch.HasCaught());
10608 try_catch.Reset();
10609 CHECK(result.IsEmpty());
10610}
10611
10612
10613static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10614 TryCatch try_catch;
10615 // Verboseness is important: it triggers message delivery which can call into
10616 // external code.
10617 try_catch.SetVerbose(true);
10618 CompileRun("throw 'from JS';");
10619 CHECK(try_catch.HasCaught());
10620 CHECK(!i::Isolate::Current()->has_pending_exception());
10621 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10622 return Undefined();
10623}
10624
10625
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010626static int call_depth;
10627
10628
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010629static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10630 TryCatch try_catch;
10631}
10632
10633
10634static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010635 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010636}
10637
10638
10639static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010640 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010641}
10642
10643
10644static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10645 Handle<String> errorMessageString = message->Get();
10646 CHECK(!errorMessageString.IsEmpty());
10647 message->GetStackTrace();
10648 message->GetScriptResourceName();
10649}
10650
10651THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10652 HandleScope scope;
10653 LocalContext context;
10654
10655 Local<Function> func =
10656 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10657 context->Global()->Set(v8_str("func"), func);
10658
10659 MessageCallback callbacks[] =
10660 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10661 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10662 MessageCallback callback = callbacks[i];
10663 if (callback != NULL) {
10664 V8::AddMessageListener(callback);
10665 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +000010666 // Some small number to control number of times message handler should
10667 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010668 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010669 ExpectFalse(
10670 "var thrown = false;\n"
10671 "try { func(); } catch(e) { thrown = true; }\n"
10672 "thrown\n");
10673 if (callback != NULL) {
10674 V8::RemoveMessageListeners(callback);
10675 }
10676 }
10677}
10678
10679
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010680static v8::Handle<Value> ParentGetter(Local<String> name,
10681 const AccessorInfo& info) {
10682 ApiTestFuzzer::Fuzz();
10683 return v8_num(1);
10684}
10685
10686
10687static v8::Handle<Value> ChildGetter(Local<String> name,
10688 const AccessorInfo& info) {
10689 ApiTestFuzzer::Fuzz();
10690 return v8_num(42);
10691}
10692
10693
10694THREADED_TEST(Overriding) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010695 i::FLAG_es5_readonly = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010696 v8::HandleScope scope;
10697 LocalContext context;
10698
10699 // Parent template.
10700 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10701 Local<ObjectTemplate> parent_instance_templ =
10702 parent_templ->InstanceTemplate();
10703 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10704
10705 // Template that inherits from the parent template.
10706 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10707 Local<ObjectTemplate> child_instance_templ =
10708 child_templ->InstanceTemplate();
10709 child_templ->Inherit(parent_templ);
10710 // Override 'f'. The child version of 'f' should get called for child
10711 // instances.
10712 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10713 // Add 'g' twice. The 'g' added last should get called for instances.
10714 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10715 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10716
10717 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10718 // so 'h' can be shadowed on the instance object.
10719 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10720 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10721 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10722
10723 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10724 // but the attribute does not have effect because it is duplicated with
10725 // NULL setter.
10726 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10727 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10728
10729
10730
10731 // Instantiate the child template.
10732 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10733
10734 // Check that the child function overrides the parent one.
10735 context->Global()->Set(v8_str("o"), instance);
10736 Local<Value> value = v8_compile("o.f")->Run();
10737 // Check that the 'g' that was added last is hit.
10738 CHECK_EQ(42, value->Int32Value());
10739 value = v8_compile("o.g")->Run();
10740 CHECK_EQ(42, value->Int32Value());
10741
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010742 // Check that 'h' cannot be shadowed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010743 value = v8_compile("o.h = 3; o.h")->Run();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010744 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010745
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010746 // Check that 'i' cannot be shadowed or changed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010747 value = v8_compile("o.i = 3; o.i")->Run();
10748 CHECK_EQ(42, value->Int32Value());
10749}
10750
10751
10752static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10753 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010754 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010755}
10756
10757
10758THREADED_TEST(IsConstructCall) {
10759 v8::HandleScope scope;
10760
10761 // Function template with call handler.
10762 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10763 templ->SetCallHandler(IsConstructHandler);
10764
10765 LocalContext context;
10766
10767 context->Global()->Set(v8_str("f"), templ->GetFunction());
10768 Local<Value> value = v8_compile("f()")->Run();
10769 CHECK(!value->BooleanValue());
10770 value = v8_compile("new f()")->Run();
10771 CHECK(value->BooleanValue());
10772}
10773
10774
10775THREADED_TEST(ObjectProtoToString) {
10776 v8::HandleScope scope;
10777 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10778 templ->SetClassName(v8_str("MyClass"));
10779
10780 LocalContext context;
10781
10782 Local<String> customized_tostring = v8_str("customized toString");
10783
10784 // Replace Object.prototype.toString
10785 v8_compile("Object.prototype.toString = function() {"
10786 " return 'customized toString';"
10787 "}")->Run();
10788
10789 // Normal ToString call should call replaced Object.prototype.toString
10790 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10791 Local<String> value = instance->ToString();
10792 CHECK(value->IsString() && value->Equals(customized_tostring));
10793
10794 // ObjectProtoToString should not call replace toString function.
10795 value = instance->ObjectProtoToString();
10796 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10797
10798 // Check global
10799 value = context->Global()->ObjectProtoToString();
10800 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10801
10802 // Check ordinary object
10803 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010804 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010805 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10806}
10807
10808
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010809THREADED_TEST(ObjectGetConstructorName) {
10810 v8::HandleScope scope;
10811 LocalContext context;
10812 v8_compile("function Parent() {};"
10813 "function Child() {};"
10814 "Child.prototype = new Parent();"
10815 "var outer = { inner: function() { } };"
10816 "var p = new Parent();"
10817 "var c = new Child();"
10818 "var x = new outer.inner();")->Run();
10819
10820 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10821 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10822 v8_str("Parent")));
10823
10824 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10825 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10826 v8_str("Child")));
10827
10828 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10829 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10830 v8_str("outer.inner")));
10831}
10832
10833
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010834bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010835i::Semaphore* ApiTestFuzzer::all_tests_done_=
10836 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010837int ApiTestFuzzer::active_tests_;
10838int ApiTestFuzzer::tests_being_run_;
10839int ApiTestFuzzer::current_;
10840
10841
10842// We are in a callback and want to switch to another thread (if we
10843// are currently running the thread fuzzing test).
10844void ApiTestFuzzer::Fuzz() {
10845 if (!fuzzing_) return;
10846 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10847 test->ContextSwitch();
10848}
10849
10850
10851// Let the next thread go. Since it is also waiting on the V8 lock it may
10852// not start immediately.
10853bool ApiTestFuzzer::NextThread() {
10854 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010855 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010856 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010857 if (kLogThreading)
10858 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010859 return false;
10860 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010861 if (kLogThreading) {
10862 printf("Switch from %s to %s\n",
10863 test_name,
10864 RegisterThreadedTest::nth(test_position)->name());
10865 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010866 current_ = test_position;
10867 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10868 return true;
10869}
10870
10871
10872void ApiTestFuzzer::Run() {
10873 // When it is our turn...
10874 gate_->Wait();
10875 {
10876 // ... get the V8 lock and start running the test.
10877 v8::Locker locker;
10878 CallTest();
10879 }
10880 // This test finished.
10881 active_ = false;
10882 active_tests_--;
10883 // If it was the last then signal that fact.
10884 if (active_tests_ == 0) {
10885 all_tests_done_->Signal();
10886 } else {
10887 // Otherwise select a new test and start that.
10888 NextThread();
10889 }
10890}
10891
10892
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010893static unsigned linear_congruential_generator;
10894
10895
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010896void ApiTestFuzzer::SetUp(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010897 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010898 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000010899 int count = RegisterThreadedTest::count();
10900 int start = count * part / (LAST_PART + 1);
10901 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10902 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010903 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010904 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010905 }
10906 for (int i = 0; i < active_tests_; i++) {
10907 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10908 }
10909}
10910
10911
10912static void CallTestNumber(int test_number) {
10913 (RegisterThreadedTest::nth(test_number)->callback())();
10914}
10915
10916
10917void ApiTestFuzzer::RunAllTests() {
10918 // Set off the first test.
10919 current_ = -1;
10920 NextThread();
10921 // Wait till they are all done.
10922 all_tests_done_->Wait();
10923}
10924
10925
10926int ApiTestFuzzer::GetNextTestNumber() {
10927 int next_test;
10928 do {
10929 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10930 linear_congruential_generator *= 1664525u;
10931 linear_congruential_generator += 1013904223u;
10932 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10933 return next_test;
10934}
10935
10936
10937void ApiTestFuzzer::ContextSwitch() {
10938 // If the new thread is the same as the current thread there is nothing to do.
10939 if (NextThread()) {
10940 // Now it can start.
10941 v8::Unlocker unlocker;
10942 // Wait till someone starts us again.
10943 gate_->Wait();
10944 // And we're off.
10945 }
10946}
10947
10948
10949void ApiTestFuzzer::TearDown() {
10950 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000010951 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10952 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10953 if (fuzzer != NULL) fuzzer->Join();
10954 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010955}
10956
10957
10958// Lets not be needlessly self-referential.
10959TEST(Threading) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010960 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010961 ApiTestFuzzer::RunAllTests();
10962 ApiTestFuzzer::TearDown();
10963}
10964
10965TEST(Threading2) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010966 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010967 ApiTestFuzzer::RunAllTests();
10968 ApiTestFuzzer::TearDown();
10969}
10970
lrn@chromium.org1c092762011-05-09 09:42:16 +000010971TEST(Threading3) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010972 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010973 ApiTestFuzzer::RunAllTests();
10974 ApiTestFuzzer::TearDown();
10975}
10976
10977TEST(Threading4) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010978 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010979 ApiTestFuzzer::RunAllTests();
10980 ApiTestFuzzer::TearDown();
10981}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010982
10983void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010984 if (kLogThreading)
10985 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010986 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010987 if (kLogThreading)
10988 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010989}
10990
10991
10992static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010993 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010994 ApiTestFuzzer::Fuzz();
10995 v8::Unlocker unlocker;
10996 const char* code = "throw 7;";
10997 {
10998 v8::Locker nested_locker;
10999 v8::HandleScope scope;
11000 v8::Handle<Value> exception;
11001 { v8::TryCatch try_catch;
11002 v8::Handle<Value> value = CompileRun(code);
11003 CHECK(value.IsEmpty());
11004 CHECK(try_catch.HasCaught());
11005 // Make sure to wrap the exception in a new handle because
11006 // the handle returned from the TryCatch is destroyed
11007 // when the TryCatch is destroyed.
11008 exception = Local<Value>::New(try_catch.Exception());
11009 }
11010 return v8::ThrowException(exception);
11011 }
11012}
11013
11014
11015static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011016 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011017 ApiTestFuzzer::Fuzz();
11018 v8::Unlocker unlocker;
11019 const char* code = "throw 7;";
11020 {
11021 v8::Locker nested_locker;
11022 v8::HandleScope scope;
11023 v8::Handle<Value> value = CompileRun(code);
11024 CHECK(value.IsEmpty());
11025 return v8_str("foo");
11026 }
11027}
11028
11029
11030// These are locking tests that don't need to be run again
11031// as part of the locking aggregation tests.
11032TEST(NestedLockers) {
11033 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011034 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011035 v8::HandleScope scope;
11036 LocalContext env;
11037 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
11038 Local<Function> fun = fun_templ->GetFunction();
11039 env->Global()->Set(v8_str("throw_in_js"), fun);
11040 Local<Script> script = v8_compile("(function () {"
11041 " try {"
11042 " throw_in_js();"
11043 " return 42;"
11044 " } catch (e) {"
11045 " return e * 13;"
11046 " }"
11047 "})();");
11048 CHECK_EQ(91, script->Run()->Int32Value());
11049}
11050
11051
11052// These are locking tests that don't need to be run again
11053// as part of the locking aggregation tests.
11054TEST(NestedLockersNoTryCatch) {
11055 v8::Locker locker;
11056 v8::HandleScope scope;
11057 LocalContext env;
11058 Local<v8::FunctionTemplate> fun_templ =
11059 v8::FunctionTemplate::New(ThrowInJSNoCatch);
11060 Local<Function> fun = fun_templ->GetFunction();
11061 env->Global()->Set(v8_str("throw_in_js"), fun);
11062 Local<Script> script = v8_compile("(function () {"
11063 " try {"
11064 " throw_in_js();"
11065 " return 42;"
11066 " } catch (e) {"
11067 " return e * 13;"
11068 " }"
11069 "})();");
11070 CHECK_EQ(91, script->Run()->Int32Value());
11071}
11072
11073
11074THREADED_TEST(RecursiveLocking) {
11075 v8::Locker locker;
11076 {
11077 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011078 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011079 }
11080}
11081
11082
11083static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
11084 ApiTestFuzzer::Fuzz();
11085 v8::Unlocker unlocker;
11086 return v8::Undefined();
11087}
11088
11089
11090THREADED_TEST(LockUnlockLock) {
11091 {
11092 v8::Locker locker;
11093 v8::HandleScope scope;
11094 LocalContext env;
11095 Local<v8::FunctionTemplate> fun_templ =
11096 v8::FunctionTemplate::New(UnlockForAMoment);
11097 Local<Function> fun = fun_templ->GetFunction();
11098 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11099 Local<Script> script = v8_compile("(function () {"
11100 " unlock_for_a_moment();"
11101 " return 42;"
11102 "})();");
11103 CHECK_EQ(42, script->Run()->Int32Value());
11104 }
11105 {
11106 v8::Locker locker;
11107 v8::HandleScope scope;
11108 LocalContext env;
11109 Local<v8::FunctionTemplate> fun_templ =
11110 v8::FunctionTemplate::New(UnlockForAMoment);
11111 Local<Function> fun = fun_templ->GetFunction();
11112 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11113 Local<Script> script = v8_compile("(function () {"
11114 " unlock_for_a_moment();"
11115 " return 42;"
11116 "})();");
11117 CHECK_EQ(42, script->Run()->Int32Value());
11118 }
11119}
11120
11121
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011122static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011123 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011124 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011125 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011126 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11127 if (object->IsJSGlobalObject()) count++;
11128 return count;
11129}
11130
11131
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011132static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011133 // We need to collect all garbage twice to be sure that everything
11134 // has been collected. This is because inline caches are cleared in
11135 // the first garbage collection but some of the maps have already
11136 // been marked at that point. Therefore some of the maps are not
11137 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011138 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11139 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011140 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011141#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011142 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011143#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011144 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011145}
11146
11147
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011148TEST(DontLeakGlobalObjects) {
11149 // Regression test for issues 1139850 and 1174891.
11150
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011151 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011152
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011153 for (int i = 0; i < 5; i++) {
11154 { v8::HandleScope scope;
11155 LocalContext context;
11156 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011157 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011158 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011159
11160 { v8::HandleScope scope;
11161 LocalContext context;
11162 v8_compile("Date")->Run();
11163 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011164 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011165 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011166
11167 { v8::HandleScope scope;
11168 LocalContext context;
11169 v8_compile("/aaa/")->Run();
11170 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011171 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011172 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011173
11174 { v8::HandleScope scope;
11175 const char* extension_list[] = { "v8/gc" };
11176 v8::ExtensionConfiguration extensions(1, extension_list);
11177 LocalContext context(&extensions);
11178 v8_compile("gc();")->Run();
11179 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011180 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011181 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011182 }
11183}
11184
11185
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011186v8::Persistent<v8::Object> some_object;
11187v8::Persistent<v8::Object> bad_handle;
11188
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011189void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011190 v8::HandleScope scope;
11191 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011192 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011193}
11194
11195
11196THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11197 LocalContext context;
11198
11199 v8::Persistent<v8::Object> handle1, handle2;
11200 {
11201 v8::HandleScope scope;
11202 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
11203 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11204 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11205 }
11206 // Note: order is implementation dependent alas: currently
11207 // global handle nodes are processed by PostGarbageCollectionProcessing
11208 // in reverse allocation order, so if second allocated handle is deleted,
11209 // weak callback of the first handle would be able to 'reallocate' it.
11210 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
11211 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011212 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011213}
11214
11215
11216v8::Persistent<v8::Object> to_be_disposed;
11217
11218void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
11219 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011220 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011221 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011222}
11223
11224
11225THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11226 LocalContext context;
11227
11228 v8::Persistent<v8::Object> handle1, handle2;
11229 {
11230 v8::HandleScope scope;
11231 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11232 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11233 }
11234 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11235 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011236 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011237}
11238
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011239void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11240 handle.Dispose();
11241}
11242
11243void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11244 v8::HandleScope scope;
11245 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011246 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011247}
11248
11249
11250THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11251 LocalContext context;
11252
11253 v8::Persistent<v8::Object> handle1, handle2, handle3;
11254 {
11255 v8::HandleScope scope;
11256 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
11257 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11258 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11259 }
11260 handle2.MakeWeak(NULL, DisposingCallback);
11261 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011262 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011263}
11264
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011265
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011266THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011267 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011268
11269 const int nof = 2;
11270 const char* sources[nof] = {
11271 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11272 "Object()"
11273 };
11274
11275 for (int i = 0; i < nof; i++) {
11276 const char* source = sources[i];
11277 { v8::HandleScope scope;
11278 LocalContext context;
11279 CompileRun(source);
11280 }
11281 { v8::HandleScope scope;
11282 LocalContext context;
11283 CompileRun(source);
11284 }
11285 }
11286}
11287
11288
11289static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11290 v8::HandleScope inner;
11291 env->Enter();
11292 v8::Handle<Value> three = v8_num(3);
11293 v8::Handle<Value> value = inner.Close(three);
11294 env->Exit();
11295 return value;
11296}
11297
11298
11299THREADED_TEST(NestedHandleScopeAndContexts) {
11300 v8::HandleScope outer;
11301 v8::Persistent<Context> env = Context::New();
11302 env->Enter();
11303 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011304 v8::Handle<String> str(value->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011305 CHECK(!str.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011306 env->Exit();
11307 env.Dispose();
11308}
11309
11310
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011311static i::Handle<i::JSFunction>* foo_ptr = NULL;
11312static int foo_count = 0;
11313static i::Handle<i::JSFunction>* bar_ptr = NULL;
11314static int bar_count = 0;
11315
11316
11317static void entry_hook(uintptr_t function,
11318 uintptr_t return_addr_location) {
11319 i::Code* code = i::Code::GetCodeFromTargetAddress(
11320 reinterpret_cast<i::Address>(function));
11321 CHECK(code != NULL);
11322
11323 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11324 ++bar_count;
11325
11326 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11327 ++foo_count;
11328
11329 // TODO(siggi): Verify return_addr_location.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011330 // This can be done by capturing JitCodeEvents, but requires an ordered
11331 // collection.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011332}
11333
11334
11335static void RunLoopInNewEnv() {
11336 bar_ptr = NULL;
11337 foo_ptr = NULL;
11338
11339 v8::HandleScope outer;
11340 v8::Persistent<Context> env = Context::New();
11341 env->Enter();
11342
11343 const char* script =
11344 "function bar() {"
11345 " var sum = 0;"
11346 " for (i = 0; i < 100; ++i)"
11347 " sum = foo(i);"
11348 " return sum;"
11349 "}"
11350 "function foo(i) { return i * i; }";
11351 CompileRun(script);
11352 i::Handle<i::JSFunction> bar =
11353 i::Handle<i::JSFunction>::cast(
11354 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11355 ASSERT(*bar);
11356
11357 i::Handle<i::JSFunction> foo =
11358 i::Handle<i::JSFunction>::cast(
11359 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11360 ASSERT(*foo);
11361
11362 bar_ptr = &bar;
11363 foo_ptr = &foo;
11364
11365 v8::Handle<v8::Value> value = CompileRun("bar();");
11366 CHECK(value->IsNumber());
11367 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11368
11369 // Test the optimized codegen path.
11370 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11371 "bar();");
11372 CHECK(value->IsNumber());
11373 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11374
11375 env->Exit();
11376}
11377
11378
11379TEST(SetFunctionEntryHook) {
11380 i::FLAG_allow_natives_syntax = true;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011381 i::FLAG_use_inlining = false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011382
11383 // Test setting and resetting the entry hook.
11384 // Nulling it should always succeed.
11385 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11386
11387 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11388 // Setting a hook while one's active should fail.
11389 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11390
11391 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11392
11393 // Reset the entry count to zero and set the entry hook.
11394 bar_count = 0;
11395 foo_count = 0;
11396 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11397 RunLoopInNewEnv();
11398
11399 CHECK_EQ(2, bar_count);
11400 CHECK_EQ(200, foo_count);
11401
11402 // Clear the entry hook and count.
11403 bar_count = 0;
11404 foo_count = 0;
11405 v8::V8::SetFunctionEntryHook(NULL);
11406
11407 // Clear the compilation cache to make sure we don't reuse the
11408 // functions from the previous invocation.
11409 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11410
11411 // Verify that entry hooking is now disabled.
11412 RunLoopInNewEnv();
11413 CHECK_EQ(0u, bar_count);
11414 CHECK_EQ(0u, foo_count);
11415}
11416
11417
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011418static i::HashMap* code_map = NULL;
11419static int saw_bar = 0;
11420static int move_events = 0;
11421
11422
11423static bool FunctionNameIs(const char* expected,
11424 const v8::JitCodeEvent* event) {
11425 // Log lines for functions are of the general form:
11426 // "LazyCompile:<type><function_name>", where the type is one of
11427 // "*", "~" or "".
11428 static const char kPreamble[] = "LazyCompile:";
11429 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11430
11431 if (event->name.len < sizeof(kPreamble) - 1 ||
11432 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11433 return false;
11434 }
11435
11436 const char* tail = event->name.str + kPreambleLen;
11437 size_t tail_len = event->name.len - kPreambleLen;
11438 size_t expected_len = strlen(expected);
11439 if (tail_len == expected_len + 1) {
11440 if (*tail == '*' || *tail == '~') {
11441 --tail_len;
11442 ++tail;
11443 } else {
11444 return false;
11445 }
11446 }
11447
11448 if (tail_len != expected_len)
11449 return false;
11450
11451 return strncmp(tail, expected, expected_len) == 0;
11452}
11453
11454
11455static void event_handler(const v8::JitCodeEvent* event) {
11456 CHECK(event != NULL);
11457 CHECK(code_map != NULL);
11458
11459 switch (event->type) {
11460 case v8::JitCodeEvent::CODE_ADDED: {
11461 CHECK(event->code_start != NULL);
11462 CHECK_NE(0, static_cast<int>(event->code_len));
11463 CHECK(event->name.str != NULL);
11464 i::HashMap::Entry* entry =
11465 code_map->Lookup(event->code_start,
11466 i::ComputePointerHash(event->code_start),
11467 true);
11468 entry->value = reinterpret_cast<void*>(event->code_len);
11469
11470 if (FunctionNameIs("bar", event)) {
11471 ++saw_bar;
11472 }
11473 }
11474 break;
11475
11476 case v8::JitCodeEvent::CODE_MOVED: {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011477 uint32_t hash = i::ComputePointerHash(event->code_start);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011478 // We would like to never see code move that we haven't seen before,
11479 // but the code creation event does not happen until the line endings
11480 // have been calculated (this is so that we can report the line in the
11481 // script at which the function source is found, see
11482 // Compiler::RecordFunctionCompilation) and the line endings
11483 // calculations can cause a GC, which can move the newly created code
11484 // before its existence can be logged.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011485 i::HashMap::Entry* entry =
11486 code_map->Lookup(event->code_start, hash, false);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011487 if (entry != NULL) {
11488 ++move_events;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011489
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011490 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11491 code_map->Remove(event->code_start, hash);
11492
11493 entry = code_map->Lookup(event->new_code_start,
11494 i::ComputePointerHash(event->new_code_start),
11495 true);
11496 CHECK(entry != NULL);
11497 entry->value = reinterpret_cast<void*>(event->code_len);
11498 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011499 }
11500 break;
11501
11502 case v8::JitCodeEvent::CODE_REMOVED:
11503 // Object/code removal events are currently not dispatched from the GC.
11504 CHECK(false);
11505 break;
11506 default:
11507 // Impossible event.
11508 CHECK(false);
11509 break;
11510 }
11511}
11512
11513
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011514static bool MatchPointers(void* key1, void* key2) {
11515 return key1 == key2;
11516}
11517
11518
11519TEST(SetJitCodeEventHandler) {
11520 const char* script =
11521 "function bar() {"
11522 " var sum = 0;"
11523 " for (i = 0; i < 100; ++i)"
11524 " sum = foo(i);"
11525 " return sum;"
11526 "}"
11527 "function foo(i) { return i * i; };"
11528 "bar();";
11529
11530 // Run this test in a new isolate to make sure we don't
11531 // have remnants of state from other code.
11532 v8::Isolate* isolate = v8::Isolate::New();
11533 isolate->Enter();
11534
11535 {
11536 i::HashMap code(MatchPointers);
11537 code_map = &code;
11538
11539 saw_bar = 0;
11540 move_events = 0;
11541
11542 i::FLAG_stress_compaction = true;
11543 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11544
11545 v8::HandleScope scope;
11546 // Generate new code objects sparsely distributed across several
11547 // different fragmented code-space pages.
11548 const int kIterations = 10;
11549 for (int i = 0; i < kIterations; ++i) {
11550 LocalContext env;
11551
11552 v8::Handle<v8::Script> compiled_script;
11553 {
11554 i::AlwaysAllocateScope always_allocate;
11555 SimulateFullSpace(HEAP->code_space());
11556 compiled_script = v8_compile(script);
11557 }
11558 compiled_script->Run();
11559
11560 // Clear the compilation cache to get more wastage.
11561 ISOLATE->compilation_cache()->Clear();
11562 }
11563
11564 // Force code movement.
11565 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11566
11567 CHECK_LE(kIterations, saw_bar);
11568 CHECK_NE(0, move_events);
11569
11570 code_map = NULL;
11571 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11572 }
11573
11574 isolate->Exit();
11575 isolate->Dispose();
11576
11577 // Do this in a new isolate.
11578 isolate = v8::Isolate::New();
11579 isolate->Enter();
11580
11581 // Verify that we get callbacks for existing code objects when we
11582 // request enumeration of existing code.
11583 {
11584 v8::HandleScope scope;
11585 LocalContext env;
11586 CompileRun(script);
11587
11588 // Now get code through initial iteration.
11589 i::HashMap code(MatchPointers);
11590 code_map = &code;
11591
11592 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11593 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11594
11595 code_map = NULL;
11596
11597 // We expect that we got some events. Note that if we could get code removal
11598 // notifications, we could compare two collections, one created by listening
11599 // from the time of creation of an isolate, and the other by subscribing
11600 // with EnumExisting.
11601 CHECK_NE(0, code.occupancy());
11602 }
11603
11604 isolate->Exit();
11605 isolate->Dispose();
11606}
11607
11608
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011609static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11610
11611
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011612THREADED_TEST(ExternalAllocatedMemory) {
11613 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011614 v8::Persistent<Context> env(Context::New());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011615 CHECK(!env.IsEmpty());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011616 const intptr_t kSize = 1024*1024;
11617 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
11618 cast(kSize));
11619 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11620 cast(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011621}
11622
11623
11624THREADED_TEST(DisposeEnteredContext) {
11625 v8::HandleScope scope;
11626 LocalContext outer;
11627 { v8::Persistent<v8::Context> inner = v8::Context::New();
11628 inner->Enter();
11629 inner.Dispose();
11630 inner.Clear();
11631 inner->Exit();
11632 }
11633}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011634
11635
11636// Regression test for issue 54, object templates with internal fields
11637// but no accessors or interceptors did not get their internal field
11638// count set on instances.
11639THREADED_TEST(Regress54) {
11640 v8::HandleScope outer;
11641 LocalContext context;
11642 static v8::Persistent<v8::ObjectTemplate> templ;
11643 if (templ.IsEmpty()) {
11644 v8::HandleScope inner;
11645 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11646 local->SetInternalFieldCount(1);
11647 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11648 }
11649 v8::Handle<v8::Object> result = templ->NewInstance();
11650 CHECK_EQ(1, result->InternalFieldCount());
11651}
11652
11653
11654// If part of the threaded tests, this test makes ThreadingTest fail
11655// on mac.
11656TEST(CatchStackOverflow) {
11657 v8::HandleScope scope;
11658 LocalContext context;
11659 v8::TryCatch try_catch;
11660 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11661 "function f() {"
11662 " return f();"
11663 "}"
11664 ""
11665 "f();"));
11666 v8::Handle<v8::Value> result = script->Run();
11667 CHECK(result.IsEmpty());
11668}
11669
11670
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011671static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11672 const char* resource_name,
11673 int line_offset) {
11674 v8::HandleScope scope;
11675 v8::TryCatch try_catch;
11676 v8::Handle<v8::Value> result = script->Run();
11677 CHECK(result.IsEmpty());
11678 CHECK(try_catch.HasCaught());
11679 v8::Handle<v8::Message> message = try_catch.Message();
11680 CHECK(!message.IsEmpty());
11681 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11682 CHECK_EQ(91, message->GetStartPosition());
11683 CHECK_EQ(92, message->GetEndPosition());
11684 CHECK_EQ(2, message->GetStartColumn());
11685 CHECK_EQ(3, message->GetEndColumn());
11686 v8::String::AsciiValue line(message->GetSourceLine());
11687 CHECK_EQ(" throw 'nirk';", *line);
11688 v8::String::AsciiValue name(message->GetScriptResourceName());
11689 CHECK_EQ(resource_name, *name);
11690}
11691
11692
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011693THREADED_TEST(TryCatchSourceInfo) {
11694 v8::HandleScope scope;
11695 LocalContext context;
11696 v8::Handle<v8::String> source = v8::String::New(
11697 "function Foo() {\n"
11698 " return Bar();\n"
11699 "}\n"
11700 "\n"
11701 "function Bar() {\n"
11702 " return Baz();\n"
11703 "}\n"
11704 "\n"
11705 "function Baz() {\n"
11706 " throw 'nirk';\n"
11707 "}\n"
11708 "\n"
11709 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011710
11711 const char* resource_name;
11712 v8::Handle<v8::Script> script;
11713 resource_name = "test.js";
11714 script = v8::Script::Compile(source, v8::String::New(resource_name));
11715 CheckTryCatchSourceInfo(script, resource_name, 0);
11716
11717 resource_name = "test1.js";
11718 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11719 script = v8::Script::Compile(source, &origin1);
11720 CheckTryCatchSourceInfo(script, resource_name, 0);
11721
11722 resource_name = "test2.js";
11723 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11724 script = v8::Script::Compile(source, &origin2);
11725 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011726}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011727
11728
11729THREADED_TEST(CompilationCache) {
11730 v8::HandleScope scope;
11731 LocalContext context;
11732 v8::Handle<v8::String> source0 = v8::String::New("1234");
11733 v8::Handle<v8::String> source1 = v8::String::New("1234");
11734 v8::Handle<v8::Script> script0 =
11735 v8::Script::Compile(source0, v8::String::New("test.js"));
11736 v8::Handle<v8::Script> script1 =
11737 v8::Script::Compile(source1, v8::String::New("test.js"));
11738 v8::Handle<v8::Script> script2 =
11739 v8::Script::Compile(source0); // different origin
11740 CHECK_EQ(1234, script0->Run()->Int32Value());
11741 CHECK_EQ(1234, script1->Run()->Int32Value());
11742 CHECK_EQ(1234, script2->Run()->Int32Value());
11743}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011744
11745
11746static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11747 ApiTestFuzzer::Fuzz();
11748 return v8_num(42);
11749}
11750
11751
11752THREADED_TEST(CallbackFunctionName) {
11753 v8::HandleScope scope;
11754 LocalContext context;
11755 Local<ObjectTemplate> t = ObjectTemplate::New();
11756 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11757 context->Global()->Set(v8_str("obj"), t->NewInstance());
11758 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11759 CHECK(value->IsString());
11760 v8::String::AsciiValue name(value);
11761 CHECK_EQ("asdf", *name);
11762}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011763
11764
11765THREADED_TEST(DateAccess) {
11766 v8::HandleScope scope;
11767 LocalContext context;
11768 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11769 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011770 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011771}
11772
11773
11774void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011775 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011776 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11777 CHECK_EQ(elmc, props->Length());
11778 for (int i = 0; i < elmc; i++) {
11779 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11780 CHECK_EQ(elmv[i], *elm);
11781 }
11782}
11783
11784
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011785void CheckOwnProperties(v8::Handle<v8::Value> val,
11786 int elmc,
11787 const char* elmv[]) {
11788 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11789 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11790 CHECK_EQ(elmc, props->Length());
11791 for (int i = 0; i < elmc; i++) {
11792 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11793 CHECK_EQ(elmv[i], *elm);
11794 }
11795}
11796
11797
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011798THREADED_TEST(PropertyEnumeration) {
11799 v8::HandleScope scope;
11800 LocalContext context;
11801 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11802 "var result = [];"
11803 "result[0] = {};"
11804 "result[1] = {a: 1, b: 2};"
11805 "result[2] = [1, 2, 3];"
11806 "var proto = {x: 1, y: 2, z: 3};"
11807 "var x = { __proto__: proto, w: 0, z: 1 };"
11808 "result[3] = x;"
11809 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011810 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011811 CHECK_EQ(4, elms->Length());
11812 int elmc0 = 0;
11813 const char** elmv0 = NULL;
11814 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011815 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011816 int elmc1 = 2;
11817 const char* elmv1[] = {"a", "b"};
11818 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011819 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011820 int elmc2 = 3;
11821 const char* elmv2[] = {"0", "1", "2"};
11822 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011823 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011824 int elmc3 = 4;
11825 const char* elmv3[] = {"w", "z", "x", "y"};
11826 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011827 int elmc4 = 2;
11828 const char* elmv4[] = {"w", "z"};
11829 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011830}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832THREADED_TEST(PropertyEnumeration2) {
11833 v8::HandleScope scope;
11834 LocalContext context;
11835 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11836 "var result = [];"
11837 "result[0] = {};"
11838 "result[1] = {a: 1, b: 2};"
11839 "result[2] = [1, 2, 3];"
11840 "var proto = {x: 1, y: 2, z: 3};"
11841 "var x = { __proto__: proto, w: 0, z: 1 };"
11842 "result[3] = x;"
11843 "result;"))->Run();
11844 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11845 CHECK_EQ(4, elms->Length());
11846 int elmc0 = 0;
11847 const char** elmv0 = NULL;
11848 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11849
11850 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11851 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11852 CHECK_EQ(0, props->Length());
11853 for (uint32_t i = 0; i < props->Length(); i++) {
11854 printf("p[%d]\n", i);
11855 }
11856}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011857
ager@chromium.org870a0b62008-11-04 11:43:05 +000011858static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11859 Local<Value> name,
11860 v8::AccessType type,
11861 Local<Value> data) {
11862 return type != v8::ACCESS_SET;
11863}
11864
11865
11866static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11867 uint32_t key,
11868 v8::AccessType type,
11869 Local<Value> data) {
11870 return type != v8::ACCESS_SET;
11871}
11872
11873
11874THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11875 v8::HandleScope scope;
11876 LocalContext context;
11877 Local<ObjectTemplate> templ = ObjectTemplate::New();
11878 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11879 IndexedSetAccessBlocker);
11880 templ->Set(v8_str("x"), v8::True());
11881 Local<v8::Object> instance = templ->NewInstance();
11882 context->Global()->Set(v8_str("obj"), instance);
11883 Local<Value> value = CompileRun("obj.x");
11884 CHECK(value->BooleanValue());
11885}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011886
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011887
ager@chromium.org32912102009-01-16 10:38:43 +000011888static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11889 Local<Value> name,
11890 v8::AccessType type,
11891 Local<Value> data) {
11892 return false;
11893}
11894
11895
11896static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11897 uint32_t key,
11898 v8::AccessType type,
11899 Local<Value> data) {
11900 return false;
11901}
11902
11903
11904
11905THREADED_TEST(AccessChecksReenabledCorrectly) {
11906 v8::HandleScope scope;
11907 LocalContext context;
11908 Local<ObjectTemplate> templ = ObjectTemplate::New();
11909 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11910 IndexedGetAccessBlocker);
11911 templ->Set(v8_str("a"), v8_str("a"));
11912 // Add more than 8 (see kMaxFastProperties) properties
11913 // so that the constructor will force copying map.
11914 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011915 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000011916 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011917 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000011918 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011919 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000011920 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011921 buf[2] = k;
11922 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000011923 templ->Set(v8_str(buf), v8::Number::New(k));
11924 }
11925 }
11926 }
11927
11928 Local<v8::Object> instance_1 = templ->NewInstance();
11929 context->Global()->Set(v8_str("obj_1"), instance_1);
11930
11931 Local<Value> value_1 = CompileRun("obj_1.a");
11932 CHECK(value_1->IsUndefined());
11933
11934 Local<v8::Object> instance_2 = templ->NewInstance();
11935 context->Global()->Set(v8_str("obj_2"), instance_2);
11936
11937 Local<Value> value_2 = CompileRun("obj_2.a");
11938 CHECK(value_2->IsUndefined());
11939}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011940
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011941
ager@chromium.org8bb60582008-12-11 12:02:20 +000011942// This tests that access check information remains on the global
11943// object template when creating contexts.
11944THREADED_TEST(AccessControlRepeatedContextCreation) {
11945 v8::HandleScope handle_scope;
11946 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11947 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11948 IndexedSetAccessBlocker);
11949 i::Handle<i::ObjectTemplateInfo> internal_template =
11950 v8::Utils::OpenHandle(*global_template);
11951 CHECK(!internal_template->constructor()->IsUndefined());
11952 i::Handle<i::FunctionTemplateInfo> constructor(
11953 i::FunctionTemplateInfo::cast(internal_template->constructor()));
11954 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011955 v8::Persistent<Context> context0(Context::New(NULL, global_template));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011956 CHECK(!context0.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +000011957 CHECK(!constructor->access_check_info()->IsUndefined());
11958}
11959
11960
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011961THREADED_TEST(TurnOnAccessCheck) {
11962 v8::HandleScope handle_scope;
11963
11964 // Create an environment with access check to the global object disabled by
11965 // default.
11966 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11967 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11968 IndexedGetAccessBlocker,
11969 v8::Handle<v8::Value>(),
11970 false);
11971 v8::Persistent<Context> context = Context::New(NULL, global_template);
11972 Context::Scope context_scope(context);
11973
11974 // Set up a property and a number of functions.
11975 context->Global()->Set(v8_str("a"), v8_num(1));
11976 CompileRun("function f1() {return a;}"
11977 "function f2() {return a;}"
11978 "function g1() {return h();}"
11979 "function g2() {return h();}"
11980 "function h() {return 1;}");
11981 Local<Function> f1 =
11982 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11983 Local<Function> f2 =
11984 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11985 Local<Function> g1 =
11986 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11987 Local<Function> g2 =
11988 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11989 Local<Function> h =
11990 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11991
11992 // Get the global object.
11993 v8::Handle<v8::Object> global = context->Global();
11994
11995 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11996 // uses the runtime system to retreive property a whereas f2 uses global load
11997 // inline cache.
11998 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11999 for (int i = 0; i < 4; i++) {
12000 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12001 }
12002
12003 // Same for g1 and g2.
12004 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12005 for (int i = 0; i < 4; i++) {
12006 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12007 }
12008
12009 // Detach the global and turn on access check.
12010 context->DetachGlobal();
12011 context->Global()->TurnOnAccessCheck();
12012
12013 // Failing access check to property get results in undefined.
12014 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12015 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12016
12017 // Failing access check to function call results in exception.
12018 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12019 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12020
12021 // No failing access check when just returning a constant.
12022 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12023}
12024
12025
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012026static const char* kPropertyA = "a";
12027static const char* kPropertyH = "h";
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012028
12029static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
12030 Local<Value> name,
12031 v8::AccessType type,
12032 Local<Value> data) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012033 if (!name->IsString()) return false;
12034 i::Handle<i::String> name_handle =
12035 v8::Utils::OpenHandle(String::Cast(*name));
12036 return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
12037 && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012038}
12039
12040
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012041THREADED_TEST(TurnOnAccessCheckAndRecompile) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012042 v8::HandleScope handle_scope;
12043
12044 // Create an environment with access check to the global object disabled by
12045 // default. When the registered access checker will block access to properties
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012046 // a and h.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012047 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12048 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
12049 IndexedGetAccessBlocker,
12050 v8::Handle<v8::Value>(),
12051 false);
12052 v8::Persistent<Context> context = Context::New(NULL, global_template);
12053 Context::Scope context_scope(context);
12054
12055 // Set up a property and a number of functions.
12056 context->Global()->Set(v8_str("a"), v8_num(1));
12057 static const char* source = "function f1() {return a;}"
12058 "function f2() {return a;}"
12059 "function g1() {return h();}"
12060 "function g2() {return h();}"
12061 "function h() {return 1;}";
12062
12063 CompileRun(source);
12064 Local<Function> f1;
12065 Local<Function> f2;
12066 Local<Function> g1;
12067 Local<Function> g2;
12068 Local<Function> h;
12069 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12070 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12071 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12072 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12073 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12074
12075 // Get the global object.
12076 v8::Handle<v8::Object> global = context->Global();
12077
12078 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12079 // uses the runtime system to retreive property a whereas f2 uses global load
12080 // inline cache.
12081 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12082 for (int i = 0; i < 4; i++) {
12083 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12084 }
12085
12086 // Same for g1 and g2.
12087 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12088 for (int i = 0; i < 4; i++) {
12089 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12090 }
12091
12092 // Detach the global and turn on access check now blocking access to property
12093 // a and function h.
12094 context->DetachGlobal();
12095 context->Global()->TurnOnAccessCheck();
12096
12097 // Failing access check to property get results in undefined.
12098 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12099 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12100
12101 // Failing access check to function call results in exception.
12102 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12103 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12104
12105 // No failing access check when just returning a constant.
12106 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12107
12108 // Now compile the source again. And get the newly compiled functions, except
12109 // for h for which access is blocked.
12110 CompileRun(source);
12111 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12112 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12113 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12114 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12115 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
12116
12117 // Failing access check to property get results in undefined.
12118 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12119 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12120
12121 // Failing access check to function call results in exception.
12122 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12123 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12124}
12125
12126
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012127// This test verifies that pre-compilation (aka preparsing) can be called
12128// without initializing the whole VM. Thus we cannot run this test in a
12129// multi-threaded setup.
12130TEST(PreCompile) {
12131 // TODO(155): This test would break without the initialization of V8. This is
12132 // a workaround for now to make this test not fail.
12133 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012134 const char* script = "function foo(a) { return a+1; }";
12135 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012136 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012137 CHECK_NE(sd->Length(), 0);
12138 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012139 CHECK(!sd->HasError());
12140 delete sd;
12141}
12142
12143
12144TEST(PreCompileWithError) {
12145 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012146 const char* script = "function foo(a) { return 1 * * 2; }";
12147 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012148 v8::ScriptData::PreCompile(script, i::StrLength(script));
12149 CHECK(sd->HasError());
12150 delete sd;
12151}
12152
12153
12154TEST(Regress31661) {
12155 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012156 const char* script = " The Definintive Guide";
12157 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012158 v8::ScriptData::PreCompile(script, i::StrLength(script));
12159 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012160 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012161}
12162
12163
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012164// Tests that ScriptData can be serialized and deserialized.
12165TEST(PreCompileSerialization) {
12166 v8::V8::Initialize();
12167 const char* script = "function foo(a) { return a+1; }";
12168 v8::ScriptData* sd =
12169 v8::ScriptData::PreCompile(script, i::StrLength(script));
12170
12171 // Serialize.
12172 int serialized_data_length = sd->Length();
12173 char* serialized_data = i::NewArray<char>(serialized_data_length);
12174 memcpy(serialized_data, sd->Data(), serialized_data_length);
12175
12176 // Deserialize.
12177 v8::ScriptData* deserialized_sd =
12178 v8::ScriptData::New(serialized_data, serialized_data_length);
12179
12180 // Verify that the original is the same as the deserialized.
12181 CHECK_EQ(sd->Length(), deserialized_sd->Length());
12182 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
12183 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
12184
12185 delete sd;
12186 delete deserialized_sd;
12187}
12188
12189
12190// Attempts to deserialize bad data.
12191TEST(PreCompileDeserializationError) {
12192 v8::V8::Initialize();
12193 const char* data = "DONT CARE";
12194 int invalid_size = 3;
12195 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
12196
12197 CHECK_EQ(0, sd->Length());
12198
12199 delete sd;
12200}
12201
12202
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012203// Attempts to deserialize bad data.
12204TEST(PreCompileInvalidPreparseDataError) {
12205 v8::V8::Initialize();
12206 v8::HandleScope scope;
12207 LocalContext context;
12208
12209 const char* script = "function foo(){ return 5;}\n"
12210 "function bar(){ return 6 + 7;} foo();";
12211 v8::ScriptData* sd =
12212 v8::ScriptData::PreCompile(script, i::StrLength(script));
12213 CHECK(!sd->HasError());
12214 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000012215 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000012216 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012217 const int kFunctionEntryStartOffset = 0;
12218 const int kFunctionEntryEndOffset = 1;
12219 unsigned* sd_data =
12220 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012221
12222 // Overwrite function bar's end position with 0.
12223 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12224 v8::TryCatch try_catch;
12225
12226 Local<String> source = String::New(script);
12227 Local<Script> compiled_script = Script::New(source, NULL, sd);
12228 CHECK(try_catch.HasCaught());
12229 String::AsciiValue exception_value(try_catch.Message()->Get());
12230 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12231 *exception_value);
12232
12233 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012234
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012235 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012236 // will not be found when searching for it by position and we should fall
12237 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000012238 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12239 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012240 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12241 200;
12242 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012243 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012244
12245 delete sd;
12246}
12247
12248
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012249// Verifies that the Handle<String> and const char* versions of the API produce
12250// the same results (at least for one trivial case).
12251TEST(PreCompileAPIVariationsAreSame) {
12252 v8::V8::Initialize();
12253 v8::HandleScope scope;
12254
12255 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012256
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012257 v8::ScriptData* sd_from_cstring =
12258 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12259
12260 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012261 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012262 v8::String::NewExternal(resource));
12263
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012264 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12265 v8::String::New(cstring));
12266
12267 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012268 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012269 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012270 sd_from_cstring->Length()));
12271
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012272 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12273 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12274 sd_from_string->Data(),
12275 sd_from_cstring->Length()));
12276
12277
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012278 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012279 delete sd_from_external_string;
12280 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012281}
12282
12283
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012284// This tests that we do not allow dictionary load/call inline caches
12285// to use functions that have not yet been compiled. The potential
12286// problem of loading a function that has not yet been compiled can
12287// arise because we share code between contexts via the compilation
12288// cache.
12289THREADED_TEST(DictionaryICLoadedFunction) {
12290 v8::HandleScope scope;
12291 // Test LoadIC.
12292 for (int i = 0; i < 2; i++) {
12293 LocalContext context;
12294 context->Global()->Set(v8_str("tmp"), v8::True());
12295 context->Global()->Delete(v8_str("tmp"));
12296 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12297 }
12298 // Test CallIC.
12299 for (int i = 0; i < 2; i++) {
12300 LocalContext context;
12301 context->Global()->Set(v8_str("tmp"), v8::True());
12302 context->Global()->Delete(v8_str("tmp"));
12303 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12304 }
12305}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012306
12307
12308// Test that cross-context new calls use the context of the callee to
12309// create the new JavaScript object.
12310THREADED_TEST(CrossContextNew) {
12311 v8::HandleScope scope;
12312 v8::Persistent<Context> context0 = Context::New();
12313 v8::Persistent<Context> context1 = Context::New();
12314
12315 // Allow cross-domain access.
12316 Local<String> token = v8_str("<security token>");
12317 context0->SetSecurityToken(token);
12318 context1->SetSecurityToken(token);
12319
12320 // Set an 'x' property on the Object prototype and define a
12321 // constructor function in context0.
12322 context0->Enter();
12323 CompileRun("Object.prototype.x = 42; function C() {};");
12324 context0->Exit();
12325
12326 // Call the constructor function from context0 and check that the
12327 // result has the 'x' property.
12328 context1->Enter();
12329 context1->Global()->Set(v8_str("other"), context0->Global());
12330 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12331 CHECK(value->IsInt32());
12332 CHECK_EQ(42, value->Int32Value());
12333 context1->Exit();
12334
12335 // Dispose the contexts to allow them to be garbage collected.
12336 context0.Dispose();
12337 context1.Dispose();
12338}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012339
12340
12341class RegExpInterruptTest {
12342 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012343 RegExpInterruptTest() : block_(NULL) {}
12344 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012345 void RunTest() {
12346 block_ = i::OS::CreateSemaphore(0);
12347 gc_count_ = 0;
12348 gc_during_regexp_ = 0;
12349 regexp_success_ = false;
12350 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012351 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012352 gc_thread.Start();
12353 v8::Locker::StartPreemption(1);
12354
12355 LongRunningRegExp();
12356 {
12357 v8::Unlocker unlock;
12358 gc_thread.Join();
12359 }
12360 v8::Locker::StopPreemption();
12361 CHECK(regexp_success_);
12362 CHECK(gc_success_);
12363 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012364
ager@chromium.org381abbb2009-02-25 13:23:22 +000012365 private:
12366 // Number of garbage collections required.
12367 static const int kRequiredGCs = 5;
12368
12369 class GCThread : public i::Thread {
12370 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012371 explicit GCThread(RegExpInterruptTest* test)
12372 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012373 virtual void Run() {
12374 test_->CollectGarbage();
12375 }
12376 private:
12377 RegExpInterruptTest* test_;
12378 };
12379
12380 void CollectGarbage() {
12381 block_->Wait();
12382 while (gc_during_regexp_ < kRequiredGCs) {
12383 {
12384 v8::Locker lock;
12385 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012386 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012387 gc_count_++;
12388 }
12389 i::OS::Sleep(1);
12390 }
12391 gc_success_ = true;
12392 }
12393
12394 void LongRunningRegExp() {
12395 block_->Signal(); // Enable garbage collection thread on next preemption.
12396 int rounds = 0;
12397 while (gc_during_regexp_ < kRequiredGCs) {
12398 int gc_before = gc_count_;
12399 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012400 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012401 const char* c_source =
12402 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12403 ".exec('aaaaaaaaaaaaaaab') === null";
12404 Local<String> source = String::New(c_source);
12405 Local<Script> script = Script::Compile(source);
12406 Local<Value> result = script->Run();
12407 if (!result->BooleanValue()) {
12408 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12409 return;
12410 }
12411 }
12412 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012413 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012414 const char* c_source =
12415 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12416 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12417 Local<String> source = String::New(c_source);
12418 Local<Script> script = Script::Compile(source);
12419 Local<Value> result = script->Run();
12420 if (!result->BooleanValue()) {
12421 gc_during_regexp_ = kRequiredGCs;
12422 return;
12423 }
12424 }
12425 int gc_after = gc_count_;
12426 gc_during_regexp_ += gc_after - gc_before;
12427 rounds++;
12428 i::OS::Sleep(1);
12429 }
12430 regexp_success_ = true;
12431 }
12432
12433 i::Semaphore* block_;
12434 int gc_count_;
12435 int gc_during_regexp_;
12436 bool regexp_success_;
12437 bool gc_success_;
12438};
12439
12440
12441// Test that a regular expression execution can be interrupted and
12442// survive a garbage collection.
12443TEST(RegExpInterruption) {
12444 v8::Locker lock;
12445 v8::V8::Initialize();
12446 v8::HandleScope scope;
12447 Local<Context> local_env;
12448 {
12449 LocalContext env;
12450 local_env = env.local();
12451 }
12452
12453 // Local context should still be live.
12454 CHECK(!local_env.IsEmpty());
12455 local_env->Enter();
12456
12457 // Should complete without problems.
12458 RegExpInterruptTest().RunTest();
12459
12460 local_env->Exit();
12461}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012462
12463
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012464class ApplyInterruptTest {
12465 public:
12466 ApplyInterruptTest() : block_(NULL) {}
12467 ~ApplyInterruptTest() { delete block_; }
12468 void RunTest() {
12469 block_ = i::OS::CreateSemaphore(0);
12470 gc_count_ = 0;
12471 gc_during_apply_ = 0;
12472 apply_success_ = false;
12473 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012474 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012475 gc_thread.Start();
12476 v8::Locker::StartPreemption(1);
12477
12478 LongRunningApply();
12479 {
12480 v8::Unlocker unlock;
12481 gc_thread.Join();
12482 }
12483 v8::Locker::StopPreemption();
12484 CHECK(apply_success_);
12485 CHECK(gc_success_);
12486 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012487
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012488 private:
12489 // Number of garbage collections required.
12490 static const int kRequiredGCs = 2;
12491
12492 class GCThread : public i::Thread {
12493 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012494 explicit GCThread(ApplyInterruptTest* test)
12495 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012496 virtual void Run() {
12497 test_->CollectGarbage();
12498 }
12499 private:
12500 ApplyInterruptTest* test_;
12501 };
12502
12503 void CollectGarbage() {
12504 block_->Wait();
12505 while (gc_during_apply_ < kRequiredGCs) {
12506 {
12507 v8::Locker lock;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012508 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012509 gc_count_++;
12510 }
12511 i::OS::Sleep(1);
12512 }
12513 gc_success_ = true;
12514 }
12515
12516 void LongRunningApply() {
12517 block_->Signal();
12518 int rounds = 0;
12519 while (gc_during_apply_ < kRequiredGCs) {
12520 int gc_before = gc_count_;
12521 {
12522 const char* c_source =
12523 "function do_very_little(bar) {"
12524 " this.foo = bar;"
12525 "}"
12526 "for (var i = 0; i < 100000; i++) {"
12527 " do_very_little.apply(this, ['bar']);"
12528 "}";
12529 Local<String> source = String::New(c_source);
12530 Local<Script> script = Script::Compile(source);
12531 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000012532 // Check that no exception was thrown.
12533 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012534 }
12535 int gc_after = gc_count_;
12536 gc_during_apply_ += gc_after - gc_before;
12537 rounds++;
12538 }
12539 apply_success_ = true;
12540 }
12541
12542 i::Semaphore* block_;
12543 int gc_count_;
12544 int gc_during_apply_;
12545 bool apply_success_;
12546 bool gc_success_;
12547};
12548
12549
12550// Test that nothing bad happens if we get a preemption just when we were
12551// about to do an apply().
12552TEST(ApplyInterruption) {
12553 v8::Locker lock;
12554 v8::V8::Initialize();
12555 v8::HandleScope scope;
12556 Local<Context> local_env;
12557 {
12558 LocalContext env;
12559 local_env = env.local();
12560 }
12561
12562 // Local context should still be live.
12563 CHECK(!local_env.IsEmpty());
12564 local_env->Enter();
12565
12566 // Should complete without problems.
12567 ApplyInterruptTest().RunTest();
12568
12569 local_env->Exit();
12570}
12571
12572
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012573// Verify that we can clone an object
12574TEST(ObjectClone) {
12575 v8::HandleScope scope;
12576 LocalContext env;
12577
12578 const char* sample =
12579 "var rv = {};" \
12580 "rv.alpha = 'hello';" \
12581 "rv.beta = 123;" \
12582 "rv;";
12583
12584 // Create an object, verify basics.
12585 Local<Value> val = CompileRun(sample);
12586 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012587 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012588 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12589
12590 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12591 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12592 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12593
12594 // Clone it.
12595 Local<v8::Object> clone = obj->Clone();
12596 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12597 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12598 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12599
12600 // Set a property on the clone, verify each object.
12601 clone->Set(v8_str("beta"), v8::Integer::New(456));
12602 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12603 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12604}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012605
12606
ager@chromium.org5ec48922009-05-05 07:25:34 +000012607class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12608 public:
12609 explicit AsciiVectorResource(i::Vector<const char> vector)
12610 : data_(vector) {}
12611 virtual ~AsciiVectorResource() {}
12612 virtual size_t length() const { return data_.length(); }
12613 virtual const char* data() const { return data_.start(); }
12614 private:
12615 i::Vector<const char> data_;
12616};
12617
12618
12619class UC16VectorResource : public v8::String::ExternalStringResource {
12620 public:
12621 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12622 : data_(vector) {}
12623 virtual ~UC16VectorResource() {}
12624 virtual size_t length() const { return data_.length(); }
12625 virtual const i::uc16* data() const { return data_.start(); }
12626 private:
12627 i::Vector<const i::uc16> data_;
12628};
12629
12630
12631static void MorphAString(i::String* string,
12632 AsciiVectorResource* ascii_resource,
12633 UC16VectorResource* uc16_resource) {
12634 CHECK(i::StringShape(string).IsExternal());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012635 if (string->IsOneByteRepresentation()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000012636 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012638 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012639 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012640 i::ExternalTwoByteString* morphed =
12641 i::ExternalTwoByteString::cast(string);
12642 morphed->set_resource(uc16_resource);
12643 } else {
12644 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012646 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012647 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012648 i::ExternalAsciiString* morphed =
12649 i::ExternalAsciiString::cast(string);
12650 morphed->set_resource(ascii_resource);
12651 }
12652}
12653
12654
12655// Test that we can still flatten a string if the components it is built up
12656// from have been turned into 16 bit strings in the mean time.
12657THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012658 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000012659 const char* c_string = "Now is the time for all good men"
12660 " to come to the aid of the party";
12661 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12662 {
12663 v8::HandleScope scope;
12664 LocalContext env;
12665 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012666 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012667 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012668 i::Vector<const uint16_t>(two_byte_string,
12669 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012670
12671 Local<String> lhs(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 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012675
12676 env->Global()->Set(v8_str("lhs"), lhs);
12677 env->Global()->Set(v8_str("rhs"), rhs);
12678
12679 CompileRun(
12680 "var cons = lhs + rhs;"
12681 "var slice = lhs.substring(1, lhs.length - 1);"
12682 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12683
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012684 CHECK(!lhs->MayContainNonAscii());
12685 CHECK(!rhs->MayContainNonAscii());
12686
ager@chromium.org5ec48922009-05-05 07:25:34 +000012687 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12688 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12689
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012690 // This should UTF-8 without flattening, since everything is ASCII.
12691 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12692 CHECK_EQ(128, cons->Utf8Length());
12693 int nchars = -1;
12694 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12695 CHECK_EQ(128, nchars);
12696 CHECK_EQ(0, strcmp(
12697 utf_buffer,
12698 "Now is the time for all good men to come to the aid of the party"
12699 "Now is the time for all good men to come to the aid of the party"));
12700
ager@chromium.org5ec48922009-05-05 07:25:34 +000012701 // Now do some stuff to make sure the strings are flattened, etc.
12702 CompileRun(
12703 "/[^a-z]/.test(cons);"
12704 "/[^a-z]/.test(slice);"
12705 "/[^a-z]/.test(slice_on_cons);");
12706 const char* expected_cons =
12707 "Now is the time for all good men to come to the aid of the party"
12708 "Now is the time for all good men to come to the aid of the party";
12709 const char* expected_slice =
12710 "ow is the time for all good men to come to the aid of the part";
12711 const char* expected_slice_on_cons =
12712 "ow is the time for all good men to come to the aid of the party"
12713 "Now is the time for all good men to come to the aid of the part";
12714 CHECK_EQ(String::New(expected_cons),
12715 env->Global()->Get(v8_str("cons")));
12716 CHECK_EQ(String::New(expected_slice),
12717 env->Global()->Get(v8_str("slice")));
12718 CHECK_EQ(String::New(expected_slice_on_cons),
12719 env->Global()->Get(v8_str("slice_on_cons")));
12720 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012721 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000012722}
12723
12724
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012725TEST(CompileExternalTwoByteSource) {
12726 v8::HandleScope scope;
12727 LocalContext context;
12728
12729 // This is a very short list of sources, which currently is to check for a
12730 // regression caused by r2703.
12731 const char* ascii_sources[] = {
12732 "0.5",
12733 "-0.5", // This mainly testes PushBack in the Scanner.
12734 "--0.5", // This mainly testes PushBack in the Scanner.
12735 NULL
12736 };
12737
12738 // Compile the sources as external two byte strings.
12739 for (int i = 0; ascii_sources[i] != NULL; i++) {
12740 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12741 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012742 i::Vector<const uint16_t>(two_byte_string,
12743 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012744 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12745 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012746 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012747 }
12748}
12749
12750
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012751class RegExpStringModificationTest {
12752 public:
12753 RegExpStringModificationTest()
12754 : block_(i::OS::CreateSemaphore(0)),
12755 morphs_(0),
12756 morphs_during_regexp_(0),
12757 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12758 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12759 ~RegExpStringModificationTest() { delete block_; }
12760 void RunTest() {
12761 regexp_success_ = false;
12762 morph_success_ = false;
12763
12764 // Initialize the contents of two_byte_content_ to be a uc16 representation
12765 // of "aaaaaaaaaaaaaab".
12766 for (int i = 0; i < 14; i++) {
12767 two_byte_content_[i] = 'a';
12768 }
12769 two_byte_content_[14] = 'b';
12770
12771 // Create the input string for the regexp - the one we are going to change
12772 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012774
12775 // Inject the input as a global variable.
12776 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012777 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012778 i::Isolate::Current()->native_context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012779 *input_name,
12780 *input_,
12781 NONE,
12782 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012783
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012784 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012785 morph_thread.Start();
12786 v8::Locker::StartPreemption(1);
12787 LongRunningRegExp();
12788 {
12789 v8::Unlocker unlock;
12790 morph_thread.Join();
12791 }
12792 v8::Locker::StopPreemption();
12793 CHECK(regexp_success_);
12794 CHECK(morph_success_);
12795 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012796
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012797 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012798 // Number of string modifications required.
12799 static const int kRequiredModifications = 5;
12800 static const int kMaxModifications = 100;
12801
12802 class MorphThread : public i::Thread {
12803 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012804 explicit MorphThread(RegExpStringModificationTest* test)
12805 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012806 virtual void Run() {
12807 test_->MorphString();
12808 }
12809 private:
12810 RegExpStringModificationTest* test_;
12811 };
12812
12813 void MorphString() {
12814 block_->Wait();
12815 while (morphs_during_regexp_ < kRequiredModifications &&
12816 morphs_ < kMaxModifications) {
12817 {
12818 v8::Locker lock;
12819 // Swap string between ascii and two-byte representation.
12820 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000012821 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012822 morphs_++;
12823 }
12824 i::OS::Sleep(1);
12825 }
12826 morph_success_ = true;
12827 }
12828
12829 void LongRunningRegExp() {
12830 block_->Signal(); // Enable morphing thread on next preemption.
12831 while (morphs_during_regexp_ < kRequiredModifications &&
12832 morphs_ < kMaxModifications) {
12833 int morphs_before = morphs_;
12834 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000012835 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012836 // Match 15-30 "a"'s against 14 and a "b".
12837 const char* c_source =
12838 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12839 ".exec(input) === null";
12840 Local<String> source = String::New(c_source);
12841 Local<Script> script = Script::Compile(source);
12842 Local<Value> result = script->Run();
12843 CHECK(result->IsTrue());
12844 }
12845 int morphs_after = morphs_;
12846 morphs_during_regexp_ += morphs_after - morphs_before;
12847 }
12848 regexp_success_ = true;
12849 }
12850
12851 i::uc16 two_byte_content_[15];
12852 i::Semaphore* block_;
12853 int morphs_;
12854 int morphs_during_regexp_;
12855 bool regexp_success_;
12856 bool morph_success_;
12857 i::Handle<i::String> input_;
12858 AsciiVectorResource ascii_resource_;
12859 UC16VectorResource uc16_resource_;
12860};
12861
12862
12863// Test that a regular expression execution can be interrupted and
12864// the string changed without failing.
12865TEST(RegExpStringModification) {
12866 v8::Locker lock;
12867 v8::V8::Initialize();
12868 v8::HandleScope scope;
12869 Local<Context> local_env;
12870 {
12871 LocalContext env;
12872 local_env = env.local();
12873 }
12874
12875 // Local context should still be live.
12876 CHECK(!local_env.IsEmpty());
12877 local_env->Enter();
12878
12879 // Should complete without problems.
12880 RegExpStringModificationTest().RunTest();
12881
12882 local_env->Exit();
12883}
12884
12885
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012886// Test that we cannot set a property on the global object if there
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012887// is a read-only property in the prototype chain.
12888TEST(ReadOnlyPropertyInGlobalProto) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012889 i::FLAG_es5_readonly = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012890 v8::HandleScope scope;
12891 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12892 LocalContext context(0, templ);
12893 v8::Handle<v8::Object> global = context->Global();
12894 v8::Handle<v8::Object> global_proto =
12895 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12896 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12897 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12898 // Check without 'eval' or 'with'.
12899 v8::Handle<v8::Value> res =
12900 CompileRun("function f() { x = 42; return x; }; f()");
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012901 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012902 // Check with 'eval'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012903 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12904 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012905 // Check with 'with'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012906 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12907 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012908}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012909
12910static int force_set_set_count = 0;
12911static int force_set_get_count = 0;
12912bool pass_on_get = false;
12913
12914static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12915 const v8::AccessorInfo& info) {
12916 force_set_get_count++;
12917 if (pass_on_get) {
12918 return v8::Handle<v8::Value>();
12919 } else {
12920 return v8::Int32::New(3);
12921 }
12922}
12923
12924static void ForceSetSetter(v8::Local<v8::String> name,
12925 v8::Local<v8::Value> value,
12926 const v8::AccessorInfo& info) {
12927 force_set_set_count++;
12928}
12929
12930static v8::Handle<v8::Value> ForceSetInterceptSetter(
12931 v8::Local<v8::String> name,
12932 v8::Local<v8::Value> value,
12933 const v8::AccessorInfo& info) {
12934 force_set_set_count++;
12935 return v8::Undefined();
12936}
12937
12938TEST(ForceSet) {
12939 force_set_get_count = 0;
12940 force_set_set_count = 0;
12941 pass_on_get = false;
12942
12943 v8::HandleScope scope;
12944 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12945 v8::Handle<v8::String> access_property = v8::String::New("a");
12946 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12947 LocalContext context(NULL, templ);
12948 v8::Handle<v8::Object> global = context->Global();
12949
12950 // Ordinary properties
12951 v8::Handle<v8::String> simple_property = v8::String::New("p");
12952 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12953 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12954 // This should fail because the property is read-only
12955 global->Set(simple_property, v8::Int32::New(5));
12956 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12957 // This should succeed even though the property is read-only
12958 global->ForceSet(simple_property, v8::Int32::New(6));
12959 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12960
12961 // Accessors
12962 CHECK_EQ(0, force_set_set_count);
12963 CHECK_EQ(0, force_set_get_count);
12964 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12965 // CHECK_EQ the property shouldn't override it, just call the setter
12966 // which in this case does nothing.
12967 global->Set(access_property, v8::Int32::New(7));
12968 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12969 CHECK_EQ(1, force_set_set_count);
12970 CHECK_EQ(2, force_set_get_count);
12971 // Forcing the property to be set should override the accessor without
12972 // calling it
12973 global->ForceSet(access_property, v8::Int32::New(8));
12974 CHECK_EQ(8, global->Get(access_property)->Int32Value());
12975 CHECK_EQ(1, force_set_set_count);
12976 CHECK_EQ(2, force_set_get_count);
12977}
12978
12979TEST(ForceSetWithInterceptor) {
12980 force_set_get_count = 0;
12981 force_set_set_count = 0;
12982 pass_on_get = false;
12983
12984 v8::HandleScope scope;
12985 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12986 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12987 LocalContext context(NULL, templ);
12988 v8::Handle<v8::Object> global = context->Global();
12989
12990 v8::Handle<v8::String> some_property = v8::String::New("a");
12991 CHECK_EQ(0, force_set_set_count);
12992 CHECK_EQ(0, force_set_get_count);
12993 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12994 // Setting the property shouldn't override it, just call the setter
12995 // which in this case does nothing.
12996 global->Set(some_property, v8::Int32::New(7));
12997 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12998 CHECK_EQ(1, force_set_set_count);
12999 CHECK_EQ(2, force_set_get_count);
13000 // Getting the property when the interceptor returns an empty handle
13001 // should yield undefined, since the property isn't present on the
13002 // object itself yet.
13003 pass_on_get = true;
13004 CHECK(global->Get(some_property)->IsUndefined());
13005 CHECK_EQ(1, force_set_set_count);
13006 CHECK_EQ(3, force_set_get_count);
13007 // Forcing the property to be set should cause the value to be
13008 // set locally without calling the interceptor.
13009 global->ForceSet(some_property, v8::Int32::New(8));
13010 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13011 CHECK_EQ(1, force_set_set_count);
13012 CHECK_EQ(4, force_set_get_count);
13013 // Reenabling the interceptor should cause it to take precedence over
13014 // the property
13015 pass_on_get = false;
13016 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13017 CHECK_EQ(1, force_set_set_count);
13018 CHECK_EQ(5, force_set_get_count);
13019 // The interceptor should also work for other properties
13020 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
13021 CHECK_EQ(1, force_set_set_count);
13022 CHECK_EQ(6, force_set_get_count);
13023}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013024
13025
ager@chromium.orge2902be2009-06-08 12:21:35 +000013026THREADED_TEST(ForceDelete) {
13027 v8::HandleScope scope;
13028 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13029 LocalContext context(NULL, templ);
13030 v8::Handle<v8::Object> global = context->Global();
13031
13032 // Ordinary properties
13033 v8::Handle<v8::String> simple_property = v8::String::New("p");
13034 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
13035 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13036 // This should fail because the property is dont-delete.
13037 CHECK(!global->Delete(simple_property));
13038 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13039 // This should succeed even though the property is dont-delete.
13040 CHECK(global->ForceDelete(simple_property));
13041 CHECK(global->Get(simple_property)->IsUndefined());
13042}
13043
13044
13045static int force_delete_interceptor_count = 0;
13046static bool pass_on_delete = false;
13047
13048
13049static v8::Handle<v8::Boolean> ForceDeleteDeleter(
13050 v8::Local<v8::String> name,
13051 const v8::AccessorInfo& info) {
13052 force_delete_interceptor_count++;
13053 if (pass_on_delete) {
13054 return v8::Handle<v8::Boolean>();
13055 } else {
13056 return v8::True();
13057 }
13058}
13059
13060
13061THREADED_TEST(ForceDeleteWithInterceptor) {
13062 force_delete_interceptor_count = 0;
13063 pass_on_delete = false;
13064
13065 v8::HandleScope scope;
13066 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13067 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
13068 LocalContext context(NULL, templ);
13069 v8::Handle<v8::Object> global = context->Global();
13070
13071 v8::Handle<v8::String> some_property = v8::String::New("a");
13072 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
13073
13074 // Deleting a property should get intercepted and nothing should
13075 // happen.
13076 CHECK_EQ(0, force_delete_interceptor_count);
13077 CHECK(global->Delete(some_property));
13078 CHECK_EQ(1, force_delete_interceptor_count);
13079 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13080 // Deleting the property when the interceptor returns an empty
13081 // handle should not delete the property since it is DontDelete.
13082 pass_on_delete = true;
13083 CHECK(!global->Delete(some_property));
13084 CHECK_EQ(2, force_delete_interceptor_count);
13085 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13086 // Forcing the property to be deleted should delete the value
13087 // without calling the interceptor.
13088 CHECK(global->ForceDelete(some_property));
13089 CHECK(global->Get(some_property)->IsUndefined());
13090 CHECK_EQ(2, force_delete_interceptor_count);
13091}
13092
13093
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013094// Make sure that forcing a delete invalidates any IC stubs, so we
13095// don't read the hole value.
13096THREADED_TEST(ForceDeleteIC) {
13097 v8::HandleScope scope;
13098 LocalContext context;
13099 // Create a DontDelete variable on the global object.
13100 CompileRun("this.__proto__ = { foo: 'horse' };"
13101 "var foo = 'fish';"
13102 "function f() { return foo.length; }");
13103 // Initialize the IC for foo in f.
13104 CompileRun("for (var i = 0; i < 4; i++) f();");
13105 // Make sure the value of foo is correct before the deletion.
13106 CHECK_EQ(4, CompileRun("f()")->Int32Value());
13107 // Force the deletion of foo.
13108 CHECK(context->Global()->ForceDelete(v8_str("foo")));
13109 // Make sure the value for foo is read from the prototype, and that
13110 // we don't get in trouble with reading the deleted cell value
13111 // sentinel.
13112 CHECK_EQ(5, CompileRun("f()")->Int32Value());
13113}
13114
13115
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013116TEST(InlinedFunctionAcrossContexts) {
13117 i::FLAG_allow_natives_syntax = true;
13118 v8::HandleScope outer_scope;
13119 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
13120 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
13121 ctx1->Enter();
13122
13123 {
13124 v8::HandleScope inner_scope;
13125 CompileRun("var G = 42; function foo() { return G; }");
13126 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
13127 ctx2->Enter();
13128 ctx2->Global()->Set(v8_str("o"), foo);
13129 v8::Local<v8::Value> res = CompileRun(
13130 "function f() { return o(); }"
13131 "for (var i = 0; i < 10; ++i) f();"
13132 "%OptimizeFunctionOnNextCall(f);"
13133 "f();");
13134 CHECK_EQ(42, res->Int32Value());
13135 ctx2->Exit();
13136 v8::Handle<v8::String> G_property = v8::String::New("G");
13137 CHECK(ctx1->Global()->ForceDelete(G_property));
13138 ctx2->Enter();
13139 ExpectString(
13140 "(function() {"
13141 " try {"
13142 " return f();"
13143 " } catch(e) {"
13144 " return e.toString();"
13145 " }"
13146 " })()",
13147 "ReferenceError: G is not defined");
13148 ctx2->Exit();
13149 ctx1->Exit();
13150 ctx1.Dispose();
13151 }
13152 ctx2.Dispose();
13153}
13154
13155
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013156v8::Persistent<Context> calling_context0;
13157v8::Persistent<Context> calling_context1;
13158v8::Persistent<Context> calling_context2;
13159
13160
13161// Check that the call to the callback is initiated in
13162// calling_context2, the directly calling context is calling_context1
13163// and the callback itself is in calling_context0.
13164static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
13165 ApiTestFuzzer::Fuzz();
13166 CHECK(Context::GetCurrent() == calling_context0);
13167 CHECK(Context::GetCalling() == calling_context1);
13168 CHECK(Context::GetEntered() == calling_context2);
13169 return v8::Integer::New(42);
13170}
13171
13172
13173THREADED_TEST(GetCallingContext) {
13174 v8::HandleScope scope;
13175
13176 calling_context0 = Context::New();
13177 calling_context1 = Context::New();
13178 calling_context2 = Context::New();
13179
13180 // Allow cross-domain access.
13181 Local<String> token = v8_str("<security token>");
13182 calling_context0->SetSecurityToken(token);
13183 calling_context1->SetSecurityToken(token);
13184 calling_context2->SetSecurityToken(token);
13185
13186 // Create an object with a C++ callback in context0.
13187 calling_context0->Enter();
13188 Local<v8::FunctionTemplate> callback_templ =
13189 v8::FunctionTemplate::New(GetCallingContextCallback);
13190 calling_context0->Global()->Set(v8_str("callback"),
13191 callback_templ->GetFunction());
13192 calling_context0->Exit();
13193
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013194 // Expose context0 in context1 and set up a function that calls the
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013195 // callback function.
13196 calling_context1->Enter();
13197 calling_context1->Global()->Set(v8_str("context0"),
13198 calling_context0->Global());
13199 CompileRun("function f() { context0.callback() }");
13200 calling_context1->Exit();
13201
13202 // Expose context1 in context2 and call the callback function in
13203 // context0 indirectly through f in context1.
13204 calling_context2->Enter();
13205 calling_context2->Global()->Set(v8_str("context1"),
13206 calling_context1->Global());
13207 CompileRun("context1.f()");
13208 calling_context2->Exit();
13209
13210 // Dispose the contexts to allow them to be garbage collected.
13211 calling_context0.Dispose();
13212 calling_context1.Dispose();
13213 calling_context2.Dispose();
13214 calling_context0.Clear();
13215 calling_context1.Clear();
13216 calling_context2.Clear();
13217}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013218
13219
13220// Check that a variable declaration with no explicit initialization
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013221// value does shadow an existing property in the prototype chain.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013222THREADED_TEST(InitGlobalVarInProtoChain) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013223 i::FLAG_es52_globals = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013224 v8::HandleScope scope;
13225 LocalContext context;
13226 // Introduce a variable in the prototype chain.
13227 CompileRun("__proto__.x = 42");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013228 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013229 CHECK(!result->IsUndefined());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013230 CHECK_EQ(43, result->Int32Value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013231}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013232
13233
13234// Regression test for issue 398.
13235// If a function is added to an object, creating a constant function
13236// field, and the result is cloned, replacing the constant function on the
13237// original should not affect the clone.
13238// See http://code.google.com/p/v8/issues/detail?id=398
13239THREADED_TEST(ReplaceConstantFunction) {
13240 v8::HandleScope scope;
13241 LocalContext context;
13242 v8::Handle<v8::Object> obj = v8::Object::New();
13243 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13244 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13245 obj->Set(foo_string, func_templ->GetFunction());
13246 v8::Handle<v8::Object> obj_clone = obj->Clone();
13247 obj_clone->Set(foo_string, v8::String::New("Hello"));
13248 CHECK(!obj->Get(foo_string)->IsUndefined());
13249}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013250
13251
13252// Regression test for http://crbug.com/16276.
13253THREADED_TEST(Regress16276) {
13254 v8::HandleScope scope;
13255 LocalContext context;
13256 // Force the IC in f to be a dictionary load IC.
13257 CompileRun("function f(obj) { return obj.x; }\n"
13258 "var obj = { x: { foo: 42 }, y: 87 };\n"
13259 "var x = obj.x;\n"
13260 "delete obj.y;\n"
13261 "for (var i = 0; i < 5; i++) f(obj);");
13262 // Detach the global object to make 'this' refer directly to the
13263 // global object (not the proxy), and make sure that the dictionary
13264 // load IC doesn't mess up loading directly from the global object.
13265 context->DetachGlobal();
13266 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13267}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013268
13269
13270THREADED_TEST(PixelArray) {
13271 v8::HandleScope scope;
13272 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013273 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013274 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013275 i::Handle<i::ExternalPixelArray> pixels =
13276 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013277 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013278 v8::kExternalPixelArray,
13279 pixel_data));
13280 // Force GC to trigger verification.
13281 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013282 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013283 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013284 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013285 // Force GC to trigger verification.
13286 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013287 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013288 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013289 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013290 }
13291
13292 v8::Handle<v8::Object> obj = v8::Object::New();
13293 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13294 // Set the elements to be the pixels.
13295 // jsobj->set_elements(*pixels);
13296 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013297 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013298 obj->Set(v8_str("field"), v8::Int32::New(1503));
13299 context->Global()->Set(v8_str("pixels"), obj);
13300 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13301 CHECK_EQ(1503, result->Int32Value());
13302 result = CompileRun("pixels[1]");
13303 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013304
13305 result = CompileRun("var sum = 0;"
13306 "for (var i = 0; i < 8; i++) {"
13307 " sum += pixels[i] = pixels[i] = -i;"
13308 "}"
13309 "sum;");
13310 CHECK_EQ(-28, result->Int32Value());
13311
13312 result = CompileRun("var sum = 0;"
13313 "for (var i = 0; i < 8; i++) {"
13314 " sum += pixels[i] = pixels[i] = 0;"
13315 "}"
13316 "sum;");
13317 CHECK_EQ(0, result->Int32Value());
13318
13319 result = CompileRun("var sum = 0;"
13320 "for (var i = 0; i < 8; i++) {"
13321 " sum += pixels[i] = pixels[i] = 255;"
13322 "}"
13323 "sum;");
13324 CHECK_EQ(8 * 255, result->Int32Value());
13325
13326 result = CompileRun("var sum = 0;"
13327 "for (var i = 0; i < 8; i++) {"
13328 " sum += pixels[i] = pixels[i] = 256 + i;"
13329 "}"
13330 "sum;");
13331 CHECK_EQ(2076, result->Int32Value());
13332
13333 result = CompileRun("var sum = 0;"
13334 "for (var i = 0; i < 8; i++) {"
13335 " sum += pixels[i] = pixels[i] = i;"
13336 "}"
13337 "sum;");
13338 CHECK_EQ(28, result->Int32Value());
13339
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013340 result = CompileRun("var sum = 0;"
13341 "for (var i = 0; i < 8; i++) {"
13342 " sum += pixels[i];"
13343 "}"
13344 "sum;");
13345 CHECK_EQ(28, result->Int32Value());
13346
13347 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013348 i::Handle<i::Object> no_failure;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013349 no_failure =
13350 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013351 ASSERT(!no_failure.is_null());
13352 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013353 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013354 *value.location() = i::Smi::FromInt(256);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013355 no_failure =
13356 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013357 ASSERT(!no_failure.is_null());
13358 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013359 CHECK_EQ(255,
13360 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013361 *value.location() = i::Smi::FromInt(-1);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013362 no_failure =
13363 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013364 ASSERT(!no_failure.is_null());
13365 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013366 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013367
13368 result = CompileRun("for (var i = 0; i < 8; i++) {"
13369 " pixels[i] = (i * 65) - 109;"
13370 "}"
13371 "pixels[1] + pixels[6];");
13372 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013373 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13374 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13375 CHECK_EQ(21,
13376 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13377 CHECK_EQ(86,
13378 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13379 CHECK_EQ(151,
13380 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13381 CHECK_EQ(216,
13382 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13383 CHECK_EQ(255,
13384 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13385 CHECK_EQ(255,
13386 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013387 result = CompileRun("var sum = 0;"
13388 "for (var i = 0; i < 8; i++) {"
13389 " sum += pixels[i];"
13390 "}"
13391 "sum;");
13392 CHECK_EQ(984, result->Int32Value());
13393
13394 result = CompileRun("for (var i = 0; i < 8; i++) {"
13395 " pixels[i] = (i * 1.1);"
13396 "}"
13397 "pixels[1] + pixels[6];");
13398 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013399 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13400 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13401 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13402 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13403 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13404 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13405 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13406 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013407
13408 result = CompileRun("for (var i = 0; i < 8; i++) {"
13409 " pixels[7] = undefined;"
13410 "}"
13411 "pixels[7];");
13412 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013413 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013414
13415 result = CompileRun("for (var i = 0; i < 8; i++) {"
13416 " pixels[6] = '2.3';"
13417 "}"
13418 "pixels[6];");
13419 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013420 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013421
13422 result = CompileRun("for (var i = 0; i < 8; i++) {"
13423 " pixels[5] = NaN;"
13424 "}"
13425 "pixels[5];");
13426 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013427 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013428
13429 result = CompileRun("for (var i = 0; i < 8; i++) {"
13430 " pixels[8] = Infinity;"
13431 "}"
13432 "pixels[8];");
13433 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013434 CHECK_EQ(255,
13435 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013436
13437 result = CompileRun("for (var i = 0; i < 8; i++) {"
13438 " pixels[9] = -Infinity;"
13439 "}"
13440 "pixels[9];");
13441 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013442 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013443
13444 result = CompileRun("pixels[3] = 33;"
13445 "delete pixels[3];"
13446 "pixels[3];");
13447 CHECK_EQ(33, result->Int32Value());
13448
13449 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13450 "pixels[2] = 12; pixels[3] = 13;"
13451 "pixels.__defineGetter__('2',"
13452 "function() { return 120; });"
13453 "pixels[2];");
13454 CHECK_EQ(12, result->Int32Value());
13455
13456 result = CompileRun("var js_array = new Array(40);"
13457 "js_array[0] = 77;"
13458 "js_array;");
13459 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13460
13461 result = CompileRun("pixels[1] = 23;"
13462 "pixels.__proto__ = [];"
13463 "js_array.__proto__ = pixels;"
13464 "js_array.concat(pixels);");
13465 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13466 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13467
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013468 result = CompileRun("pixels[1] = 23;");
13469 CHECK_EQ(23, result->Int32Value());
13470
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013471 // Test for index greater than 255. Regression test for:
13472 // http://code.google.com/p/chromium/issues/detail?id=26337.
13473 result = CompileRun("pixels[256] = 255;");
13474 CHECK_EQ(255, result->Int32Value());
13475 result = CompileRun("var i = 0;"
13476 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13477 "i");
13478 CHECK_EQ(255, result->Int32Value());
13479
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013480 // Make sure that pixel array ICs recognize when a non-pixel array
13481 // is passed to it.
13482 result = CompileRun("function pa_load(p) {"
13483 " var sum = 0;"
13484 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13485 " return sum;"
13486 "}"
13487 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13488 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13489 "just_ints = new Object();"
13490 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13491 "for (var i = 0; i < 10; ++i) {"
13492 " result = pa_load(just_ints);"
13493 "}"
13494 "result");
13495 CHECK_EQ(32640, result->Int32Value());
13496
13497 // Make sure that pixel array ICs recognize out-of-bound accesses.
13498 result = CompileRun("function pa_load(p, start) {"
13499 " var sum = 0;"
13500 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13501 " return sum;"
13502 "}"
13503 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13504 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13505 "for (var i = 0; i < 10; ++i) {"
13506 " result = pa_load(pixels,-10);"
13507 "}"
13508 "result");
13509 CHECK_EQ(0, result->Int32Value());
13510
13511 // Make sure that generic ICs properly handles a pixel array.
13512 result = CompileRun("function pa_load(p) {"
13513 " var sum = 0;"
13514 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13515 " return sum;"
13516 "}"
13517 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13518 "just_ints = new Object();"
13519 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13520 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13521 "for (var i = 0; i < 10; ++i) {"
13522 " result = pa_load(pixels);"
13523 "}"
13524 "result");
13525 CHECK_EQ(32640, result->Int32Value());
13526
13527 // Make sure that generic load ICs recognize out-of-bound accesses in
13528 // pixel arrays.
13529 result = CompileRun("function pa_load(p, start) {"
13530 " var sum = 0;"
13531 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13532 " return sum;"
13533 "}"
13534 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13535 "just_ints = new Object();"
13536 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13537 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13538 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13539 "for (var i = 0; i < 10; ++i) {"
13540 " result = pa_load(pixels,-10);"
13541 "}"
13542 "result");
13543 CHECK_EQ(0, result->Int32Value());
13544
13545 // Make sure that generic ICs properly handles other types than pixel
13546 // arrays (that the inlined fast pixel array test leaves the right information
13547 // in the right registers).
13548 result = CompileRun("function pa_load(p) {"
13549 " var sum = 0;"
13550 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13551 " return sum;"
13552 "}"
13553 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13554 "just_ints = new Object();"
13555 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13556 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13557 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13558 "sparse_array = new Object();"
13559 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13560 "sparse_array[1000000] = 3;"
13561 "for (var i = 0; i < 10; ++i) {"
13562 " result = pa_load(sparse_array);"
13563 "}"
13564 "result");
13565 CHECK_EQ(32640, result->Int32Value());
13566
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013567 // Make sure that pixel array store ICs clamp values correctly.
13568 result = CompileRun("function pa_store(p) {"
13569 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13570 "}"
13571 "pa_store(pixels);"
13572 "var sum = 0;"
13573 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13574 "sum");
13575 CHECK_EQ(48896, result->Int32Value());
13576
13577 // Make sure that pixel array stores correctly handle accesses outside
13578 // of the pixel array..
13579 result = CompileRun("function pa_store(p,start) {"
13580 " for (var j = 0; j < 256; j++) {"
13581 " p[j+start] = j * 2;"
13582 " }"
13583 "}"
13584 "pa_store(pixels,0);"
13585 "pa_store(pixels,-128);"
13586 "var sum = 0;"
13587 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13588 "sum");
13589 CHECK_EQ(65280, result->Int32Value());
13590
13591 // Make sure that the generic store stub correctly handle accesses outside
13592 // of the pixel array..
13593 result = CompileRun("function pa_store(p,start) {"
13594 " for (var j = 0; j < 256; j++) {"
13595 " p[j+start] = j * 2;"
13596 " }"
13597 "}"
13598 "pa_store(pixels,0);"
13599 "just_ints = new Object();"
13600 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13601 "pa_store(just_ints, 0);"
13602 "pa_store(pixels,-128);"
13603 "var sum = 0;"
13604 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13605 "sum");
13606 CHECK_EQ(65280, result->Int32Value());
13607
13608 // Make sure that the generic keyed store stub clamps pixel array values
13609 // correctly.
13610 result = CompileRun("function pa_store(p) {"
13611 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13612 "}"
13613 "pa_store(pixels);"
13614 "just_ints = new Object();"
13615 "pa_store(just_ints);"
13616 "pa_store(pixels);"
13617 "var sum = 0;"
13618 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13619 "sum");
13620 CHECK_EQ(48896, result->Int32Value());
13621
13622 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013623 result = CompileRun("function pa_load(p) {"
13624 " var sum = 0;"
13625 " for (var i=0; i<256; ++i) {"
13626 " sum += p[i];"
13627 " }"
13628 " return sum; "
13629 "}"
13630 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013631 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013632 " result = pa_load(pixels);"
13633 "}"
13634 "result");
13635 CHECK_EQ(32640, result->Int32Value());
13636
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013637 // Make sure that pixel array stores are optimized by crankshaft.
13638 result = CompileRun("function pa_init(p) {"
13639 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13640 "}"
13641 "function pa_load(p) {"
13642 " var sum = 0;"
13643 " for (var i=0; i<256; ++i) {"
13644 " sum += p[i];"
13645 " }"
13646 " return sum; "
13647 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013648 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013649 " pa_init(pixels);"
13650 "}"
13651 "result = pa_load(pixels);"
13652 "result");
13653 CHECK_EQ(32640, result->Int32Value());
13654
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013655 free(pixel_data);
13656}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013657
ager@chromium.org96c75b52009-08-26 09:13:16 +000013658
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013659THREADED_TEST(PixelArrayInfo) {
13660 v8::HandleScope scope;
13661 LocalContext context;
13662 for (int size = 0; size < 100; size += 10) {
13663 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13664 v8::Handle<v8::Object> obj = v8::Object::New();
13665 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13666 CHECK(obj->HasIndexedPropertiesInPixelData());
13667 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13668 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13669 free(pixel_data);
13670 }
13671}
13672
13673
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013674static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13675 uint32_t index,
13676 const AccessorInfo& info) {
13677 ApiTestFuzzer::Fuzz();
13678 return v8::Handle<Value>();
13679}
13680
13681
13682static v8::Handle<Value> NotHandledIndexedPropertySetter(
13683 uint32_t index,
13684 Local<Value> value,
13685 const AccessorInfo& info) {
13686 ApiTestFuzzer::Fuzz();
13687 return v8::Handle<Value>();
13688}
13689
13690
13691THREADED_TEST(PixelArrayWithInterceptor) {
13692 v8::HandleScope scope;
13693 LocalContext context;
13694 const int kElementCount = 260;
13695 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013696 i::Handle<i::ExternalPixelArray> pixels =
13697 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013698 FACTORY->NewExternalArray(kElementCount,
13699 v8::kExternalPixelArray,
13700 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013701 for (int i = 0; i < kElementCount; i++) {
13702 pixels->set(i, i % 256);
13703 }
13704 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13705 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13706 NotHandledIndexedPropertySetter);
13707 v8::Handle<v8::Object> obj = templ->NewInstance();
13708 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13709 context->Global()->Set(v8_str("pixels"), obj);
13710 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13711 CHECK_EQ(1, result->Int32Value());
13712 result = CompileRun("var sum = 0;"
13713 "for (var i = 0; i < 8; i++) {"
13714 " sum += pixels[i] = pixels[i] = -i;"
13715 "}"
13716 "sum;");
13717 CHECK_EQ(-28, result->Int32Value());
13718 result = CompileRun("pixels.hasOwnProperty('1')");
13719 CHECK(result->BooleanValue());
13720 free(pixel_data);
13721}
13722
13723
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013724static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13725 switch (array_type) {
13726 case v8::kExternalByteArray:
13727 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013728 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013729 return 1;
13730 break;
13731 case v8::kExternalShortArray:
13732 case v8::kExternalUnsignedShortArray:
13733 return 2;
13734 break;
13735 case v8::kExternalIntArray:
13736 case v8::kExternalUnsignedIntArray:
13737 case v8::kExternalFloatArray:
13738 return 4;
13739 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013740 case v8::kExternalDoubleArray:
13741 return 8;
13742 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013743 default:
13744 UNREACHABLE();
13745 return -1;
13746 }
13747 UNREACHABLE();
13748 return -1;
13749}
13750
13751
ager@chromium.org3811b432009-10-28 14:53:37 +000013752template <class ExternalArrayClass, class ElementType>
13753static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13754 int64_t low,
13755 int64_t high) {
13756 v8::HandleScope scope;
13757 LocalContext context;
13758 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013759 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000013760 ElementType* array_data =
13761 static_cast<ElementType*>(malloc(kElementCount * element_size));
13762 i::Handle<ExternalArrayClass> array =
13763 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013764 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013765 // Force GC to trigger verification.
13766 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013767 for (int i = 0; i < kElementCount; i++) {
13768 array->set(i, static_cast<ElementType>(i));
13769 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013770 // Force GC to trigger verification.
13771 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013772 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013773 CHECK_EQ(static_cast<int64_t>(i),
13774 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000013775 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13776 }
13777
13778 v8::Handle<v8::Object> obj = v8::Object::New();
13779 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13780 // Set the elements to be the external array.
13781 obj->SetIndexedPropertiesToExternalArrayData(array_data,
13782 array_type,
13783 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013784 CHECK_EQ(
13785 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013786 obj->Set(v8_str("field"), v8::Int32::New(1503));
13787 context->Global()->Set(v8_str("ext_array"), obj);
13788 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13789 CHECK_EQ(1503, result->Int32Value());
13790 result = CompileRun("ext_array[1]");
13791 CHECK_EQ(1, result->Int32Value());
13792
13793 // Check pass through of assigned smis
13794 result = CompileRun("var sum = 0;"
13795 "for (var i = 0; i < 8; i++) {"
13796 " sum += ext_array[i] = ext_array[i] = -i;"
13797 "}"
13798 "sum;");
13799 CHECK_EQ(-28, result->Int32Value());
13800
13801 // Check assigned smis
13802 result = CompileRun("for (var i = 0; i < 8; i++) {"
13803 " ext_array[i] = i;"
13804 "}"
13805 "var sum = 0;"
13806 "for (var i = 0; i < 8; i++) {"
13807 " sum += ext_array[i];"
13808 "}"
13809 "sum;");
13810 CHECK_EQ(28, result->Int32Value());
13811
13812 // Check assigned smis in reverse order
13813 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13814 " ext_array[i] = i;"
13815 "}"
13816 "var sum = 0;"
13817 "for (var i = 0; i < 8; i++) {"
13818 " sum += ext_array[i];"
13819 "}"
13820 "sum;");
13821 CHECK_EQ(28, result->Int32Value());
13822
13823 // Check pass through of assigned HeapNumbers
13824 result = CompileRun("var sum = 0;"
13825 "for (var i = 0; i < 16; i+=2) {"
13826 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13827 "}"
13828 "sum;");
13829 CHECK_EQ(-28, result->Int32Value());
13830
13831 // Check assigned HeapNumbers
13832 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13833 " ext_array[i] = (i * 0.5);"
13834 "}"
13835 "var sum = 0;"
13836 "for (var i = 0; i < 16; i+=2) {"
13837 " sum += ext_array[i];"
13838 "}"
13839 "sum;");
13840 CHECK_EQ(28, result->Int32Value());
13841
13842 // Check assigned HeapNumbers in reverse order
13843 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13844 " ext_array[i] = (i * 0.5);"
13845 "}"
13846 "var sum = 0;"
13847 "for (var i = 0; i < 16; i+=2) {"
13848 " sum += ext_array[i];"
13849 "}"
13850 "sum;");
13851 CHECK_EQ(28, result->Int32Value());
13852
13853 i::ScopedVector<char> test_buf(1024);
13854
13855 // Check legal boundary conditions.
13856 // The repeated loads and stores ensure the ICs are exercised.
13857 const char* boundary_program =
13858 "var res = 0;"
13859 "for (var i = 0; i < 16; i++) {"
13860 " ext_array[i] = %lld;"
13861 " if (i > 8) {"
13862 " res = ext_array[i];"
13863 " }"
13864 "}"
13865 "res;";
13866 i::OS::SNPrintF(test_buf,
13867 boundary_program,
13868 low);
13869 result = CompileRun(test_buf.start());
13870 CHECK_EQ(low, result->IntegerValue());
13871
13872 i::OS::SNPrintF(test_buf,
13873 boundary_program,
13874 high);
13875 result = CompileRun(test_buf.start());
13876 CHECK_EQ(high, result->IntegerValue());
13877
13878 // Check misprediction of type in IC.
13879 result = CompileRun("var tmp_array = ext_array;"
13880 "var sum = 0;"
13881 "for (var i = 0; i < 8; i++) {"
13882 " tmp_array[i] = i;"
13883 " sum += tmp_array[i];"
13884 " if (i == 4) {"
13885 " tmp_array = {};"
13886 " }"
13887 "}"
13888 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013889 // Force GC to trigger verification.
13890 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013891 CHECK_EQ(28, result->Int32Value());
13892
13893 // Make sure out-of-range loads do not throw.
13894 i::OS::SNPrintF(test_buf,
13895 "var caught_exception = false;"
13896 "try {"
13897 " ext_array[%d];"
13898 "} catch (e) {"
13899 " caught_exception = true;"
13900 "}"
13901 "caught_exception;",
13902 kElementCount);
13903 result = CompileRun(test_buf.start());
13904 CHECK_EQ(false, result->BooleanValue());
13905
13906 // Make sure out-of-range stores do not throw.
13907 i::OS::SNPrintF(test_buf,
13908 "var caught_exception = false;"
13909 "try {"
13910 " ext_array[%d] = 1;"
13911 "} catch (e) {"
13912 " caught_exception = true;"
13913 "}"
13914 "caught_exception;",
13915 kElementCount);
13916 result = CompileRun(test_buf.start());
13917 CHECK_EQ(false, result->BooleanValue());
13918
13919 // Check other boundary conditions, values and operations.
13920 result = CompileRun("for (var i = 0; i < 8; i++) {"
13921 " ext_array[7] = undefined;"
13922 "}"
13923 "ext_array[7];");
13924 CHECK_EQ(0, result->Int32Value());
yangguo@chromium.org56454712012-02-16 15:33:53 +000013925 if (array_type == v8::kExternalDoubleArray ||
13926 array_type == v8::kExternalFloatArray) {
13927 CHECK_EQ(
ulan@chromium.org812308e2012-02-29 15:58:45 +000013928 static_cast<int>(i::OS::nan_value()),
yangguo@chromium.org56454712012-02-16 15:33:53 +000013929 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13930 } else {
13931 CHECK_EQ(0, static_cast<int>(
13932 jsobj->GetElement(7)->ToObjectChecked()->Number()));
13933 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013934
13935 result = CompileRun("for (var i = 0; i < 8; i++) {"
13936 " ext_array[6] = '2.3';"
13937 "}"
13938 "ext_array[6];");
13939 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013940 CHECK_EQ(
13941 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013942
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013943 if (array_type != v8::kExternalFloatArray &&
13944 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013945 // Though the specification doesn't state it, be explicit about
13946 // converting NaNs and +/-Infinity to zero.
13947 result = CompileRun("for (var i = 0; i < 8; i++) {"
13948 " ext_array[i] = 5;"
13949 "}"
13950 "for (var i = 0; i < 8; i++) {"
13951 " ext_array[i] = NaN;"
13952 "}"
13953 "ext_array[5];");
13954 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013955 CHECK_EQ(0,
13956 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013957
13958 result = CompileRun("for (var i = 0; i < 8; i++) {"
13959 " ext_array[i] = 5;"
13960 "}"
13961 "for (var i = 0; i < 8; i++) {"
13962 " ext_array[i] = Infinity;"
13963 "}"
13964 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013965 int expected_value =
13966 (array_type == v8::kExternalPixelArray) ? 255 : 0;
13967 CHECK_EQ(expected_value, result->Int32Value());
13968 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013969 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013970
13971 result = CompileRun("for (var i = 0; i < 8; i++) {"
13972 " ext_array[i] = 5;"
13973 "}"
13974 "for (var i = 0; i < 8; i++) {"
13975 " ext_array[i] = -Infinity;"
13976 "}"
13977 "ext_array[5];");
13978 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013979 CHECK_EQ(0,
13980 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013981
13982 // Check truncation behavior of integral arrays.
13983 const char* unsigned_data =
13984 "var source_data = [0.6, 10.6];"
13985 "var expected_results = [0, 10];";
13986 const char* signed_data =
13987 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13988 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013989 const char* pixel_data =
13990 "var source_data = [0.6, 10.6];"
13991 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013992 bool is_unsigned =
13993 (array_type == v8::kExternalUnsignedByteArray ||
13994 array_type == v8::kExternalUnsignedShortArray ||
13995 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013996 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013997
13998 i::OS::SNPrintF(test_buf,
13999 "%s"
14000 "var all_passed = true;"
14001 "for (var i = 0; i < source_data.length; i++) {"
14002 " for (var j = 0; j < 8; j++) {"
14003 " ext_array[j] = source_data[i];"
14004 " }"
14005 " all_passed = all_passed &&"
14006 " (ext_array[5] == expected_results[i]);"
14007 "}"
14008 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014009 (is_unsigned ?
14010 unsigned_data :
14011 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014012 result = CompileRun(test_buf.start());
14013 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000014014 }
14015
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000014016 for (int i = 0; i < kElementCount; i++) {
14017 array->set(i, static_cast<ElementType>(i));
14018 }
14019 // Test complex assignments
14020 result = CompileRun("function ee_op_test_complex_func(sum) {"
14021 " for (var i = 0; i < 40; ++i) {"
14022 " sum += (ext_array[i] += 1);"
14023 " sum += (ext_array[i] -= 1);"
14024 " } "
14025 " return sum;"
14026 "}"
14027 "sum=0;"
14028 "for (var i=0;i<10000;++i) {"
14029 " sum=ee_op_test_complex_func(sum);"
14030 "}"
14031 "sum;");
14032 CHECK_EQ(16000000, result->Int32Value());
14033
14034 // Test count operations
14035 result = CompileRun("function ee_op_test_count_func(sum) {"
14036 " for (var i = 0; i < 40; ++i) {"
14037 " sum += (++ext_array[i]);"
14038 " sum += (--ext_array[i]);"
14039 " } "
14040 " return sum;"
14041 "}"
14042 "sum=0;"
14043 "for (var i=0;i<10000;++i) {"
14044 " sum=ee_op_test_count_func(sum);"
14045 "}"
14046 "sum;");
14047 CHECK_EQ(16000000, result->Int32Value());
14048
ager@chromium.org3811b432009-10-28 14:53:37 +000014049 result = CompileRun("ext_array[3] = 33;"
14050 "delete ext_array[3];"
14051 "ext_array[3];");
14052 CHECK_EQ(33, result->Int32Value());
14053
14054 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14055 "ext_array[2] = 12; ext_array[3] = 13;"
14056 "ext_array.__defineGetter__('2',"
14057 "function() { return 120; });"
14058 "ext_array[2];");
14059 CHECK_EQ(12, result->Int32Value());
14060
14061 result = CompileRun("var js_array = new Array(40);"
14062 "js_array[0] = 77;"
14063 "js_array;");
14064 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14065
14066 result = CompileRun("ext_array[1] = 23;"
14067 "ext_array.__proto__ = [];"
14068 "js_array.__proto__ = ext_array;"
14069 "js_array.concat(ext_array);");
14070 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14071 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14072
14073 result = CompileRun("ext_array[1] = 23;");
14074 CHECK_EQ(23, result->Int32Value());
14075
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014076 // Test more complex manipulations which cause eax to contain values
14077 // that won't be completely overwritten by loads from the arrays.
14078 // This catches bugs in the instructions used for the KeyedLoadIC
14079 // for byte and word types.
14080 {
14081 const int kXSize = 300;
14082 const int kYSize = 300;
14083 const int kLargeElementCount = kXSize * kYSize * 4;
14084 ElementType* large_array_data =
14085 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014086 v8::Handle<v8::Object> large_obj = v8::Object::New();
14087 // Set the elements to be the external array.
14088 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14089 array_type,
14090 kLargeElementCount);
14091 context->Global()->Set(v8_str("large_array"), large_obj);
14092 // Initialize contents of a few rows.
14093 for (int x = 0; x < 300; x++) {
14094 int row = 0;
14095 int offset = row * 300 * 4;
14096 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14097 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14098 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14099 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14100 row = 150;
14101 offset = row * 300 * 4;
14102 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14103 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14104 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14105 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14106 row = 298;
14107 offset = row * 300 * 4;
14108 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14109 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14110 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14111 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14112 }
14113 // The goal of the code below is to make "offset" large enough
14114 // that the computation of the index (which goes into eax) has
14115 // high bits set which will not be overwritten by a byte or short
14116 // load.
14117 result = CompileRun("var failed = false;"
14118 "var offset = 0;"
14119 "for (var i = 0; i < 300; i++) {"
14120 " if (large_array[4 * i] != 127 ||"
14121 " large_array[4 * i + 1] != 0 ||"
14122 " large_array[4 * i + 2] != 0 ||"
14123 " large_array[4 * i + 3] != 127) {"
14124 " failed = true;"
14125 " }"
14126 "}"
14127 "offset = 150 * 300 * 4;"
14128 "for (var i = 0; i < 300; i++) {"
14129 " if (large_array[offset + 4 * i] != 127 ||"
14130 " large_array[offset + 4 * i + 1] != 0 ||"
14131 " large_array[offset + 4 * i + 2] != 0 ||"
14132 " large_array[offset + 4 * i + 3] != 127) {"
14133 " failed = true;"
14134 " }"
14135 "}"
14136 "offset = 298 * 300 * 4;"
14137 "for (var i = 0; i < 300; i++) {"
14138 " if (large_array[offset + 4 * i] != 127 ||"
14139 " large_array[offset + 4 * i + 1] != 0 ||"
14140 " large_array[offset + 4 * i + 2] != 0 ||"
14141 " large_array[offset + 4 * i + 3] != 127) {"
14142 " failed = true;"
14143 " }"
14144 "}"
14145 "!failed;");
14146 CHECK_EQ(true, result->BooleanValue());
14147 free(large_array_data);
14148 }
14149
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014150 // The "" property descriptor is overloaded to store information about
14151 // the external array. Ensure that setting and accessing the "" property
14152 // works (it should overwrite the information cached about the external
14153 // array in the DescriptorArray) in various situations.
14154 result = CompileRun("ext_array[''] = 23; ext_array['']");
14155 CHECK_EQ(23, result->Int32Value());
14156
14157 // Property "" set after the external array is associated with the object.
14158 {
14159 v8::Handle<v8::Object> obj2 = v8::Object::New();
14160 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
14161 obj2->Set(v8_str(""), v8::Int32::New(1503));
14162 // Set the elements to be the external array.
14163 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14164 array_type,
14165 kElementCount);
14166 context->Global()->Set(v8_str("ext_array"), obj2);
14167 result = CompileRun("ext_array['']");
14168 CHECK_EQ(1503, result->Int32Value());
14169 }
14170
14171 // Property "" set after the external array is associated with the object.
14172 {
14173 v8::Handle<v8::Object> obj2 = v8::Object::New();
14174 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14175 // Set the elements to be the external array.
14176 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14177 array_type,
14178 kElementCount);
14179 obj2->Set(v8_str(""), v8::Int32::New(1503));
14180 context->Global()->Set(v8_str("ext_array"), obj2);
14181 result = CompileRun("ext_array['']");
14182 CHECK_EQ(1503, result->Int32Value());
14183 }
14184
14185 // Should reuse the map from previous test.
14186 {
14187 v8::Handle<v8::Object> obj2 = v8::Object::New();
14188 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14189 // Set the elements to be the external array. Should re-use the map
14190 // from previous test.
14191 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14192 array_type,
14193 kElementCount);
14194 context->Global()->Set(v8_str("ext_array"), obj2);
14195 result = CompileRun("ext_array['']");
14196 }
14197
14198 // Property "" is a constant function that shouldn't not be interfered with
14199 // when an external array is set.
14200 {
14201 v8::Handle<v8::Object> obj2 = v8::Object::New();
14202 // Start
14203 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14204
14205 // Add a constant function to an object.
14206 context->Global()->Set(v8_str("ext_array"), obj2);
14207 result = CompileRun("ext_array[''] = function() {return 1503;};"
14208 "ext_array['']();");
14209
14210 // Add an external array transition to the same map that
14211 // has the constant transition.
14212 v8::Handle<v8::Object> obj3 = v8::Object::New();
14213 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14214 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14215 array_type,
14216 kElementCount);
14217 context->Global()->Set(v8_str("ext_array"), obj3);
14218 }
14219
14220 // If a external array transition is in the map, it should get clobbered
14221 // by a constant function.
14222 {
14223 // Add an external array transition.
14224 v8::Handle<v8::Object> obj3 = v8::Object::New();
14225 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14226 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14227 array_type,
14228 kElementCount);
14229
14230 // Add a constant function to the same map that just got an external array
14231 // transition.
14232 v8::Handle<v8::Object> obj2 = v8::Object::New();
14233 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14234 context->Global()->Set(v8_str("ext_array"), obj2);
14235 result = CompileRun("ext_array[''] = function() {return 1503;};"
14236 "ext_array['']();");
14237 }
14238
ager@chromium.org3811b432009-10-28 14:53:37 +000014239 free(array_data);
14240}
14241
14242
14243THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014244 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014245 v8::kExternalByteArray,
14246 -128,
14247 127);
14248}
14249
14250
14251THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014252 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014253 v8::kExternalUnsignedByteArray,
14254 0,
14255 255);
14256}
14257
14258
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014259THREADED_TEST(ExternalPixelArray) {
14260 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14261 v8::kExternalPixelArray,
14262 0,
14263 255);
14264}
14265
14266
ager@chromium.org3811b432009-10-28 14:53:37 +000014267THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014268 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014269 v8::kExternalShortArray,
14270 -32768,
14271 32767);
14272}
14273
14274
14275THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014276 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014277 v8::kExternalUnsignedShortArray,
14278 0,
14279 65535);
14280}
14281
14282
14283THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014284 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014285 v8::kExternalIntArray,
14286 INT_MIN, // -2147483648
14287 INT_MAX); // 2147483647
14288}
14289
14290
14291THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014292 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014293 v8::kExternalUnsignedIntArray,
14294 0,
14295 UINT_MAX); // 4294967295
14296}
14297
14298
14299THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014300 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014301 v8::kExternalFloatArray,
14302 -500,
14303 500);
14304}
14305
14306
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014307THREADED_TEST(ExternalDoubleArray) {
14308 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14309 v8::kExternalDoubleArray,
14310 -500,
14311 500);
14312}
14313
14314
ager@chromium.org3811b432009-10-28 14:53:37 +000014315THREADED_TEST(ExternalArrays) {
14316 TestExternalByteArray();
14317 TestExternalUnsignedByteArray();
14318 TestExternalShortArray();
14319 TestExternalUnsignedShortArray();
14320 TestExternalIntArray();
14321 TestExternalUnsignedIntArray();
14322 TestExternalFloatArray();
14323}
14324
14325
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014326void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14327 v8::HandleScope scope;
14328 LocalContext context;
14329 for (int size = 0; size < 100; size += 10) {
14330 int element_size = ExternalArrayElementSize(array_type);
14331 void* external_data = malloc(size * element_size);
14332 v8::Handle<v8::Object> obj = v8::Object::New();
14333 obj->SetIndexedPropertiesToExternalArrayData(
14334 external_data, array_type, size);
14335 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14336 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14337 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14338 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14339 free(external_data);
14340 }
14341}
14342
14343
14344THREADED_TEST(ExternalArrayInfo) {
14345 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14346 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14347 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14348 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14349 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14350 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14351 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014352 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014353 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014354}
14355
14356
danno@chromium.org412fa512012-09-14 13:28:26 +000014357void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14358 v8::Handle<v8::Object> obj = v8::Object::New();
14359 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14360 last_location = last_message = NULL;
14361 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14362 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14363 CHECK_NE(NULL, last_location);
14364 CHECK_NE(NULL, last_message);
14365}
14366
14367
14368TEST(ExternalArrayLimits) {
14369 v8::HandleScope scope;
14370 LocalContext context;
14371 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14372 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14373 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14374 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14375 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14376 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14377 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14378 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14379 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14380 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14381 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14382 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14383 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14384 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14385 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14386 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14387 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14388 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14389}
14390
14391
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014392THREADED_TEST(ScriptContextDependence) {
14393 v8::HandleScope scope;
14394 LocalContext c1;
14395 const char *source = "foo";
14396 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14397 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14398 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14399 CHECK_EQ(dep->Run()->Int32Value(), 100);
14400 CHECK_EQ(indep->Run()->Int32Value(), 100);
14401 LocalContext c2;
14402 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14403 CHECK_EQ(dep->Run()->Int32Value(), 100);
14404 CHECK_EQ(indep->Run()->Int32Value(), 101);
14405}
14406
ager@chromium.org96c75b52009-08-26 09:13:16 +000014407
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014408THREADED_TEST(StackTrace) {
14409 v8::HandleScope scope;
14410 LocalContext context;
14411 v8::TryCatch try_catch;
14412 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14413 v8::Handle<v8::String> src = v8::String::New(source);
14414 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14415 v8::Script::New(src, origin)->Run();
14416 CHECK(try_catch.HasCaught());
14417 v8::String::Utf8Value stack(try_catch.StackTrace());
14418 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14419}
ager@chromium.org96c75b52009-08-26 09:13:16 +000014420
14421
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014422// Checks that a StackFrame has certain expected values.
14423void checkStackFrame(const char* expected_script_name,
14424 const char* expected_func_name, int expected_line_number,
14425 int expected_column, bool is_eval, bool is_constructor,
14426 v8::Handle<v8::StackFrame> frame) {
14427 v8::HandleScope scope;
14428 v8::String::Utf8Value func_name(frame->GetFunctionName());
14429 v8::String::Utf8Value script_name(frame->GetScriptName());
14430 if (*script_name == NULL) {
14431 // The situation where there is no associated script, like for evals.
14432 CHECK(expected_script_name == NULL);
14433 } else {
14434 CHECK(strstr(*script_name, expected_script_name) != NULL);
14435 }
14436 CHECK(strstr(*func_name, expected_func_name) != NULL);
14437 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14438 CHECK_EQ(expected_column, frame->GetColumn());
14439 CHECK_EQ(is_eval, frame->IsEval());
14440 CHECK_EQ(is_constructor, frame->IsConstructor());
14441}
14442
14443
14444v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
14445 v8::HandleScope scope;
14446 const char* origin = "capture-stack-trace-test";
14447 const int kOverviewTest = 1;
14448 const int kDetailedTest = 2;
14449
14450 ASSERT(args.Length() == 1);
14451
14452 int testGroup = args[0]->Int32Value();
14453 if (testGroup == kOverviewTest) {
14454 v8::Handle<v8::StackTrace> stackTrace =
14455 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14456 CHECK_EQ(4, stackTrace->GetFrameCount());
14457 checkStackFrame(origin, "bar", 2, 10, false, false,
14458 stackTrace->GetFrame(0));
14459 checkStackFrame(origin, "foo", 6, 3, false, false,
14460 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014461 // This is the source string inside the eval which has the call to foo.
14462 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014463 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014464 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014465 checkStackFrame(origin, "", 8, 7, false, false,
14466 stackTrace->GetFrame(3));
14467
14468 CHECK(stackTrace->AsArray()->IsArray());
14469 } else if (testGroup == kDetailedTest) {
14470 v8::Handle<v8::StackTrace> stackTrace =
14471 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14472 CHECK_EQ(4, stackTrace->GetFrameCount());
14473 checkStackFrame(origin, "bat", 4, 22, false, false,
14474 stackTrace->GetFrame(0));
14475 checkStackFrame(origin, "baz", 8, 3, false, true,
14476 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014477#ifdef ENABLE_DEBUGGER_SUPPORT
14478 bool is_eval = true;
14479#else // ENABLE_DEBUGGER_SUPPORT
14480 bool is_eval = false;
14481#endif // ENABLE_DEBUGGER_SUPPORT
14482
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014483 // This is the source string inside the eval which has the call to baz.
14484 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014485 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014486 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014487 checkStackFrame(origin, "", 10, 1, false, false,
14488 stackTrace->GetFrame(3));
14489
14490 CHECK(stackTrace->AsArray()->IsArray());
14491 }
14492 return v8::Undefined();
14493}
14494
14495
14496// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014497// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14498// THREADED_TEST(CaptureStackTrace) {
14499TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014500 v8::HandleScope scope;
14501 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14502 Local<ObjectTemplate> templ = ObjectTemplate::New();
14503 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14504 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14505 LocalContext context(0, templ);
14506
14507 // Test getting OVERVIEW information. Should ignore information that is not
14508 // script name, function name, line number, and column offset.
14509 const char *overview_source =
14510 "function bar() {\n"
14511 " var y; AnalyzeStackInNativeCode(1);\n"
14512 "}\n"
14513 "function foo() {\n"
14514 "\n"
14515 " bar();\n"
14516 "}\n"
14517 "var x;eval('new foo();');";
14518 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014519 v8::Handle<Value> overview_result(
14520 v8::Script::New(overview_src, origin)->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014521 CHECK(!overview_result.IsEmpty());
14522 CHECK(overview_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014523
14524 // Test getting DETAILED information.
14525 const char *detailed_source =
14526 "function bat() {AnalyzeStackInNativeCode(2);\n"
14527 "}\n"
14528 "\n"
14529 "function baz() {\n"
14530 " bat();\n"
14531 "}\n"
14532 "eval('new baz();');";
14533 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14534 // Make the script using a non-zero line and column offset.
14535 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14536 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14537 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14538 v8::Handle<v8::Script> detailed_script(
14539 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014540 v8::Handle<Value> detailed_result(detailed_script->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014541 CHECK(!detailed_result.IsEmpty());
14542 CHECK(detailed_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014543}
14544
14545
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014546static void StackTraceForUncaughtExceptionListener(
14547 v8::Handle<v8::Message> message,
14548 v8::Handle<Value>) {
14549 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14550 CHECK_EQ(2, stack_trace->GetFrameCount());
14551 checkStackFrame("origin", "foo", 2, 3, false, false,
14552 stack_trace->GetFrame(0));
14553 checkStackFrame("origin", "bar", 5, 3, false, false,
14554 stack_trace->GetFrame(1));
14555}
14556
14557TEST(CaptureStackTraceForUncaughtException) {
14558 report_count = 0;
14559 v8::HandleScope scope;
14560 LocalContext env;
14561 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14562 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14563
14564 Script::Compile(v8_str("function foo() {\n"
14565 " throw 1;\n"
14566 "};\n"
14567 "function bar() {\n"
14568 " foo();\n"
14569 "};"),
14570 v8_str("origin"))->Run();
14571 v8::Local<v8::Object> global = env->Global();
14572 Local<Value> trouble = global->Get(v8_str("bar"));
14573 CHECK(trouble->IsFunction());
14574 Function::Cast(*trouble)->Call(global, 0, NULL);
14575 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14576 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14577}
14578
14579
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014580TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14581 v8::HandleScope scope;
14582 LocalContext env;
14583 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14584 1024,
14585 v8::StackTrace::kDetailed);
14586
14587 CompileRun(
14588 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14589 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14590 " 'isConstructor'];\n"
14591 "for (var i = 0; i < setters.length; i++) {\n"
14592 " var prop = setters[i];\n"
14593 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14594 "}\n");
14595 CompileRun("throw 'exception';");
14596 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14597}
14598
14599
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014600static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14601 v8::Handle<v8::Value> data) {
14602 // Use the frame where JavaScript is called from.
14603 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14604 CHECK(!stack_trace.IsEmpty());
14605 int frame_count = stack_trace->GetFrameCount();
14606 CHECK_EQ(3, frame_count);
14607 int line_number[] = {1, 2, 5};
14608 for (int i = 0; i < frame_count; i++) {
14609 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14610 }
14611}
14612
14613
14614// Test that we only return the stack trace at the site where the exception
14615// is first thrown (not where it is rethrown).
14616TEST(RethrowStackTrace) {
14617 v8::HandleScope scope;
14618 LocalContext env;
14619 // We make sure that
14620 // - the stack trace of the ReferenceError in g() is reported.
14621 // - the stack trace is not overwritten when e1 is rethrown by t().
14622 // - the stack trace of e2 does not overwrite that of e1.
14623 const char* source =
14624 "function g() { error; } \n"
14625 "function f() { g(); } \n"
14626 "function t(e) { throw e; } \n"
14627 "try { \n"
14628 " f(); \n"
14629 "} catch (e1) { \n"
14630 " try { \n"
14631 " error; \n"
14632 " } catch (e2) { \n"
14633 " t(e1); \n"
14634 " } \n"
14635 "} \n";
14636 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14637 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14638 CompileRun(source);
14639 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14640 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14641}
14642
14643
14644static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14645 v8::Handle<v8::Value> data) {
14646 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14647 CHECK(!stack_trace.IsEmpty());
14648 int frame_count = stack_trace->GetFrameCount();
14649 CHECK_EQ(2, frame_count);
14650 int line_number[] = {3, 7};
14651 for (int i = 0; i < frame_count; i++) {
14652 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14653 }
14654}
14655
14656
14657// Test that we do not recognize identity for primitive exceptions.
14658TEST(RethrowPrimitiveStackTrace) {
14659 v8::HandleScope scope;
14660 LocalContext env;
14661 // We do not capture stack trace for non Error objects on creation time.
14662 // Instead, we capture the stack trace on last throw.
14663 const char* source =
14664 "function g() { throw 404; } \n"
14665 "function f() { g(); } \n"
14666 "function t(e) { throw e; } \n"
14667 "try { \n"
14668 " f(); \n"
14669 "} catch (e1) { \n"
14670 " t(e1) \n"
14671 "} \n";
14672 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14673 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14674 CompileRun(source);
14675 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14676 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14677}
14678
14679
14680static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14681 v8::Handle<v8::Value> data) {
14682 // Use the frame where JavaScript is called from.
14683 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14684 CHECK(!stack_trace.IsEmpty());
14685 CHECK_EQ(1, stack_trace->GetFrameCount());
14686 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14687}
14688
14689
14690// Test that the stack trace is captured when the error object is created and
14691// not where it is thrown.
14692TEST(RethrowExistingStackTrace) {
14693 v8::HandleScope scope;
14694 LocalContext env;
14695 const char* source =
14696 "var e = new Error(); \n"
14697 "throw e; \n";
14698 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14699 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14700 CompileRun(source);
14701 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14702 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14703}
14704
14705
14706static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14707 v8::Handle<v8::Value> data) {
14708 // Use the frame where JavaScript is called from.
14709 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14710 CHECK(!stack_trace.IsEmpty());
14711 CHECK_EQ(1, stack_trace->GetFrameCount());
14712 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14713}
14714
14715
14716// Test that the stack trace is captured where the bogus Error object is thrown.
14717TEST(RethrowBogusErrorStackTrace) {
14718 v8::HandleScope scope;
14719 LocalContext env;
14720 const char* source =
14721 "var e = {__proto__: new Error()} \n"
14722 "throw e; \n";
14723 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14724 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14725 CompileRun(source);
14726 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14727 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14728}
14729
14730
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014731v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
14732 v8::HandleScope scope;
14733 v8::Handle<v8::StackTrace> stackTrace =
14734 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14735 CHECK_EQ(5, stackTrace->GetFrameCount());
14736 v8::Handle<v8::String> url = v8_str("eval_url");
14737 for (int i = 0; i < 3; i++) {
14738 v8::Handle<v8::String> name =
14739 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14740 CHECK(!name.IsEmpty());
14741 CHECK_EQ(url, name);
14742 }
14743 return v8::Undefined();
14744}
14745
14746
14747TEST(SourceURLInStackTrace) {
14748 v8::HandleScope scope;
14749 Local<ObjectTemplate> templ = ObjectTemplate::New();
14750 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14751 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14752 LocalContext context(0, templ);
14753
14754 const char *source =
14755 "function outer() {\n"
14756 "function bar() {\n"
14757 " AnalyzeStackOfEvalWithSourceURL();\n"
14758 "}\n"
14759 "function foo() {\n"
14760 "\n"
14761 " bar();\n"
14762 "}\n"
14763 "foo();\n"
14764 "}\n"
14765 "eval('(' + outer +')()//@ sourceURL=eval_url');";
14766 CHECK(CompileRun(source)->IsUndefined());
14767}
14768
14769
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000014770v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
14771 const v8::Arguments& args) {
14772 v8::HandleScope scope;
14773 v8::Handle<v8::StackTrace> stackTrace =
14774 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14775 CHECK_EQ(4, stackTrace->GetFrameCount());
14776 v8::Handle<v8::String> url = v8_str("url");
14777 for (int i = 0; i < 3; i++) {
14778 v8::Handle<v8::String> name =
14779 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14780 CHECK(!name.IsEmpty());
14781 CHECK_EQ(url, name);
14782 }
14783 return v8::Undefined();
14784}
14785
14786
14787TEST(InlineScriptWithSourceURLInStackTrace) {
14788 v8::HandleScope scope;
14789 Local<ObjectTemplate> templ = ObjectTemplate::New();
14790 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14791 v8::FunctionTemplate::New(
14792 AnalyzeStackOfInlineScriptWithSourceURL));
14793 LocalContext context(0, templ);
14794
14795 const char *source =
14796 "function outer() {\n"
14797 "function bar() {\n"
14798 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14799 "}\n"
14800 "function foo() {\n"
14801 "\n"
14802 " bar();\n"
14803 "}\n"
14804 "foo();\n"
14805 "}\n"
14806 "outer()\n"
14807 "//@ sourceURL=source_url";
14808 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14809}
14810
14811
14812v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
14813 const v8::Arguments& args) {
14814 v8::HandleScope scope;
14815 v8::Handle<v8::StackTrace> stackTrace =
14816 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14817 CHECK_EQ(4, stackTrace->GetFrameCount());
14818 v8::Handle<v8::String> url = v8_str("source_url");
14819 for (int i = 0; i < 3; i++) {
14820 v8::Handle<v8::String> name =
14821 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14822 CHECK(!name.IsEmpty());
14823 CHECK_EQ(url, name);
14824 }
14825 return v8::Undefined();
14826}
14827
14828
14829TEST(DynamicWithSourceURLInStackTrace) {
14830 v8::HandleScope scope;
14831 Local<ObjectTemplate> templ = ObjectTemplate::New();
14832 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14833 v8::FunctionTemplate::New(
14834 AnalyzeStackOfDynamicScriptWithSourceURL));
14835 LocalContext context(0, templ);
14836
14837 const char *source =
14838 "function outer() {\n"
14839 "function bar() {\n"
14840 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14841 "}\n"
14842 "function foo() {\n"
14843 "\n"
14844 " bar();\n"
14845 "}\n"
14846 "foo();\n"
14847 "}\n"
14848 "outer()\n"
14849 "//@ sourceURL=source_url";
14850 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14851}
14852
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014853static void CreateGarbageInOldSpace() {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014854 v8::HandleScope scope;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014855 i::AlwaysAllocateScope always_allocate;
14856 for (int i = 0; i < 1000; i++) {
14857 FACTORY->NewFixedArray(1000, i::TENURED);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014858 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014859}
14860
14861// Test that idle notification can be handled and eventually returns true.
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014862TEST(IdleNotification) {
14863 const intptr_t MB = 1024 * 1024;
14864 v8::HandleScope scope;
14865 LocalContext env;
14866 intptr_t initial_size = HEAP->SizeOfObjects();
14867 CreateGarbageInOldSpace();
14868 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14869 CHECK_GT(size_with_garbage, initial_size + MB);
14870 bool finished = false;
14871 for (int i = 0; i < 200 && !finished; i++) {
14872 finished = v8::V8::IdleNotification();
14873 }
14874 intptr_t final_size = HEAP->SizeOfObjects();
14875 CHECK(finished);
14876 CHECK_LT(final_size, initial_size + 1);
14877}
14878
14879
14880// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014881TEST(IdleNotificationWithSmallHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014882 const intptr_t MB = 1024 * 1024;
14883 const int IdlePauseInMs = 900;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014884 v8::HandleScope scope;
14885 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014886 intptr_t initial_size = HEAP->SizeOfObjects();
14887 CreateGarbageInOldSpace();
14888 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14889 CHECK_GT(size_with_garbage, initial_size + MB);
14890 bool finished = false;
14891 for (int i = 0; i < 200 && !finished; i++) {
14892 finished = v8::V8::IdleNotification(IdlePauseInMs);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014893 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014894 intptr_t final_size = HEAP->SizeOfObjects();
14895 CHECK(finished);
14896 CHECK_LT(final_size, initial_size + 1);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014897}
14898
14899
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014900// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014901TEST(IdleNotificationWithLargeHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014902 const intptr_t MB = 1024 * 1024;
14903 const int IdlePauseInMs = 900;
yangguo@chromium.org56454712012-02-16 15:33:53 +000014904 v8::HandleScope scope;
14905 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014906 intptr_t initial_size = HEAP->SizeOfObjects();
14907 CreateGarbageInOldSpace();
14908 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14909 CHECK_GT(size_with_garbage, initial_size + MB);
14910 bool finished = false;
14911 for (int i = 0; i < 200 && !finished; i++) {
14912 finished = v8::V8::IdleNotification(IdlePauseInMs);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014913 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014914 intptr_t final_size = HEAP->SizeOfObjects();
14915 CHECK(finished);
14916 CHECK_LT(final_size, initial_size + 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014917}
14918
14919
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014920TEST(Regress2107) {
14921 const intptr_t MB = 1024 * 1024;
14922 const int kShortIdlePauseInMs = 100;
14923 const int kLongIdlePauseInMs = 1000;
14924 v8::HandleScope scope;
14925 LocalContext env;
14926 intptr_t initial_size = HEAP->SizeOfObjects();
14927 // Send idle notification to start a round of incremental GCs.
14928 v8::V8::IdleNotification(kShortIdlePauseInMs);
14929 // Emulate 7 page reloads.
14930 for (int i = 0; i < 7; i++) {
14931 v8::Persistent<v8::Context> ctx = v8::Context::New();
14932 ctx->Enter();
14933 CreateGarbageInOldSpace();
14934 ctx->Exit();
14935 ctx.Dispose();
14936 v8::V8::ContextDisposedNotification();
14937 v8::V8::IdleNotification(kLongIdlePauseInMs);
14938 }
14939 // Create garbage and check that idle notification still collects it.
14940 CreateGarbageInOldSpace();
14941 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14942 CHECK_GT(size_with_garbage, initial_size + MB);
14943 bool finished = false;
14944 for (int i = 0; i < 200 && !finished; i++) {
14945 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14946 }
14947 intptr_t final_size = HEAP->SizeOfObjects();
14948 CHECK_LT(final_size, initial_size + 1);
14949}
14950
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014951static uint32_t* stack_limit;
14952
14953static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014954 stack_limit = reinterpret_cast<uint32_t*>(
14955 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014956 return v8::Undefined();
14957}
14958
14959
14960// Uses the address of a local variable to determine the stack top now.
14961// Given a size, returns an address that is that far from the current
14962// top of stack.
14963static uint32_t* ComputeStackLimit(uint32_t size) {
14964 uint32_t* answer = &size - (size / sizeof(size));
14965 // If the size is very large and the stack is very near the bottom of
14966 // memory then the calculation above may wrap around and give an address
14967 // that is above the (downwards-growing) stack. In that case we return
14968 // a very low address.
14969 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14970 return answer;
14971}
14972
14973
14974TEST(SetResourceConstraints) {
14975 static const int K = 1024;
14976 uint32_t* set_limit = ComputeStackLimit(128 * K);
14977
14978 // Set stack limit.
14979 v8::ResourceConstraints constraints;
14980 constraints.set_stack_limit(set_limit);
14981 CHECK(v8::SetResourceConstraints(&constraints));
14982
14983 // Execute a script.
14984 v8::HandleScope scope;
14985 LocalContext env;
14986 Local<v8::FunctionTemplate> fun_templ =
14987 v8::FunctionTemplate::New(GetStackLimitCallback);
14988 Local<Function> fun = fun_templ->GetFunction();
14989 env->Global()->Set(v8_str("get_stack_limit"), fun);
14990 CompileRun("get_stack_limit();");
14991
14992 CHECK(stack_limit == set_limit);
14993}
14994
14995
14996TEST(SetResourceConstraintsInThread) {
14997 uint32_t* set_limit;
14998 {
14999 v8::Locker locker;
15000 static const int K = 1024;
15001 set_limit = ComputeStackLimit(128 * K);
15002
15003 // Set stack limit.
15004 v8::ResourceConstraints constraints;
15005 constraints.set_stack_limit(set_limit);
15006 CHECK(v8::SetResourceConstraints(&constraints));
15007
15008 // Execute a script.
15009 v8::HandleScope scope;
15010 LocalContext env;
15011 Local<v8::FunctionTemplate> fun_templ =
15012 v8::FunctionTemplate::New(GetStackLimitCallback);
15013 Local<Function> fun = fun_templ->GetFunction();
15014 env->Global()->Set(v8_str("get_stack_limit"), fun);
15015 CompileRun("get_stack_limit();");
15016
15017 CHECK(stack_limit == set_limit);
15018 }
15019 {
15020 v8::Locker locker;
15021 CHECK(stack_limit == set_limit);
15022 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000015023}
ager@chromium.org3811b432009-10-28 14:53:37 +000015024
15025
15026THREADED_TEST(GetHeapStatistics) {
15027 v8::HandleScope scope;
15028 LocalContext c1;
15029 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015030 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
15031 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015032 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015033 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15034 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015035}
15036
15037
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015038class VisitorImpl : public v8::ExternalResourceVisitor {
15039 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015040 explicit VisitorImpl(TestResource** resource) {
15041 for (int i = 0; i < 4; i++) {
15042 resource_[i] = resource[i];
15043 found_resource_[i] = false;
15044 }
15045 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015046 virtual ~VisitorImpl() {}
15047 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15048 if (!string->IsExternal()) {
15049 CHECK(string->IsExternalAscii());
15050 return;
15051 }
15052 v8::String::ExternalStringResource* resource =
15053 string->GetExternalStringResource();
15054 CHECK(resource);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015055 for (int i = 0; i < 4; i++) {
15056 if (resource_[i] == resource) {
15057 CHECK(!found_resource_[i]);
15058 found_resource_[i] = true;
15059 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015060 }
15061 }
15062 void CheckVisitedResources() {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015063 for (int i = 0; i < 4; i++) {
15064 CHECK(found_resource_[i]);
15065 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015066 }
15067
15068 private:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015069 v8::String::ExternalStringResource* resource_[4];
15070 bool found_resource_[4];
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015071};
15072
15073TEST(VisitExternalStrings) {
15074 v8::HandleScope scope;
15075 LocalContext env;
15076 const char* string = "Some string";
15077 uint16_t* two_byte_string = AsciiToTwoByteString(string);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015078 TestResource* resource[4];
15079 resource[0] = new TestResource(two_byte_string);
15080 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
15081 resource[1] = new TestResource(two_byte_string);
15082 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015083
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015084 // Externalized symbol.
15085 resource[2] = new TestResource(two_byte_string);
15086 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
15087 CHECK(string2->MakeExternal(resource[2]));
15088
15089 // Symbolized External.
15090 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15091 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
15092 HEAP->CollectAllAvailableGarbage(); // Tenure string.
15093 // Turn into a symbol.
15094 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15095 CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure());
15096 CHECK(string3_i->IsSymbol());
15097
15098 // We need to add usages for string* to avoid warnings in GCC 4.7
15099 CHECK(string0->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015100 CHECK(string1->IsExternal());
15101 CHECK(string2->IsExternal());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015102 CHECK(string3->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015103
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015104 VisitorImpl visitor(resource);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015105 v8::V8::VisitExternalResources(&visitor);
15106 visitor.CheckVisitedResources();
15107}
15108
15109
ager@chromium.org3811b432009-10-28 14:53:37 +000015110static double DoubleFromBits(uint64_t value) {
15111 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015112 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015113 return target;
15114}
15115
15116
15117static uint64_t DoubleToBits(double value) {
15118 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015119 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015120 return target;
15121}
15122
15123
15124static double DoubleToDateTime(double input) {
15125 double date_limit = 864e13;
15126 if (IsNaN(input) || input < -date_limit || input > date_limit) {
15127 return i::OS::nan_value();
15128 }
15129 return (input < 0) ? -(floor(-input)) : floor(input);
15130}
15131
15132// We don't have a consistent way to write 64-bit constants syntactically, so we
15133// split them into two 32-bit constants and combine them programmatically.
15134static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15135 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15136}
15137
15138
15139THREADED_TEST(QuietSignalingNaNs) {
15140 v8::HandleScope scope;
15141 LocalContext context;
15142 v8::TryCatch try_catch;
15143
15144 // Special double values.
15145 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15146 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15147 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15148 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15149 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15150 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15151 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15152
15153 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15154 // on either side of the epoch.
15155 double date_limit = 864e13;
15156
15157 double test_values[] = {
15158 snan,
15159 qnan,
15160 infinity,
15161 max_normal,
15162 date_limit + 1,
15163 date_limit,
15164 min_normal,
15165 max_denormal,
15166 min_denormal,
15167 0,
15168 -0,
15169 -min_denormal,
15170 -max_denormal,
15171 -min_normal,
15172 -date_limit,
15173 -date_limit - 1,
15174 -max_normal,
15175 -infinity,
15176 -qnan,
15177 -snan
15178 };
15179 int num_test_values = 20;
15180
15181 for (int i = 0; i < num_test_values; i++) {
15182 double test_value = test_values[i];
15183
15184 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15185 v8::Handle<v8::Value> number = v8::Number::New(test_value);
15186 double stored_number = number->NumberValue();
15187 if (!IsNaN(test_value)) {
15188 CHECK_EQ(test_value, stored_number);
15189 } else {
15190 uint64_t stored_bits = DoubleToBits(stored_number);
15191 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015192#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15193 // Most significant fraction bit for quiet nan is set to 0
15194 // on MIPS architecture. Allowed by IEEE-754.
15195 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15196#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015197 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015198#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015199 }
15200
15201 // Check that Date::New preserves non-NaNs in the date range and
15202 // quiets SNaNs.
15203 v8::Handle<v8::Value> date = v8::Date::New(test_value);
15204 double expected_stored_date = DoubleToDateTime(test_value);
15205 double stored_date = date->NumberValue();
15206 if (!IsNaN(expected_stored_date)) {
15207 CHECK_EQ(expected_stored_date, stored_date);
15208 } else {
15209 uint64_t stored_bits = DoubleToBits(stored_date);
15210 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015211#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15212 // Most significant fraction bit for quiet nan is set to 0
15213 // on MIPS architecture. Allowed by IEEE-754.
15214 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15215#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015216 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015217#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015218 }
15219 }
15220}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015221
15222
15223static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
15224 v8::HandleScope scope;
15225 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015226 v8::Handle<v8::String> str(args[0]->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015227 USE(str);
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015228 if (tc.HasCaught())
15229 return tc.ReThrow();
15230 return v8::Undefined();
15231}
15232
15233
15234// Test that an exception can be propagated down through a spaghetti
15235// stack using ReThrow.
15236THREADED_TEST(SpaghettiStackReThrow) {
15237 v8::HandleScope scope;
15238 LocalContext context;
15239 context->Global()->Set(
15240 v8::String::New("s"),
15241 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15242 v8::TryCatch try_catch;
15243 CompileRun(
15244 "var i = 0;"
15245 "var o = {"
15246 " toString: function () {"
15247 " if (i == 10) {"
15248 " throw 'Hey!';"
15249 " } else {"
15250 " i++;"
15251 " return s(o);"
15252 " }"
15253 " }"
15254 "};"
15255 "s(o);");
15256 CHECK(try_catch.HasCaught());
15257 v8::String::Utf8Value value(try_catch.Exception());
15258 CHECK_EQ(0, strcmp(*value, "Hey!"));
15259}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015260
15261
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015262TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015263 v8::V8::Initialize();
15264
15265 v8::HandleScope scope;
15266 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000015267 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015268 int gc_count;
15269
ager@chromium.org60121232009-12-03 11:25:37 +000015270 // Create a context used to keep the code from aging in the compilation
15271 // cache.
15272 other_context = Context::New();
15273
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015274 // Context-dependent context data creates reference from the compilation
15275 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015276 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015277 context = Context::New();
15278 {
15279 v8::HandleScope scope;
15280
15281 context->Enter();
15282 Local<v8::String> obj = v8::String::New("");
15283 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000015284 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015285 context->Exit();
15286 }
15287 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015288 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015289 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015290 other_context->Enter();
15291 CompileRun(source_simple);
15292 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015293 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015294 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015295 }
ager@chromium.org60121232009-12-03 11:25:37 +000015296 CHECK_GE(2, gc_count);
15297 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015298
15299 // Eval in a function creates reference from the compilation cache to the
15300 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015301 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015302 context = Context::New();
15303 {
15304 v8::HandleScope scope;
15305
15306 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000015307 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015308 context->Exit();
15309 }
15310 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015311 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015312 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015313 other_context->Enter();
15314 CompileRun(source_eval);
15315 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015316 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015317 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015318 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000015319 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015320 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015321
15322 // Looking up the line number for an exception creates reference from the
15323 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015324 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015325 context = Context::New();
15326 {
15327 v8::HandleScope scope;
15328
15329 context->Enter();
15330 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000015331 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015332 CHECK(try_catch.HasCaught());
15333 v8::Handle<v8::Message> message = try_catch.Message();
15334 CHECK(!message.IsEmpty());
15335 CHECK_EQ(1, message->GetLineNumber());
15336 context->Exit();
15337 }
15338 context.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000015339 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015340 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015341 other_context->Enter();
15342 CompileRun(source_exception);
15343 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015344 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015345 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015346 }
ager@chromium.org60121232009-12-03 11:25:37 +000015347 CHECK_GE(2, gc_count);
15348 CHECK_EQ(1, GetGlobalObjectsCount());
15349
15350 other_context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015351 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015352}
ager@chromium.org5c838252010-02-19 08:53:10 +000015353
15354
15355THREADED_TEST(ScriptOrigin) {
15356 v8::HandleScope scope;
15357 LocalContext env;
15358 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15359 v8::Handle<v8::String> script = v8::String::New(
15360 "function f() {}\n\nfunction g() {}");
15361 v8::Script::Compile(script, &origin)->Run();
15362 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15363 env->Global()->Get(v8::String::New("f")));
15364 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15365 env->Global()->Get(v8::String::New("g")));
15366
15367 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15368 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15369 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15370
15371 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15372 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15373 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15374}
15375
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015376THREADED_TEST(FunctionGetInferredName) {
15377 v8::HandleScope scope;
15378 LocalContext env;
15379 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15380 v8::Handle<v8::String> script = v8::String::New(
15381 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15382 v8::Script::Compile(script, &origin)->Run();
15383 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15384 env->Global()->Get(v8::String::New("f")));
15385 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15386}
ager@chromium.org5c838252010-02-19 08:53:10 +000015387
15388THREADED_TEST(ScriptLineNumber) {
15389 v8::HandleScope scope;
15390 LocalContext env;
15391 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15392 v8::Handle<v8::String> script = v8::String::New(
15393 "function f() {}\n\nfunction g() {}");
15394 v8::Script::Compile(script, &origin)->Run();
15395 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15396 env->Global()->Get(v8::String::New("f")));
15397 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15398 env->Global()->Get(v8::String::New("g")));
15399 CHECK_EQ(0, f->GetScriptLineNumber());
15400 CHECK_EQ(2, g->GetScriptLineNumber());
15401}
15402
15403
danno@chromium.orgc612e022011-11-10 11:38:15 +000015404THREADED_TEST(ScriptColumnNumber) {
15405 v8::HandleScope scope;
15406 LocalContext env;
15407 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15408 v8::Integer::New(3), v8::Integer::New(2));
15409 v8::Handle<v8::String> script = v8::String::New(
15410 "function foo() {}\n\n function bar() {}");
15411 v8::Script::Compile(script, &origin)->Run();
15412 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15413 env->Global()->Get(v8::String::New("foo")));
15414 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15415 env->Global()->Get(v8::String::New("bar")));
15416 CHECK_EQ(14, foo->GetScriptColumnNumber());
15417 CHECK_EQ(17, bar->GetScriptColumnNumber());
15418}
15419
15420
15421THREADED_TEST(FunctionGetScriptId) {
15422 v8::HandleScope scope;
15423 LocalContext env;
15424 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15425 v8::Integer::New(3), v8::Integer::New(2));
15426 v8::Handle<v8::String> scriptSource = v8::String::New(
15427 "function foo() {}\n\n function bar() {}");
15428 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15429 script->Run();
15430 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15431 env->Global()->Get(v8::String::New("foo")));
15432 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15433 env->Global()->Get(v8::String::New("bar")));
15434 CHECK_EQ(script->Id(), foo->GetScriptId());
15435 CHECK_EQ(script->Id(), bar->GetScriptId());
15436}
15437
15438
ager@chromium.org5c838252010-02-19 08:53:10 +000015439static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15440 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015441 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15442 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015443 return v8_num(42);
15444}
15445
15446
15447static void SetterWhichSetsYOnThisTo23(Local<String> name,
15448 Local<Value> value,
15449 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015450 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15451 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015452 info.This()->Set(v8_str("y"), v8_num(23));
15453}
15454
15455
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015456Handle<Value> FooGetInterceptor(Local<String> name,
15457 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015458 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15459 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015460 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15461 return v8_num(42);
15462}
15463
15464
15465Handle<Value> FooSetInterceptor(Local<String> name,
15466 Local<Value> value,
15467 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015468 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15469 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015470 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15471 info.This()->Set(v8_str("y"), v8_num(23));
15472 return v8_num(23);
15473}
15474
15475
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015476TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015477 v8::HandleScope scope;
15478 Local<ObjectTemplate> templ = ObjectTemplate::New();
15479 templ->SetAccessor(v8_str("x"),
15480 GetterWhichReturns42,
15481 SetterWhichSetsYOnThisTo23);
15482 LocalContext context;
15483 context->Global()->Set(v8_str("P"), templ->NewInstance());
15484 CompileRun("function C1() {"
15485 " this.x = 23;"
15486 "};"
15487 "C1.prototype = P;"
15488 "function C2() {"
15489 " this.x = 23"
15490 "};"
15491 "C2.prototype = { };"
15492 "C2.prototype.__proto__ = P;");
15493
15494 v8::Local<v8::Script> script;
15495 script = v8::Script::Compile(v8_str("new C1();"));
15496 for (int i = 0; i < 10; i++) {
15497 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15498 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15499 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15500 }
15501
15502 script = v8::Script::Compile(v8_str("new C2();"));
15503 for (int i = 0; i < 10; i++) {
15504 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15505 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15506 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15507 }
15508}
15509
15510
15511static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15512 Local<String> name, const AccessorInfo& info) {
15513 return v8_num(42);
15514}
15515
15516
15517static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15518 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15519 if (name->Equals(v8_str("x"))) {
15520 info.This()->Set(v8_str("y"), v8_num(23));
15521 }
15522 return v8::Handle<Value>();
15523}
15524
15525
15526THREADED_TEST(InterceptorOnConstructorPrototype) {
15527 v8::HandleScope scope;
15528 Local<ObjectTemplate> templ = ObjectTemplate::New();
15529 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15530 NamedPropertySetterWhichSetsYOnThisTo23);
15531 LocalContext context;
15532 context->Global()->Set(v8_str("P"), templ->NewInstance());
15533 CompileRun("function C1() {"
15534 " this.x = 23;"
15535 "};"
15536 "C1.prototype = P;"
15537 "function C2() {"
15538 " this.x = 23"
15539 "};"
15540 "C2.prototype = { };"
15541 "C2.prototype.__proto__ = P;");
15542
15543 v8::Local<v8::Script> script;
15544 script = v8::Script::Compile(v8_str("new C1();"));
15545 for (int i = 0; i < 10; i++) {
15546 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15547 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15548 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15549 }
15550
15551 script = v8::Script::Compile(v8_str("new C2();"));
15552 for (int i = 0; i < 10; i++) {
15553 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15554 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15555 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15556 }
15557}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015558
15559
15560TEST(Bug618) {
15561 const char* source = "function C1() {"
15562 " this.x = 23;"
15563 "};"
15564 "C1.prototype = P;";
15565
15566 v8::HandleScope scope;
15567 LocalContext context;
15568 v8::Local<v8::Script> script;
15569
15570 // Use a simple object as prototype.
15571 v8::Local<v8::Object> prototype = v8::Object::New();
15572 prototype->Set(v8_str("y"), v8_num(42));
15573 context->Global()->Set(v8_str("P"), prototype);
15574
15575 // This compile will add the code to the compilation cache.
15576 CompileRun(source);
15577
15578 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015579 // Allow enough iterations for the inobject slack tracking logic
15580 // to finalize instance size and install the fast construct stub.
15581 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015582 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15583 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15584 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15585 }
15586
15587 // Use an API object with accessors as prototype.
15588 Local<ObjectTemplate> templ = ObjectTemplate::New();
15589 templ->SetAccessor(v8_str("x"),
15590 GetterWhichReturns42,
15591 SetterWhichSetsYOnThisTo23);
15592 context->Global()->Set(v8_str("P"), templ->NewInstance());
15593
15594 // This compile will get the code from the compilation cache.
15595 CompileRun(source);
15596
15597 script = v8::Script::Compile(v8_str("new C1();"));
15598 for (int i = 0; i < 10; i++) {
15599 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15600 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15601 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15602 }
15603}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015604
15605int prologue_call_count = 0;
15606int epilogue_call_count = 0;
15607int prologue_call_count_second = 0;
15608int epilogue_call_count_second = 0;
15609
15610void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15611 ++prologue_call_count;
15612}
15613
15614void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15615 ++epilogue_call_count;
15616}
15617
15618void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15619 ++prologue_call_count_second;
15620}
15621
15622void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15623 ++epilogue_call_count_second;
15624}
15625
15626TEST(GCCallbacks) {
15627 LocalContext context;
15628
15629 v8::V8::AddGCPrologueCallback(PrologueCallback);
15630 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15631 CHECK_EQ(0, prologue_call_count);
15632 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015633 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015634 CHECK_EQ(1, prologue_call_count);
15635 CHECK_EQ(1, epilogue_call_count);
15636 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15637 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015638 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015639 CHECK_EQ(2, prologue_call_count);
15640 CHECK_EQ(2, epilogue_call_count);
15641 CHECK_EQ(1, prologue_call_count_second);
15642 CHECK_EQ(1, epilogue_call_count_second);
15643 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15644 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015645 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015646 CHECK_EQ(2, prologue_call_count);
15647 CHECK_EQ(2, epilogue_call_count);
15648 CHECK_EQ(2, prologue_call_count_second);
15649 CHECK_EQ(2, epilogue_call_count_second);
15650 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15651 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015652 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015653 CHECK_EQ(2, prologue_call_count);
15654 CHECK_EQ(2, epilogue_call_count);
15655 CHECK_EQ(2, prologue_call_count_second);
15656 CHECK_EQ(2, epilogue_call_count_second);
15657}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015658
15659
15660THREADED_TEST(AddToJSFunctionResultCache) {
15661 i::FLAG_allow_natives_syntax = true;
15662 v8::HandleScope scope;
15663
15664 LocalContext context;
15665
15666 const char* code =
15667 "(function() {"
15668 " var key0 = 'a';"
15669 " var key1 = 'b';"
15670 " var r0 = %_GetFromCache(0, key0);"
15671 " var r1 = %_GetFromCache(0, key1);"
15672 " var r0_ = %_GetFromCache(0, key0);"
15673 " if (r0 !== r0_)"
15674 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15675 " var r1_ = %_GetFromCache(0, key1);"
15676 " if (r1 !== r1_)"
15677 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15678 " return 'PASSED';"
15679 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015680 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015681 ExpectString(code, "PASSED");
15682}
15683
15684
15685static const int k0CacheSize = 16;
15686
15687THREADED_TEST(FillJSFunctionResultCache) {
15688 i::FLAG_allow_natives_syntax = true;
15689 v8::HandleScope scope;
15690
15691 LocalContext context;
15692
15693 const char* code =
15694 "(function() {"
15695 " var k = 'a';"
15696 " var r = %_GetFromCache(0, k);"
15697 " for (var i = 0; i < 16; i++) {"
15698 " %_GetFromCache(0, 'a' + i);"
15699 " };"
15700 " if (r === %_GetFromCache(0, k))"
15701 " return 'FAILED: k0CacheSize is too small';"
15702 " return 'PASSED';"
15703 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015704 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015705 ExpectString(code, "PASSED");
15706}
15707
15708
15709THREADED_TEST(RoundRobinGetFromCache) {
15710 i::FLAG_allow_natives_syntax = true;
15711 v8::HandleScope scope;
15712
15713 LocalContext context;
15714
15715 const char* code =
15716 "(function() {"
15717 " var keys = [];"
15718 " for (var i = 0; i < 16; i++) keys.push(i);"
15719 " var values = [];"
15720 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15721 " for (var i = 0; i < 16; i++) {"
15722 " var v = %_GetFromCache(0, keys[i]);"
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000015723 " if (v.toString() !== values[i].toString())"
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015724 " return 'Wrong value for ' + "
15725 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15726 " };"
15727 " return 'PASSED';"
15728 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015729 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015730 ExpectString(code, "PASSED");
15731}
15732
15733
15734THREADED_TEST(ReverseGetFromCache) {
15735 i::FLAG_allow_natives_syntax = true;
15736 v8::HandleScope scope;
15737
15738 LocalContext context;
15739
15740 const char* code =
15741 "(function() {"
15742 " var keys = [];"
15743 " for (var i = 0; i < 16; i++) keys.push(i);"
15744 " var values = [];"
15745 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15746 " for (var i = 15; i >= 16; i--) {"
15747 " var v = %_GetFromCache(0, keys[i]);"
15748 " if (v !== values[i])"
15749 " return 'Wrong value for ' + "
15750 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15751 " };"
15752 " return 'PASSED';"
15753 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015754 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015755 ExpectString(code, "PASSED");
15756}
15757
15758
15759THREADED_TEST(TestEviction) {
15760 i::FLAG_allow_natives_syntax = true;
15761 v8::HandleScope scope;
15762
15763 LocalContext context;
15764
15765 const char* code =
15766 "(function() {"
15767 " for (var i = 0; i < 2*16; i++) {"
15768 " %_GetFromCache(0, 'a' + i);"
15769 " };"
15770 " return 'PASSED';"
15771 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015772 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015773 ExpectString(code, "PASSED");
15774}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015775
15776
15777THREADED_TEST(TwoByteStringInAsciiCons) {
15778 // See Chromium issue 47824.
15779 v8::HandleScope scope;
15780
15781 LocalContext context;
15782 const char* init_code =
15783 "var str1 = 'abelspendabel';"
15784 "var str2 = str1 + str1 + str1;"
15785 "str2;";
15786 Local<Value> result = CompileRun(init_code);
15787
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015788 Local<Value> indexof = CompileRun("str2.indexOf('els')");
15789 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15790
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015791 CHECK(result->IsString());
15792 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15793 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015794 CHECK(string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015795
15796 FlattenString(string);
15797 i::Handle<i::String> flat_string = FlattenGetString(string);
15798
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015799 CHECK(string->IsOneByteRepresentation());
15800 CHECK(flat_string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015801
15802 // Create external resource.
15803 uint16_t* uc16_buffer = new uint16_t[length + 1];
15804
15805 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15806 uc16_buffer[length] = 0;
15807
15808 TestResource resource(uc16_buffer);
15809
15810 flat_string->MakeExternal(&resource);
15811
15812 CHECK(flat_string->IsTwoByteRepresentation());
15813
15814 // At this point, we should have a Cons string which is flat and ASCII,
15815 // with a first half that is a two-byte string (although it only contains
15816 // ASCII characters). This is a valid sequence of steps, and it can happen
15817 // in real pages.
15818
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000015819 CHECK(string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015820 i::ConsString* cons = i::ConsString::cast(*string);
15821 CHECK_EQ(0, cons->second()->length());
15822 CHECK(cons->first()->IsTwoByteRepresentation());
15823
15824 // Check that some string operations work.
15825
15826 // Atom RegExp.
15827 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15828 CHECK_EQ(6, reresult->Int32Value());
15829
15830 // Nonatom RegExp.
15831 reresult = CompileRun("str2.match(/abe./g).length;");
15832 CHECK_EQ(6, reresult->Int32Value());
15833
15834 reresult = CompileRun("str2.search(/bel/g);");
15835 CHECK_EQ(1, reresult->Int32Value());
15836
15837 reresult = CompileRun("str2.search(/be./g);");
15838 CHECK_EQ(1, reresult->Int32Value());
15839
15840 ExpectTrue("/bel/g.test(str2);");
15841
15842 ExpectTrue("/be./g.test(str2);");
15843
15844 reresult = CompileRun("/bel/g.exec(str2);");
15845 CHECK(!reresult->IsNull());
15846
15847 reresult = CompileRun("/be./g.exec(str2);");
15848 CHECK(!reresult->IsNull());
15849
15850 ExpectString("str2.substring(2, 10);", "elspenda");
15851
15852 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15853
15854 ExpectString("str2.charAt(2);", "e");
15855
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015856 ExpectObject("str2.indexOf('els');", indexof);
15857
15858 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15859
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015860 reresult = CompileRun("str2.charCodeAt(2);");
15861 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
15862}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015863
15864
15865// Failed access check callback that performs a GC on each invocation.
15866void FailedAccessCheckCallbackGC(Local<v8::Object> target,
15867 v8::AccessType type,
15868 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015869 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015870}
15871
15872
15873TEST(GCInFailedAccessCheckCallback) {
15874 // Install a failed access check callback that performs a GC on each
15875 // invocation. Then force the callback to be called from va
15876
15877 v8::V8::Initialize();
15878 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
15879
15880 v8::HandleScope scope;
15881
15882 // Create an ObjectTemplate for global objects and install access
15883 // check callbacks that will block access.
15884 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
15885 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15886 IndexedGetAccessBlocker,
15887 v8::Handle<v8::Value>(),
15888 false);
15889
15890 // Create a context and set an x property on it's global object.
15891 LocalContext context0(NULL, global_template);
15892 context0->Global()->Set(v8_str("x"), v8_num(42));
15893 v8::Handle<v8::Object> global0 = context0->Global();
15894
15895 // Create a context with a different security token so that the
15896 // failed access check callback will be called on each access.
15897 LocalContext context1(NULL, global_template);
15898 context1->Global()->Set(v8_str("other"), global0);
15899
15900 // Get property with failed access check.
15901 ExpectUndefined("other.x");
15902
15903 // Get element with failed access check.
15904 ExpectUndefined("other[0]");
15905
15906 // Set property with failed access check.
15907 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15908 CHECK(result->IsObject());
15909
15910 // Set element with failed access check.
15911 result = CompileRun("other[0] = new Object()");
15912 CHECK(result->IsObject());
15913
15914 // Get property attribute with failed access check.
15915 ExpectFalse("\'x\' in other");
15916
15917 // Get property attribute for element with failed access check.
15918 ExpectFalse("0 in other");
15919
15920 // Delete property.
15921 ExpectFalse("delete other.x");
15922
15923 // Delete element.
15924 CHECK_EQ(false, global0->Delete(0));
15925
15926 // DefineAccessor.
15927 CHECK_EQ(false,
15928 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15929
15930 // Define JavaScript accessor.
15931 ExpectUndefined("Object.prototype.__defineGetter__.call("
15932 " other, \'x\', function() { return 42; })");
15933
15934 // LookupAccessor.
15935 ExpectUndefined("Object.prototype.__lookupGetter__.call("
15936 " other, \'x\')");
15937
15938 // HasLocalElement.
15939 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15940
15941 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15942 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15943 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15944
15945 // Reset the failed access check callback so it does not influence
15946 // the other tests.
15947 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
15948}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000015949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015950TEST(DefaultIsolateGetCurrent) {
15951 CHECK(v8::Isolate::GetCurrent() != NULL);
15952 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15953 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15954 printf("*** %s\n", "DefaultIsolateGetCurrent success");
15955}
15956
15957TEST(IsolateNewDispose) {
15958 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15959 v8::Isolate* isolate = v8::Isolate::New();
15960 CHECK(isolate != NULL);
15961 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15962 CHECK(current_isolate != isolate);
15963 CHECK(current_isolate == v8::Isolate::GetCurrent());
15964
15965 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15966 last_location = last_message = NULL;
15967 isolate->Dispose();
15968 CHECK_EQ(last_location, NULL);
15969 CHECK_EQ(last_message, NULL);
15970}
15971
15972TEST(IsolateEnterExitDefault) {
15973 v8::HandleScope scope;
15974 LocalContext context;
15975 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15976 CHECK(current_isolate != NULL); // Default isolate.
15977 ExpectString("'hello'", "hello");
15978 current_isolate->Enter();
15979 ExpectString("'still working'", "still working");
15980 current_isolate->Exit();
15981 ExpectString("'still working 2'", "still working 2");
15982 current_isolate->Exit();
15983 // Default isolate is always, well, 'default current'.
15984 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15985 // Still working since default isolate is auto-entering any thread
15986 // that has no isolate and attempts to execute V8 APIs.
15987 ExpectString("'still working 3'", "still working 3");
15988}
15989
15990TEST(DisposeDefaultIsolate) {
15991 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15992
15993 // Run some V8 code to trigger default isolate to become 'current'.
15994 v8::HandleScope scope;
15995 LocalContext context;
15996 ExpectString("'run some V8'", "run some V8");
15997
15998 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15999 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16000 last_location = last_message = NULL;
16001 isolate->Dispose();
16002 // It is not possible to dispose default isolate via Isolate API.
16003 CHECK_NE(last_location, NULL);
16004 CHECK_NE(last_message, NULL);
16005}
16006
16007TEST(RunDefaultAndAnotherIsolate) {
16008 v8::HandleScope scope;
16009 LocalContext context;
16010
16011 // Enter new isolate.
16012 v8::Isolate* isolate = v8::Isolate::New();
16013 CHECK(isolate);
16014 isolate->Enter();
16015 { // Need this block because subsequent Exit() will deallocate Heap,
16016 // so we need all scope objects to be deconstructed when it happens.
16017 v8::HandleScope scope_new;
16018 LocalContext context_new;
16019
16020 // Run something in new isolate.
16021 CompileRun("var foo = 153;");
16022 ExpectTrue("function f() { return foo == 153; }; f()");
16023 }
16024 isolate->Exit();
16025
16026 // This runs automatically in default isolate.
16027 // Variables in another isolate should be not available.
16028 ExpectTrue("function f() {"
16029 " try {"
16030 " foo;"
16031 " return false;"
16032 " } catch(e) {"
16033 " return true;"
16034 " }"
16035 "};"
16036 "var bar = 371;"
16037 "f()");
16038
16039 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16040 last_location = last_message = NULL;
16041 isolate->Dispose();
16042 CHECK_EQ(last_location, NULL);
16043 CHECK_EQ(last_message, NULL);
16044
16045 // Check that default isolate still runs.
16046 ExpectTrue("function f() { return bar == 371; }; f()");
16047}
16048
16049TEST(DisposeIsolateWhenInUse) {
16050 v8::Isolate* isolate = v8::Isolate::New();
16051 CHECK(isolate);
16052 isolate->Enter();
16053 v8::HandleScope scope;
16054 LocalContext context;
16055 // Run something in this isolate.
16056 ExpectTrue("true");
16057 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16058 last_location = last_message = NULL;
16059 // Still entered, should fail.
16060 isolate->Dispose();
16061 CHECK_NE(last_location, NULL);
16062 CHECK_NE(last_message, NULL);
16063}
16064
16065TEST(RunTwoIsolatesOnSingleThread) {
16066 // Run isolate 1.
16067 v8::Isolate* isolate1 = v8::Isolate::New();
16068 isolate1->Enter();
16069 v8::Persistent<v8::Context> context1 = v8::Context::New();
16070
16071 {
16072 v8::Context::Scope cscope(context1);
16073 v8::HandleScope scope;
16074 // Run something in new isolate.
16075 CompileRun("var foo = 'isolate 1';");
16076 ExpectString("function f() { return foo; }; f()", "isolate 1");
16077 }
16078
16079 // Run isolate 2.
16080 v8::Isolate* isolate2 = v8::Isolate::New();
16081 v8::Persistent<v8::Context> context2;
16082
16083 {
16084 v8::Isolate::Scope iscope(isolate2);
16085 context2 = v8::Context::New();
16086 v8::Context::Scope cscope(context2);
16087 v8::HandleScope scope;
16088
16089 // Run something in new isolate.
16090 CompileRun("var foo = 'isolate 2';");
16091 ExpectString("function f() { return foo; }; f()", "isolate 2");
16092 }
16093
16094 {
16095 v8::Context::Scope cscope(context1);
16096 v8::HandleScope scope;
16097 // Now again in isolate 1
16098 ExpectString("function f() { return foo; }; f()", "isolate 1");
16099 }
16100
16101 isolate1->Exit();
16102
16103 // Run some stuff in default isolate.
16104 v8::Persistent<v8::Context> context_default = v8::Context::New();
16105
16106 {
16107 v8::Context::Scope cscope(context_default);
16108 v8::HandleScope scope;
16109 // Variables in other isolates should be not available, verify there
16110 // is an exception.
16111 ExpectTrue("function f() {"
16112 " try {"
16113 " foo;"
16114 " return false;"
16115 " } catch(e) {"
16116 " return true;"
16117 " }"
16118 "};"
16119 "var isDefaultIsolate = true;"
16120 "f()");
16121 }
16122
16123 isolate1->Enter();
16124
16125 {
16126 v8::Isolate::Scope iscope(isolate2);
16127 v8::Context::Scope cscope(context2);
16128 v8::HandleScope scope;
16129 ExpectString("function f() { return foo; }; f()", "isolate 2");
16130 }
16131
16132 {
16133 v8::Context::Scope cscope(context1);
16134 v8::HandleScope scope;
16135 ExpectString("function f() { return foo; }; f()", "isolate 1");
16136 }
16137
16138 {
16139 v8::Isolate::Scope iscope(isolate2);
16140 context2.Dispose();
16141 }
16142
16143 context1.Dispose();
16144 isolate1->Exit();
16145
16146 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16147 last_location = last_message = NULL;
16148
16149 isolate1->Dispose();
16150 CHECK_EQ(last_location, NULL);
16151 CHECK_EQ(last_message, NULL);
16152
16153 isolate2->Dispose();
16154 CHECK_EQ(last_location, NULL);
16155 CHECK_EQ(last_message, NULL);
16156
16157 // Check that default isolate still runs.
16158 {
16159 v8::Context::Scope cscope(context_default);
16160 v8::HandleScope scope;
16161 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
16162 }
16163}
16164
16165static int CalcFibonacci(v8::Isolate* isolate, int limit) {
16166 v8::Isolate::Scope isolate_scope(isolate);
16167 v8::HandleScope scope;
16168 LocalContext context;
16169 i::ScopedVector<char> code(1024);
16170 i::OS::SNPrintF(code, "function fib(n) {"
16171 " if (n <= 2) return 1;"
16172 " return fib(n-1) + fib(n-2);"
16173 "}"
16174 "fib(%d)", limit);
16175 Local<Value> value = CompileRun(code.start());
16176 CHECK(value->IsNumber());
16177 return static_cast<int>(value->NumberValue());
16178}
16179
16180class IsolateThread : public v8::internal::Thread {
16181 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016182 IsolateThread(v8::Isolate* isolate, int fib_limit)
16183 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016184 isolate_(isolate),
16185 fib_limit_(fib_limit),
16186 result_(0) { }
16187
16188 void Run() {
16189 result_ = CalcFibonacci(isolate_, fib_limit_);
16190 }
16191
16192 int result() { return result_; }
16193
16194 private:
16195 v8::Isolate* isolate_;
16196 int fib_limit_;
16197 int result_;
16198};
16199
16200TEST(MultipleIsolatesOnIndividualThreads) {
16201 v8::Isolate* isolate1 = v8::Isolate::New();
16202 v8::Isolate* isolate2 = v8::Isolate::New();
16203
16204 IsolateThread thread1(isolate1, 21);
16205 IsolateThread thread2(isolate2, 12);
16206
16207 // Compute some fibonacci numbers on 3 threads in 3 isolates.
16208 thread1.Start();
16209 thread2.Start();
16210
16211 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
16212 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
16213
16214 thread1.Join();
16215 thread2.Join();
16216
16217 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
16218 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
16219 CHECK_EQ(result1, 10946);
16220 CHECK_EQ(result2, 144);
16221 CHECK_EQ(result1, thread1.result());
16222 CHECK_EQ(result2, thread2.result());
16223
16224 isolate1->Dispose();
16225 isolate2->Dispose();
16226}
16227
lrn@chromium.org1c092762011-05-09 09:42:16 +000016228TEST(IsolateDifferentContexts) {
16229 v8::Isolate* isolate = v8::Isolate::New();
16230 Persistent<v8::Context> context;
16231 {
16232 v8::Isolate::Scope isolate_scope(isolate);
16233 v8::HandleScope handle_scope;
16234 context = v8::Context::New();
16235 v8::Context::Scope context_scope(context);
16236 Local<Value> v = CompileRun("2");
16237 CHECK(v->IsNumber());
16238 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16239 }
16240 {
16241 v8::Isolate::Scope isolate_scope(isolate);
16242 v8::HandleScope handle_scope;
16243 context = v8::Context::New();
16244 v8::Context::Scope context_scope(context);
16245 Local<Value> v = CompileRun("22");
16246 CHECK(v->IsNumber());
16247 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16248 }
16249}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016250
16251class InitDefaultIsolateThread : public v8::internal::Thread {
16252 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016253 enum TestCase {
16254 IgnoreOOM,
16255 SetResourceConstraints,
16256 SetFatalHandler,
16257 SetCounterFunction,
16258 SetCreateHistogramFunction,
16259 SetAddHistogramSampleFunction
16260 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016261
16262 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016263 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016264 testCase_(testCase),
16265 result_(false) { }
16266
16267 void Run() {
16268 switch (testCase_) {
16269 case IgnoreOOM:
16270 v8::V8::IgnoreOutOfMemoryException();
16271 break;
16272
16273 case SetResourceConstraints: {
16274 static const int K = 1024;
16275 v8::ResourceConstraints constraints;
16276 constraints.set_max_young_space_size(256 * K);
16277 constraints.set_max_old_space_size(4 * K * K);
16278 v8::SetResourceConstraints(&constraints);
16279 break;
16280 }
16281
16282 case SetFatalHandler:
16283 v8::V8::SetFatalErrorHandler(NULL);
16284 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016285
16286 case SetCounterFunction:
16287 v8::V8::SetCounterFunction(NULL);
16288 break;
16289
16290 case SetCreateHistogramFunction:
16291 v8::V8::SetCreateHistogramFunction(NULL);
16292 break;
16293
16294 case SetAddHistogramSampleFunction:
16295 v8::V8::SetAddHistogramSampleFunction(NULL);
16296 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016297 }
16298 result_ = true;
16299 }
16300
16301 bool result() { return result_; }
16302
16303 private:
16304 TestCase testCase_;
16305 bool result_;
16306};
16307
16308
16309static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16310 InitDefaultIsolateThread thread(testCase);
16311 thread.Start();
16312 thread.Join();
16313 CHECK_EQ(thread.result(), true);
16314}
16315
16316TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16317 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16318}
16319
16320TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16321 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16322}
16323
16324TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16325 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16326}
16327
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016328TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16329 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16330}
16331
16332TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16333 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16334}
16335
16336TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16337 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16338}
16339
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016340
16341TEST(StringCheckMultipleContexts) {
16342 const char* code =
16343 "(function() { return \"a\".charAt(0); })()";
16344
16345 {
16346 // Run the code twice in the first context to initialize the call IC.
16347 v8::HandleScope scope;
16348 LocalContext context1;
16349 ExpectString(code, "a");
16350 ExpectString(code, "a");
16351 }
16352
16353 {
16354 // Change the String.prototype in the second context and check
16355 // that the right function gets called.
16356 v8::HandleScope scope;
16357 LocalContext context2;
16358 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16359 ExpectString(code, "not a");
16360 }
16361}
16362
16363
16364TEST(NumberCheckMultipleContexts) {
16365 const char* code =
16366 "(function() { return (42).toString(); })()";
16367
16368 {
16369 // Run the code twice in the first context to initialize the call IC.
16370 v8::HandleScope scope;
16371 LocalContext context1;
16372 ExpectString(code, "42");
16373 ExpectString(code, "42");
16374 }
16375
16376 {
16377 // Change the Number.prototype in the second context and check
16378 // that the right function gets called.
16379 v8::HandleScope scope;
16380 LocalContext context2;
16381 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16382 ExpectString(code, "not 42");
16383 }
16384}
16385
16386
16387TEST(BooleanCheckMultipleContexts) {
16388 const char* code =
16389 "(function() { return true.toString(); })()";
16390
16391 {
16392 // Run the code twice in the first context to initialize the call IC.
16393 v8::HandleScope scope;
16394 LocalContext context1;
16395 ExpectString(code, "true");
16396 ExpectString(code, "true");
16397 }
16398
16399 {
16400 // Change the Boolean.prototype in the second context and check
16401 // that the right function gets called.
16402 v8::HandleScope scope;
16403 LocalContext context2;
16404 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16405 ExpectString(code, "");
16406 }
16407}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016408
16409
16410TEST(DontDeleteCellLoadIC) {
16411 const char* function_code =
16412 "function readCell() { while (true) { return cell; } }";
16413
16414 {
16415 // Run the code twice in the first context to initialize the load
16416 // IC for a don't delete cell.
16417 v8::HandleScope scope;
16418 LocalContext context1;
16419 CompileRun("var cell = \"first\";");
16420 ExpectBoolean("delete cell", false);
16421 CompileRun(function_code);
16422 ExpectString("readCell()", "first");
16423 ExpectString("readCell()", "first");
16424 }
16425
16426 {
16427 // Use a deletable cell in the second context.
16428 v8::HandleScope scope;
16429 LocalContext context2;
16430 CompileRun("cell = \"second\";");
16431 CompileRun(function_code);
16432 ExpectString("readCell()", "second");
16433 ExpectBoolean("delete cell", true);
16434 ExpectString("(function() {"
16435 " try {"
16436 " return readCell();"
16437 " } catch(e) {"
16438 " return e.toString();"
16439 " }"
16440 "})()",
16441 "ReferenceError: cell is not defined");
16442 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016443 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016444 ExpectString("readCell()", "new_second");
16445 ExpectString("readCell()", "new_second");
16446 }
16447}
16448
16449
16450TEST(DontDeleteCellLoadICForceDelete) {
16451 const char* function_code =
16452 "function readCell() { while (true) { return cell; } }";
16453
16454 // Run the code twice to initialize the load IC for a don't delete
16455 // cell.
16456 v8::HandleScope scope;
16457 LocalContext context;
16458 CompileRun("var cell = \"value\";");
16459 ExpectBoolean("delete cell", false);
16460 CompileRun(function_code);
16461 ExpectString("readCell()", "value");
16462 ExpectString("readCell()", "value");
16463
16464 // Delete the cell using the API and check the inlined code works
16465 // correctly.
16466 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16467 ExpectString("(function() {"
16468 " try {"
16469 " return readCell();"
16470 " } catch(e) {"
16471 " return e.toString();"
16472 " }"
16473 "})()",
16474 "ReferenceError: cell is not defined");
16475}
16476
16477
16478TEST(DontDeleteCellLoadICAPI) {
16479 const char* function_code =
16480 "function readCell() { while (true) { return cell; } }";
16481
16482 // Run the code twice to initialize the load IC for a don't delete
16483 // cell created using the API.
16484 v8::HandleScope scope;
16485 LocalContext context;
16486 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16487 ExpectBoolean("delete cell", false);
16488 CompileRun(function_code);
16489 ExpectString("readCell()", "value");
16490 ExpectString("readCell()", "value");
16491
16492 // Delete the cell using the API and check the inlined code works
16493 // correctly.
16494 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16495 ExpectString("(function() {"
16496 " try {"
16497 " return readCell();"
16498 " } catch(e) {"
16499 " return e.toString();"
16500 " }"
16501 "})()",
16502 "ReferenceError: cell is not defined");
16503}
16504
16505
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016506class Visitor42 : public v8::PersistentHandleVisitor {
16507 public:
16508 explicit Visitor42(v8::Persistent<v8::Object> object)
16509 : counter_(0), object_(object) { }
16510
16511 virtual void VisitPersistentHandle(Persistent<Value> value,
16512 uint16_t class_id) {
16513 if (class_id == 42) {
16514 CHECK(value->IsObject());
16515 v8::Persistent<v8::Object> visited =
16516 v8::Persistent<v8::Object>::Cast(value);
16517 CHECK_EQ(42, visited.WrapperClassId());
16518 CHECK_EQ(object_, visited);
16519 ++counter_;
16520 }
16521 }
16522
16523 int counter_;
16524 v8::Persistent<v8::Object> object_;
16525};
16526
16527
16528TEST(PersistentHandleVisitor) {
16529 v8::HandleScope scope;
16530 LocalContext context;
16531 v8::Persistent<v8::Object> object =
16532 v8::Persistent<v8::Object>::New(v8::Object::New());
16533 CHECK_EQ(0, object.WrapperClassId());
16534 object.SetWrapperClassId(42);
16535 CHECK_EQ(42, object.WrapperClassId());
16536
16537 Visitor42 visitor(object);
16538 v8::V8::VisitHandlesWithClassIds(&visitor);
16539 CHECK_EQ(1, visitor.counter_);
16540
16541 object.Dispose();
16542}
16543
16544
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016545TEST(RegExp) {
16546 v8::HandleScope scope;
16547 LocalContext context;
16548
16549 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16550 CHECK(re->IsRegExp());
16551 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016552 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016553
16554 re = v8::RegExp::New(v8_str("bar"),
16555 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16556 v8::RegExp::kGlobal));
16557 CHECK(re->IsRegExp());
16558 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016559 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16560 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016561
16562 re = v8::RegExp::New(v8_str("baz"),
16563 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16564 v8::RegExp::kMultiline));
16565 CHECK(re->IsRegExp());
16566 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016567 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16568 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016569
16570 re = CompileRun("/quux/").As<v8::RegExp>();
16571 CHECK(re->IsRegExp());
16572 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016573 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016574
16575 re = CompileRun("/quux/gm").As<v8::RegExp>();
16576 CHECK(re->IsRegExp());
16577 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016578 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16579 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016580
16581 // Override the RegExp constructor and check the API constructor
16582 // still works.
16583 CompileRun("RegExp = function() {}");
16584
16585 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16586 CHECK(re->IsRegExp());
16587 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016588 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016589
16590 re = v8::RegExp::New(v8_str("foobarbaz"),
16591 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16592 v8::RegExp::kMultiline));
16593 CHECK(re->IsRegExp());
16594 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016595 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16596 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016597
16598 context->Global()->Set(v8_str("re"), re);
16599 ExpectTrue("re.test('FoobarbaZ')");
16600
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016601 // RegExps are objects on which you can set properties.
16602 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016603 v8::Handle<v8::Value> value(CompileRun("re.property"));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000016604 CHECK_EQ(32, value->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016605
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016606 v8::TryCatch try_catch;
16607 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16608 CHECK(re.IsEmpty());
16609 CHECK(try_catch.HasCaught());
16610 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16611 ExpectTrue("ex instanceof SyntaxError");
16612}
16613
16614
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016615THREADED_TEST(Equals) {
16616 v8::HandleScope handleScope;
16617 LocalContext localContext;
16618
16619 v8::Handle<v8::Object> globalProxy = localContext->Global();
16620 v8::Handle<Value> global = globalProxy->GetPrototype();
16621
16622 CHECK(global->StrictEquals(global));
16623 CHECK(!global->StrictEquals(globalProxy));
16624 CHECK(!globalProxy->StrictEquals(global));
16625 CHECK(globalProxy->StrictEquals(globalProxy));
16626
16627 CHECK(global->Equals(global));
16628 CHECK(!global->Equals(globalProxy));
16629 CHECK(!globalProxy->Equals(global));
16630 CHECK(globalProxy->Equals(globalProxy));
16631}
16632
16633
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016634static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16635 const v8::AccessorInfo& info ) {
16636 return v8_str("42!");
16637}
16638
16639
16640static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16641 v8::Handle<v8::Array> result = v8::Array::New();
16642 result->Set(0, v8_str("universalAnswer"));
16643 return result;
16644}
16645
16646
16647TEST(NamedEnumeratorAndForIn) {
16648 v8::HandleScope handle_scope;
16649 LocalContext context;
16650 v8::Context::Scope context_scope(context.local());
16651
16652 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16653 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16654 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16655 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16656 "var result = []; for (var k in o) result.push(k); result"));
16657 CHECK_EQ(1, result->Length());
16658 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16659}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016660
16661
16662TEST(DefinePropertyPostDetach) {
16663 v8::HandleScope scope;
16664 LocalContext context;
16665 v8::Handle<v8::Object> proxy = context->Global();
16666 v8::Handle<v8::Function> define_property =
16667 CompileRun("(function() {"
16668 " Object.defineProperty("
16669 " this,"
16670 " 1,"
16671 " { configurable: true, enumerable: true, value: 3 });"
16672 "})").As<Function>();
16673 context->DetachGlobal();
16674 define_property->Call(proxy, 0, NULL);
16675}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016676
16677
16678static void InstallContextId(v8::Handle<Context> context, int id) {
16679 Context::Scope scope(context);
16680 CompileRun("Object.prototype").As<Object>()->
16681 Set(v8_str("context_id"), v8::Integer::New(id));
16682}
16683
16684
16685static void CheckContextId(v8::Handle<Object> object, int expected) {
16686 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16687}
16688
16689
16690THREADED_TEST(CreationContext) {
16691 HandleScope handle_scope;
16692 Persistent<Context> context1 = Context::New();
16693 InstallContextId(context1, 1);
16694 Persistent<Context> context2 = Context::New();
16695 InstallContextId(context2, 2);
16696 Persistent<Context> context3 = Context::New();
16697 InstallContextId(context3, 3);
16698
16699 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16700
16701 Local<Object> object1;
16702 Local<Function> func1;
16703 {
16704 Context::Scope scope(context1);
16705 object1 = Object::New();
16706 func1 = tmpl->GetFunction();
16707 }
16708
16709 Local<Object> object2;
16710 Local<Function> func2;
16711 {
16712 Context::Scope scope(context2);
16713 object2 = Object::New();
16714 func2 = tmpl->GetFunction();
16715 }
16716
16717 Local<Object> instance1;
16718 Local<Object> instance2;
16719
16720 {
16721 Context::Scope scope(context3);
16722 instance1 = func1->NewInstance();
16723 instance2 = func2->NewInstance();
16724 }
16725
16726 CHECK(object1->CreationContext() == context1);
16727 CheckContextId(object1, 1);
16728 CHECK(func1->CreationContext() == context1);
16729 CheckContextId(func1, 1);
16730 CHECK(instance1->CreationContext() == context1);
16731 CheckContextId(instance1, 1);
16732 CHECK(object2->CreationContext() == context2);
16733 CheckContextId(object2, 2);
16734 CHECK(func2->CreationContext() == context2);
16735 CheckContextId(func2, 2);
16736 CHECK(instance2->CreationContext() == context2);
16737 CheckContextId(instance2, 2);
16738
16739 {
16740 Context::Scope scope(context1);
16741 CHECK(object1->CreationContext() == context1);
16742 CheckContextId(object1, 1);
16743 CHECK(func1->CreationContext() == context1);
16744 CheckContextId(func1, 1);
16745 CHECK(instance1->CreationContext() == context1);
16746 CheckContextId(instance1, 1);
16747 CHECK(object2->CreationContext() == context2);
16748 CheckContextId(object2, 2);
16749 CHECK(func2->CreationContext() == context2);
16750 CheckContextId(func2, 2);
16751 CHECK(instance2->CreationContext() == context2);
16752 CheckContextId(instance2, 2);
16753 }
16754
16755 {
16756 Context::Scope scope(context2);
16757 CHECK(object1->CreationContext() == context1);
16758 CheckContextId(object1, 1);
16759 CHECK(func1->CreationContext() == context1);
16760 CheckContextId(func1, 1);
16761 CHECK(instance1->CreationContext() == context1);
16762 CheckContextId(instance1, 1);
16763 CHECK(object2->CreationContext() == context2);
16764 CheckContextId(object2, 2);
16765 CHECK(func2->CreationContext() == context2);
16766 CheckContextId(func2, 2);
16767 CHECK(instance2->CreationContext() == context2);
16768 CheckContextId(instance2, 2);
16769 }
16770
16771 context1.Dispose();
16772 context2.Dispose();
16773 context3.Dispose();
16774}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016775
16776
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000016777THREADED_TEST(CreationContextOfJsFunction) {
16778 HandleScope handle_scope;
16779 Persistent<Context> context = Context::New();
16780 InstallContextId(context, 1);
16781
16782 Local<Object> function;
16783 {
16784 Context::Scope scope(context);
16785 function = CompileRun("function foo() {}; foo").As<Object>();
16786 }
16787
16788 CHECK(function->CreationContext() == context);
16789 CheckContextId(function, 1);
16790
16791 context.Dispose();
16792}
16793
16794
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016795Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16796 const AccessorInfo& info) {
16797 if (index == 42) return v8_str("yes");
16798 return Handle<v8::Integer>();
16799}
16800
16801
16802Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16803 const AccessorInfo& info) {
16804 if (property->Equals(v8_str("foo"))) return v8_str("yes");
16805 return Handle<Value>();
16806}
16807
16808
16809Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
16810 uint32_t index, const AccessorInfo& info) {
16811 if (index == 42) return v8_num(1).As<v8::Integer>();
16812 return Handle<v8::Integer>();
16813}
16814
16815
16816Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
16817 Local<String> property, const AccessorInfo& info) {
16818 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
16819 return Handle<v8::Integer>();
16820}
16821
16822
16823Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
16824 Local<String> property, const AccessorInfo& info) {
16825 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
16826 return Handle<v8::Integer>();
16827}
16828
16829
16830Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16831 const AccessorInfo& info) {
16832 return v8_str("yes");
16833}
16834
16835
16836TEST(HasOwnProperty) {
16837 v8::HandleScope scope;
16838 LocalContext env;
16839 { // Check normal properties and defined getters.
16840 Handle<Value> value = CompileRun(
16841 "function Foo() {"
16842 " this.foo = 11;"
16843 " this.__defineGetter__('baz', function() { return 1; });"
16844 "};"
16845 "function Bar() { "
16846 " this.bar = 13;"
16847 " this.__defineGetter__('bla', function() { return 2; });"
16848 "};"
16849 "Bar.prototype = new Foo();"
16850 "new Bar();");
16851 CHECK(value->IsObject());
16852 Handle<Object> object = value->ToObject();
16853 CHECK(object->Has(v8_str("foo")));
16854 CHECK(!object->HasOwnProperty(v8_str("foo")));
16855 CHECK(object->HasOwnProperty(v8_str("bar")));
16856 CHECK(object->Has(v8_str("baz")));
16857 CHECK(!object->HasOwnProperty(v8_str("baz")));
16858 CHECK(object->HasOwnProperty(v8_str("bla")));
16859 }
16860 { // Check named getter interceptors.
16861 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16862 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
16863 Handle<Object> instance = templ->NewInstance();
16864 CHECK(!instance->HasOwnProperty(v8_str("42")));
16865 CHECK(instance->HasOwnProperty(v8_str("foo")));
16866 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16867 }
16868 { // Check indexed getter interceptors.
16869 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16870 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
16871 Handle<Object> instance = templ->NewInstance();
16872 CHECK(instance->HasOwnProperty(v8_str("42")));
16873 CHECK(!instance->HasOwnProperty(v8_str("43")));
16874 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16875 }
16876 { // Check named query interceptors.
16877 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16878 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
16879 Handle<Object> instance = templ->NewInstance();
16880 CHECK(instance->HasOwnProperty(v8_str("foo")));
16881 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16882 }
16883 { // Check indexed query interceptors.
16884 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16885 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
16886 Handle<Object> instance = templ->NewInstance();
16887 CHECK(instance->HasOwnProperty(v8_str("42")));
16888 CHECK(!instance->HasOwnProperty(v8_str("41")));
16889 }
16890 { // Check callbacks.
16891 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16892 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
16893 Handle<Object> instance = templ->NewInstance();
16894 CHECK(instance->HasOwnProperty(v8_str("foo")));
16895 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16896 }
16897 { // Check that query wins on disagreement.
16898 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16899 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16900 0,
16901 HasOwnPropertyNamedPropertyQuery2);
16902 Handle<Object> instance = templ->NewInstance();
16903 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16904 CHECK(instance->HasOwnProperty(v8_str("bar")));
16905 }
16906}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016907
16908
16909void CheckCodeGenerationAllowed() {
16910 Handle<Value> result = CompileRun("eval('42')");
16911 CHECK_EQ(42, result->Int32Value());
16912 result = CompileRun("(function(e) { return e('42'); })(eval)");
16913 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016914 result = CompileRun("var f = new Function('return 42'); f()");
16915 CHECK_EQ(42, result->Int32Value());
16916}
16917
16918
16919void CheckCodeGenerationDisallowed() {
16920 TryCatch try_catch;
16921
16922 Handle<Value> result = CompileRun("eval('42')");
16923 CHECK(result.IsEmpty());
16924 CHECK(try_catch.HasCaught());
16925 try_catch.Reset();
16926
16927 result = CompileRun("(function(e) { return e('42'); })(eval)");
16928 CHECK(result.IsEmpty());
16929 CHECK(try_catch.HasCaught());
16930 try_catch.Reset();
16931
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016932 result = CompileRun("var f = new Function('return 42'); f()");
16933 CHECK(result.IsEmpty());
16934 CHECK(try_catch.HasCaught());
16935}
16936
16937
16938bool CodeGenerationAllowed(Local<Context> context) {
16939 ApiTestFuzzer::Fuzz();
16940 return true;
16941}
16942
16943
16944bool CodeGenerationDisallowed(Local<Context> context) {
16945 ApiTestFuzzer::Fuzz();
16946 return false;
16947}
16948
16949
16950THREADED_TEST(AllowCodeGenFromStrings) {
16951 v8::HandleScope scope;
16952 LocalContext context;
16953
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016954 // eval and the Function constructor allowed by default.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016955 CHECK(context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016956 CheckCodeGenerationAllowed();
16957
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016958 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016959 context->AllowCodeGenerationFromStrings(false);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016960 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016961 CheckCodeGenerationDisallowed();
16962
16963 // Allow again.
16964 context->AllowCodeGenerationFromStrings(true);
16965 CheckCodeGenerationAllowed();
16966
16967 // Disallow but setting a global callback that will allow the calls.
16968 context->AllowCodeGenerationFromStrings(false);
16969 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016970 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016971 CheckCodeGenerationAllowed();
16972
16973 // Set a callback that disallows the code generation.
16974 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016975 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016976 CheckCodeGenerationDisallowed();
16977}
lrn@chromium.org1c092762011-05-09 09:42:16 +000016978
16979
ulan@chromium.org56c14af2012-09-20 12:51:09 +000016980TEST(SetErrorMessageForCodeGenFromStrings) {
16981 v8::HandleScope scope;
16982 LocalContext context;
16983 TryCatch try_catch;
16984
16985 Handle<String> message = v8_str("Message") ;
16986 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
16987 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16988 context->AllowCodeGenerationFromStrings(false);
16989 context->SetErrorMessageForCodeGenerationFromStrings(message);
16990 Handle<Value> result = CompileRun("eval('42')");
16991 CHECK(result.IsEmpty());
16992 CHECK(try_catch.HasCaught());
16993 Handle<String> actual_message = try_catch.Message()->Get();
16994 CHECK(expected_message->Equals(actual_message));
16995}
16996
16997
lrn@chromium.org1c092762011-05-09 09:42:16 +000016998static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16999 return v8::Undefined();
17000}
17001
17002
17003THREADED_TEST(CallAPIFunctionOnNonObject) {
17004 v8::HandleScope scope;
17005 LocalContext context;
17006 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
17007 Handle<Function> function = templ->GetFunction();
17008 context->Global()->Set(v8_str("f"), function);
17009 TryCatch try_catch;
17010 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000017011}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000017012
17013
17014// Regression test for issue 1470.
17015THREADED_TEST(ReadOnlyIndexedProperties) {
17016 v8::HandleScope scope;
17017 Local<ObjectTemplate> templ = ObjectTemplate::New();
17018
17019 LocalContext context;
17020 Local<v8::Object> obj = templ->NewInstance();
17021 context->Global()->Set(v8_str("obj"), obj);
17022 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17023 obj->Set(v8_str("1"), v8_str("foobar"));
17024 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
17025 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
17026 obj->Set(v8_num(2), v8_str("foobar"));
17027 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
17028
17029 // Test non-smi case.
17030 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17031 obj->Set(v8_str("2000000000"), v8_str("foobar"));
17032 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
17033}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017034
17035
17036THREADED_TEST(Regress1516) {
17037 v8::HandleScope scope;
17038
17039 LocalContext context;
17040 { v8::HandleScope temp_scope;
17041 CompileRun("({'a': 0})");
17042 }
17043
17044 int elements;
17045 { i::MapCache* map_cache =
17046 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
17047 elements = map_cache->NumberOfElements();
17048 CHECK_LE(1, elements);
17049 }
17050
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +000017051 i::Isolate::Current()->heap()->CollectAllGarbage(
17052 i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017053 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
17054 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
17055 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
17056 CHECK_GT(elements, map_cache->NumberOfElements());
17057 }
17058 }
17059}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017060
17061
17062static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
17063 Local<Value> name,
17064 v8::AccessType type,
17065 Local<Value> data) {
17066 // Only block read access to __proto__.
17067 if (type == v8::ACCESS_GET &&
17068 name->IsString() &&
17069 name->ToString()->Length() == 9 &&
17070 name->ToString()->Utf8Length() == 9) {
17071 char buffer[10];
17072 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
17073 return strncmp(buffer, "__proto__", 9) != 0;
17074 }
17075
17076 return true;
17077}
17078
17079
17080THREADED_TEST(Regress93759) {
17081 HandleScope scope;
17082
17083 // Template for object with security check.
17084 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
17085 // We don't do indexing, so any callback can be used for that.
17086 no_proto_template->SetAccessCheckCallbacks(
17087 BlockProtoNamedSecurityTestCallback,
17088 IndexedSecurityTestCallback);
17089
17090 // Templates for objects with hidden prototypes and possibly security check.
17091 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
17092 hidden_proto_template->SetHiddenPrototype(true);
17093
17094 Local<FunctionTemplate> protected_hidden_proto_template =
17095 v8::FunctionTemplate::New();
17096 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
17097 BlockProtoNamedSecurityTestCallback,
17098 IndexedSecurityTestCallback);
17099 protected_hidden_proto_template->SetHiddenPrototype(true);
17100
17101 // Context for "foreign" objects used in test.
17102 Persistent<Context> context = v8::Context::New();
17103 context->Enter();
17104
17105 // Plain object, no security check.
17106 Local<Object> simple_object = Object::New();
17107
17108 // Object with explicit security check.
17109 Local<Object> protected_object =
17110 no_proto_template->NewInstance();
17111
17112 // JSGlobalProxy object, always have security check.
17113 Local<Object> proxy_object =
17114 context->Global();
17115
17116 // Global object, the prototype of proxy_object. No security checks.
17117 Local<Object> global_object =
17118 proxy_object->GetPrototype()->ToObject();
17119
17120 // Hidden prototype without security check.
17121 Local<Object> hidden_prototype =
17122 hidden_proto_template->GetFunction()->NewInstance();
17123 Local<Object> object_with_hidden =
17124 Object::New();
17125 object_with_hidden->SetPrototype(hidden_prototype);
17126
17127 // Hidden prototype with security check on the hidden prototype.
17128 Local<Object> protected_hidden_prototype =
17129 protected_hidden_proto_template->GetFunction()->NewInstance();
17130 Local<Object> object_with_protected_hidden =
17131 Object::New();
17132 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
17133
17134 context->Exit();
17135
17136 // Template for object for second context. Values to test are put on it as
17137 // properties.
17138 Local<ObjectTemplate> global_template = ObjectTemplate::New();
17139 global_template->Set(v8_str("simple"), simple_object);
17140 global_template->Set(v8_str("protected"), protected_object);
17141 global_template->Set(v8_str("global"), global_object);
17142 global_template->Set(v8_str("proxy"), proxy_object);
17143 global_template->Set(v8_str("hidden"), object_with_hidden);
17144 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
17145
17146 LocalContext context2(NULL, global_template);
17147
17148 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
17149 CHECK(result1->Equals(simple_object->GetPrototype()));
17150
17151 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
17152 CHECK(result2->Equals(Undefined()));
17153
17154 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
17155 CHECK(result3->Equals(global_object->GetPrototype()));
17156
17157 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
17158 CHECK(result4->Equals(Undefined()));
17159
17160 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
17161 CHECK(result5->Equals(
17162 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
17163
17164 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
17165 CHECK(result6->Equals(Undefined()));
17166
17167 context.Dispose();
17168}
17169
17170
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017171THREADED_TEST(Regress125988) {
17172 v8::HandleScope scope;
17173 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
17174 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
17175 LocalContext env;
17176 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
17177 CompileRun("var a = new Object();"
17178 "var b = new Intercept();"
17179 "var c = new Object();"
17180 "c.__proto__ = b;"
17181 "b.__proto__ = a;"
17182 "a.x = 23;"
17183 "for (var i = 0; i < 3; i++) c.x;");
17184 ExpectBoolean("c.hasOwnProperty('x')", false);
17185 ExpectInt32("c.x", 23);
17186 CompileRun("a.y = 42;"
17187 "for (var i = 0; i < 3; i++) c.x;");
17188 ExpectBoolean("c.hasOwnProperty('x')", false);
17189 ExpectInt32("c.x", 23);
17190 ExpectBoolean("c.hasOwnProperty('y')", false);
17191 ExpectInt32("c.y", 42);
17192}
17193
17194
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017195static void TestReceiver(Local<Value> expected_result,
17196 Local<Value> expected_receiver,
17197 const char* code) {
17198 Local<Value> result = CompileRun(code);
17199 CHECK(result->IsObject());
17200 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
17201 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
17202}
17203
17204
17205THREADED_TEST(ForeignFunctionReceiver) {
17206 HandleScope scope;
17207
17208 // Create two contexts with different "id" properties ('i' and 'o').
17209 // Call a function both from its own context and from a the foreign
17210 // context, and see what "this" is bound to (returning both "this"
17211 // and "this.id" for comparison).
17212
17213 Persistent<Context> foreign_context = v8::Context::New();
17214 foreign_context->Enter();
17215 Local<Value> foreign_function =
17216 CompileRun("function func() { return { 0: this.id, "
17217 " 1: this, "
17218 " toString: function() { "
17219 " return this[0];"
17220 " }"
17221 " };"
17222 "}"
17223 "var id = 'i';"
17224 "func;");
17225 CHECK(foreign_function->IsFunction());
17226 foreign_context->Exit();
17227
17228 LocalContext context;
17229
17230 Local<String> password = v8_str("Password");
17231 // Don't get hit by security checks when accessing foreign_context's
17232 // global receiver (aka. global proxy).
17233 context->SetSecurityToken(password);
17234 foreign_context->SetSecurityToken(password);
17235
17236 Local<String> i = v8_str("i");
17237 Local<String> o = v8_str("o");
17238 Local<String> id = v8_str("id");
17239
17240 CompileRun("function ownfunc() { return { 0: this.id, "
17241 " 1: this, "
17242 " toString: function() { "
17243 " return this[0];"
17244 " }"
17245 " };"
17246 "}"
17247 "var id = 'o';"
17248 "ownfunc");
17249 context->Global()->Set(v8_str("func"), foreign_function);
17250
17251 // Sanity check the contexts.
17252 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17253 CHECK(o->Equals(context->Global()->Get(id)));
17254
17255 // Checking local function's receiver.
17256 // Calling function using its call/apply methods.
17257 TestReceiver(o, context->Global(), "ownfunc.call()");
17258 TestReceiver(o, context->Global(), "ownfunc.apply()");
17259 // Making calls through built-in functions.
17260 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17261 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17262 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17263 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17264 // Calling with environment record as base.
17265 TestReceiver(o, context->Global(), "ownfunc()");
17266 // Calling with no base.
17267 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17268
17269 // Checking foreign function return value.
17270 // Calling function using its call/apply methods.
17271 TestReceiver(i, foreign_context->Global(), "func.call()");
17272 TestReceiver(i, foreign_context->Global(), "func.apply()");
17273 // Calling function using another context's call/apply methods.
17274 TestReceiver(i, foreign_context->Global(),
17275 "Function.prototype.call.call(func)");
17276 TestReceiver(i, foreign_context->Global(),
17277 "Function.prototype.call.apply(func)");
17278 TestReceiver(i, foreign_context->Global(),
17279 "Function.prototype.apply.call(func)");
17280 TestReceiver(i, foreign_context->Global(),
17281 "Function.prototype.apply.apply(func)");
17282 // Making calls through built-in functions.
17283 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17284 // ToString(func()) is func()[0], i.e., the returned this.id.
17285 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17286 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17287 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17288
17289 // TODO(1547): Make the following also return "i".
17290 // Calling with environment record as base.
17291 TestReceiver(o, context->Global(), "func()");
17292 // Calling with no base.
17293 TestReceiver(o, context->Global(), "(1,func)()");
17294
17295 foreign_context.Dispose();
17296}
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017297
17298
17299uint8_t callback_fired = 0;
17300
17301
17302void CallCompletedCallback1() {
17303 i::OS::Print("Firing callback 1.\n");
17304 callback_fired ^= 1; // Toggle first bit.
17305}
17306
17307
17308void CallCompletedCallback2() {
17309 i::OS::Print("Firing callback 2.\n");
17310 callback_fired ^= 2; // Toggle second bit.
17311}
17312
17313
17314Handle<Value> RecursiveCall(const Arguments& args) {
17315 int32_t level = args[0]->Int32Value();
17316 if (level < 3) {
17317 level++;
17318 i::OS::Print("Entering recursion level %d.\n", level);
17319 char script[64];
17320 i::Vector<char> script_vector(script, sizeof(script));
17321 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17322 CompileRun(script_vector.start());
17323 i::OS::Print("Leaving recursion level %d.\n", level);
17324 CHECK_EQ(0, callback_fired);
17325 } else {
17326 i::OS::Print("Recursion ends.\n");
17327 CHECK_EQ(0, callback_fired);
17328 }
17329 return Undefined();
17330}
17331
17332
17333TEST(CallCompletedCallback) {
17334 v8::HandleScope scope;
17335 LocalContext env;
17336 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17337 v8::FunctionTemplate::New(RecursiveCall);
17338 env->Global()->Set(v8_str("recursion"),
17339 recursive_runtime->GetFunction());
17340 // Adding the same callback a second time has no effect.
17341 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17342 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17343 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17344 i::OS::Print("--- Script (1) ---\n");
17345 Local<Script> script =
17346 v8::Script::Compile(v8::String::New("recursion(0)"));
17347 script->Run();
17348 CHECK_EQ(3, callback_fired);
17349
17350 i::OS::Print("\n--- Script (2) ---\n");
17351 callback_fired = 0;
17352 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17353 script->Run();
17354 CHECK_EQ(2, callback_fired);
17355
17356 i::OS::Print("\n--- Function ---\n");
17357 callback_fired = 0;
17358 Local<Function> recursive_function =
17359 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17360 v8::Handle<Value> args[] = { v8_num(0) };
17361 recursive_function->Call(env->Global(), 1, args);
17362 CHECK_EQ(2, callback_fired);
17363}
17364
17365
17366void CallCompletedCallbackNoException() {
17367 v8::HandleScope scope;
17368 CompileRun("1+1;");
17369}
17370
17371
17372void CallCompletedCallbackException() {
17373 v8::HandleScope scope;
17374 CompileRun("throw 'second exception';");
17375}
17376
17377
17378TEST(CallCompletedCallbackOneException) {
17379 v8::HandleScope scope;
17380 LocalContext env;
17381 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17382 CompileRun("throw 'exception';");
17383}
17384
17385
17386TEST(CallCompletedCallbackTwoExceptions) {
17387 v8::HandleScope scope;
17388 LocalContext env;
17389 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17390 CompileRun("throw 'first exception';");
17391}
ulan@chromium.org812308e2012-02-29 15:58:45 +000017392
17393
17394static int probes_counter = 0;
17395static int misses_counter = 0;
17396static int updates_counter = 0;
17397
17398
17399static int* LookupCounter(const char* name) {
17400 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17401 return &probes_counter;
17402 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17403 return &misses_counter;
17404 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17405 return &updates_counter;
17406 }
17407 return NULL;
17408}
17409
17410
17411static const char* kMegamorphicTestProgram =
17412 "function ClassA() { };"
17413 "function ClassB() { };"
17414 "ClassA.prototype.foo = function() { };"
17415 "ClassB.prototype.foo = function() { };"
17416 "function fooify(obj) { obj.foo(); };"
17417 "var a = new ClassA();"
17418 "var b = new ClassB();"
17419 "for (var i = 0; i < 10000; i++) {"
17420 " fooify(a);"
17421 " fooify(b);"
17422 "}";
17423
17424
17425static void StubCacheHelper(bool primary) {
17426 V8::SetCounterFunction(LookupCounter);
17427 USE(kMegamorphicTestProgram);
17428#ifdef DEBUG
17429 i::FLAG_native_code_counters = true;
17430 if (primary) {
17431 i::FLAG_test_primary_stub_cache = true;
17432 } else {
17433 i::FLAG_test_secondary_stub_cache = true;
17434 }
17435 i::FLAG_crankshaft = false;
17436 v8::HandleScope scope;
17437 LocalContext env;
17438 int initial_probes = probes_counter;
17439 int initial_misses = misses_counter;
17440 int initial_updates = updates_counter;
17441 CompileRun(kMegamorphicTestProgram);
17442 int probes = probes_counter - initial_probes;
17443 int misses = misses_counter - initial_misses;
17444 int updates = updates_counter - initial_updates;
17445 CHECK_LT(updates, 10);
17446 CHECK_LT(misses, 10);
17447 CHECK_GE(probes, 10000);
17448#endif
17449}
17450
17451
17452TEST(SecondaryStubCache) {
17453 StubCacheHelper(true);
17454}
17455
17456
17457TEST(PrimaryStubCache) {
17458 StubCacheHelper(false);
17459}
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017460
17461
17462static int fatal_error_callback_counter = 0;
17463static void CountingErrorCallback(const char* location, const char* message) {
17464 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17465 fatal_error_callback_counter++;
17466}
17467
17468
17469TEST(StaticGetters) {
17470 v8::HandleScope scope;
17471 LocalContext context;
17472 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17473 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17474 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17475 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17476 i::Handle<i::Object> null_value = FACTORY->null_value();
17477 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17478 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17479 i::Handle<i::Object> true_value = FACTORY->true_value();
17480 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17481 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17482 i::Handle<i::Object> false_value = FACTORY->false_value();
17483 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17484 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17485
17486 // Test after-death behavior.
17487 CHECK(i::Internals::IsInitialized(isolate));
17488 CHECK_EQ(0, fatal_error_callback_counter);
17489 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17490 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17491 i::Isolate::Current()->TearDown();
17492 CHECK(!i::Internals::IsInitialized(isolate));
17493 CHECK_EQ(1, fatal_error_callback_counter);
17494 CHECK(v8::Undefined().IsEmpty());
17495 CHECK_EQ(2, fatal_error_callback_counter);
17496 CHECK(v8::Undefined(isolate).IsEmpty());
17497 CHECK_EQ(3, fatal_error_callback_counter);
17498 CHECK(v8::Null().IsEmpty());
17499 CHECK_EQ(4, fatal_error_callback_counter);
17500 CHECK(v8::Null(isolate).IsEmpty());
17501 CHECK_EQ(5, fatal_error_callback_counter);
17502 CHECK(v8::True().IsEmpty());
17503 CHECK_EQ(6, fatal_error_callback_counter);
17504 CHECK(v8::True(isolate).IsEmpty());
17505 CHECK_EQ(7, fatal_error_callback_counter);
17506 CHECK(v8::False().IsEmpty());
17507 CHECK_EQ(8, fatal_error_callback_counter);
17508 CHECK(v8::False(isolate).IsEmpty());
17509 CHECK_EQ(9, fatal_error_callback_counter);
17510}
17511
17512
17513TEST(IsolateEmbedderData) {
17514 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17515 CHECK_EQ(NULL, isolate->GetData());
17516 CHECK_EQ(NULL, ISOLATE->GetData());
17517 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17518 isolate->SetData(data1);
17519 CHECK_EQ(data1, isolate->GetData());
17520 CHECK_EQ(data1, ISOLATE->GetData());
17521 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17522 ISOLATE->SetData(data2);
17523 CHECK_EQ(data2, isolate->GetData());
17524 CHECK_EQ(data2, ISOLATE->GetData());
17525 ISOLATE->TearDown();
17526 CHECK_EQ(data2, isolate->GetData());
17527 CHECK_EQ(data2, ISOLATE->GetData());
17528}
17529
17530
17531TEST(StringEmpty) {
17532 v8::HandleScope scope;
17533 LocalContext context;
17534 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17535 i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17536 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17537 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17538
17539 // Test after-death behavior.
17540 CHECK(i::Internals::IsInitialized(isolate));
17541 CHECK_EQ(0, fatal_error_callback_counter);
17542 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17543 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17544 i::Isolate::Current()->TearDown();
17545 CHECK(!i::Internals::IsInitialized(isolate));
17546 CHECK_EQ(1, fatal_error_callback_counter);
17547 CHECK(v8::String::Empty().IsEmpty());
17548 CHECK_EQ(2, fatal_error_callback_counter);
17549 CHECK(v8::String::Empty(isolate).IsEmpty());
17550 CHECK_EQ(3, fatal_error_callback_counter);
17551}
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017552
17553
17554static int instance_checked_getter_count = 0;
17555static Handle<Value> InstanceCheckedGetter(Local<String> name,
17556 const AccessorInfo& info) {
17557 CHECK_EQ(name, v8_str("foo"));
17558 instance_checked_getter_count++;
17559 return v8_num(11);
17560}
17561
17562
17563static int instance_checked_setter_count = 0;
17564static void InstanceCheckedSetter(Local<String> name,
17565 Local<Value> value,
17566 const AccessorInfo& info) {
17567 CHECK_EQ(name, v8_str("foo"));
17568 CHECK_EQ(value, v8_num(23));
17569 instance_checked_setter_count++;
17570}
17571
17572
17573static void CheckInstanceCheckedResult(int getters,
17574 int setters,
17575 bool expects_callbacks,
17576 TryCatch* try_catch) {
17577 if (expects_callbacks) {
17578 CHECK(!try_catch->HasCaught());
17579 CHECK_EQ(getters, instance_checked_getter_count);
17580 CHECK_EQ(setters, instance_checked_setter_count);
17581 } else {
17582 CHECK(try_catch->HasCaught());
17583 CHECK_EQ(0, instance_checked_getter_count);
17584 CHECK_EQ(0, instance_checked_setter_count);
17585 }
17586 try_catch->Reset();
17587}
17588
17589
17590static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17591 instance_checked_getter_count = 0;
17592 instance_checked_setter_count = 0;
17593 TryCatch try_catch;
17594
17595 // Test path through generic runtime code.
17596 CompileRun("obj.foo");
17597 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17598 CompileRun("obj.foo = 23");
17599 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17600
17601 // Test path through generated LoadIC and StoredIC.
17602 CompileRun("function test_get(o) { o.foo; }"
17603 "test_get(obj);");
17604 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17605 CompileRun("test_get(obj);");
17606 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17607 CompileRun("test_get(obj);");
17608 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17609 CompileRun("function test_set(o) { o.foo = 23; }"
17610 "test_set(obj);");
17611 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17612 CompileRun("test_set(obj);");
17613 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17614 CompileRun("test_set(obj);");
17615 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17616
17617 // Test path through optimized code.
17618 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17619 "test_get(obj);");
17620 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17621 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17622 "test_set(obj);");
17623 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17624
17625 // Cleanup so that closures start out fresh in next check.
17626 CompileRun("%DeoptimizeFunction(test_get);"
17627 "%ClearFunctionTypeFeedback(test_get);"
17628 "%DeoptimizeFunction(test_set);"
17629 "%ClearFunctionTypeFeedback(test_set);");
17630}
17631
17632
17633THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17634 v8::internal::FLAG_allow_natives_syntax = true;
17635 v8::HandleScope scope;
17636 LocalContext context;
17637
17638 Local<FunctionTemplate> templ = FunctionTemplate::New();
17639 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17640 inst->SetAccessor(v8_str("foo"),
17641 InstanceCheckedGetter, InstanceCheckedSetter,
17642 Handle<Value>(),
17643 v8::DEFAULT,
17644 v8::None,
17645 v8::AccessorSignature::New(templ));
17646 context->Global()->Set(v8_str("f"), templ->GetFunction());
17647
17648 printf("Testing positive ...\n");
17649 CompileRun("var obj = new f();");
17650 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17651 CheckInstanceCheckedAccessors(true);
17652
17653 printf("Testing negative ...\n");
17654 CompileRun("var obj = {};"
17655 "obj.__proto__ = new f();");
17656 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17657 CheckInstanceCheckedAccessors(false);
17658}
17659
17660
17661THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17662 v8::internal::FLAG_allow_natives_syntax = true;
17663 v8::HandleScope scope;
17664 LocalContext context;
17665
17666 Local<FunctionTemplate> templ = FunctionTemplate::New();
17667 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17668 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17669 inst->SetAccessor(v8_str("foo"),
17670 InstanceCheckedGetter, InstanceCheckedSetter,
17671 Handle<Value>(),
17672 v8::DEFAULT,
17673 v8::None,
17674 v8::AccessorSignature::New(templ));
17675 context->Global()->Set(v8_str("f"), templ->GetFunction());
17676
17677 printf("Testing positive ...\n");
17678 CompileRun("var obj = new f();");
17679 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17680 CheckInstanceCheckedAccessors(true);
17681
17682 printf("Testing negative ...\n");
17683 CompileRun("var obj = {};"
17684 "obj.__proto__ = new f();");
17685 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17686 CheckInstanceCheckedAccessors(false);
17687}
17688
17689
17690THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17691 v8::internal::FLAG_allow_natives_syntax = true;
17692 v8::HandleScope scope;
17693 LocalContext context;
17694
17695 Local<FunctionTemplate> templ = FunctionTemplate::New();
17696 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17697 proto->SetAccessor(v8_str("foo"),
17698 InstanceCheckedGetter, InstanceCheckedSetter,
17699 Handle<Value>(),
17700 v8::DEFAULT,
17701 v8::None,
17702 v8::AccessorSignature::New(templ));
17703 context->Global()->Set(v8_str("f"), templ->GetFunction());
17704
17705 printf("Testing positive ...\n");
17706 CompileRun("var obj = new f();");
17707 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17708 CheckInstanceCheckedAccessors(true);
17709
17710 printf("Testing negative ...\n");
17711 CompileRun("var obj = {};"
17712 "obj.__proto__ = new f();");
17713 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17714 CheckInstanceCheckedAccessors(false);
17715
17716 printf("Testing positive with modified prototype chain ...\n");
17717 CompileRun("var obj = new f();"
17718 "var pro = {};"
17719 "pro.__proto__ = obj.__proto__;"
17720 "obj.__proto__ = pro;");
17721 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17722 CheckInstanceCheckedAccessors(true);
17723}
17724
17725
17726TEST(TryFinallyMessage) {
17727 v8::HandleScope scope;
17728 LocalContext context;
17729 {
17730 // Test that the original error message is not lost if there is a
17731 // recursive call into Javascript is done in the finally block, e.g. to
17732 // initialize an IC. (crbug.com/129171)
17733 TryCatch try_catch;
17734 const char* trigger_ic =
17735 "try { \n"
17736 " throw new Error('test'); \n"
17737 "} finally { \n"
17738 " var x = 0; \n"
17739 " x++; \n" // Trigger an IC initialization here.
17740 "} \n";
17741 CompileRun(trigger_ic);
17742 CHECK(try_catch.HasCaught());
17743 Local<Message> message = try_catch.Message();
17744 CHECK(!message.IsEmpty());
17745 CHECK_EQ(2, message->GetLineNumber());
17746 }
17747
17748 {
17749 // Test that the original exception message is indeed overwritten if
17750 // a new error is thrown in the finally block.
17751 TryCatch try_catch;
17752 const char* throw_again =
17753 "try { \n"
17754 " throw new Error('test'); \n"
17755 "} finally { \n"
17756 " var x = 0; \n"
17757 " x++; \n"
17758 " throw new Error('again'); \n" // This is the new uncaught error.
17759 "} \n";
17760 CompileRun(throw_again);
17761 CHECK(try_catch.HasCaught());
17762 Local<Message> message = try_catch.Message();
17763 CHECK(!message.IsEmpty());
17764 CHECK_EQ(6, message->GetLineNumber());
17765 }
17766}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017767
17768
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017769static void Helper137002(bool do_store,
17770 bool polymorphic,
17771 bool remove_accessor,
17772 bool interceptor) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017773 LocalContext context;
17774 Local<ObjectTemplate> templ = ObjectTemplate::New();
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017775 if (interceptor) {
17776 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17777 } else {
17778 templ->SetAccessor(v8_str("foo"),
17779 GetterWhichReturns42,
17780 SetterWhichSetsYOnThisTo23);
17781 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017782 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17783
17784 // Turn monomorphic on slow object with native accessor, then turn
17785 // polymorphic, finally optimize to create negative lookup and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017786 CompileRun(do_store ?
17787 "function f(x) { x.foo = void 0; }" :
17788 "function f(x) { return x.foo; }");
17789 CompileRun("obj.y = void 0;");
17790 if (!interceptor) {
17791 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17792 }
17793 CompileRun("obj.__proto__ = null;"
17794 "f(obj); f(obj); f(obj);");
17795 if (polymorphic) {
17796 CompileRun("f({});");
17797 }
17798 CompileRun("obj.y = void 0;"
17799 "%OptimizeFunctionOnNextCall(f);");
17800 if (remove_accessor) {
17801 CompileRun("delete obj.foo;");
17802 }
17803 CompileRun("var result = f(obj);");
17804 if (do_store) {
17805 CompileRun("result = obj.y;");
17806 }
17807 if (remove_accessor && !interceptor) {
17808 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17809 } else {
17810 CHECK_EQ(do_store ? 23 : 42,
17811 context->Global()->Get(v8_str("result"))->Int32Value());
17812 }
17813}
17814
17815
17816THREADED_TEST(Regress137002a) {
17817 i::FLAG_allow_natives_syntax = true;
17818 i::FLAG_compilation_cache = false;
17819 v8::HandleScope scope;
17820 for (int i = 0; i < 16; i++) {
17821 Helper137002(i & 8, i & 4, i & 2, i & 1);
17822 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017823}
17824
17825
17826THREADED_TEST(Regress137002b) {
17827 i::FLAG_allow_natives_syntax = true;
17828 v8::HandleScope scope;
17829 LocalContext context;
17830 Local<ObjectTemplate> templ = ObjectTemplate::New();
17831 templ->SetAccessor(v8_str("foo"),
17832 GetterWhichReturns42,
17833 SetterWhichSetsYOnThisTo23);
17834 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17835
17836 // Turn monomorphic on slow object with native accessor, then just
17837 // delete the property and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017838 CompileRun("function load(x) { return x.foo; }"
17839 "function store(x) { x.foo = void 0; }"
17840 "function keyed_load(x, key) { return x[key]; }"
17841 // Second version of function has a different source (add void 0)
17842 // so that it does not share code with the first version. This
17843 // ensures that the ICs are monomorphic.
17844 "function load2(x) { void 0; return x.foo; }"
17845 "function store2(x) { void 0; x.foo = void 0; }"
17846 "function keyed_load2(x, key) { void 0; return x[key]; }"
17847
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017848 "obj.y = void 0;"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017849 "obj.__proto__ = null;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017850 "var subobj = {};"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017851 "subobj.y = void 0;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017852 "subobj.__proto__ = obj;"
17853 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17854
17855 // Make the ICs monomorphic.
17856 "load(obj); load(obj);"
17857 "load2(subobj); load2(subobj);"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017858 "store(obj); store(obj);"
17859 "store2(subobj); store2(subobj);"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017860 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
17861 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
17862
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017863 // Actually test the shiny new ICs and better not crash. This
17864 // serves as a regression test for issue 142088 as well.
17865 "load(obj);"
17866 "load2(subobj);"
17867 "store(obj);"
17868 "store2(subobj);"
17869 "keyed_load(obj, 'foo');"
17870 "keyed_load2(subobj, 'foo');"
17871
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017872 // Delete the accessor. It better not be called any more now.
17873 "delete obj.foo;"
17874 "obj.y = void 0;"
17875 "subobj.y = void 0;"
17876
17877 "var load_result = load(obj);"
17878 "var load_result2 = load2(subobj);"
17879 "var keyed_load_result = keyed_load(obj, 'foo');"
17880 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
17881 "store(obj);"
17882 "store2(subobj);"
17883 "var y_from_obj = obj.y;"
17884 "var y_from_subobj = subobj.y;");
17885 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
17886 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
17887 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
17888 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
17889 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
17890 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017891}
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017892
17893
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017894THREADED_TEST(Regress142088) {
17895 i::FLAG_allow_natives_syntax = true;
17896 v8::HandleScope scope;
17897 LocalContext context;
17898 Local<ObjectTemplate> templ = ObjectTemplate::New();
17899 templ->SetAccessor(v8_str("foo"),
17900 GetterWhichReturns42,
17901 SetterWhichSetsYOnThisTo23);
17902 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17903
17904 CompileRun("function load(x) { return x.foo; }"
17905 "var o = Object.create(obj);"
17906 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17907 "load(o); load(o); load(o); load(o);");
17908}
17909
17910
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017911THREADED_TEST(Regress137496) {
17912 i::FLAG_expose_gc = true;
17913 v8::HandleScope scope;
17914 LocalContext context;
17915
17916 // Compile a try-finally clause where the finally block causes a GC
17917 // while there still is a message pending for external reporting.
17918 TryCatch try_catch;
17919 try_catch.SetVerbose(true);
17920 CompileRun("try { throw new Error(); } finally { gc(); }");
17921 CHECK(try_catch.HasCaught());
17922}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017923
17924
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000017925THREADED_TEST(Regress149912) {
17926 v8::HandleScope scope;
17927 LocalContext context;
17928 Handle<FunctionTemplate> templ = FunctionTemplate::New();
17929 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17930 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
17931 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
17932}
17933
17934
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000017935THREADED_TEST(Regress157124) {
17936 v8::HandleScope scope;
17937 LocalContext context;
17938 Local<ObjectTemplate> templ = ObjectTemplate::New();
17939 Local<Object> obj = templ->NewInstance();
17940 obj->GetIdentityHash();
17941 obj->DeleteHiddenValue(v8_str("Bug"));
17942}
17943
17944
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017945#ifndef WIN32
17946class ThreadInterruptTest {
17947 public:
17948 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17949 ~ThreadInterruptTest() { delete sem_; }
17950
17951 void RunTest() {
17952 sem_ = i::OS::CreateSemaphore(0);
17953
17954 InterruptThread i_thread(this);
17955 i_thread.Start();
17956
17957 sem_->Wait();
17958 CHECK_EQ(kExpectedValue, sem_value_);
17959 }
17960
17961 private:
17962 static const int kExpectedValue = 1;
17963
17964 class InterruptThread : public i::Thread {
17965 public:
17966 explicit InterruptThread(ThreadInterruptTest* test)
17967 : Thread("InterruptThread"), test_(test) {}
17968
17969 virtual void Run() {
17970 struct sigaction action;
17971
17972 // Ensure that we'll enter waiting condition
17973 i::OS::Sleep(100);
17974
17975 // Setup signal handler
17976 memset(&action, 0, sizeof(action));
17977 action.sa_handler = SignalHandler;
17978 sigaction(SIGCHLD, &action, NULL);
17979
17980 // Send signal
17981 kill(getpid(), SIGCHLD);
17982
17983 // Ensure that if wait has returned because of error
17984 i::OS::Sleep(100);
17985
17986 // Set value and signal semaphore
17987 test_->sem_value_ = 1;
17988 test_->sem_->Signal();
17989 }
17990
17991 static void SignalHandler(int signal) {
17992 }
17993
17994 private:
17995 ThreadInterruptTest* test_;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017996 };
17997
17998 i::Semaphore* sem_;
17999 volatile int sem_value_;
18000};
18001
18002
18003THREADED_TEST(SemaphoreInterruption) {
18004 ThreadInterruptTest().RunTest();
18005}
18006#endif // WIN32