blob: a4dcc545b64f6a2874a8099c0843c273d5040592 [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
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000028// We want to test our deprecated API entries, too.
29#define V8_DISABLE_DEPRECATIONS 1
30
ager@chromium.org3811b432009-10-28 14:53:37 +000031#include <limits.h>
32
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000033#ifndef WIN32
34#include <signal.h> // kill
35#include <unistd.h> // getpid
36#endif // WIN32
37
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000038#include "v8.h"
39
40#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000041#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000042#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000043#include "execution.h"
verwaest@chromium.org753aee42012-07-17 16:15:42 +000044#include "objects.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#include "snapshot.h"
46#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000047#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000048#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000049#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000050#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000051
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000052static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000053
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000054static bool IsNaN(double x) {
55#ifdef WIN32
56 return _isnan(x);
57#else
58 return isnan(x);
59#endif
60}
61
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000063using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000064using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000065using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000066using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000067using ::v8::FunctionTemplate;
68using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000069using ::v8::HandleScope;
70using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000071using ::v8::Message;
72using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000073using ::v8::Object;
74using ::v8::ObjectTemplate;
75using ::v8::Persistent;
76using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000077using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000078using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000079using ::v8::TryCatch;
80using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000081using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000082using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000084
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000085static void ExpectString(const char* code, const char* expected) {
86 Local<Value> result = CompileRun(code);
87 CHECK(result->IsString());
88 String::AsciiValue ascii(result);
89 CHECK_EQ(expected, *ascii);
90}
91
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000092static void ExpectInt32(const char* code, int expected) {
93 Local<Value> result = CompileRun(code);
94 CHECK(result->IsInt32());
95 CHECK_EQ(expected, result->Int32Value());
96}
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000097
98static void ExpectBoolean(const char* code, bool expected) {
99 Local<Value> result = CompileRun(code);
100 CHECK(result->IsBoolean());
101 CHECK_EQ(expected, result->BooleanValue());
102}
103
104
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000105static void ExpectTrue(const char* code) {
106 ExpectBoolean(code, true);
107}
108
109
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000110static void ExpectFalse(const char* code) {
111 ExpectBoolean(code, false);
112}
113
114
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000115static void ExpectObject(const char* code, Local<Value> expected) {
116 Local<Value> result = CompileRun(code);
117 CHECK(result->Equals(expected));
118}
119
120
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000121static void ExpectUndefined(const char* code) {
122 Local<Value> result = CompileRun(code);
123 CHECK(result->IsUndefined());
124}
125
126
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000127static int signature_callback_count;
128static v8::Handle<Value> IncrementingSignatureCallback(
129 const v8::Arguments& args) {
130 ApiTestFuzzer::Fuzz();
131 signature_callback_count++;
132 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
133 for (int i = 0; i < args.Length(); i++)
134 result->Set(v8::Integer::New(i), args[i]);
135 return result;
136}
137
138
139static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
140 ApiTestFuzzer::Fuzz();
141 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
142 for (int i = 0; i < args.Length(); i++) {
143 result->Set(v8::Integer::New(i), args[i]);
144 }
145 return result;
146}
147
148
149THREADED_TEST(Handles) {
150 v8::HandleScope scope;
151 Local<Context> local_env;
152 {
153 LocalContext env;
154 local_env = env.local();
155 }
156
157 // Local context should still be live.
158 CHECK(!local_env.IsEmpty());
159 local_env->Enter();
160
161 v8::Handle<v8::Primitive> undef = v8::Undefined();
162 CHECK(!undef.IsEmpty());
163 CHECK(undef->IsUndefined());
164
165 const char* c_source = "1 + 2 + 3";
166 Local<String> source = String::New(c_source);
167 Local<Script> script = Script::Compile(source);
168 CHECK_EQ(6, script->Run()->Int32Value());
169
170 local_env->Exit();
171}
172
173
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000174THREADED_TEST(ReceiverSignature) {
175 v8::HandleScope scope;
176 LocalContext env;
177 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
178 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
179 fun->PrototypeTemplate()->Set(
180 v8_str("m"),
181 v8::FunctionTemplate::New(IncrementingSignatureCallback,
182 v8::Handle<Value>(),
183 sig));
184 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
185 signature_callback_count = 0;
186 CompileRun(
187 "var o = new Fun();"
188 "o.m();");
189 CHECK_EQ(1, signature_callback_count);
190 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
191 sub_fun->Inherit(fun);
192 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
193 CompileRun(
194 "var o = new SubFun();"
195 "o.m();");
196 CHECK_EQ(2, signature_callback_count);
197
198 v8::TryCatch try_catch;
199 CompileRun(
200 "var o = { };"
201 "o.m = Fun.prototype.m;"
202 "o.m();");
203 CHECK_EQ(2, signature_callback_count);
204 CHECK(try_catch.HasCaught());
205 try_catch.Reset();
206 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
207 sub_fun->Inherit(fun);
208 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
209 CompileRun(
210 "var o = new UnrelFun();"
211 "o.m = Fun.prototype.m;"
212 "o.m();");
213 CHECK_EQ(2, signature_callback_count);
214 CHECK(try_catch.HasCaught());
215}
216
217
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000218THREADED_TEST(ArgumentSignature) {
219 v8::HandleScope scope;
220 LocalContext env;
221 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
222 cons->SetClassName(v8_str("Cons"));
223 v8::Handle<v8::Signature> sig =
224 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
225 v8::Handle<v8::FunctionTemplate> fun =
226 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
227 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
228 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
229
230 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000231 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232
233 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000234 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235
236 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000237 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
239 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
240 cons1->SetClassName(v8_str("Cons1"));
241 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
242 cons2->SetClassName(v8_str("Cons2"));
243 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
244 cons3->SetClassName(v8_str("Cons3"));
245
246 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
247 v8::Handle<v8::Signature> wsig =
248 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
249 v8::Handle<v8::FunctionTemplate> fun2 =
250 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
251
252 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
253 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
254 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
255 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
256 v8::Handle<Value> value4 = CompileRun(
257 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
258 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000259 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000260
261 v8::Handle<Value> value5 = CompileRun(
262 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000263 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264
265 v8::Handle<Value> value6 = CompileRun(
266 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000267 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268
269 v8::Handle<Value> value7 = CompileRun(
270 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
271 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000272 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000273
274 v8::Handle<Value> value8 = CompileRun(
275 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000276 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277}
278
279
280THREADED_TEST(HulIgennem) {
281 v8::HandleScope scope;
282 LocalContext env;
283 v8::Handle<v8::Primitive> undef = v8::Undefined();
284 Local<String> undef_str = undef->ToString();
285 char* value = i::NewArray<char>(undef_str->Length() + 1);
286 undef_str->WriteAscii(value);
287 CHECK_EQ(0, strcmp(value, "undefined"));
288 i::DeleteArray(value);
289}
290
291
292THREADED_TEST(Access) {
293 v8::HandleScope scope;
294 LocalContext env;
295 Local<v8::Object> obj = v8::Object::New();
296 Local<Value> foo_before = obj->Get(v8_str("foo"));
297 CHECK(foo_before->IsUndefined());
298 Local<String> bar_str = v8_str("bar");
299 obj->Set(v8_str("foo"), bar_str);
300 Local<Value> foo_after = obj->Get(v8_str("foo"));
301 CHECK(!foo_after->IsUndefined());
302 CHECK(foo_after->IsString());
303 CHECK_EQ(bar_str, foo_after);
304}
305
306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000307THREADED_TEST(AccessElement) {
308 v8::HandleScope scope;
309 LocalContext env;
310 Local<v8::Object> obj = v8::Object::New();
311 Local<Value> before = obj->Get(1);
312 CHECK(before->IsUndefined());
313 Local<String> bar_str = v8_str("bar");
314 obj->Set(1, bar_str);
315 Local<Value> after = obj->Get(1);
316 CHECK(!after->IsUndefined());
317 CHECK(after->IsString());
318 CHECK_EQ(bar_str, after);
319
320 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
321 CHECK_EQ(v8_str("a"), value->Get(0));
322 CHECK_EQ(v8_str("b"), value->Get(1));
323}
324
325
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000326THREADED_TEST(Script) {
327 v8::HandleScope scope;
328 LocalContext env;
329 const char* c_source = "1 + 2 + 3";
330 Local<String> source = String::New(c_source);
331 Local<Script> script = Script::Compile(source);
332 CHECK_EQ(6, script->Run()->Int32Value());
333}
334
335
336static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000337 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000339 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340 return converted;
341}
342
343
344class TestResource: public String::ExternalStringResource {
345 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000346 explicit TestResource(uint16_t* data, int* counter = NULL)
347 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000348 while (data[length_]) ++length_;
349 }
350
351 ~TestResource() {
352 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000353 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354 }
355
356 const uint16_t* data() const {
357 return data_;
358 }
359
360 size_t length() const {
361 return length_;
362 }
363 private:
364 uint16_t* data_;
365 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000366 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367};
368
369
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000370class TestAsciiResource: public String::ExternalAsciiStringResource {
371 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000372 explicit TestAsciiResource(const char* data, int* counter = NULL)
373 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374
375 ~TestAsciiResource() {
376 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000377 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000378 }
379
380 const char* data() const {
381 return data_;
382 }
383
384 size_t length() const {
385 return length_;
386 }
387 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000388 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000389 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000390 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000391};
392
393
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000394THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000395 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396 const char* c_source = "1 + 2 * 3";
397 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
398 {
399 v8::HandleScope scope;
400 LocalContext env;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000401 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402 Local<String> source = String::NewExternal(resource);
403 Local<Script> script = Script::Compile(source);
404 Local<Value> value = script->Run();
405 CHECK(value->IsNumber());
406 CHECK_EQ(7, value->Int32Value());
407 CHECK(source->IsExternal());
408 CHECK_EQ(resource,
409 static_cast<TestResource*>(source->GetExternalStringResource()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000410 String::Encoding encoding = String::UNKNOWN_ENCODING;
411 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
412 source->GetExternalStringResourceBase(&encoding));
413 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000414 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000415 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 v8::internal::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000418 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000419 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000420}
421
422
423THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000424 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425 const char* c_source = "1 + 2 * 3";
426 {
427 v8::HandleScope scope;
428 LocalContext env;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000429 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
430 &dispose_count);
431 Local<String> source = String::NewExternal(resource);
432 CHECK(source->IsExternalAscii());
433 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
434 source->GetExternalAsciiStringResource());
435 String::Encoding encoding = String::UNKNOWN_ENCODING;
436 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
437 source->GetExternalStringResourceBase(&encoding));
438 CHECK_EQ(String::ASCII_ENCODING, encoding);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439 Local<Script> script = Script::Compile(source);
440 Local<Value> value = script->Run();
441 CHECK(value->IsNumber());
442 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000444 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000448 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000449}
450
451
ager@chromium.org6f10e412009-02-13 10:11:16 +0000452THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000453 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000454 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
455 {
456 v8::HandleScope scope;
457 LocalContext env;
458 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
461 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000462 CHECK_EQ(source->IsExternal(), false);
463 CHECK_EQ(source->IsExternalAscii(), false);
464 String::Encoding encoding = String::UNKNOWN_ENCODING;
465 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
466 CHECK_EQ(String::ASCII_ENCODING, encoding);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000467 bool success = source->MakeExternal(new TestResource(two_byte_source,
468 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000469 CHECK(success);
470 Local<Script> script = Script::Compile(source);
471 Local<Value> value = script->Run();
472 CHECK(value->IsNumber());
473 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000474 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000475 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000478 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000479 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000480}
481
482
483THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000484 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000485 const char* c_source = "1 + 2 * 3";
486 {
487 v8::HandleScope scope;
488 LocalContext env;
489 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
492 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000493 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000494 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000495 CHECK(success);
496 Local<Script> script = Script::Compile(source);
497 Local<Value> value = script->Run();
498 CHECK(value->IsNumber());
499 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000500 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000501 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000502 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000504 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000505 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000506}
507
508
ager@chromium.org5c838252010-02-19 08:53:10 +0000509TEST(MakingExternalStringConditions) {
510 v8::HandleScope scope;
511 LocalContext env;
512
513 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 HEAP->CollectGarbage(i::NEW_SPACE);
515 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000516
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000517 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000518 Local<String> small_string = String::New(two_byte_string);
519 i::DeleteArray(two_byte_string);
520
ager@chromium.org5c838252010-02-19 08:53:10 +0000521 // We should refuse to externalize newly created small string.
522 CHECK(!small_string->CanMakeExternal());
523 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
525 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000526 // Old space strings should be accepted.
527 CHECK(small_string->CanMakeExternal());
528
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000529 two_byte_string = AsciiToTwoByteString("small string 2");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000530 small_string = String::New(two_byte_string);
531 i::DeleteArray(two_byte_string);
532
ager@chromium.org5c838252010-02-19 08:53:10 +0000533 // We should refuse externalizing newly created small string.
534 CHECK(!small_string->CanMakeExternal());
535 for (int i = 0; i < 100; i++) {
536 String::Value value(small_string);
537 }
538 // Frequently used strings should be accepted.
539 CHECK(small_string->CanMakeExternal());
540
541 const int buf_size = 10 * 1024;
542 char* buf = i::NewArray<char>(buf_size);
543 memset(buf, 'a', buf_size);
544 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000545
546 two_byte_string = AsciiToTwoByteString(buf);
547 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000548 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000549 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000550 // Large strings should be immediately accepted.
551 CHECK(large_string->CanMakeExternal());
552}
553
554
555TEST(MakingExternalAsciiStringConditions) {
556 v8::HandleScope scope;
557 LocalContext env;
558
559 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 HEAP->CollectGarbage(i::NEW_SPACE);
561 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000562
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000563 Local<String> small_string = String::New("s1");
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 // We should refuse to externalize newly created small string.
565 CHECK(!small_string->CanMakeExternal());
566 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
568 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000569 // Old space strings should be accepted.
570 CHECK(small_string->CanMakeExternal());
571
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000572 small_string = String::New("small string 2");
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 // We should refuse externalizing newly created small string.
574 CHECK(!small_string->CanMakeExternal());
575 for (int i = 0; i < 100; i++) {
576 String::Value value(small_string);
577 }
578 // Frequently used strings should be accepted.
579 CHECK(small_string->CanMakeExternal());
580
581 const int buf_size = 10 * 1024;
582 char* buf = i::NewArray<char>(buf_size);
583 memset(buf, 'a', buf_size);
584 buf[buf_size - 1] = '\0';
585 Local<String> large_string = String::New(buf);
586 i::DeleteArray(buf);
587 // Large strings should be immediately accepted.
588 CHECK(large_string->CanMakeExternal());
589}
590
591
ager@chromium.org6f10e412009-02-13 10:11:16 +0000592THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000593 {
594 v8::HandleScope scope;
595 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
596 Local<String> string =
597 String::NewExternal(new TestResource(two_byte_string));
598 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
599 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
601 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
602 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000603 CHECK(isymbol->IsSymbol());
604 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000605 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
606 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000607}
608
609
610THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000611 {
612 v8::HandleScope scope;
613 const char* one_byte_string = "test string";
614 Local<String> string = String::NewExternal(
615 new TestAsciiResource(i::StrDup(one_byte_string)));
616 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
617 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
619 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
620 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000621 CHECK(isymbol->IsSymbol());
622 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000623 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
624 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000625}
626
627
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628THREADED_TEST(ScavengeExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000629 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000630 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 {
632 v8::HandleScope scope;
633 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
634 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000635 String::NewExternal(new TestResource(two_byte_string,
636 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000637 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 HEAP->CollectGarbage(i::NEW_SPACE);
639 in_new_space = HEAP->InNewSpace(*istring);
640 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000641 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000642 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000644 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645}
646
647
648THREADED_TEST(ScavengeExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000649 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000650 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 {
652 v8::HandleScope scope;
653 const char* one_byte_string = "test string";
654 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000655 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000656 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 HEAP->CollectGarbage(i::NEW_SPACE);
658 in_new_space = HEAP->InNewSpace(*istring);
659 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000660 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000663 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000664}
665
666
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000667class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
668 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000669 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000670 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000671 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000672
673 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000674 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000675 dispose_(dispose) { }
676
677 void Dispose() {
678 ++dispose_calls;
679 if (dispose_) delete this;
680 }
681 private:
682 bool dispose_;
683};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000684
685
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000686int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000687int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000688
689
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000691 const char* c_source = "1 + 2 * 3";
692
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000693 // Use a stack allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000694 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000695 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
696 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000697 {
698 v8::HandleScope scope;
699 LocalContext env;
700 Local<String> source = String::NewExternal(&res_stack);
701 Local<Script> script = Script::Compile(source);
702 Local<Value> value = script->Run();
703 CHECK(value->IsNumber());
704 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000705 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000706 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000707 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000708 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000709 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000710 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000711 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000712
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000713 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000714 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000715 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
716 TestAsciiResource* res_heap =
717 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000718 {
719 v8::HandleScope scope;
720 LocalContext env;
721 Local<String> source = String::NewExternal(res_heap);
722 Local<Script> script = Script::Compile(source);
723 Local<Value> value = script->Run();
724 CHECK(value->IsNumber());
725 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000727 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000728 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000729 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000731 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000732 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000733}
734
735
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000736THREADED_TEST(StringConcat) {
737 {
738 v8::HandleScope scope;
739 LocalContext env;
740 const char* one_byte_string_1 = "function a_times_t";
741 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
742 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
743 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
744 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
745 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
746 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
747 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000748
749 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
750 Local<String> right = String::New(two_byte_source);
751 i::DeleteArray(two_byte_source);
752
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000753 Local<String> source = String::Concat(left, right);
754 right = String::NewExternal(
755 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
756 source = String::Concat(source, right);
757 right = String::NewExternal(
758 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
759 source = String::Concat(source, right);
760 right = v8_str(one_byte_string_2);
761 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000762
763 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
764 right = String::New(two_byte_source);
765 i::DeleteArray(two_byte_source);
766
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000767 source = String::Concat(source, right);
768 right = String::NewExternal(
769 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
770 source = String::Concat(source, right);
771 Local<Script> script = Script::Compile(source);
772 Local<Value> value = script->Run();
773 CHECK(value->IsNumber());
774 CHECK_EQ(68, value->Int32Value());
775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000777 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
778 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000779}
780
781
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782THREADED_TEST(GlobalProperties) {
783 v8::HandleScope scope;
784 LocalContext env;
785 v8::Handle<v8::Object> global = env->Global();
786 global->Set(v8_str("pi"), v8_num(3.1415926));
787 Local<Value> pi = global->Get(v8_str("pi"));
788 CHECK_EQ(3.1415926, pi->NumberValue());
789}
790
791
792static v8::Handle<Value> handle_call(const v8::Arguments& args) {
793 ApiTestFuzzer::Fuzz();
794 return v8_num(102);
795}
796
797
798static v8::Handle<Value> construct_call(const v8::Arguments& args) {
799 ApiTestFuzzer::Fuzz();
800 args.This()->Set(v8_str("x"), v8_num(1));
801 args.This()->Set(v8_str("y"), v8_num(2));
802 return args.This();
803}
804
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000805static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
806 ApiTestFuzzer::Fuzz();
807 return v8_num(239);
808}
809
810
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000811THREADED_TEST(FunctionTemplate) {
812 v8::HandleScope scope;
813 LocalContext env;
814 {
815 Local<v8::FunctionTemplate> fun_templ =
816 v8::FunctionTemplate::New(handle_call);
817 Local<Function> fun = fun_templ->GetFunction();
818 env->Global()->Set(v8_str("obj"), fun);
819 Local<Script> script = v8_compile("obj()");
820 CHECK_EQ(102, script->Run()->Int32Value());
821 }
822 // Use SetCallHandler to initialize a function template, should work like the
823 // previous one.
824 {
825 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
826 fun_templ->SetCallHandler(handle_call);
827 Local<Function> fun = fun_templ->GetFunction();
828 env->Global()->Set(v8_str("obj"), fun);
829 Local<Script> script = v8_compile("obj()");
830 CHECK_EQ(102, script->Run()->Int32Value());
831 }
832 // Test constructor calls.
833 {
834 Local<v8::FunctionTemplate> fun_templ =
835 v8::FunctionTemplate::New(construct_call);
836 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000837 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000838 Local<Function> fun = fun_templ->GetFunction();
839 env->Global()->Set(v8_str("obj"), fun);
840 Local<Script> script = v8_compile("var s = new obj(); s.x");
841 CHECK_EQ(1, script->Run()->Int32Value());
842
843 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
844 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000845
846 result = v8_compile("(new obj()).m")->Run();
847 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000848 }
849}
850
851
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000852static void* expected_ptr;
853static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
854 void* ptr = v8::External::Unwrap(args.Data());
855 CHECK_EQ(expected_ptr, ptr);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000856 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000857}
858
859
860static void TestExternalPointerWrapping() {
861 v8::HandleScope scope;
862 LocalContext env;
863
864 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
865
866 v8::Handle<v8::Object> obj = v8::Object::New();
867 obj->Set(v8_str("func"),
868 v8::FunctionTemplate::New(callback, data)->GetFunction());
869 env->Global()->Set(v8_str("obj"), obj);
870
871 CHECK(CompileRun(
872 "function foo() {\n"
873 " for (var i = 0; i < 13; i++) obj.func();\n"
874 "}\n"
875 "foo(), true")->BooleanValue());
876}
877
878
879THREADED_TEST(ExternalWrap) {
880 // Check heap allocated object.
881 int* ptr = new int;
882 expected_ptr = ptr;
883 TestExternalPointerWrapping();
884 delete ptr;
885
886 // Check stack allocated object.
887 int foo;
888 expected_ptr = &foo;
889 TestExternalPointerWrapping();
890
891 // Check not aligned addresses.
892 const int n = 100;
893 char* s = new char[n];
894 for (int i = 0; i < n; i++) {
895 expected_ptr = s + i;
896 TestExternalPointerWrapping();
897 }
898
899 delete[] s;
900
901 // Check several invalid addresses.
902 expected_ptr = reinterpret_cast<void*>(1);
903 TestExternalPointerWrapping();
904
905 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
906 TestExternalPointerWrapping();
907
908 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
909 TestExternalPointerWrapping();
910
911#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000912 // Check a value with a leading 1 bit in x64 Smi encoding.
913 expected_ptr = reinterpret_cast<void*>(0x400000000);
914 TestExternalPointerWrapping();
915
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000916 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
917 TestExternalPointerWrapping();
918
919 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
920 TestExternalPointerWrapping();
921#endif
922}
923
924
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000925THREADED_TEST(FindInstanceInPrototypeChain) {
926 v8::HandleScope scope;
927 LocalContext env;
928
929 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
930 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
931 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
932 derived->Inherit(base);
933
934 Local<v8::Function> base_function = base->GetFunction();
935 Local<v8::Function> derived_function = derived->GetFunction();
936 Local<v8::Function> other_function = other->GetFunction();
937
938 Local<v8::Object> base_instance = base_function->NewInstance();
939 Local<v8::Object> derived_instance = derived_function->NewInstance();
940 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
941 Local<v8::Object> other_instance = other_function->NewInstance();
942 derived_instance2->Set(v8_str("__proto__"), derived_instance);
943 other_instance->Set(v8_str("__proto__"), derived_instance2);
944
945 // base_instance is only an instance of base.
946 CHECK_EQ(base_instance,
947 base_instance->FindInstanceInPrototypeChain(base));
948 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
949 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
950
951 // derived_instance is an instance of base and derived.
952 CHECK_EQ(derived_instance,
953 derived_instance->FindInstanceInPrototypeChain(base));
954 CHECK_EQ(derived_instance,
955 derived_instance->FindInstanceInPrototypeChain(derived));
956 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
957
958 // other_instance is an instance of other and its immediate
959 // prototype derived_instance2 is an instance of base and derived.
960 // Note, derived_instance is an instance of base and derived too,
961 // but it comes after derived_instance2 in the prototype chain of
962 // other_instance.
963 CHECK_EQ(derived_instance2,
964 other_instance->FindInstanceInPrototypeChain(base));
965 CHECK_EQ(derived_instance2,
966 other_instance->FindInstanceInPrototypeChain(derived));
967 CHECK_EQ(other_instance,
968 other_instance->FindInstanceInPrototypeChain(other));
969}
970
971
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000972THREADED_TEST(TinyInteger) {
973 v8::HandleScope scope;
974 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000975 v8::Isolate* isolate = v8::Isolate::GetCurrent();
976
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000977 int32_t value = 239;
978 Local<v8::Integer> value_obj = v8::Integer::New(value);
979 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000980
981 value_obj = v8::Integer::New(value, isolate);
982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000983}
984
985
986THREADED_TEST(BigSmiInteger) {
987 v8::HandleScope scope;
988 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000989 v8::Isolate* isolate = v8::Isolate::GetCurrent();
990
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000991 int32_t value = i::Smi::kMaxValue;
992 // We cannot add one to a Smi::kMaxValue without wrapping.
993 if (i::kSmiValueSize < 32) {
994 CHECK(i::Smi::IsValid(value));
995 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000996
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000997 Local<v8::Integer> value_obj = v8::Integer::New(value);
998 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000999
1000 value_obj = v8::Integer::New(value, isolate);
1001 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001002 }
1003}
1004
1005
1006THREADED_TEST(BigInteger) {
1007 v8::HandleScope scope;
1008 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001009 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1010
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001011 // We cannot add one to a Smi::kMaxValue without wrapping.
1012 if (i::kSmiValueSize < 32) {
1013 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1014 // The code will not be run in that case, due to the "if" guard.
1015 int32_t value =
1016 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1017 CHECK(value > i::Smi::kMaxValue);
1018 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001019
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001020 Local<v8::Integer> value_obj = v8::Integer::New(value);
1021 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001022
1023 value_obj = v8::Integer::New(value, isolate);
1024 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001025 }
1026}
1027
1028
1029THREADED_TEST(TinyUnsignedInteger) {
1030 v8::HandleScope scope;
1031 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001032 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1033
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001034 uint32_t value = 239;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001035
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001036 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1037 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001038
1039 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1040 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001041}
1042
1043
1044THREADED_TEST(BigUnsignedSmiInteger) {
1045 v8::HandleScope scope;
1046 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001047 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1048
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001049 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1050 CHECK(i::Smi::IsValid(value));
1051 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001052
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001053 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1054 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001055
1056 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1057 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001058}
1059
1060
1061THREADED_TEST(BigUnsignedInteger) {
1062 v8::HandleScope scope;
1063 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001064 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1065
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001066 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1067 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1068 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001069
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001070 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1071 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001072
1073 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1074 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001075}
1076
1077
1078THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1079 v8::HandleScope scope;
1080 LocalContext env;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001081 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1082
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001083 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1084 uint32_t value = INT32_MAX_AS_UINT + 1;
1085 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001086
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001087 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1088 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001089
1090 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1091 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001092}
1093
1094
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001095THREADED_TEST(IsNativeError) {
1096 v8::HandleScope scope;
1097 LocalContext env;
1098 v8::Handle<Value> syntax_error = CompileRun(
1099 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1100 CHECK(syntax_error->IsNativeError());
1101 v8::Handle<Value> not_error = CompileRun("{a:42}");
1102 CHECK(!not_error->IsNativeError());
1103 v8::Handle<Value> not_object = CompileRun("42");
1104 CHECK(!not_object->IsNativeError());
1105}
1106
1107
1108THREADED_TEST(StringObject) {
1109 v8::HandleScope scope;
1110 LocalContext env;
1111 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1112 CHECK(boxed_string->IsStringObject());
1113 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1114 CHECK(!unboxed_string->IsStringObject());
1115 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1116 CHECK(!boxed_not_string->IsStringObject());
1117 v8::Handle<Value> not_object = CompileRun("0");
1118 CHECK(!not_object->IsStringObject());
1119 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1120 CHECK(!as_boxed.IsEmpty());
1121 Local<v8::String> the_string = as_boxed->StringValue();
1122 CHECK(!the_string.IsEmpty());
1123 ExpectObject("\"test\"", the_string);
1124 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1125 CHECK(new_boxed_string->IsStringObject());
1126 as_boxed = new_boxed_string.As<v8::StringObject>();
1127 the_string = as_boxed->StringValue();
1128 CHECK(!the_string.IsEmpty());
1129 ExpectObject("\"test\"", the_string);
1130}
1131
1132
1133THREADED_TEST(NumberObject) {
1134 v8::HandleScope scope;
1135 LocalContext env;
1136 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1137 CHECK(boxed_number->IsNumberObject());
1138 v8::Handle<Value> unboxed_number = CompileRun("42");
1139 CHECK(!unboxed_number->IsNumberObject());
1140 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1141 CHECK(!boxed_not_number->IsNumberObject());
1142 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1143 CHECK(!as_boxed.IsEmpty());
1144 double the_number = as_boxed->NumberValue();
1145 CHECK_EQ(42.0, the_number);
1146 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1147 CHECK(new_boxed_number->IsNumberObject());
1148 as_boxed = new_boxed_number.As<v8::NumberObject>();
1149 the_number = as_boxed->NumberValue();
1150 CHECK_EQ(43.0, the_number);
1151}
1152
1153
1154THREADED_TEST(BooleanObject) {
1155 v8::HandleScope scope;
1156 LocalContext env;
1157 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1158 CHECK(boxed_boolean->IsBooleanObject());
1159 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1160 CHECK(!unboxed_boolean->IsBooleanObject());
1161 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1162 CHECK(!boxed_not_boolean->IsBooleanObject());
1163 v8::Handle<v8::BooleanObject> as_boxed =
1164 boxed_boolean.As<v8::BooleanObject>();
1165 CHECK(!as_boxed.IsEmpty());
1166 bool the_boolean = as_boxed->BooleanValue();
1167 CHECK_EQ(true, the_boolean);
1168 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1169 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1170 CHECK(boxed_true->IsBooleanObject());
1171 CHECK(boxed_false->IsBooleanObject());
1172 as_boxed = boxed_true.As<v8::BooleanObject>();
1173 CHECK_EQ(true, as_boxed->BooleanValue());
1174 as_boxed = boxed_false.As<v8::BooleanObject>();
1175 CHECK_EQ(false, as_boxed->BooleanValue());
1176}
1177
1178
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001179THREADED_TEST(Number) {
1180 v8::HandleScope scope;
1181 LocalContext env;
1182 double PI = 3.1415926;
1183 Local<v8::Number> pi_obj = v8::Number::New(PI);
1184 CHECK_EQ(PI, pi_obj->NumberValue());
1185}
1186
1187
1188THREADED_TEST(ToNumber) {
1189 v8::HandleScope scope;
1190 LocalContext env;
1191 Local<String> str = v8_str("3.1415926");
1192 CHECK_EQ(3.1415926, str->NumberValue());
1193 v8::Handle<v8::Boolean> t = v8::True();
1194 CHECK_EQ(1.0, t->NumberValue());
1195 v8::Handle<v8::Boolean> f = v8::False();
1196 CHECK_EQ(0.0, f->NumberValue());
1197}
1198
1199
1200THREADED_TEST(Date) {
1201 v8::HandleScope scope;
1202 LocalContext env;
1203 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001204 Local<Value> date = v8::Date::New(PI);
1205 CHECK_EQ(3.0, date->NumberValue());
1206 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1207 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001208}
1209
1210
1211THREADED_TEST(Boolean) {
1212 v8::HandleScope scope;
1213 LocalContext env;
1214 v8::Handle<v8::Boolean> t = v8::True();
1215 CHECK(t->Value());
1216 v8::Handle<v8::Boolean> f = v8::False();
1217 CHECK(!f->Value());
1218 v8::Handle<v8::Primitive> u = v8::Undefined();
1219 CHECK(!u->BooleanValue());
1220 v8::Handle<v8::Primitive> n = v8::Null();
1221 CHECK(!n->BooleanValue());
1222 v8::Handle<String> str1 = v8_str("");
1223 CHECK(!str1->BooleanValue());
1224 v8::Handle<String> str2 = v8_str("x");
1225 CHECK(str2->BooleanValue());
1226 CHECK(!v8::Number::New(0)->BooleanValue());
1227 CHECK(v8::Number::New(-1)->BooleanValue());
1228 CHECK(v8::Number::New(1)->BooleanValue());
1229 CHECK(v8::Number::New(42)->BooleanValue());
1230 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1231}
1232
1233
1234static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1235 ApiTestFuzzer::Fuzz();
1236 return v8_num(13.4);
1237}
1238
1239
1240static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1241 ApiTestFuzzer::Fuzz();
1242 return v8_num(876);
1243}
1244
1245
1246THREADED_TEST(GlobalPrototype) {
1247 v8::HandleScope scope;
1248 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1249 func_templ->PrototypeTemplate()->Set(
1250 "dummy",
1251 v8::FunctionTemplate::New(DummyCallHandler));
1252 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1253 templ->Set("x", v8_num(200));
1254 templ->SetAccessor(v8_str("m"), GetM);
1255 LocalContext env(0, templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001256 v8::Handle<Script> script(v8_compile("dummy()"));
1257 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001258 CHECK_EQ(13.4, result->NumberValue());
1259 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1260 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1261}
1262
1263
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001264THREADED_TEST(ObjectTemplate) {
1265 v8::HandleScope scope;
1266 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1267 templ1->Set("x", v8_num(10));
1268 templ1->Set("y", v8_num(13));
1269 LocalContext env;
1270 Local<v8::Object> instance1 = templ1->NewInstance();
1271 env->Global()->Set(v8_str("p"), instance1);
1272 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1273 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1274 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1275 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1276 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1277 templ2->Set("a", v8_num(12));
1278 templ2->Set("b", templ1);
1279 Local<v8::Object> instance2 = templ2->NewInstance();
1280 env->Global()->Set(v8_str("q"), instance2);
1281 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1282 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1283 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1284 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1285}
1286
1287
1288static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1289 ApiTestFuzzer::Fuzz();
1290 return v8_num(17.2);
1291}
1292
1293
1294static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1295 ApiTestFuzzer::Fuzz();
1296 return v8_num(15.2);
1297}
1298
1299
1300THREADED_TEST(DescriptorInheritance) {
1301 v8::HandleScope scope;
1302 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1303 super->PrototypeTemplate()->Set("flabby",
1304 v8::FunctionTemplate::New(GetFlabby));
1305 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1306
1307 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1308
1309 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1310 base1->Inherit(super);
1311 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1312
1313 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1314 base2->Inherit(super);
1315 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1316
1317 LocalContext env;
1318
1319 env->Global()->Set(v8_str("s"), super->GetFunction());
1320 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1321 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1322
1323 // Checks right __proto__ chain.
1324 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1325 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1326
1327 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1328
1329 // Instance accessor should not be visible on function object or its prototype
1330 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1331 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1332 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1333
1334 env->Global()->Set(v8_str("obj"),
1335 base1->GetFunction()->NewInstance());
1336 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1337 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1338 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1339 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1340 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1341
1342 env->Global()->Set(v8_str("obj2"),
1343 base2->GetFunction()->NewInstance());
1344 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1345 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1346 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1347 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1348 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1349
1350 // base1 and base2 cannot cross reference to each's prototype
1351 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1352 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1353}
1354
1355
1356int echo_named_call_count;
1357
1358
1359static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1360 const AccessorInfo& info) {
1361 ApiTestFuzzer::Fuzz();
1362 CHECK_EQ(v8_str("data"), info.Data());
1363 echo_named_call_count++;
1364 return name;
1365}
1366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367// Helper functions for Interceptor/Accessor interaction tests
1368
1369Handle<Value> SimpleAccessorGetter(Local<String> name,
1370 const AccessorInfo& info) {
1371 Handle<Object> self = info.This();
1372 return self->Get(String::Concat(v8_str("accessor_"), name));
1373}
1374
1375void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1376 const AccessorInfo& info) {
1377 Handle<Object> self = info.This();
1378 self->Set(String::Concat(v8_str("accessor_"), name), value);
1379}
1380
1381Handle<Value> EmptyInterceptorGetter(Local<String> name,
1382 const AccessorInfo& info) {
1383 return Handle<Value>();
1384}
1385
1386Handle<Value> EmptyInterceptorSetter(Local<String> name,
1387 Local<Value> value,
1388 const AccessorInfo& info) {
1389 return Handle<Value>();
1390}
1391
1392Handle<Value> InterceptorGetter(Local<String> name,
1393 const AccessorInfo& info) {
1394 // Intercept names that start with 'interceptor_'.
1395 String::AsciiValue ascii(name);
1396 char* name_str = *ascii;
1397 char prefix[] = "interceptor_";
1398 int i;
1399 for (i = 0; name_str[i] && prefix[i]; ++i) {
1400 if (name_str[i] != prefix[i]) return Handle<Value>();
1401 }
1402 Handle<Object> self = info.This();
1403 return self->GetHiddenValue(v8_str(name_str + i));
1404}
1405
1406Handle<Value> InterceptorSetter(Local<String> name,
1407 Local<Value> value,
1408 const AccessorInfo& info) {
1409 // Intercept accesses that set certain integer values.
1410 if (value->IsInt32() && value->Int32Value() < 10000) {
1411 Handle<Object> self = info.This();
1412 self->SetHiddenValue(name, value);
1413 return value;
1414 }
1415 return Handle<Value>();
1416}
1417
1418void AddAccessor(Handle<FunctionTemplate> templ,
1419 Handle<String> name,
1420 v8::AccessorGetter getter,
1421 v8::AccessorSetter setter) {
1422 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1423}
1424
1425void AddInterceptor(Handle<FunctionTemplate> templ,
1426 v8::NamedPropertyGetter getter,
1427 v8::NamedPropertySetter setter) {
1428 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1429}
1430
1431THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1432 v8::HandleScope scope;
1433 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1434 Handle<FunctionTemplate> child = FunctionTemplate::New();
1435 child->Inherit(parent);
1436 AddAccessor(parent, v8_str("age"),
1437 SimpleAccessorGetter, SimpleAccessorSetter);
1438 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1439 LocalContext env;
1440 env->Global()->Set(v8_str("Child"), child->GetFunction());
1441 CompileRun("var child = new Child;"
1442 "child.age = 10;");
1443 ExpectBoolean("child.hasOwnProperty('age')", false);
1444 ExpectInt32("child.age", 10);
1445 ExpectInt32("child.accessor_age", 10);
1446}
1447
1448THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1449 v8::HandleScope scope;
1450 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1451 Handle<FunctionTemplate> child = FunctionTemplate::New();
1452 child->Inherit(parent);
1453 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1454 LocalContext env;
1455 env->Global()->Set(v8_str("Child"), child->GetFunction());
1456 CompileRun("var child = new Child;"
1457 "var parent = child.__proto__;"
1458 "Object.defineProperty(parent, 'age', "
1459 " {get: function(){ return this.accessor_age; }, "
1460 " set: function(v){ this.accessor_age = v; }, "
1461 " enumerable: true, configurable: true});"
1462 "child.age = 10;");
1463 ExpectBoolean("child.hasOwnProperty('age')", false);
1464 ExpectInt32("child.age", 10);
1465 ExpectInt32("child.accessor_age", 10);
1466}
1467
1468THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1469 v8::HandleScope scope;
1470 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1471 Handle<FunctionTemplate> child = FunctionTemplate::New();
1472 child->Inherit(parent);
1473 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1474 LocalContext env;
1475 env->Global()->Set(v8_str("Child"), child->GetFunction());
1476 CompileRun("var child = new Child;"
1477 "var parent = child.__proto__;"
1478 "parent.name = 'Alice';");
1479 ExpectBoolean("child.hasOwnProperty('name')", false);
1480 ExpectString("child.name", "Alice");
1481 CompileRun("child.name = 'Bob';");
1482 ExpectString("child.name", "Bob");
1483 ExpectBoolean("child.hasOwnProperty('name')", true);
1484 ExpectString("parent.name", "Alice");
1485}
1486
1487THREADED_TEST(SwitchFromInterceptorToAccessor) {
1488 v8::HandleScope scope;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001489 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1490 AddAccessor(templ, v8_str("age"),
1491 SimpleAccessorGetter, SimpleAccessorSetter);
1492 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1493 LocalContext env;
1494 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1495 CompileRun("var obj = new Obj;"
1496 "function setAge(i){ obj.age = i; };"
1497 "for(var i = 0; i <= 10000; i++) setAge(i);");
1498 // All i < 10000 go to the interceptor.
1499 ExpectInt32("obj.interceptor_age", 9999);
1500 // The last i goes to the accessor.
1501 ExpectInt32("obj.accessor_age", 10000);
1502}
1503
1504THREADED_TEST(SwitchFromAccessorToInterceptor) {
1505 v8::HandleScope scope;
1506 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1507 AddAccessor(templ, v8_str("age"),
1508 SimpleAccessorGetter, SimpleAccessorSetter);
1509 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1510 LocalContext env;
1511 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1512 CompileRun("var obj = new Obj;"
1513 "function setAge(i){ obj.age = i; };"
1514 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1515 // All i >= 10000 go to the accessor.
1516 ExpectInt32("obj.accessor_age", 10000);
1517 // The last i goes to the interceptor.
1518 ExpectInt32("obj.interceptor_age", 9999);
1519}
1520
1521THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1522 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1524 Handle<FunctionTemplate> child = FunctionTemplate::New();
1525 child->Inherit(parent);
1526 AddAccessor(parent, v8_str("age"),
1527 SimpleAccessorGetter, SimpleAccessorSetter);
1528 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1529 LocalContext env;
1530 env->Global()->Set(v8_str("Child"), child->GetFunction());
1531 CompileRun("var child = new Child;"
1532 "function setAge(i){ child.age = i; };"
1533 "for(var i = 0; i <= 10000; i++) setAge(i);");
1534 // All i < 10000 go to the interceptor.
1535 ExpectInt32("child.interceptor_age", 9999);
1536 // The last i goes to the accessor.
1537 ExpectInt32("child.accessor_age", 10000);
1538}
1539
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001540THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 v8::HandleScope scope;
1542 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1543 Handle<FunctionTemplate> child = FunctionTemplate::New();
1544 child->Inherit(parent);
1545 AddAccessor(parent, v8_str("age"),
1546 SimpleAccessorGetter, SimpleAccessorSetter);
1547 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1548 LocalContext env;
1549 env->Global()->Set(v8_str("Child"), child->GetFunction());
1550 CompileRun("var child = new Child;"
1551 "function setAge(i){ child.age = i; };"
1552 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1553 // All i >= 10000 go to the accessor.
1554 ExpectInt32("child.accessor_age", 10000);
1555 // The last i goes to the interceptor.
1556 ExpectInt32("child.interceptor_age", 9999);
1557}
1558
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001559THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1560 v8::HandleScope scope;
1561 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1562 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1563 LocalContext env;
1564 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1565 CompileRun("var obj = new Obj;"
1566 "function setter(i) { this.accessor_age = i; };"
1567 "function getter() { return this.accessor_age; };"
1568 "function setAge(i) { obj.age = i; };"
1569 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1570 "for(var i = 0; i <= 10000; i++) setAge(i);");
1571 // All i < 10000 go to the interceptor.
1572 ExpectInt32("obj.interceptor_age", 9999);
1573 // The last i goes to the JavaScript accessor.
1574 ExpectInt32("obj.accessor_age", 10000);
1575 // The installed JavaScript getter is still intact.
1576 // This last part is a regression test for issue 1651 and relies on the fact
1577 // that both interceptor and accessor are being installed on the same object.
1578 ExpectInt32("obj.age", 10000);
1579 ExpectBoolean("obj.hasOwnProperty('age')", true);
1580 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1581}
1582
1583THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
1584 v8::HandleScope scope;
1585 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1586 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1587 LocalContext env;
1588 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1589 CompileRun("var obj = new Obj;"
1590 "function setter(i) { this.accessor_age = i; };"
1591 "function getter() { return this.accessor_age; };"
1592 "function setAge(i) { obj.age = i; };"
1593 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1594 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1595 // All i >= 10000 go to the accessor.
1596 ExpectInt32("obj.accessor_age", 10000);
1597 // The last i goes to the interceptor.
1598 ExpectInt32("obj.interceptor_age", 9999);
1599 // The installed JavaScript getter is still intact.
1600 // This last part is a regression test for issue 1651 and relies on the fact
1601 // that both interceptor and accessor are being installed on the same object.
1602 ExpectInt32("obj.age", 10000);
1603 ExpectBoolean("obj.hasOwnProperty('age')", true);
1604 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1605}
1606
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607THREADED_TEST(SwitchFromInterceptorToProperty) {
1608 v8::HandleScope scope;
1609 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1610 Handle<FunctionTemplate> child = FunctionTemplate::New();
1611 child->Inherit(parent);
1612 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1613 LocalContext env;
1614 env->Global()->Set(v8_str("Child"), child->GetFunction());
1615 CompileRun("var child = new Child;"
1616 "function setAge(i){ child.age = i; };"
1617 "for(var i = 0; i <= 10000; i++) setAge(i);");
1618 // All i < 10000 go to the interceptor.
1619 ExpectInt32("child.interceptor_age", 9999);
1620 // The last i goes to child's own property.
1621 ExpectInt32("child.age", 10000);
1622}
1623
1624THREADED_TEST(SwitchFromPropertyToInterceptor) {
1625 v8::HandleScope scope;
1626 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1627 Handle<FunctionTemplate> child = FunctionTemplate::New();
1628 child->Inherit(parent);
1629 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1630 LocalContext env;
1631 env->Global()->Set(v8_str("Child"), child->GetFunction());
1632 CompileRun("var child = new Child;"
1633 "function setAge(i){ child.age = i; };"
1634 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1635 // All i >= 10000 go to child's own property.
1636 ExpectInt32("child.age", 10000);
1637 // The last i goes to the interceptor.
1638 ExpectInt32("child.interceptor_age", 9999);
1639}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001640
1641THREADED_TEST(NamedPropertyHandlerGetter) {
1642 echo_named_call_count = 0;
1643 v8::HandleScope scope;
1644 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1645 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1646 0, 0, 0, 0,
1647 v8_str("data"));
1648 LocalContext env;
1649 env->Global()->Set(v8_str("obj"),
1650 templ->GetFunction()->NewInstance());
1651 CHECK_EQ(echo_named_call_count, 0);
1652 v8_compile("obj.x")->Run();
1653 CHECK_EQ(echo_named_call_count, 1);
1654 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1655 v8::Handle<Value> str = CompileRun(code);
1656 String::AsciiValue value(str);
1657 CHECK_EQ(*value, "oddlepoddle");
1658 // Check default behavior
1659 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1660 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1661 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1662}
1663
1664
1665int echo_indexed_call_count = 0;
1666
1667
1668static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1669 const AccessorInfo& info) {
1670 ApiTestFuzzer::Fuzz();
1671 CHECK_EQ(v8_num(637), info.Data());
1672 echo_indexed_call_count++;
1673 return v8_num(index);
1674}
1675
1676
1677THREADED_TEST(IndexedPropertyHandlerGetter) {
1678 v8::HandleScope scope;
1679 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1680 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1681 0, 0, 0, 0,
1682 v8_num(637));
1683 LocalContext env;
1684 env->Global()->Set(v8_str("obj"),
1685 templ->GetFunction()->NewInstance());
1686 Local<Script> script = v8_compile("obj[900]");
1687 CHECK_EQ(script->Run()->Int32Value(), 900);
1688}
1689
1690
1691v8::Handle<v8::Object> bottom;
1692
1693static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1694 uint32_t index,
1695 const AccessorInfo& info) {
1696 ApiTestFuzzer::Fuzz();
1697 CHECK(info.This()->Equals(bottom));
1698 return v8::Handle<Value>();
1699}
1700
1701static v8::Handle<Value> CheckThisNamedPropertyHandler(
1702 Local<String> name,
1703 const AccessorInfo& info) {
1704 ApiTestFuzzer::Fuzz();
1705 CHECK(info.This()->Equals(bottom));
1706 return v8::Handle<Value>();
1707}
1708
1709
1710v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1711 Local<Value> value,
1712 const AccessorInfo& info) {
1713 ApiTestFuzzer::Fuzz();
1714 CHECK(info.This()->Equals(bottom));
1715 return v8::Handle<Value>();
1716}
1717
1718
1719v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1720 Local<Value> value,
1721 const AccessorInfo& info) {
1722 ApiTestFuzzer::Fuzz();
1723 CHECK(info.This()->Equals(bottom));
1724 return v8::Handle<Value>();
1725}
1726
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001727v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001728 uint32_t index,
1729 const AccessorInfo& info) {
1730 ApiTestFuzzer::Fuzz();
1731 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001732 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001733}
1734
1735
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001736v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001737 const AccessorInfo& info) {
1738 ApiTestFuzzer::Fuzz();
1739 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001740 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001741}
1742
1743
1744v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1745 uint32_t index,
1746 const AccessorInfo& info) {
1747 ApiTestFuzzer::Fuzz();
1748 CHECK(info.This()->Equals(bottom));
1749 return v8::Handle<v8::Boolean>();
1750}
1751
1752
1753v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1754 Local<String> property,
1755 const AccessorInfo& info) {
1756 ApiTestFuzzer::Fuzz();
1757 CHECK(info.This()->Equals(bottom));
1758 return v8::Handle<v8::Boolean>();
1759}
1760
1761
1762v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1763 const AccessorInfo& info) {
1764 ApiTestFuzzer::Fuzz();
1765 CHECK(info.This()->Equals(bottom));
1766 return v8::Handle<v8::Array>();
1767}
1768
1769
1770v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1771 const AccessorInfo& info) {
1772 ApiTestFuzzer::Fuzz();
1773 CHECK(info.This()->Equals(bottom));
1774 return v8::Handle<v8::Array>();
1775}
1776
1777
1778THREADED_TEST(PropertyHandlerInPrototype) {
1779 v8::HandleScope scope;
1780 LocalContext env;
1781
1782 // Set up a prototype chain with three interceptors.
1783 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1784 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1785 CheckThisIndexedPropertyHandler,
1786 CheckThisIndexedPropertySetter,
1787 CheckThisIndexedPropertyQuery,
1788 CheckThisIndexedPropertyDeleter,
1789 CheckThisIndexedPropertyEnumerator);
1790
1791 templ->InstanceTemplate()->SetNamedPropertyHandler(
1792 CheckThisNamedPropertyHandler,
1793 CheckThisNamedPropertySetter,
1794 CheckThisNamedPropertyQuery,
1795 CheckThisNamedPropertyDeleter,
1796 CheckThisNamedPropertyEnumerator);
1797
1798 bottom = templ->GetFunction()->NewInstance();
1799 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1800 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1801
1802 bottom->Set(v8_str("__proto__"), middle);
1803 middle->Set(v8_str("__proto__"), top);
1804 env->Global()->Set(v8_str("obj"), bottom);
1805
1806 // Indexed and named get.
1807 Script::Compile(v8_str("obj[0]"))->Run();
1808 Script::Compile(v8_str("obj.x"))->Run();
1809
1810 // Indexed and named set.
1811 Script::Compile(v8_str("obj[1] = 42"))->Run();
1812 Script::Compile(v8_str("obj.y = 42"))->Run();
1813
1814 // Indexed and named query.
1815 Script::Compile(v8_str("0 in obj"))->Run();
1816 Script::Compile(v8_str("'x' in obj"))->Run();
1817
1818 // Indexed and named deleter.
1819 Script::Compile(v8_str("delete obj[0]"))->Run();
1820 Script::Compile(v8_str("delete obj.x"))->Run();
1821
1822 // Enumerators.
1823 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1824}
1825
1826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1828 const AccessorInfo& info) {
1829 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001830 if (v8_str("pre")->Equals(key)) {
1831 return v8_str("PrePropertyHandler: pre");
1832 }
1833 return v8::Handle<String>();
1834}
1835
1836
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001837static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1838 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001839 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001840 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001841 }
1842
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001843 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001844}
1845
1846
1847THREADED_TEST(PrePropertyHandler) {
1848 v8::HandleScope scope;
1849 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1850 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1851 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001852 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001853 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001854 Script::Compile(v8_str(
1855 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1856 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1857 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1858 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1859 CHECK_EQ(v8_str("Object: on"), result_on);
1860 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1861 CHECK(result_post.IsEmpty());
1862}
1863
1864
ager@chromium.org870a0b62008-11-04 11:43:05 +00001865THREADED_TEST(UndefinedIsNotEnumerable) {
1866 v8::HandleScope scope;
1867 LocalContext env;
1868 v8::Handle<Value> result = Script::Compile(v8_str(
1869 "this.propertyIsEnumerable(undefined)"))->Run();
1870 CHECK(result->IsFalse());
1871}
1872
1873
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001874v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001875static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001876
1877
1878static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1879 ApiTestFuzzer::Fuzz();
1880 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1881 if (depth == kTargetRecursionDepth) return v8::Undefined();
1882 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1883 return call_recursively_script->Run();
1884}
1885
1886
1887static v8::Handle<Value> CallFunctionRecursivelyCall(
1888 const v8::Arguments& args) {
1889 ApiTestFuzzer::Fuzz();
1890 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1891 if (depth == kTargetRecursionDepth) {
1892 printf("[depth = %d]\n", depth);
1893 return v8::Undefined();
1894 }
1895 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1896 v8::Handle<Value> function =
1897 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001898 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001899}
1900
1901
1902THREADED_TEST(DeepCrossLanguageRecursion) {
1903 v8::HandleScope scope;
1904 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1905 global->Set(v8_str("callScriptRecursively"),
1906 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1907 global->Set(v8_str("callFunctionRecursively"),
1908 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1909 LocalContext env(NULL, global);
1910
1911 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1912 call_recursively_script = v8_compile("callScriptRecursively()");
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001913 call_recursively_script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 call_recursively_script = v8::Handle<Script>();
1915
1916 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1917 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1918}
1919
1920
1921static v8::Handle<Value>
1922 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1923 ApiTestFuzzer::Fuzz();
1924 return v8::ThrowException(key);
1925}
1926
1927
1928static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1929 Local<Value>,
1930 const AccessorInfo&) {
1931 v8::ThrowException(key);
1932 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1933}
1934
1935
1936THREADED_TEST(CallbackExceptionRegression) {
1937 v8::HandleScope scope;
1938 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1939 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1940 ThrowingPropertyHandlerSet);
1941 LocalContext env;
1942 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1943 v8::Handle<Value> otto = Script::Compile(v8_str(
1944 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1945 CHECK_EQ(v8_str("otto"), otto);
1946 v8::Handle<Value> netto = Script::Compile(v8_str(
1947 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1948 CHECK_EQ(v8_str("netto"), netto);
1949}
1950
1951
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952THREADED_TEST(FunctionPrototype) {
1953 v8::HandleScope scope;
1954 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1955 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1956 LocalContext env;
1957 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1958 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1959 CHECK_EQ(script->Run()->Int32Value(), 321);
1960}
1961
1962
1963THREADED_TEST(InternalFields) {
1964 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001965 LocalContext env;
1966
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001967 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1968 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1969 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001970 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1971 CHECK_EQ(1, obj->InternalFieldCount());
1972 CHECK(obj->GetInternalField(0)->IsUndefined());
1973 obj->SetInternalField(0, v8_num(17));
1974 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1975}
1976
1977
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001978THREADED_TEST(GlobalObjectInternalFields) {
1979 v8::HandleScope scope;
1980 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1981 global_template->SetInternalFieldCount(1);
1982 LocalContext env(NULL, global_template);
1983 v8::Handle<v8::Object> global_proxy = env->Global();
1984 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1985 CHECK_EQ(1, global->InternalFieldCount());
1986 CHECK(global->GetInternalField(0)->IsUndefined());
1987 global->SetInternalField(0, v8_num(17));
1988 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1989}
1990
1991
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001992THREADED_TEST(InternalFieldsNativePointers) {
1993 v8::HandleScope scope;
1994 LocalContext env;
1995
1996 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1997 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1998 instance_templ->SetInternalFieldCount(1);
1999 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2000 CHECK_EQ(1, obj->InternalFieldCount());
2001 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2002
2003 char* data = new char[100];
2004
2005 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002006 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002007 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002008 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002009
2010 // Check reading and writing aligned pointers.
2011 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002012 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002013 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2014
2015 // Check reading and writing unaligned pointers.
2016 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002017 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002018 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2019
2020 delete[] data;
2021}
2022
2023
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002024THREADED_TEST(InternalFieldsNativePointersAndExternal) {
2025 v8::HandleScope scope;
2026 LocalContext env;
2027
2028 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2029 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2030 instance_templ->SetInternalFieldCount(1);
2031 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2032 CHECK_EQ(1, obj->InternalFieldCount());
2033 CHECK(obj->GetPointerFromInternalField(0) == NULL);
2034
2035 char* data = new char[100];
2036
2037 void* aligned = data;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002038 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002039 void* unaligned = data + 1;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002040 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002041
2042 obj->SetPointerInInternalField(0, aligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002043 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002044 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
2045
2046 obj->SetPointerInInternalField(0, unaligned);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002047 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002048 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
2049
2050 obj->SetInternalField(0, v8::External::Wrap(aligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002051 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002052 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
2053
2054 obj->SetInternalField(0, v8::External::Wrap(unaligned));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002055 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002056 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
2057
2058 delete[] data;
2059}
2060
2061
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002062static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2063 void* value) {
2064 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2065 obj->SetPointerInInternalField(0, value);
2066 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2067 CHECK_EQ(value, obj->GetPointerFromInternalField(0));
2068}
2069
2070
2071THREADED_TEST(InternalFieldsAlignedPointers) {
2072 v8::HandleScope scope;
2073 LocalContext env;
2074
2075 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2076 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2077 instance_templ->SetInternalFieldCount(1);
2078 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2079 CHECK_EQ(1, obj->InternalFieldCount());
2080
2081 CheckAlignedPointerInInternalField(obj, NULL);
2082
2083 int* heap_allocated = new int[100];
2084 CheckAlignedPointerInInternalField(obj, heap_allocated);
2085 delete[] heap_allocated;
2086
2087 int stack_allocated[100];
2088 CheckAlignedPointerInInternalField(obj, stack_allocated);
2089
2090 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2091 CheckAlignedPointerInInternalField(obj, huge);
2092}
2093
2094
2095static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2096 int index,
2097 void* value) {
2098 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2099 (*env)->SetAlignedPointerInEmbedderData(index, value);
2100 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2101 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2102}
2103
2104
2105static void* AlignedTestPointer(int i) {
2106 return reinterpret_cast<void*>(i * 1234);
2107}
2108
2109
2110THREADED_TEST(EmbedderDataAlignedPointers) {
2111 v8::HandleScope scope;
2112 LocalContext env;
2113
2114 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2115
2116 int* heap_allocated = new int[100];
2117 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2118 delete[] heap_allocated;
2119
2120 int stack_allocated[100];
2121 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2122
2123 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2124 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2125
2126 // Test growing of the embedder data's backing store.
2127 for (int i = 0; i < 100; i++) {
2128 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2129 }
2130 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2131 for (int i = 0; i < 100; i++) {
2132 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2133 }
2134}
2135
2136
2137static void CheckEmbedderData(LocalContext* env,
2138 int index,
2139 v8::Handle<Value> data) {
2140 (*env)->SetEmbedderData(index, data);
2141 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2142}
2143
2144THREADED_TEST(EmbedderData) {
2145 v8::HandleScope scope;
2146 LocalContext env;
2147
2148 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2149 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2150 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2151 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2152}
2153
2154
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002155THREADED_TEST(IdentityHash) {
2156 v8::HandleScope scope;
2157 LocalContext env;
2158
2159 // Ensure that the test starts with an fresh heap to test whether the hash
2160 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002161 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002162 Local<v8::Object> obj = v8::Object::New();
2163 int hash = obj->GetIdentityHash();
2164 int hash1 = obj->GetIdentityHash();
2165 CHECK_EQ(hash, hash1);
2166 int hash2 = v8::Object::New()->GetIdentityHash();
2167 // Since the identity hash is essentially a random number two consecutive
2168 // objects should not be assigned the same hash code. If the test below fails
2169 // the random number generator should be evaluated.
2170 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002171 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002172 int hash3 = v8::Object::New()->GetIdentityHash();
2173 // Make sure that the identity hash is not based on the initial address of
2174 // the object alone. If the test below fails the random number generator
2175 // should be evaluated.
2176 CHECK_NE(hash, hash3);
2177 int hash4 = obj->GetIdentityHash();
2178 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002179
2180 // Check identity hashes behaviour in the presence of JS accessors.
2181 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2182 {
2183 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2184 Local<v8::Object> o1 = v8::Object::New();
2185 Local<v8::Object> o2 = v8::Object::New();
2186 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2187 }
2188 {
2189 CompileRun(
2190 "function cnst() { return 42; };\n"
2191 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2192 Local<v8::Object> o1 = v8::Object::New();
2193 Local<v8::Object> o2 = v8::Object::New();
2194 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2195 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002196}
2197
2198
2199THREADED_TEST(HiddenProperties) {
2200 v8::HandleScope scope;
2201 LocalContext env;
2202
2203 v8::Local<v8::Object> obj = v8::Object::New();
2204 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2205 v8::Local<v8::String> empty = v8_str("");
2206 v8::Local<v8::String> prop_name = v8_str("prop_name");
2207
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002208 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002209
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002210 // Make sure delete of a non-existent hidden value works
2211 CHECK(obj->DeleteHiddenValue(key));
2212
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002213 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2214 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2215 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2216 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2217
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002218 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002219
2220 // Make sure we do not find the hidden property.
2221 CHECK(!obj->Has(empty));
2222 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2223 CHECK(obj->Get(empty)->IsUndefined());
2224 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2225 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2227 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2228
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002229 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002230
2231 // Add another property and delete it afterwards to force the object in
2232 // slow case.
2233 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2234 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2235 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2236 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2237 CHECK(obj->Delete(prop_name));
2238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2239
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002240 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002241
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002242 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2243 CHECK(obj->GetHiddenValue(key).IsEmpty());
2244
2245 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002246 CHECK(obj->DeleteHiddenValue(key));
2247 CHECK(obj->GetHiddenValue(key).IsEmpty());
2248}
2249
2250
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002251THREADED_TEST(Regress97784) {
2252 // Regression test for crbug.com/97784
2253 // Messing with the Object.prototype should not have effect on
2254 // hidden properties.
2255 v8::HandleScope scope;
2256 LocalContext env;
2257
2258 v8::Local<v8::Object> obj = v8::Object::New();
2259 v8::Local<v8::String> key = v8_str("hidden");
2260
2261 CompileRun(
2262 "set_called = false;"
2263 "Object.defineProperty("
2264 " Object.prototype,"
2265 " 'hidden',"
2266 " {get: function() { return 45; },"
2267 " set: function() { set_called = true; }})");
2268
2269 CHECK(obj->GetHiddenValue(key).IsEmpty());
2270 // Make sure that the getter and setter from Object.prototype is not invoked.
2271 // If it did we would have full access to the hidden properties in
2272 // the accessor.
2273 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2274 ExpectFalse("set_called");
2275 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2276}
2277
2278
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002279static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002280static v8::Handle<Value> InterceptorForHiddenProperties(
2281 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002282 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002283 return v8::Handle<Value>();
2284}
2285
2286
2287THREADED_TEST(HiddenPropertiesWithInterceptors) {
2288 v8::HandleScope scope;
2289 LocalContext context;
2290
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002291 interceptor_for_hidden_properties_called = false;
2292
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002293 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2294
2295 // Associate an interceptor with an object and start setting hidden values.
2296 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2297 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2298 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2299 Local<v8::Function> function = fun_templ->GetFunction();
2300 Local<v8::Object> obj = function->NewInstance();
2301 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2302 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002303 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002304}
2305
2306
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002307THREADED_TEST(External) {
2308 v8::HandleScope scope;
2309 int x = 3;
2310 Local<v8::External> ext = v8::External::New(&x);
2311 LocalContext env;
2312 env->Global()->Set(v8_str("ext"), ext);
2313 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002314 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002315 int* ptr = static_cast<int*>(reext->Value());
2316 CHECK_EQ(x, 3);
2317 *ptr = 10;
2318 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002319
2320 // Make sure unaligned pointers are wrapped properly.
2321 char* data = i::StrDup("0123456789");
2322 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2323 Local<v8::Value> one = v8::External::Wrap(&data[1]);
2324 Local<v8::Value> two = v8::External::Wrap(&data[2]);
2325 Local<v8::Value> three = v8::External::Wrap(&data[3]);
2326
2327 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2328 CHECK_EQ('0', *char_ptr);
2329 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2330 CHECK_EQ('1', *char_ptr);
2331 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2332 CHECK_EQ('2', *char_ptr);
2333 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2334 CHECK_EQ('3', *char_ptr);
2335 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002336}
2337
2338
2339THREADED_TEST(GlobalHandle) {
2340 v8::Persistent<String> global;
2341 {
2342 v8::HandleScope scope;
2343 Local<String> str = v8_str("str");
2344 global = v8::Persistent<String>::New(str);
2345 }
2346 CHECK_EQ(global->Length(), 3);
2347 global.Dispose();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002348
2349 {
2350 v8::HandleScope scope;
2351 Local<String> str = v8_str("str");
2352 global = v8::Persistent<String>::New(str);
2353 }
2354 CHECK_EQ(global->Length(), 3);
2355 global.Dispose(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002356}
2357
2358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359class WeakCallCounter {
2360 public:
2361 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2362 int id() { return id_; }
2363 void increment() { number_of_weak_calls_++; }
2364 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2365 private:
2366 int id_;
2367 int number_of_weak_calls_;
2368};
2369
2370
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002371static void WeakPointerCallback(Persistent<Value> handle, void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2373 CHECK_EQ(1234, counter->id());
2374 counter->increment();
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002375 handle.Dispose();
2376}
2377
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002378
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002379THREADED_TEST(ApiObjectGroups) {
2380 HandleScope scope;
2381 LocalContext env;
2382
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002383 Persistent<Object> g1s1;
2384 Persistent<Object> g1s2;
2385 Persistent<Object> g1c1;
2386 Persistent<Object> g2s1;
2387 Persistent<Object> g2s2;
2388 Persistent<Object> g2c1;
2389
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002390 WeakCallCounter counter(1234);
2391
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002392 {
2393 HandleScope scope;
2394 g1s1 = Persistent<Object>::New(Object::New());
2395 g1s2 = Persistent<Object>::New(Object::New());
2396 g1c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002397 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2398 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2399 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002400
2401 g2s1 = Persistent<Object>::New(Object::New());
2402 g2s2 = Persistent<Object>::New(Object::New());
2403 g2c1 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002404 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2405 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2406 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002407 }
2408
2409 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2410
2411 // Connect group 1 and 2, make a cycle.
2412 CHECK(g1s2->Set(0, g2s2));
2413 CHECK(g2s1->Set(0, g1s1));
2414
2415 {
2416 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2417 Persistent<Value> g1_children[] = { g1c1 };
2418 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2419 Persistent<Value> g2_children[] = { g2c1 };
2420 V8::AddObjectGroup(g1_objects, 2);
2421 V8::AddImplicitReferences(g1s1, g1_children, 1);
2422 V8::AddObjectGroup(g2_objects, 2);
2423 V8::AddImplicitReferences(g2s2, g2_children, 1);
2424 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002425 // Do a single full GC, ensure incremental marking is stopped.
2426 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002427
2428 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002429 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002430
2431 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002432 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002433 // But make children strong roots---all the objects (except for children)
2434 // should be collectable now.
2435 g1c1.ClearWeak();
2436 g2c1.ClearWeak();
2437
2438 // Groups are deleted, rebuild groups.
2439 {
2440 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2441 Persistent<Value> g1_children[] = { g1c1 };
2442 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2443 Persistent<Value> g2_children[] = { g2c1 };
2444 V8::AddObjectGroup(g1_objects, 2);
2445 V8::AddImplicitReferences(g1s1, g1_children, 1);
2446 V8::AddObjectGroup(g2_objects, 2);
2447 V8::AddImplicitReferences(g2s2, g2_children, 1);
2448 }
2449
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002450 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002451
2452 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002453 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002454
2455 // And now make children weak again and collect them.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002456 g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2457 g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002458
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002459 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002460 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002461}
2462
2463
2464THREADED_TEST(ApiObjectGroupsCycle) {
2465 HandleScope scope;
2466 LocalContext env;
2467
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002468 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002469
2470 Persistent<Object> g1s1;
2471 Persistent<Object> g1s2;
2472 Persistent<Object> g2s1;
2473 Persistent<Object> g2s2;
2474 Persistent<Object> g3s1;
2475 Persistent<Object> g3s2;
2476
2477 {
2478 HandleScope scope;
2479 g1s1 = Persistent<Object>::New(Object::New());
2480 g1s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002481 g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2482 g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002483
2484 g2s1 = Persistent<Object>::New(Object::New());
2485 g2s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002486 g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2487 g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002488
2489 g3s1 = Persistent<Object>::New(Object::New());
2490 g3s2 = Persistent<Object>::New(Object::New());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002491 g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2492 g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002493 }
2494
2495 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
2496
2497 // Connect groups. We're building the following cycle:
2498 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2499 // groups.
2500 {
2501 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2502 Persistent<Value> g1_children[] = { g2s1 };
2503 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2504 Persistent<Value> g2_children[] = { g3s1 };
2505 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2506 Persistent<Value> g3_children[] = { g1s1 };
2507 V8::AddObjectGroup(g1_objects, 2);
2508 V8::AddImplicitReferences(g1s1, g1_children, 1);
2509 V8::AddObjectGroup(g2_objects, 2);
2510 V8::AddImplicitReferences(g2s1, g2_children, 1);
2511 V8::AddObjectGroup(g3_objects, 2);
2512 V8::AddImplicitReferences(g3s1, g3_children, 1);
2513 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002514 // Do a single full GC
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002515 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002516
2517 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002518 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002519
2520 // Weaken the root.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002521 root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002522
2523 // Groups are deleted, rebuild groups.
2524 {
2525 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2526 Persistent<Value> g1_children[] = { g2s1 };
2527 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2528 Persistent<Value> g2_children[] = { g3s1 };
2529 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2530 Persistent<Value> g3_children[] = { g1s1 };
2531 V8::AddObjectGroup(g1_objects, 2);
2532 V8::AddImplicitReferences(g1s1, g1_children, 1);
2533 V8::AddObjectGroup(g2_objects, 2);
2534 V8::AddImplicitReferences(g2s1, g2_children, 1);
2535 V8::AddObjectGroup(g3_objects, 2);
2536 V8::AddImplicitReferences(g3s1, g3_children, 1);
2537 }
2538
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002539 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002540
2541 // All objects should be gone. 7 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002542 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002543}
2544
2545
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002546THREADED_TEST(ScriptException) {
2547 v8::HandleScope scope;
2548 LocalContext env;
2549 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2550 v8::TryCatch try_catch;
2551 Local<Value> result = script->Run();
2552 CHECK(result.IsEmpty());
2553 CHECK(try_catch.HasCaught());
2554 String::AsciiValue exception_value(try_catch.Exception());
2555 CHECK_EQ(*exception_value, "panama!");
2556}
2557
2558
2559bool message_received;
2560
2561
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002562static void check_message_0(v8::Handle<v8::Message> message,
2563 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002564 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002565 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002566 message_received = true;
2567}
2568
2569
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002570THREADED_TEST(MessageHandler0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002571 message_received = false;
2572 v8::HandleScope scope;
2573 CHECK(!message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002574 v8::V8::AddMessageListener(check_message_0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002575 LocalContext context;
2576 v8::ScriptOrigin origin =
2577 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002578 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2579 &origin);
2580 script->SetData(v8_str("7.56"));
2581 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002582 CHECK(message_received);
2583 // clear out the message listener
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002584 v8::V8::RemoveMessageListeners(check_message_0);
2585}
2586
2587
2588static void check_message_1(v8::Handle<v8::Message> message,
2589 v8::Handle<Value> data) {
2590 CHECK(data->IsNumber());
2591 CHECK_EQ(1337, data->Int32Value());
2592 message_received = true;
2593}
2594
2595
2596TEST(MessageHandler1) {
2597 message_received = false;
2598 v8::HandleScope scope;
2599 CHECK(!message_received);
2600 v8::V8::AddMessageListener(check_message_1);
2601 LocalContext context;
2602 CompileRun("throw 1337;");
2603 CHECK(message_received);
2604 // clear out the message listener
2605 v8::V8::RemoveMessageListeners(check_message_1);
2606}
2607
2608
2609static void check_message_2(v8::Handle<v8::Message> message,
2610 v8::Handle<Value> data) {
2611 LocalContext context;
2612 CHECK(data->IsObject());
2613 v8::Local<v8::Value> hidden_property =
2614 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2615 CHECK(v8_str("hidden value")->Equals(hidden_property));
2616 message_received = true;
2617}
2618
2619
2620TEST(MessageHandler2) {
2621 message_received = false;
2622 v8::HandleScope scope;
2623 CHECK(!message_received);
2624 v8::V8::AddMessageListener(check_message_2);
2625 LocalContext context;
2626 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2627 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2628 v8_str("hidden value"));
2629 context->Global()->Set(v8_str("error"), error);
2630 CompileRun("throw error;");
2631 CHECK(message_received);
2632 // clear out the message listener
2633 v8::V8::RemoveMessageListeners(check_message_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002634}
2635
2636
2637THREADED_TEST(GetSetProperty) {
2638 v8::HandleScope scope;
2639 LocalContext context;
2640 context->Global()->Set(v8_str("foo"), v8_num(14));
2641 context->Global()->Set(v8_str("12"), v8_num(92));
2642 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2643 context->Global()->Set(v8_num(13), v8_num(56));
2644 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2645 CHECK_EQ(14, foo->Int32Value());
2646 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2647 CHECK_EQ(92, twelve->Int32Value());
2648 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2649 CHECK_EQ(32, sixteen->Int32Value());
2650 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2651 CHECK_EQ(56, thirteen->Int32Value());
2652 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2653 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2654 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2655 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2656 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2657 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2658 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2659 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2660 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2661}
2662
2663
2664THREADED_TEST(PropertyAttributes) {
2665 v8::HandleScope scope;
2666 LocalContext context;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002667 // none
2668 Local<String> prop = v8_str("none");
2669 context->Global()->Set(prop, v8_num(7));
2670 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002671 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002672 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002673 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2674 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002675 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002676 Script::Compile(v8_str("read_only = 9"))->Run();
2677 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2678 context->Global()->Set(prop, v8_num(10));
2679 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2680 // dont-delete
2681 prop = v8_str("dont_delete");
2682 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2683 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2684 Script::Compile(v8_str("delete dont_delete"))->Run();
2685 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002686 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2687 // dont-enum
2688 prop = v8_str("dont_enum");
2689 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2690 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2691 // absent
2692 prop = v8_str("absent");
2693 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2694 Local<Value> fake_prop = v8_num(1);
2695 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2696 // exception
2697 TryCatch try_catch;
2698 Local<Value> exception =
2699 CompileRun("({ toString: function() { throw 'exception';} })");
2700 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2701 CHECK(try_catch.HasCaught());
2702 String::AsciiValue exception_value(try_catch.Exception());
2703 CHECK_EQ("exception", *exception_value);
2704 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002705}
2706
2707
2708THREADED_TEST(Array) {
2709 v8::HandleScope scope;
2710 LocalContext context;
2711 Local<v8::Array> array = v8::Array::New();
2712 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002713 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002714 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002715 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002716 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002717 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002718 CHECK_EQ(3, array->Length());
2719 CHECK(!array->Has(0));
2720 CHECK(!array->Has(1));
2721 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002722 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002723 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002724 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002725 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002726 CHECK_EQ(1, arr->Get(0)->Int32Value());
2727 CHECK_EQ(2, arr->Get(1)->Int32Value());
2728 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002729 array = v8::Array::New(27);
2730 CHECK_EQ(27, array->Length());
2731 array = v8::Array::New(-27);
2732 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002733}
2734
2735
2736v8::Handle<Value> HandleF(const v8::Arguments& args) {
2737 v8::HandleScope scope;
2738 ApiTestFuzzer::Fuzz();
2739 Local<v8::Array> result = v8::Array::New(args.Length());
2740 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002741 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002742 return scope.Close(result);
2743}
2744
2745
2746THREADED_TEST(Vector) {
2747 v8::HandleScope scope;
2748 Local<ObjectTemplate> global = ObjectTemplate::New();
2749 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2750 LocalContext context(0, global);
2751
2752 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002753 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002754 CHECK_EQ(0, a0->Length());
2755
2756 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002757 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002758 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002759 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002760
2761 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002762 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002763 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002764 CHECK_EQ(12, a2->Get(0)->Int32Value());
2765 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002766
2767 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002768 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002769 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002770 CHECK_EQ(14, a3->Get(0)->Int32Value());
2771 CHECK_EQ(15, a3->Get(1)->Int32Value());
2772 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002773
2774 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002775 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002776 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002777 CHECK_EQ(17, a4->Get(0)->Int32Value());
2778 CHECK_EQ(18, a4->Get(1)->Int32Value());
2779 CHECK_EQ(19, a4->Get(2)->Int32Value());
2780 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002781}
2782
2783
2784THREADED_TEST(FunctionCall) {
2785 v8::HandleScope scope;
2786 LocalContext context;
2787 CompileRun(
2788 "function Foo() {"
2789 " var result = [];"
2790 " for (var i = 0; i < arguments.length; i++) {"
2791 " result.push(arguments[i]);"
2792 " }"
2793 " return result;"
2794 "}");
2795 Local<Function> Foo =
2796 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2797
2798 v8::Handle<Value>* args0 = NULL;
2799 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2800 CHECK_EQ(0, a0->Length());
2801
2802 v8::Handle<Value> args1[] = { v8_num(1.1) };
2803 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2804 CHECK_EQ(1, a1->Length());
2805 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2806
2807 v8::Handle<Value> args2[] = { v8_num(2.2),
2808 v8_num(3.3) };
2809 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2810 CHECK_EQ(2, a2->Length());
2811 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2812 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2813
2814 v8::Handle<Value> args3[] = { v8_num(4.4),
2815 v8_num(5.5),
2816 v8_num(6.6) };
2817 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2818 CHECK_EQ(3, a3->Length());
2819 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2820 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2821 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2822
2823 v8::Handle<Value> args4[] = { v8_num(7.7),
2824 v8_num(8.8),
2825 v8_num(9.9),
2826 v8_num(10.11) };
2827 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2828 CHECK_EQ(4, a4->Length());
2829 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2830 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2831 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2832 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2833}
2834
2835
2836static const char* js_code_causing_out_of_memory =
2837 "var a = new Array(); while(true) a.push(a);";
2838
2839
2840// These tests run for a long time and prevent us from running tests
2841// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002842TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002843 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002844 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002845 // Set heap limits.
2846 static const int K = 1024;
2847 v8::ResourceConstraints constraints;
2848 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002849 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002850 v8::SetResourceConstraints(&constraints);
2851
2852 // Execute a script that causes out of memory.
2853 v8::HandleScope scope;
2854 LocalContext context;
2855 v8::V8::IgnoreOutOfMemoryException();
2856 Local<Script> script =
2857 Script::Compile(String::New(js_code_causing_out_of_memory));
2858 Local<Value> result = script->Run();
2859
2860 // Check for out of memory state.
2861 CHECK(result.IsEmpty());
2862 CHECK(context->HasOutOfMemoryException());
2863}
2864
2865
2866v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2867 ApiTestFuzzer::Fuzz();
2868
2869 v8::HandleScope scope;
2870 LocalContext context;
2871 Local<Script> script =
2872 Script::Compile(String::New(js_code_causing_out_of_memory));
2873 Local<Value> result = script->Run();
2874
2875 // Check for out of memory state.
2876 CHECK(result.IsEmpty());
2877 CHECK(context->HasOutOfMemoryException());
2878
2879 return result;
2880}
2881
2882
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002883TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002884 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002885 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002886 // Set heap limits.
2887 static const int K = 1024;
2888 v8::ResourceConstraints constraints;
2889 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002890 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002891 v8::SetResourceConstraints(&constraints);
2892
2893 v8::HandleScope scope;
2894 Local<ObjectTemplate> templ = ObjectTemplate::New();
2895 templ->Set(v8_str("ProvokeOutOfMemory"),
2896 v8::FunctionTemplate::New(ProvokeOutOfMemory));
2897 LocalContext context(0, templ);
2898 v8::V8::IgnoreOutOfMemoryException();
2899 Local<Value> result = CompileRun(
2900 "var thrown = false;"
2901 "try {"
2902 " ProvokeOutOfMemory();"
2903 "} catch (e) {"
2904 " thrown = true;"
2905 "}");
2906 // Check for out of memory state.
2907 CHECK(result.IsEmpty());
2908 CHECK(context->HasOutOfMemoryException());
2909}
2910
2911
2912TEST(HugeConsStringOutOfMemory) {
2913 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002915 // Set heap limits.
2916 static const int K = 1024;
2917 v8::ResourceConstraints constraints;
2918 constraints.set_max_young_space_size(256 * K);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002919 constraints.set_max_old_space_size(3 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002920 v8::SetResourceConstraints(&constraints);
2921
2922 // Execute a script that causes out of memory.
2923 v8::V8::IgnoreOutOfMemoryException();
2924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002925 v8::HandleScope scope;
2926 LocalContext context;
2927
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002928 // Build huge string. This should fail with out of memory exception.
2929 Local<Value> result = CompileRun(
2930 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002931 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002932
2933 // Check for out of memory state.
2934 CHECK(result.IsEmpty());
2935 CHECK(context->HasOutOfMemoryException());
2936}
2937
2938
2939THREADED_TEST(ConstructCall) {
2940 v8::HandleScope scope;
2941 LocalContext context;
2942 CompileRun(
2943 "function Foo() {"
2944 " var result = [];"
2945 " for (var i = 0; i < arguments.length; i++) {"
2946 " result.push(arguments[i]);"
2947 " }"
2948 " return result;"
2949 "}");
2950 Local<Function> Foo =
2951 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2952
2953 v8::Handle<Value>* args0 = NULL;
2954 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2955 CHECK_EQ(0, a0->Length());
2956
2957 v8::Handle<Value> args1[] = { v8_num(1.1) };
2958 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2959 CHECK_EQ(1, a1->Length());
2960 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2961
2962 v8::Handle<Value> args2[] = { v8_num(2.2),
2963 v8_num(3.3) };
2964 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2965 CHECK_EQ(2, a2->Length());
2966 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2967 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2968
2969 v8::Handle<Value> args3[] = { v8_num(4.4),
2970 v8_num(5.5),
2971 v8_num(6.6) };
2972 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2973 CHECK_EQ(3, a3->Length());
2974 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2975 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2976 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2977
2978 v8::Handle<Value> args4[] = { v8_num(7.7),
2979 v8_num(8.8),
2980 v8_num(9.9),
2981 v8_num(10.11) };
2982 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2983 CHECK_EQ(4, a4->Length());
2984 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2985 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2986 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2987 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2988}
2989
2990
2991static void CheckUncle(v8::TryCatch* try_catch) {
2992 CHECK(try_catch->HasCaught());
2993 String::AsciiValue str_value(try_catch->Exception());
2994 CHECK_EQ(*str_value, "uncle?");
2995 try_catch->Reset();
2996}
2997
2998
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002999THREADED_TEST(ConversionNumber) {
3000 v8::HandleScope scope;
3001 LocalContext env;
3002 // Very large number.
3003 CompileRun("var obj = Math.pow(2,32) * 1237;");
3004 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3005 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
3006 CHECK_EQ(0, obj->ToInt32()->Value());
3007 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
3008 // Large number.
3009 CompileRun("var obj = -1234567890123;");
3010 obj = env->Global()->Get(v8_str("obj"));
3011 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
3012 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
3013 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
3014 // Small positive integer.
3015 CompileRun("var obj = 42;");
3016 obj = env->Global()->Get(v8_str("obj"));
3017 CHECK_EQ(42.0, obj->ToNumber()->Value());
3018 CHECK_EQ(42, obj->ToInt32()->Value());
3019 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3020 // Negative integer.
3021 CompileRun("var obj = -37;");
3022 obj = env->Global()->Get(v8_str("obj"));
3023 CHECK_EQ(-37.0, obj->ToNumber()->Value());
3024 CHECK_EQ(-37, obj->ToInt32()->Value());
3025 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
3026 // Positive non-int32 integer.
3027 CompileRun("var obj = 0x81234567;");
3028 obj = env->Global()->Get(v8_str("obj"));
3029 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
3030 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
3031 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
3032 // Fraction.
3033 CompileRun("var obj = 42.3;");
3034 obj = env->Global()->Get(v8_str("obj"));
3035 CHECK_EQ(42.3, obj->ToNumber()->Value());
3036 CHECK_EQ(42, obj->ToInt32()->Value());
3037 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3038 // Large negative fraction.
3039 CompileRun("var obj = -5726623061.75;");
3040 obj = env->Global()->Get(v8_str("obj"));
3041 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
3042 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
3043 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
3044}
3045
3046
3047THREADED_TEST(isNumberType) {
3048 v8::HandleScope scope;
3049 LocalContext env;
3050 // Very large number.
3051 CompileRun("var obj = Math.pow(2,32) * 1237;");
3052 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3053 CHECK(!obj->IsInt32());
3054 CHECK(!obj->IsUint32());
3055 // Large negative number.
3056 CompileRun("var obj = -1234567890123;");
3057 obj = env->Global()->Get(v8_str("obj"));
3058 CHECK(!obj->IsInt32());
3059 CHECK(!obj->IsUint32());
3060 // Small positive integer.
3061 CompileRun("var obj = 42;");
3062 obj = env->Global()->Get(v8_str("obj"));
3063 CHECK(obj->IsInt32());
3064 CHECK(obj->IsUint32());
3065 // Negative integer.
3066 CompileRun("var obj = -37;");
3067 obj = env->Global()->Get(v8_str("obj"));
3068 CHECK(obj->IsInt32());
3069 CHECK(!obj->IsUint32());
3070 // Positive non-int32 integer.
3071 CompileRun("var obj = 0x81234567;");
3072 obj = env->Global()->Get(v8_str("obj"));
3073 CHECK(!obj->IsInt32());
3074 CHECK(obj->IsUint32());
3075 // Fraction.
3076 CompileRun("var obj = 42.3;");
3077 obj = env->Global()->Get(v8_str("obj"));
3078 CHECK(!obj->IsInt32());
3079 CHECK(!obj->IsUint32());
3080 // Large negative fraction.
3081 CompileRun("var obj = -5726623061.75;");
3082 obj = env->Global()->Get(v8_str("obj"));
3083 CHECK(!obj->IsInt32());
3084 CHECK(!obj->IsUint32());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003085 // Positive zero
3086 CompileRun("var obj = 0.0;");
3087 obj = env->Global()->Get(v8_str("obj"));
3088 CHECK(obj->IsInt32());
3089 CHECK(obj->IsUint32());
3090 // Positive zero
3091 CompileRun("var obj = -0.0;");
3092 obj = env->Global()->Get(v8_str("obj"));
3093 CHECK(!obj->IsInt32());
3094 CHECK(!obj->IsUint32());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003095}
3096
3097
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003098THREADED_TEST(ConversionException) {
3099 v8::HandleScope scope;
3100 LocalContext env;
3101 CompileRun(
3102 "function TestClass() { };"
3103 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3104 "var obj = new TestClass();");
3105 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3106
3107 v8::TryCatch try_catch;
3108
3109 Local<Value> to_string_result = obj->ToString();
3110 CHECK(to_string_result.IsEmpty());
3111 CheckUncle(&try_catch);
3112
3113 Local<Value> to_number_result = obj->ToNumber();
3114 CHECK(to_number_result.IsEmpty());
3115 CheckUncle(&try_catch);
3116
3117 Local<Value> to_integer_result = obj->ToInteger();
3118 CHECK(to_integer_result.IsEmpty());
3119 CheckUncle(&try_catch);
3120
3121 Local<Value> to_uint32_result = obj->ToUint32();
3122 CHECK(to_uint32_result.IsEmpty());
3123 CheckUncle(&try_catch);
3124
3125 Local<Value> to_int32_result = obj->ToInt32();
3126 CHECK(to_int32_result.IsEmpty());
3127 CheckUncle(&try_catch);
3128
3129 Local<Value> to_object_result = v8::Undefined()->ToObject();
3130 CHECK(to_object_result.IsEmpty());
3131 CHECK(try_catch.HasCaught());
3132 try_catch.Reset();
3133
3134 int32_t int32_value = obj->Int32Value();
3135 CHECK_EQ(0, int32_value);
3136 CheckUncle(&try_catch);
3137
3138 uint32_t uint32_value = obj->Uint32Value();
3139 CHECK_EQ(0, uint32_value);
3140 CheckUncle(&try_catch);
3141
3142 double number_value = obj->NumberValue();
3143 CHECK_NE(0, IsNaN(number_value));
3144 CheckUncle(&try_catch);
3145
3146 int64_t integer_value = obj->IntegerValue();
3147 CHECK_EQ(0.0, static_cast<double>(integer_value));
3148 CheckUncle(&try_catch);
3149}
3150
3151
3152v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3153 ApiTestFuzzer::Fuzz();
3154 return v8::ThrowException(v8_str("konto"));
3155}
3156
3157
ager@chromium.org8bb60582008-12-11 12:02:20 +00003158v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003159 if (args.Length() < 1) return v8::False();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003160 v8::HandleScope scope;
3161 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003162 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3163 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003164 return v8::Boolean::New(try_catch.HasCaught());
3165}
3166
3167
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003168THREADED_TEST(APICatch) {
3169 v8::HandleScope scope;
3170 Local<ObjectTemplate> templ = ObjectTemplate::New();
3171 templ->Set(v8_str("ThrowFromC"),
3172 v8::FunctionTemplate::New(ThrowFromC));
3173 LocalContext context(0, templ);
3174 CompileRun(
3175 "var thrown = false;"
3176 "try {"
3177 " ThrowFromC();"
3178 "} catch (e) {"
3179 " thrown = true;"
3180 "}");
3181 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3182 CHECK(thrown->BooleanValue());
3183}
3184
3185
ager@chromium.org8bb60582008-12-11 12:02:20 +00003186THREADED_TEST(APIThrowTryCatch) {
3187 v8::HandleScope scope;
3188 Local<ObjectTemplate> templ = ObjectTemplate::New();
3189 templ->Set(v8_str("ThrowFromC"),
3190 v8::FunctionTemplate::New(ThrowFromC));
3191 LocalContext context(0, templ);
3192 v8::TryCatch try_catch;
3193 CompileRun("ThrowFromC();");
3194 CHECK(try_catch.HasCaught());
3195}
3196
3197
3198// Test that a try-finally block doesn't shadow a try-catch block
3199// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003200//
3201// BUG(271): Some of the exception propagation does not work on the
3202// ARM simulator because the simulator separates the C++ stack and the
3203// JS stack. This test therefore fails on the simulator. The test is
3204// not threaded to allow the threading tests to run on the simulator.
3205TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003206 v8::HandleScope scope;
3207 Local<ObjectTemplate> templ = ObjectTemplate::New();
3208 templ->Set(v8_str("CCatcher"),
3209 v8::FunctionTemplate::New(CCatcher));
3210 LocalContext context(0, templ);
3211 Local<Value> result = CompileRun("try {"
3212 " try {"
3213 " CCatcher('throw 7;');"
3214 " } finally {"
3215 " }"
3216 "} catch (e) {"
3217 "}");
3218 CHECK(result->IsTrue());
3219}
3220
3221
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003222static void check_reference_error_message(
3223 v8::Handle<v8::Message> message,
3224 v8::Handle<v8::Value> data) {
3225 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3226 CHECK(message->Get()->Equals(v8_str(reference_error)));
3227}
3228
3229
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003230static v8::Handle<Value> Fail(const v8::Arguments& args) {
3231 ApiTestFuzzer::Fuzz();
3232 CHECK(false);
3233 return v8::Undefined();
3234}
3235
3236
3237// Test that overwritten methods are not invoked on uncaught exception
3238// formatting. However, they are invoked when performing normal error
3239// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003240TEST(APIThrowMessageOverwrittenToString) {
3241 v8::HandleScope scope;
3242 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003243 Local<ObjectTemplate> templ = ObjectTemplate::New();
3244 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3245 LocalContext context(NULL, templ);
3246 CompileRun("asdf;");
3247 CompileRun("var limit = {};"
3248 "limit.valueOf = fail;"
3249 "Error.stackTraceLimit = limit;");
3250 CompileRun("asdf");
3251 CompileRun("Array.prototype.pop = fail;");
3252 CompileRun("Object.prototype.hasOwnProperty = fail;");
3253 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003254 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3255 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003256 CompileRun("ReferenceError.prototype.toString ="
3257 " function() { return 'Whoops' }");
3258 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003259 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3260 CompileRun("asdf;");
3261 CompileRun("ReferenceError.prototype.constructor = void 0;");
3262 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003263 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3264 CompileRun("asdf;");
3265 CompileRun("ReferenceError.prototype = new Object();");
3266 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003267 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3268 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003269 CompileRun("ReferenceError.prototype.constructor = new Object();"
3270 "ReferenceError.prototype.constructor.name = 1;"
3271 "Number.prototype.toString = function() { return 'Whoops'; };"
3272 "ReferenceError.prototype.toString = Object.prototype.toString;");
3273 CompileRun("asdf;");
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003274 v8::V8::RemoveMessageListeners(check_reference_error_message);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003275}
3276
3277
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003278static void check_custom_error_message(
3279 v8::Handle<v8::Message> message,
3280 v8::Handle<v8::Value> data) {
3281 const char* uncaught_error = "Uncaught MyError toString";
3282 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3283}
3284
3285
3286TEST(CustomErrorToString) {
3287 v8::HandleScope scope;
3288 v8::V8::AddMessageListener(check_custom_error_message);
3289 LocalContext context;
3290 CompileRun(
3291 "function MyError(name, message) { "
3292 " this.name = name; "
3293 " this.message = message; "
3294 "} "
3295 "MyError.prototype = Object.create(Error.prototype); "
3296 "MyError.prototype.toString = function() { "
3297 " return 'MyError toString'; "
3298 "}; "
3299 "throw new MyError('my name', 'my message'); ");
3300 v8::V8::RemoveMessageListeners(check_custom_error_message);
3301}
3302
3303
ager@chromium.org8bb60582008-12-11 12:02:20 +00003304static void receive_message(v8::Handle<v8::Message> message,
3305 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003306 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003307 message_received = true;
3308}
3309
3310
3311TEST(APIThrowMessage) {
3312 message_received = false;
3313 v8::HandleScope scope;
3314 v8::V8::AddMessageListener(receive_message);
3315 Local<ObjectTemplate> templ = ObjectTemplate::New();
3316 templ->Set(v8_str("ThrowFromC"),
3317 v8::FunctionTemplate::New(ThrowFromC));
3318 LocalContext context(0, templ);
3319 CompileRun("ThrowFromC();");
3320 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003321 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003322}
3323
3324
3325TEST(APIThrowMessageAndVerboseTryCatch) {
3326 message_received = false;
3327 v8::HandleScope scope;
3328 v8::V8::AddMessageListener(receive_message);
3329 Local<ObjectTemplate> templ = ObjectTemplate::New();
3330 templ->Set(v8_str("ThrowFromC"),
3331 v8::FunctionTemplate::New(ThrowFromC));
3332 LocalContext context(0, templ);
3333 v8::TryCatch try_catch;
3334 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003335 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003336 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003337 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003338 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003339 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003340}
3341
3342
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003343TEST(APIStackOverflowAndVerboseTryCatch) {
3344 message_received = false;
3345 v8::HandleScope scope;
3346 v8::V8::AddMessageListener(receive_message);
3347 LocalContext context;
3348 v8::TryCatch try_catch;
3349 try_catch.SetVerbose(true);
3350 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3351 CHECK(try_catch.HasCaught());
3352 CHECK(result.IsEmpty());
3353 CHECK(message_received);
3354 v8::V8::RemoveMessageListeners(receive_message);
3355}
3356
3357
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003358THREADED_TEST(ExternalScriptException) {
3359 v8::HandleScope scope;
3360 Local<ObjectTemplate> templ = ObjectTemplate::New();
3361 templ->Set(v8_str("ThrowFromC"),
3362 v8::FunctionTemplate::New(ThrowFromC));
3363 LocalContext context(0, templ);
3364
3365 v8::TryCatch try_catch;
3366 Local<Script> script
3367 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3368 Local<Value> result = script->Run();
3369 CHECK(result.IsEmpty());
3370 CHECK(try_catch.HasCaught());
3371 String::AsciiValue exception_value(try_catch.Exception());
3372 CHECK_EQ("konto", *exception_value);
3373}
3374
3375
3376
3377v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3378 ApiTestFuzzer::Fuzz();
3379 CHECK_EQ(4, args.Length());
3380 int count = args[0]->Int32Value();
3381 int cInterval = args[2]->Int32Value();
3382 if (count == 0) {
3383 return v8::ThrowException(v8_str("FromC"));
3384 } else {
3385 Local<v8::Object> global = Context::GetCurrent()->Global();
3386 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3387 v8::Handle<Value> argv[] = { v8_num(count - 1),
3388 args[1],
3389 args[2],
3390 args[3] };
3391 if (count % cInterval == 0) {
3392 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003393 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003394 int expected = args[3]->Int32Value();
3395 if (try_catch.HasCaught()) {
3396 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003397 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003398 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003399 } else {
3400 CHECK_NE(expected, count);
3401 }
3402 return result;
3403 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003404 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003405 }
3406 }
3407}
3408
3409
3410v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3411 ApiTestFuzzer::Fuzz();
3412 CHECK_EQ(3, args.Length());
3413 bool equality = args[0]->BooleanValue();
3414 int count = args[1]->Int32Value();
3415 int expected = args[2]->Int32Value();
3416 if (equality) {
3417 CHECK_EQ(count, expected);
3418 } else {
3419 CHECK_NE(count, expected);
3420 }
3421 return v8::Undefined();
3422}
3423
3424
ager@chromium.org8bb60582008-12-11 12:02:20 +00003425THREADED_TEST(EvalInTryFinally) {
3426 v8::HandleScope scope;
3427 LocalContext context;
3428 v8::TryCatch try_catch;
3429 CompileRun("(function() {"
3430 " try {"
3431 " eval('asldkf (*&^&*^');"
3432 " } finally {"
3433 " return;"
3434 " }"
3435 "})()");
3436 CHECK(!try_catch.HasCaught());
3437}
3438
3439
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003440// This test works by making a stack of alternating JavaScript and C
3441// activations. These activations set up exception handlers with regular
3442// intervals, one interval for C activations and another for JavaScript
3443// activations. When enough activations have been created an exception is
3444// thrown and we check that the right activation catches the exception and that
3445// no other activations do. The right activation is always the topmost one with
3446// a handler, regardless of whether it is in JavaScript or C.
3447//
3448// The notation used to describe a test case looks like this:
3449//
3450// *JS[4] *C[3] @JS[2] C[1] JS[0]
3451//
3452// Each entry is an activation, either JS or C. The index is the count at that
3453// level. Stars identify activations with exception handlers, the @ identifies
3454// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003455//
3456// BUG(271): Some of the exception propagation does not work on the
3457// ARM simulator because the simulator separates the C++ stack and the
3458// JS stack. This test therefore fails on the simulator. The test is
3459// not threaded to allow the threading tests to run on the simulator.
3460TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003461 v8::HandleScope scope;
3462 Local<ObjectTemplate> templ = ObjectTemplate::New();
3463 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3464 templ->Set(v8_str("CThrowCountDown"),
3465 v8::FunctionTemplate::New(CThrowCountDown));
3466 LocalContext context(0, templ);
3467 CompileRun(
3468 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3469 " if (count == 0) throw 'FromJS';"
3470 " if (count % jsInterval == 0) {"
3471 " try {"
3472 " var value = CThrowCountDown(count - 1,"
3473 " jsInterval,"
3474 " cInterval,"
3475 " expected);"
3476 " check(false, count, expected);"
3477 " return value;"
3478 " } catch (e) {"
3479 " check(true, count, expected);"
3480 " }"
3481 " } else {"
3482 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3483 " }"
3484 "}");
3485 Local<Function> fun =
3486 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3487
3488 const int argc = 4;
3489 // count jsInterval cInterval expected
3490
3491 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3492 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3493 fun->Call(fun, argc, a0);
3494
3495 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3496 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3497 fun->Call(fun, argc, a1);
3498
3499 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3500 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3501 fun->Call(fun, argc, a2);
3502
3503 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3504 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3505 fun->Call(fun, argc, a3);
3506
3507 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3508 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3509 fun->Call(fun, argc, a4);
3510
3511 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3512 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3513 fun->Call(fun, argc, a5);
3514}
3515
3516
3517v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3518 ApiTestFuzzer::Fuzz();
3519 CHECK_EQ(1, args.Length());
3520 return v8::ThrowException(args[0]);
3521}
3522
3523
3524THREADED_TEST(ThrowValues) {
3525 v8::HandleScope scope;
3526 Local<ObjectTemplate> templ = ObjectTemplate::New();
3527 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3528 LocalContext context(0, templ);
3529 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3530 "function Run(obj) {"
3531 " try {"
3532 " Throw(obj);"
3533 " } catch (e) {"
3534 " return e;"
3535 " }"
3536 " return 'no exception';"
3537 "}"
3538 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3539 CHECK_EQ(5, result->Length());
3540 CHECK(result->Get(v8::Integer::New(0))->IsString());
3541 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3542 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3543 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3544 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3545 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3546 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3547}
3548
3549
3550THREADED_TEST(CatchZero) {
3551 v8::HandleScope scope;
3552 LocalContext context;
3553 v8::TryCatch try_catch;
3554 CHECK(!try_catch.HasCaught());
3555 Script::Compile(v8_str("throw 10"))->Run();
3556 CHECK(try_catch.HasCaught());
3557 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3558 try_catch.Reset();
3559 CHECK(!try_catch.HasCaught());
3560 Script::Compile(v8_str("throw 0"))->Run();
3561 CHECK(try_catch.HasCaught());
3562 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3563}
3564
3565
3566THREADED_TEST(CatchExceptionFromWith) {
3567 v8::HandleScope scope;
3568 LocalContext context;
3569 v8::TryCatch try_catch;
3570 CHECK(!try_catch.HasCaught());
3571 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3572 CHECK(try_catch.HasCaught());
3573}
3574
3575
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003576THREADED_TEST(TryCatchAndFinallyHidingException) {
3577 v8::HandleScope scope;
3578 LocalContext context;
3579 v8::TryCatch try_catch;
3580 CHECK(!try_catch.HasCaught());
3581 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3582 CompileRun("f({toString: function() { throw 42; }});");
3583 CHECK(!try_catch.HasCaught());
3584}
3585
3586
3587v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3588 v8::TryCatch try_catch;
3589 return v8::Undefined();
3590}
3591
3592
3593THREADED_TEST(TryCatchAndFinally) {
3594 v8::HandleScope scope;
3595 LocalContext context;
3596 context->Global()->Set(
3597 v8_str("native_with_try_catch"),
3598 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3599 v8::TryCatch try_catch;
3600 CHECK(!try_catch.HasCaught());
3601 CompileRun(
3602 "try {\n"
3603 " throw new Error('a');\n"
3604 "} finally {\n"
3605 " native_with_try_catch();\n"
3606 "}\n");
3607 CHECK(try_catch.HasCaught());
3608}
3609
3610
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003611THREADED_TEST(Equality) {
3612 v8::HandleScope scope;
3613 LocalContext context;
3614 // Check that equality works at all before relying on CHECK_EQ
3615 CHECK(v8_str("a")->Equals(v8_str("a")));
3616 CHECK(!v8_str("a")->Equals(v8_str("b")));
3617
3618 CHECK_EQ(v8_str("a"), v8_str("a"));
3619 CHECK_NE(v8_str("a"), v8_str("b"));
3620 CHECK_EQ(v8_num(1), v8_num(1));
3621 CHECK_EQ(v8_num(1.00), v8_num(1));
3622 CHECK_NE(v8_num(1), v8_num(2));
3623
3624 // Assume String is not symbol.
3625 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3626 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3627 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3628 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3629 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3630 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3631 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3632 CHECK(!not_a_number->StrictEquals(not_a_number));
3633 CHECK(v8::False()->StrictEquals(v8::False()));
3634 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3635
3636 v8::Handle<v8::Object> obj = v8::Object::New();
3637 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3638 CHECK(alias->StrictEquals(obj));
3639 alias.Dispose();
3640}
3641
3642
3643THREADED_TEST(MultiRun) {
3644 v8::HandleScope scope;
3645 LocalContext context;
3646 Local<Script> script = Script::Compile(v8_str("x"));
3647 for (int i = 0; i < 10; i++)
3648 script->Run();
3649}
3650
3651
3652static v8::Handle<Value> GetXValue(Local<String> name,
3653 const AccessorInfo& info) {
3654 ApiTestFuzzer::Fuzz();
3655 CHECK_EQ(info.Data(), v8_str("donut"));
3656 CHECK_EQ(name, v8_str("x"));
3657 return name;
3658}
3659
3660
3661THREADED_TEST(SimplePropertyRead) {
3662 v8::HandleScope scope;
3663 Local<ObjectTemplate> templ = ObjectTemplate::New();
3664 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3665 LocalContext context;
3666 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3667 Local<Script> script = Script::Compile(v8_str("obj.x"));
3668 for (int i = 0; i < 10; i++) {
3669 Local<Value> result = script->Run();
3670 CHECK_EQ(result, v8_str("x"));
3671 }
3672}
3673
ager@chromium.org5c838252010-02-19 08:53:10 +00003674THREADED_TEST(DefinePropertyOnAPIAccessor) {
3675 v8::HandleScope scope;
3676 Local<ObjectTemplate> templ = ObjectTemplate::New();
3677 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3678 LocalContext context;
3679 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3680
3681 // Uses getOwnPropertyDescriptor to check the configurable status
3682 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003683 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003684 "obj, 'x');"
3685 "prop.configurable;"));
3686 Local<Value> result = script_desc->Run();
3687 CHECK_EQ(result->BooleanValue(), true);
3688
3689 // Redefine get - but still configurable
3690 Local<Script> script_define
3691 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3692 " configurable: true };"
3693 "Object.defineProperty(obj, 'x', desc);"
3694 "obj.x"));
3695 result = script_define->Run();
3696 CHECK_EQ(result, v8_num(42));
3697
3698 // Check that the accessor is still configurable
3699 result = script_desc->Run();
3700 CHECK_EQ(result->BooleanValue(), true);
3701
3702 // Redefine to a non-configurable
3703 script_define
3704 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3705 " configurable: false };"
3706 "Object.defineProperty(obj, 'x', desc);"
3707 "obj.x"));
3708 result = script_define->Run();
3709 CHECK_EQ(result, v8_num(43));
3710 result = script_desc->Run();
3711 CHECK_EQ(result->BooleanValue(), false);
3712
3713 // Make sure that it is not possible to redefine again
3714 v8::TryCatch try_catch;
3715 result = script_define->Run();
3716 CHECK(try_catch.HasCaught());
3717 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003718 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003719}
3720
3721THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3722 v8::HandleScope scope;
3723 Local<ObjectTemplate> templ = ObjectTemplate::New();
3724 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3725 LocalContext context;
3726 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3727
3728 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3729 "Object.getOwnPropertyDescriptor( "
3730 "obj, 'x');"
3731 "prop.configurable;"));
3732 Local<Value> result = script_desc->Run();
3733 CHECK_EQ(result->BooleanValue(), true);
3734
3735 Local<Script> script_define =
3736 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3737 " configurable: true };"
3738 "Object.defineProperty(obj, 'x', desc);"
3739 "obj.x"));
3740 result = script_define->Run();
3741 CHECK_EQ(result, v8_num(42));
3742
3743
3744 result = script_desc->Run();
3745 CHECK_EQ(result->BooleanValue(), true);
3746
3747
3748 script_define =
3749 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3750 " configurable: false };"
3751 "Object.defineProperty(obj, 'x', desc);"
3752 "obj.x"));
3753 result = script_define->Run();
3754 CHECK_EQ(result, v8_num(43));
3755 result = script_desc->Run();
3756
3757 CHECK_EQ(result->BooleanValue(), false);
3758
3759 v8::TryCatch try_catch;
3760 result = script_define->Run();
3761 CHECK(try_catch.HasCaught());
3762 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003763 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003764}
3765
3766
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003767static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3768 char const* name) {
3769 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3770}
ager@chromium.org5c838252010-02-19 08:53:10 +00003771
3772
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003773THREADED_TEST(DefineAPIAccessorOnObject) {
3774 v8::HandleScope scope;
3775 Local<ObjectTemplate> templ = ObjectTemplate::New();
3776 LocalContext context;
3777
3778 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3779 CompileRun("var obj2 = {};");
3780
3781 CHECK(CompileRun("obj1.x")->IsUndefined());
3782 CHECK(CompileRun("obj2.x")->IsUndefined());
3783
3784 CHECK(GetGlobalProperty(&context, "obj1")->
3785 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3786
3787 ExpectString("obj1.x", "x");
3788 CHECK(CompileRun("obj2.x")->IsUndefined());
3789
3790 CHECK(GetGlobalProperty(&context, "obj2")->
3791 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3792
3793 ExpectString("obj1.x", "x");
3794 ExpectString("obj2.x", "x");
3795
3796 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3797 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3798
3799 CompileRun("Object.defineProperty(obj1, 'x',"
3800 "{ get: function() { return 'y'; }, configurable: true })");
3801
3802 ExpectString("obj1.x", "y");
3803 ExpectString("obj2.x", "x");
3804
3805 CompileRun("Object.defineProperty(obj2, 'x',"
3806 "{ get: function() { return 'y'; }, configurable: true })");
3807
3808 ExpectString("obj1.x", "y");
3809 ExpectString("obj2.x", "y");
3810
3811 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3812 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3813
3814 CHECK(GetGlobalProperty(&context, "obj1")->
3815 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3816 CHECK(GetGlobalProperty(&context, "obj2")->
3817 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3818
3819 ExpectString("obj1.x", "x");
3820 ExpectString("obj2.x", "x");
3821
3822 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3823 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3824
3825 // Define getters/setters, but now make them not configurable.
3826 CompileRun("Object.defineProperty(obj1, 'x',"
3827 "{ get: function() { return 'z'; }, configurable: false })");
3828 CompileRun("Object.defineProperty(obj2, 'x',"
3829 "{ get: function() { return 'z'; }, configurable: false })");
3830
3831 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3832 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3833
3834 ExpectString("obj1.x", "z");
3835 ExpectString("obj2.x", "z");
3836
3837 CHECK(!GetGlobalProperty(&context, "obj1")->
3838 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3839 CHECK(!GetGlobalProperty(&context, "obj2")->
3840 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3841
3842 ExpectString("obj1.x", "z");
3843 ExpectString("obj2.x", "z");
3844}
3845
3846
3847THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3848 v8::HandleScope scope;
3849 Local<ObjectTemplate> templ = ObjectTemplate::New();
3850 LocalContext context;
3851
3852 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3853 CompileRun("var obj2 = {};");
3854
3855 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3856 v8_str("x"),
3857 GetXValue, NULL,
3858 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3859 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3860 v8_str("x"),
3861 GetXValue, NULL,
3862 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3863
3864 ExpectString("obj1.x", "x");
3865 ExpectString("obj2.x", "x");
3866
3867 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3868 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3869
3870 CHECK(!GetGlobalProperty(&context, "obj1")->
3871 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3872 CHECK(!GetGlobalProperty(&context, "obj2")->
3873 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3874
3875 {
3876 v8::TryCatch try_catch;
3877 CompileRun("Object.defineProperty(obj1, 'x',"
3878 "{get: function() { return 'func'; }})");
3879 CHECK(try_catch.HasCaught());
3880 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003881 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003882 }
3883 {
3884 v8::TryCatch try_catch;
3885 CompileRun("Object.defineProperty(obj2, 'x',"
3886 "{get: function() { return 'func'; }})");
3887 CHECK(try_catch.HasCaught());
3888 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003889 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003890 }
3891}
3892
3893
3894static v8::Handle<Value> Get239Value(Local<String> name,
3895 const AccessorInfo& info) {
3896 ApiTestFuzzer::Fuzz();
3897 CHECK_EQ(info.Data(), v8_str("donut"));
3898 CHECK_EQ(name, v8_str("239"));
3899 return name;
3900}
3901
3902
3903THREADED_TEST(ElementAPIAccessor) {
3904 v8::HandleScope scope;
3905 Local<ObjectTemplate> templ = ObjectTemplate::New();
3906 LocalContext context;
3907
3908 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3909 CompileRun("var obj2 = {};");
3910
3911 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3912 v8_str("239"),
3913 Get239Value, NULL,
3914 v8_str("donut")));
3915 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3916 v8_str("239"),
3917 Get239Value, NULL,
3918 v8_str("donut")));
3919
3920 ExpectString("obj1[239]", "239");
3921 ExpectString("obj2[239]", "239");
3922 ExpectString("obj1['239']", "239");
3923 ExpectString("obj2['239']", "239");
3924}
3925
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003926
3927v8::Persistent<Value> xValue;
3928
3929
3930static void SetXValue(Local<String> name,
3931 Local<Value> value,
3932 const AccessorInfo& info) {
3933 CHECK_EQ(value, v8_num(4));
3934 CHECK_EQ(info.Data(), v8_str("donut"));
3935 CHECK_EQ(name, v8_str("x"));
3936 CHECK(xValue.IsEmpty());
3937 xValue = v8::Persistent<Value>::New(value);
3938}
3939
3940
3941THREADED_TEST(SimplePropertyWrite) {
3942 v8::HandleScope scope;
3943 Local<ObjectTemplate> templ = ObjectTemplate::New();
3944 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3945 LocalContext context;
3946 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3947 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3948 for (int i = 0; i < 10; i++) {
3949 CHECK(xValue.IsEmpty());
3950 script->Run();
3951 CHECK_EQ(v8_num(4), xValue);
3952 xValue.Dispose();
3953 xValue = v8::Persistent<Value>();
3954 }
3955}
3956
3957
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003958THREADED_TEST(SetterOnly) {
3959 v8::HandleScope scope;
3960 Local<ObjectTemplate> templ = ObjectTemplate::New();
3961 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
3962 LocalContext context;
3963 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3964 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3965 for (int i = 0; i < 10; i++) {
3966 CHECK(xValue.IsEmpty());
3967 script->Run();
3968 CHECK_EQ(v8_num(4), xValue);
3969 xValue.Dispose();
3970 xValue = v8::Persistent<Value>();
3971 }
3972}
3973
3974
3975THREADED_TEST(NoAccessors) {
3976 v8::HandleScope scope;
3977 Local<ObjectTemplate> templ = ObjectTemplate::New();
3978 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
3979 LocalContext context;
3980 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3981 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
3982 for (int i = 0; i < 10; i++) {
3983 script->Run();
3984 }
3985}
3986
3987
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003988static v8::Handle<Value> XPropertyGetter(Local<String> property,
3989 const AccessorInfo& info) {
3990 ApiTestFuzzer::Fuzz();
3991 CHECK(info.Data()->IsUndefined());
3992 return property;
3993}
3994
3995
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003996THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003997 v8::HandleScope scope;
3998 Local<ObjectTemplate> templ = ObjectTemplate::New();
3999 templ->SetNamedPropertyHandler(XPropertyGetter);
4000 LocalContext context;
4001 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4002 Local<Script> script = Script::Compile(v8_str("obj.x"));
4003 for (int i = 0; i < 10; i++) {
4004 Local<Value> result = script->Run();
4005 CHECK_EQ(result, v8_str("x"));
4006 }
4007}
4008
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004009
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004010THREADED_TEST(NamedInterceptorDictionaryIC) {
4011 v8::HandleScope scope;
4012 Local<ObjectTemplate> templ = ObjectTemplate::New();
4013 templ->SetNamedPropertyHandler(XPropertyGetter);
4014 LocalContext context;
4015 // Create an object with a named interceptor.
4016 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
4017 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
4018 for (int i = 0; i < 10; i++) {
4019 Local<Value> result = script->Run();
4020 CHECK_EQ(result, v8_str("x"));
4021 }
4022 // Create a slow case object and a function accessing a property in
4023 // that slow case object (with dictionary probing in generated
4024 // code). Then force object with a named interceptor into slow-case,
4025 // pass it to the function, and check that the interceptor is called
4026 // instead of accessing the local property.
4027 Local<Value> result =
4028 CompileRun("function get_x(o) { return o.x; };"
4029 "var obj = { x : 42, y : 0 };"
4030 "delete obj.y;"
4031 "for (var i = 0; i < 10; i++) get_x(obj);"
4032 "interceptor_obj.x = 42;"
4033 "interceptor_obj.y = 10;"
4034 "delete interceptor_obj.y;"
4035 "get_x(interceptor_obj)");
4036 CHECK_EQ(result, v8_str("x"));
4037}
4038
4039
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004040THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
4041 v8::HandleScope scope;
4042
4043 v8::Persistent<Context> context1 = Context::New();
4044
4045 context1->Enter();
4046 Local<ObjectTemplate> templ = ObjectTemplate::New();
4047 templ->SetNamedPropertyHandler(XPropertyGetter);
4048 // Create an object with a named interceptor.
4049 v8::Local<v8::Object> object = templ->NewInstance();
4050 context1->Global()->Set(v8_str("interceptor_obj"), object);
4051
4052 // Force the object into the slow case.
4053 CompileRun("interceptor_obj.y = 0;"
4054 "delete interceptor_obj.y;");
4055 context1->Exit();
4056
4057 {
4058 // Introduce the object into a different context.
4059 // Repeat named loads to exercise ICs.
4060 LocalContext context2;
4061 context2->Global()->Set(v8_str("interceptor_obj"), object);
4062 Local<Value> result =
4063 CompileRun("function get_x(o) { return o.x; }"
4064 "interceptor_obj.x = 42;"
4065 "for (var i=0; i != 10; i++) {"
4066 " get_x(interceptor_obj);"
4067 "}"
4068 "get_x(interceptor_obj)");
4069 // Check that the interceptor was actually invoked.
4070 CHECK_EQ(result, v8_str("x"));
4071 }
4072
4073 // Return to the original context and force some object to the slow case
4074 // to cause the NormalizedMapCache to verify.
4075 context1->Enter();
4076 CompileRun("var obj = { x : 0 }; delete obj.x;");
4077 context1->Exit();
4078
4079 context1.Dispose();
4080}
4081
4082
ager@chromium.org5c838252010-02-19 08:53:10 +00004083static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
4084 const AccessorInfo& info) {
4085 // Set x on the prototype object and do not handle the get request.
4086 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004087 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00004088 return v8::Handle<Value>();
4089}
4090
4091
4092// This is a regression test for http://crbug.com/20104. Map
4093// transitions should not interfere with post interceptor lookup.
4094THREADED_TEST(NamedInterceptorMapTransitionRead) {
4095 v8::HandleScope scope;
4096 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
4097 Local<v8::ObjectTemplate> instance_template
4098 = function_template->InstanceTemplate();
4099 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
4100 LocalContext context;
4101 context->Global()->Set(v8_str("F"), function_template->GetFunction());
4102 // Create an instance of F and introduce a map transition for x.
4103 CompileRun("var o = new F(); o.x = 23;");
4104 // Create an instance of F and invoke the getter. The result should be 23.
4105 Local<Value> result = CompileRun("o = new F(); o.x");
4106 CHECK_EQ(result->Int32Value(), 23);
4107}
4108
4109
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004110static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4111 const AccessorInfo& info) {
4112 ApiTestFuzzer::Fuzz();
4113 if (index == 37) {
4114 return v8::Handle<Value>(v8_num(625));
4115 }
4116 return v8::Handle<Value>();
4117}
4118
4119
4120static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4121 Local<Value> value,
4122 const AccessorInfo& info) {
4123 ApiTestFuzzer::Fuzz();
4124 if (index == 39) {
4125 return value;
4126 }
4127 return v8::Handle<Value>();
4128}
4129
4130
4131THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
4132 v8::HandleScope scope;
4133 Local<ObjectTemplate> templ = ObjectTemplate::New();
4134 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4135 IndexedPropertySetter);
4136 LocalContext context;
4137 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4138 Local<Script> getter_script = Script::Compile(v8_str(
4139 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4140 Local<Script> setter_script = Script::Compile(v8_str(
4141 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4142 "obj[17] = 23;"
4143 "obj.foo;"));
4144 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4145 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4146 "obj[39] = 47;"
4147 "obj.foo;")); // This setter should not run, due to the interceptor.
4148 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4149 "obj[37];"));
4150 Local<Value> result = getter_script->Run();
4151 CHECK_EQ(v8_num(5), result);
4152 result = setter_script->Run();
4153 CHECK_EQ(v8_num(23), result);
4154 result = interceptor_setter_script->Run();
4155 CHECK_EQ(v8_num(23), result);
4156 result = interceptor_getter_script->Run();
4157 CHECK_EQ(v8_num(625), result);
4158}
4159
4160
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004161static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4162 uint32_t index,
4163 const AccessorInfo& info) {
4164 ApiTestFuzzer::Fuzz();
4165 if (index < 25) {
4166 return v8::Handle<Value>(v8_num(index));
4167 }
4168 return v8::Handle<Value>();
4169}
4170
4171
4172static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4173 uint32_t index,
4174 Local<Value> value,
4175 const AccessorInfo& info) {
4176 ApiTestFuzzer::Fuzz();
4177 if (index < 25) {
4178 return v8::Handle<Value>(v8_num(index));
4179 }
4180 return v8::Handle<Value>();
4181}
4182
4183
4184Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4185 const AccessorInfo& info) {
4186 // Force the list of returned keys to be stored in a FastDoubleArray.
4187 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4188 "keys = new Array(); keys[125000] = 1;"
4189 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4190 "keys.length = 25; keys;"));
4191 Local<Value> result = indexed_property_names_script->Run();
4192 return Local<v8::Array>(::v8::Array::Cast(*result));
4193}
4194
4195
4196// Make sure that the the interceptor code in the runtime properly handles
4197// merging property name lists for double-array-backed arrays.
4198THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
4199 v8::HandleScope scope;
4200 Local<ObjectTemplate> templ = ObjectTemplate::New();
4201 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4202 UnboxedDoubleIndexedPropertySetter,
4203 0,
4204 0,
4205 UnboxedDoubleIndexedPropertyEnumerator);
4206 LocalContext context;
4207 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4208 // When obj is created, force it to be Stored in a FastDoubleArray.
4209 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4210 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4211 "key_count = 0; "
4212 "for (x in obj) {key_count++;};"
4213 "obj;"));
4214 Local<Value> result = create_unboxed_double_script->Run();
4215 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4216 Local<Script> key_count_check = Script::Compile(v8_str(
4217 "key_count;"));
4218 result = key_count_check->Run();
4219 CHECK_EQ(v8_num(40013), result);
4220}
4221
4222
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004223Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4224 const AccessorInfo& info) {
4225 // Force the list of returned keys to be stored in a Arguments object.
4226 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4227 "function f(w,x) {"
4228 " return arguments;"
4229 "}"
4230 "keys = f(0, 1, 2, 3);"
4231 "keys;"));
4232 Local<Value> result = indexed_property_names_script->Run();
4233 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4234}
4235
4236
4237static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4238 uint32_t index,
4239 const AccessorInfo& info) {
4240 ApiTestFuzzer::Fuzz();
4241 if (index < 4) {
4242 return v8::Handle<Value>(v8_num(index));
4243 }
4244 return v8::Handle<Value>();
4245}
4246
4247
4248// Make sure that the the interceptor code in the runtime properly handles
4249// merging property name lists for non-string arguments arrays.
4250THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
4251 v8::HandleScope scope;
4252 Local<ObjectTemplate> templ = ObjectTemplate::New();
4253 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4254 0,
4255 0,
4256 0,
4257 NonStrictArgsIndexedPropertyEnumerator);
4258 LocalContext context;
4259 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4260 Local<Script> create_args_script =
4261 Script::Compile(v8_str(
4262 "var key_count = 0;"
4263 "for (x in obj) {key_count++;} key_count;"));
4264 Local<Value> result = create_args_script->Run();
4265 CHECK_EQ(v8_num(4), result);
4266}
4267
4268
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004269static v8::Handle<Value> IdentityIndexedPropertyGetter(
4270 uint32_t index,
4271 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004272 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004273}
4274
4275
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004276THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
4277 v8::HandleScope scope;
4278 Local<ObjectTemplate> templ = ObjectTemplate::New();
4279 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4280
4281 LocalContext context;
4282 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4283
4284 // Check fast object case.
4285 const char* fast_case_code =
4286 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4287 ExpectString(fast_case_code, "0");
4288
4289 // Check slow case.
4290 const char* slow_case_code =
4291 "obj.x = 1; delete obj.x;"
4292 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4293 ExpectString(slow_case_code, "1");
4294}
4295
4296
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004297THREADED_TEST(IndexedInterceptorWithNoSetter) {
4298 v8::HandleScope scope;
4299 Local<ObjectTemplate> templ = ObjectTemplate::New();
4300 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4301
4302 LocalContext context;
4303 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4304
4305 const char* code =
4306 "try {"
4307 " obj[0] = 239;"
4308 " for (var i = 0; i < 100; i++) {"
4309 " var v = obj[0];"
4310 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4311 " }"
4312 " 'PASSED'"
4313 "} catch(e) {"
4314 " e"
4315 "}";
4316 ExpectString(code, "PASSED");
4317}
4318
4319
ager@chromium.org5c838252010-02-19 08:53:10 +00004320THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
4321 v8::HandleScope scope;
4322 Local<ObjectTemplate> templ = ObjectTemplate::New();
4323 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4324
4325 LocalContext context;
4326 Local<v8::Object> obj = templ->NewInstance();
4327 obj->TurnOnAccessCheck();
4328 context->Global()->Set(v8_str("obj"), obj);
4329
4330 const char* code =
4331 "try {"
4332 " for (var i = 0; i < 100; i++) {"
4333 " var v = obj[0];"
4334 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4335 " }"
4336 " 'PASSED'"
4337 "} catch(e) {"
4338 " e"
4339 "}";
4340 ExpectString(code, "PASSED");
4341}
4342
4343
4344THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4345 i::FLAG_allow_natives_syntax = true;
4346 v8::HandleScope scope;
4347 Local<ObjectTemplate> templ = ObjectTemplate::New();
4348 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4349
4350 LocalContext context;
4351 Local<v8::Object> obj = templ->NewInstance();
4352 context->Global()->Set(v8_str("obj"), obj);
4353
4354 const char* code =
4355 "try {"
4356 " for (var i = 0; i < 100; i++) {"
4357 " var expected = i;"
4358 " if (i == 5) {"
4359 " %EnableAccessChecks(obj);"
4360 " expected = undefined;"
4361 " }"
4362 " var v = obj[i];"
4363 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4364 " if (i == 5) %DisableAccessChecks(obj);"
4365 " }"
4366 " 'PASSED'"
4367 "} catch(e) {"
4368 " e"
4369 "}";
4370 ExpectString(code, "PASSED");
4371}
4372
4373
4374THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4375 v8::HandleScope scope;
4376 Local<ObjectTemplate> templ = ObjectTemplate::New();
4377 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4378
4379 LocalContext context;
4380 Local<v8::Object> obj = templ->NewInstance();
4381 context->Global()->Set(v8_str("obj"), obj);
4382
4383 const char* code =
4384 "try {"
4385 " for (var i = 0; i < 100; i++) {"
4386 " var v = obj[i];"
4387 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4388 " }"
4389 " 'PASSED'"
4390 "} catch(e) {"
4391 " e"
4392 "}";
4393 ExpectString(code, "PASSED");
4394}
4395
4396
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004397THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4398 v8::HandleScope scope;
4399 Local<ObjectTemplate> templ = ObjectTemplate::New();
4400 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4401
4402 LocalContext context;
4403 Local<v8::Object> obj = templ->NewInstance();
4404 context->Global()->Set(v8_str("obj"), obj);
4405
4406 const char* code =
4407 "try {"
4408 " for (var i = 0; i < 100; i++) {"
4409 " var expected = i;"
4410 " var key = i;"
4411 " if (i == 25) {"
4412 " key = -1;"
4413 " expected = undefined;"
4414 " }"
4415 " if (i == 50) {"
4416 " /* probe minimal Smi number on 32-bit platforms */"
4417 " key = -(1 << 30);"
4418 " expected = undefined;"
4419 " }"
4420 " if (i == 75) {"
4421 " /* probe minimal Smi number on 64-bit platforms */"
4422 " key = 1 << 31;"
4423 " expected = undefined;"
4424 " }"
4425 " var v = obj[key];"
4426 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4427 " }"
4428 " 'PASSED'"
4429 "} catch(e) {"
4430 " e"
4431 "}";
4432 ExpectString(code, "PASSED");
4433}
4434
4435
ager@chromium.org5c838252010-02-19 08:53:10 +00004436THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4437 v8::HandleScope scope;
4438 Local<ObjectTemplate> templ = ObjectTemplate::New();
4439 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4440
4441 LocalContext context;
4442 Local<v8::Object> obj = templ->NewInstance();
4443 context->Global()->Set(v8_str("obj"), obj);
4444
4445 const char* code =
4446 "try {"
4447 " for (var i = 0; i < 100; i++) {"
4448 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004449 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004450 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004451 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004452 " expected = undefined;"
4453 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004454 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004455 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4456 " }"
4457 " 'PASSED'"
4458 "} catch(e) {"
4459 " e"
4460 "}";
4461 ExpectString(code, "PASSED");
4462}
4463
4464
4465THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4466 v8::HandleScope scope;
4467 Local<ObjectTemplate> templ = ObjectTemplate::New();
4468 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4469
4470 LocalContext context;
4471 Local<v8::Object> obj = templ->NewInstance();
4472 context->Global()->Set(v8_str("obj"), obj);
4473
4474 const char* code =
4475 "var original = obj;"
4476 "try {"
4477 " for (var i = 0; i < 100; i++) {"
4478 " var expected = i;"
4479 " if (i == 50) {"
4480 " obj = {50: 'foobar'};"
4481 " expected = 'foobar';"
4482 " }"
4483 " var v = obj[i];"
4484 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4485 " if (i == 50) obj = original;"
4486 " }"
4487 " 'PASSED'"
4488 "} catch(e) {"
4489 " e"
4490 "}";
4491 ExpectString(code, "PASSED");
4492}
4493
4494
4495THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4496 v8::HandleScope scope;
4497 Local<ObjectTemplate> templ = ObjectTemplate::New();
4498 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4499
4500 LocalContext context;
4501 Local<v8::Object> obj = templ->NewInstance();
4502 context->Global()->Set(v8_str("obj"), obj);
4503
4504 const char* code =
4505 "var original = obj;"
4506 "try {"
4507 " for (var i = 0; i < 100; i++) {"
4508 " var expected = i;"
4509 " if (i == 5) {"
4510 " obj = 239;"
4511 " expected = undefined;"
4512 " }"
4513 " var v = obj[i];"
4514 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4515 " if (i == 5) obj = original;"
4516 " }"
4517 " 'PASSED'"
4518 "} catch(e) {"
4519 " e"
4520 "}";
4521 ExpectString(code, "PASSED");
4522}
4523
4524
4525THREADED_TEST(IndexedInterceptorOnProto) {
4526 v8::HandleScope scope;
4527 Local<ObjectTemplate> templ = ObjectTemplate::New();
4528 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4529
4530 LocalContext context;
4531 Local<v8::Object> obj = templ->NewInstance();
4532 context->Global()->Set(v8_str("obj"), obj);
4533
4534 const char* code =
4535 "var o = {__proto__: obj};"
4536 "try {"
4537 " for (var i = 0; i < 100; i++) {"
4538 " var v = o[i];"
4539 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4540 " }"
4541 " 'PASSED'"
4542 "} catch(e) {"
4543 " e"
4544 "}";
4545 ExpectString(code, "PASSED");
4546}
4547
4548
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004549THREADED_TEST(MultiContexts) {
4550 v8::HandleScope scope;
4551 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4552 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4553
4554 Local<String> password = v8_str("Password");
4555
4556 // Create an environment
4557 LocalContext context0(0, templ);
4558 context0->SetSecurityToken(password);
4559 v8::Handle<v8::Object> global0 = context0->Global();
4560 global0->Set(v8_str("custom"), v8_num(1234));
4561 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4562
4563 // Create an independent environment
4564 LocalContext context1(0, templ);
4565 context1->SetSecurityToken(password);
4566 v8::Handle<v8::Object> global1 = context1->Global();
4567 global1->Set(v8_str("custom"), v8_num(1234));
4568 CHECK_NE(global0, global1);
4569 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4570 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4571
4572 // Now create a new context with the old global
4573 LocalContext context2(0, templ, global1);
4574 context2->SetSecurityToken(password);
4575 v8::Handle<v8::Object> global2 = context2->Global();
4576 CHECK_EQ(global1, global2);
4577 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4578 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4579}
4580
4581
4582THREADED_TEST(FunctionPrototypeAcrossContexts) {
4583 // Make sure that functions created by cloning boilerplates cannot
4584 // communicate through their __proto__ field.
4585
4586 v8::HandleScope scope;
4587
4588 LocalContext env0;
4589 v8::Handle<v8::Object> global0 =
4590 env0->Global();
4591 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004592 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004593 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004594 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004595 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004596 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004597 proto0->Set(v8_str("custom"), v8_num(1234));
4598
4599 LocalContext env1;
4600 v8::Handle<v8::Object> global1 =
4601 env1->Global();
4602 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004603 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004604 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004605 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004606 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004607 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004608 CHECK(!proto1->Has(v8_str("custom")));
4609}
4610
4611
4612THREADED_TEST(Regress892105) {
4613 // Make sure that object and array literals created by cloning
4614 // boilerplates cannot communicate through their __proto__
4615 // field. This is rather difficult to check, but we try to add stuff
4616 // to Object.prototype and Array.prototype and create a new
4617 // environment. This should succeed.
4618
4619 v8::HandleScope scope;
4620
4621 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4622 "Array.prototype.arr = 4567;"
4623 "8901");
4624
4625 LocalContext env0;
4626 Local<Script> script0 = Script::Compile(source);
4627 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4628
4629 LocalContext env1;
4630 Local<Script> script1 = Script::Compile(source);
4631 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4632}
4633
4634
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004635THREADED_TEST(UndetectableObject) {
4636 v8::HandleScope scope;
4637 LocalContext env;
4638
4639 Local<v8::FunctionTemplate> desc =
4640 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4641 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4642
4643 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4644 env->Global()->Set(v8_str("undetectable"), obj);
4645
4646 ExpectString("undetectable.toString()", "[object Object]");
4647 ExpectString("typeof undetectable", "undefined");
4648 ExpectString("typeof(undetectable)", "undefined");
4649 ExpectBoolean("typeof undetectable == 'undefined'", true);
4650 ExpectBoolean("typeof undetectable == 'object'", false);
4651 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4652 ExpectBoolean("!undetectable", true);
4653
4654 ExpectObject("true&&undetectable", obj);
4655 ExpectBoolean("false&&undetectable", false);
4656 ExpectBoolean("true||undetectable", true);
4657 ExpectObject("false||undetectable", obj);
4658
4659 ExpectObject("undetectable&&true", obj);
4660 ExpectObject("undetectable&&false", obj);
4661 ExpectBoolean("undetectable||true", true);
4662 ExpectBoolean("undetectable||false", false);
4663
4664 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004665 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004666 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004667 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004668 ExpectBoolean("undetectable==undetectable", true);
4669
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004670
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004671 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004672 ExpectBoolean("null===undetectable", false);
4673 ExpectBoolean("undetectable===undefined", false);
4674 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004675 ExpectBoolean("undetectable===undetectable", true);
4676}
4677
4678
ager@chromium.org04921a82011-06-27 13:21:41 +00004679THREADED_TEST(VoidLiteral) {
4680 v8::HandleScope scope;
4681 LocalContext env;
4682
4683 Local<v8::FunctionTemplate> desc =
4684 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4685 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4686
4687 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4688 env->Global()->Set(v8_str("undetectable"), obj);
4689
4690 ExpectBoolean("undefined == void 0", true);
4691 ExpectBoolean("undetectable == void 0", true);
4692 ExpectBoolean("null == void 0", true);
4693 ExpectBoolean("undefined === void 0", true);
4694 ExpectBoolean("undetectable === void 0", false);
4695 ExpectBoolean("null === void 0", false);
4696
4697 ExpectBoolean("void 0 == undefined", true);
4698 ExpectBoolean("void 0 == undetectable", true);
4699 ExpectBoolean("void 0 == null", true);
4700 ExpectBoolean("void 0 === undefined", true);
4701 ExpectBoolean("void 0 === undetectable", false);
4702 ExpectBoolean("void 0 === null", false);
4703
4704 ExpectString("(function() {"
4705 " try {"
4706 " return x === void 0;"
4707 " } catch(e) {"
4708 " return e.toString();"
4709 " }"
4710 "})()",
4711 "ReferenceError: x is not defined");
4712 ExpectString("(function() {"
4713 " try {"
4714 " return void 0 === x;"
4715 " } catch(e) {"
4716 " return e.toString();"
4717 " }"
4718 "})()",
4719 "ReferenceError: x is not defined");
4720}
4721
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004722
4723THREADED_TEST(ExtensibleOnUndetectable) {
4724 v8::HandleScope scope;
4725 LocalContext env;
4726
4727 Local<v8::FunctionTemplate> desc =
4728 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4729 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4730
4731 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4732 env->Global()->Set(v8_str("undetectable"), obj);
4733
4734 Local<String> source = v8_str("undetectable.x = 42;"
4735 "undetectable.x");
4736
4737 Local<Script> script = Script::Compile(source);
4738
4739 CHECK_EQ(v8::Integer::New(42), script->Run());
4740
4741 ExpectBoolean("Object.isExtensible(undetectable)", true);
4742
4743 source = v8_str("Object.preventExtensions(undetectable);");
4744 script = Script::Compile(source);
4745 script->Run();
4746 ExpectBoolean("Object.isExtensible(undetectable)", false);
4747
4748 source = v8_str("undetectable.y = 2000;");
4749 script = Script::Compile(source);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004750 script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004751 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004752}
4753
4754
4755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004756THREADED_TEST(UndetectableString) {
4757 v8::HandleScope scope;
4758 LocalContext env;
4759
4760 Local<String> obj = String::NewUndetectable("foo");
4761 env->Global()->Set(v8_str("undetectable"), obj);
4762
4763 ExpectString("undetectable", "foo");
4764 ExpectString("typeof undetectable", "undefined");
4765 ExpectString("typeof(undetectable)", "undefined");
4766 ExpectBoolean("typeof undetectable == 'undefined'", true);
4767 ExpectBoolean("typeof undetectable == 'string'", false);
4768 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4769 ExpectBoolean("!undetectable", true);
4770
4771 ExpectObject("true&&undetectable", obj);
4772 ExpectBoolean("false&&undetectable", false);
4773 ExpectBoolean("true||undetectable", true);
4774 ExpectObject("false||undetectable", obj);
4775
4776 ExpectObject("undetectable&&true", obj);
4777 ExpectObject("undetectable&&false", obj);
4778 ExpectBoolean("undetectable||true", true);
4779 ExpectBoolean("undetectable||false", false);
4780
4781 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004782 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004783 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004784 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004785 ExpectBoolean("undetectable==undetectable", true);
4786
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004787
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004788 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004789 ExpectBoolean("null===undetectable", false);
4790 ExpectBoolean("undetectable===undefined", false);
4791 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004792 ExpectBoolean("undetectable===undetectable", true);
4793}
4794
4795
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004796TEST(UndetectableOptimized) {
4797 i::FLAG_allow_natives_syntax = true;
4798 v8::HandleScope scope;
4799 LocalContext env;
4800
4801 Local<String> obj = String::NewUndetectable("foo");
4802 env->Global()->Set(v8_str("undetectable"), obj);
4803 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4804
4805 ExpectString(
4806 "function testBranch() {"
4807 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4808 " if (%_IsUndetectableObject(detectable)) throw 2;"
4809 "}\n"
4810 "function testBool() {"
4811 " var b1 = !%_IsUndetectableObject(undetectable);"
4812 " var b2 = %_IsUndetectableObject(detectable);"
4813 " if (b1) throw 3;"
4814 " if (b2) throw 4;"
4815 " return b1 == b2;"
4816 "}\n"
4817 "%OptimizeFunctionOnNextCall(testBranch);"
4818 "%OptimizeFunctionOnNextCall(testBool);"
4819 "for (var i = 0; i < 10; i++) {"
4820 " testBranch();"
4821 " testBool();"
4822 "}\n"
4823 "\"PASS\"",
4824 "PASS");
4825}
4826
4827
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004828template <typename T> static void USE(T) { }
4829
4830
4831// This test is not intended to be run, just type checked.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004832static inline void PersistentHandles() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004833 USE(PersistentHandles);
4834 Local<String> str = v8_str("foo");
4835 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4836 USE(p_str);
4837 Local<Script> scr = Script::Compile(v8_str(""));
4838 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4839 USE(p_scr);
4840 Local<ObjectTemplate> templ = ObjectTemplate::New();
4841 v8::Persistent<ObjectTemplate> p_templ =
4842 v8::Persistent<ObjectTemplate>::New(templ);
4843 USE(p_templ);
4844}
4845
4846
4847static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4848 ApiTestFuzzer::Fuzz();
4849 return v8::Undefined();
4850}
4851
4852
4853THREADED_TEST(GlobalObjectTemplate) {
4854 v8::HandleScope handle_scope;
4855 Local<ObjectTemplate> global_template = ObjectTemplate::New();
4856 global_template->Set(v8_str("JSNI_Log"),
4857 v8::FunctionTemplate::New(HandleLogDelegator));
4858 v8::Persistent<Context> context = Context::New(0, global_template);
4859 Context::Scope context_scope(context);
4860 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4861 context.Dispose();
4862}
4863
4864
4865static const char* kSimpleExtensionSource =
4866 "function Foo() {"
4867 " return 4;"
4868 "}";
4869
4870
4871THREADED_TEST(SimpleExtensions) {
4872 v8::HandleScope handle_scope;
4873 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4874 const char* extension_names[] = { "simpletest" };
4875 v8::ExtensionConfiguration extensions(1, extension_names);
4876 v8::Handle<Context> context = Context::New(&extensions);
4877 Context::Scope lock(context);
4878 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4879 CHECK_EQ(result, v8::Integer::New(4));
4880}
4881
4882
danno@chromium.org412fa512012-09-14 13:28:26 +00004883THREADED_TEST(NullExtensions) {
4884 v8::HandleScope handle_scope;
4885 v8::RegisterExtension(new Extension("nulltest", NULL));
4886 const char* extension_names[] = { "nulltest" };
4887 v8::ExtensionConfiguration extensions(1, extension_names);
4888 v8::Handle<Context> context = Context::New(&extensions);
4889 Context::Scope lock(context);
4890 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
4891 CHECK_EQ(result, v8::Integer::New(4));
4892}
4893
4894
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004895static const char* kEmbeddedExtensionSource =
4896 "function Ret54321(){return 54321;}~~@@$"
4897 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4898static const int kEmbeddedExtensionSourceValidLen = 34;
4899
4900
4901THREADED_TEST(ExtensionMissingSourceLength) {
4902 v8::HandleScope handle_scope;
4903 v8::RegisterExtension(new Extension("srclentest_fail",
4904 kEmbeddedExtensionSource));
4905 const char* extension_names[] = { "srclentest_fail" };
4906 v8::ExtensionConfiguration extensions(1, extension_names);
4907 v8::Handle<Context> context = Context::New(&extensions);
4908 CHECK_EQ(0, *context);
4909}
4910
4911
4912THREADED_TEST(ExtensionWithSourceLength) {
4913 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4914 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4915 v8::HandleScope handle_scope;
4916 i::ScopedVector<char> extension_name(32);
4917 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4918 v8::RegisterExtension(new Extension(extension_name.start(),
4919 kEmbeddedExtensionSource, 0, 0,
4920 source_len));
4921 const char* extension_names[1] = { extension_name.start() };
4922 v8::ExtensionConfiguration extensions(1, extension_names);
4923 v8::Handle<Context> context = Context::New(&extensions);
4924 if (source_len == kEmbeddedExtensionSourceValidLen) {
4925 Context::Scope lock(context);
4926 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4927 CHECK_EQ(v8::Integer::New(54321), result);
4928 } else {
4929 // Anything but exactly the right length should fail to compile.
4930 CHECK_EQ(0, *context);
4931 }
4932 }
4933}
4934
4935
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004936static const char* kEvalExtensionSource1 =
4937 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004938 " var x = 42;"
4939 " return eval('x');"
4940 "}";
4941
4942
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004943static const char* kEvalExtensionSource2 =
4944 "(function() {"
4945 " var x = 42;"
4946 " function e() {"
4947 " return eval('x');"
4948 " }"
4949 " this.UseEval2 = e;"
4950 "})()";
4951
4952
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004953THREADED_TEST(UseEvalFromExtension) {
4954 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004955 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4956 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4957 const char* extension_names[] = { "evaltest1", "evaltest2" };
4958 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004959 v8::Handle<Context> context = Context::New(&extensions);
4960 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004961 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4962 CHECK_EQ(result, v8::Integer::New(42));
4963 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004964 CHECK_EQ(result, v8::Integer::New(42));
4965}
4966
4967
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004968static const char* kWithExtensionSource1 =
4969 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004970 " var x = 42;"
4971 " with({x:87}) { return x; }"
4972 "}";
4973
4974
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004975
4976static const char* kWithExtensionSource2 =
4977 "(function() {"
4978 " var x = 42;"
4979 " function e() {"
4980 " with ({x:87}) { return x; }"
4981 " }"
4982 " this.UseWith2 = e;"
4983 "})()";
4984
4985
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004986THREADED_TEST(UseWithFromExtension) {
4987 v8::HandleScope handle_scope;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004988 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4989 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4990 const char* extension_names[] = { "withtest1", "withtest2" };
4991 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004992 v8::Handle<Context> context = Context::New(&extensions);
4993 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004994 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4995 CHECK_EQ(result, v8::Integer::New(87));
4996 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00004997 CHECK_EQ(result, v8::Integer::New(87));
4998}
4999
5000
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005001THREADED_TEST(AutoExtensions) {
5002 v8::HandleScope handle_scope;
5003 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5004 extension->set_auto_enable(true);
5005 v8::RegisterExtension(extension);
5006 v8::Handle<Context> context = Context::New();
5007 Context::Scope lock(context);
5008 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5009 CHECK_EQ(result, v8::Integer::New(4));
5010}
5011
5012
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005013static const char* kSyntaxErrorInExtensionSource =
5014 "[";
5015
5016
5017// Test that a syntax error in an extension does not cause a fatal
5018// error but results in an empty context.
5019THREADED_TEST(SyntaxErrorExtensions) {
5020 v8::HandleScope handle_scope;
5021 v8::RegisterExtension(new Extension("syntaxerror",
5022 kSyntaxErrorInExtensionSource));
5023 const char* extension_names[] = { "syntaxerror" };
5024 v8::ExtensionConfiguration extensions(1, extension_names);
5025 v8::Handle<Context> context = Context::New(&extensions);
5026 CHECK(context.IsEmpty());
5027}
5028
5029
5030static const char* kExceptionInExtensionSource =
5031 "throw 42";
5032
5033
5034// Test that an exception when installing an extension does not cause
5035// a fatal error but results in an empty context.
5036THREADED_TEST(ExceptionExtensions) {
5037 v8::HandleScope handle_scope;
5038 v8::RegisterExtension(new Extension("exception",
5039 kExceptionInExtensionSource));
5040 const char* extension_names[] = { "exception" };
5041 v8::ExtensionConfiguration extensions(1, extension_names);
5042 v8::Handle<Context> context = Context::New(&extensions);
5043 CHECK(context.IsEmpty());
5044}
5045
5046
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005047static const char* kNativeCallInExtensionSource =
5048 "function call_runtime_last_index_of(x) {"
5049 " return %StringLastIndexOf(x, 'bob', 10);"
5050 "}";
5051
5052
5053static const char* kNativeCallTest =
5054 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
5055
5056// Test that a native runtime calls are supported in extensions.
5057THREADED_TEST(NativeCallInExtensions) {
5058 v8::HandleScope handle_scope;
5059 v8::RegisterExtension(new Extension("nativecall",
5060 kNativeCallInExtensionSource));
5061 const char* extension_names[] = { "nativecall" };
5062 v8::ExtensionConfiguration extensions(1, extension_names);
5063 v8::Handle<Context> context = Context::New(&extensions);
5064 Context::Scope lock(context);
5065 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
5066 CHECK_EQ(result, v8::Integer::New(3));
5067}
5068
5069
whesse@chromium.org7b260152011-06-20 15:33:18 +00005070class NativeFunctionExtension : public Extension {
5071 public:
5072 NativeFunctionExtension(const char* name,
5073 const char* source,
5074 v8::InvocationCallback fun = &Echo)
5075 : Extension(name, source),
5076 function_(fun) { }
5077
5078 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5079 v8::Handle<v8::String> name) {
5080 return v8::FunctionTemplate::New(function_);
5081 }
5082
5083 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
5084 if (args.Length() >= 1) return (args[0]);
5085 return v8::Undefined();
5086 }
5087 private:
5088 v8::InvocationCallback function_;
5089};
5090
5091
5092THREADED_TEST(NativeFunctionDeclaration) {
5093 v8::HandleScope handle_scope;
5094 const char* name = "nativedecl";
5095 v8::RegisterExtension(new NativeFunctionExtension(name,
5096 "native function foo();"));
5097 const char* extension_names[] = { name };
5098 v8::ExtensionConfiguration extensions(1, extension_names);
5099 v8::Handle<Context> context = Context::New(&extensions);
5100 Context::Scope lock(context);
5101 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
5102 CHECK_EQ(result, v8::Integer::New(42));
5103}
5104
5105
5106THREADED_TEST(NativeFunctionDeclarationError) {
5107 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005108 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005109 // Syntax error in extension code.
5110 v8::RegisterExtension(new NativeFunctionExtension(name,
5111 "native\nfunction foo();"));
5112 const char* extension_names[] = { name };
5113 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005114 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005115 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005116}
5117
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005118
whesse@chromium.org7b260152011-06-20 15:33:18 +00005119THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
5120 v8::HandleScope handle_scope;
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005121 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005122 // Syntax error in extension code - escape code in "native" means that
5123 // it's not treated as a keyword.
5124 v8::RegisterExtension(new NativeFunctionExtension(
5125 name,
5126 "nativ\\u0065 function foo();"));
5127 const char* extension_names[] = { name };
5128 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005129 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005130 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005131}
5132
5133
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005134static void CheckDependencies(const char* name, const char* expected) {
5135 v8::HandleScope handle_scope;
5136 v8::ExtensionConfiguration config(1, &name);
5137 LocalContext context(&config);
5138 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5139}
5140
5141
5142/*
5143 * Configuration:
5144 *
5145 * /-- B <--\
5146 * A <- -- D <-- E
5147 * \-- C <--/
5148 */
5149THREADED_TEST(ExtensionDependency) {
5150 static const char* kEDeps[] = { "D" };
5151 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5152 static const char* kDDeps[] = { "B", "C" };
5153 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5154 static const char* kBCDeps[] = { "A" };
5155 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5156 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5157 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5158 CheckDependencies("A", "undefinedA");
5159 CheckDependencies("B", "undefinedAB");
5160 CheckDependencies("C", "undefinedAC");
5161 CheckDependencies("D", "undefinedABCD");
5162 CheckDependencies("E", "undefinedABCDE");
5163 v8::HandleScope handle_scope;
5164 static const char* exts[2] = { "C", "E" };
5165 v8::ExtensionConfiguration config(2, exts);
5166 LocalContext context(&config);
5167 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5168}
5169
5170
5171static const char* kExtensionTestScript =
5172 "native function A();"
5173 "native function B();"
5174 "native function C();"
5175 "function Foo(i) {"
5176 " if (i == 0) return A();"
5177 " if (i == 1) return B();"
5178 " if (i == 2) return C();"
5179 "}";
5180
5181
5182static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5183 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005184 if (args.IsConstructCall()) {
5185 args.This()->Set(v8_str("data"), args.Data());
5186 return v8::Null();
5187 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005188 return args.Data();
5189}
5190
5191
5192class FunctionExtension : public Extension {
5193 public:
5194 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5195 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5196 v8::Handle<String> name);
5197};
5198
5199
5200static int lookup_count = 0;
5201v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5202 v8::Handle<String> name) {
5203 lookup_count++;
5204 if (name->Equals(v8_str("A"))) {
5205 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5206 } else if (name->Equals(v8_str("B"))) {
5207 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5208 } else if (name->Equals(v8_str("C"))) {
5209 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5210 } else {
5211 return v8::Handle<v8::FunctionTemplate>();
5212 }
5213}
5214
5215
5216THREADED_TEST(FunctionLookup) {
5217 v8::RegisterExtension(new FunctionExtension());
5218 v8::HandleScope handle_scope;
5219 static const char* exts[1] = { "functiontest" };
5220 v8::ExtensionConfiguration config(1, exts);
5221 LocalContext context(&config);
5222 CHECK_EQ(3, lookup_count);
5223 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5224 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5225 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5226}
5227
5228
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005229THREADED_TEST(NativeFunctionConstructCall) {
5230 v8::RegisterExtension(new FunctionExtension());
5231 v8::HandleScope handle_scope;
5232 static const char* exts[1] = { "functiontest" };
5233 v8::ExtensionConfiguration config(1, exts);
5234 LocalContext context(&config);
5235 for (int i = 0; i < 10; i++) {
5236 // Run a few times to ensure that allocation of objects doesn't
5237 // change behavior of a constructor function.
5238 CHECK_EQ(v8::Integer::New(8),
5239 Script::Compile(v8_str("(new A()).data"))->Run());
5240 CHECK_EQ(v8::Integer::New(7),
5241 Script::Compile(v8_str("(new B()).data"))->Run());
5242 CHECK_EQ(v8::Integer::New(6),
5243 Script::Compile(v8_str("(new C()).data"))->Run());
5244 }
5245}
5246
5247
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005248static const char* last_location;
5249static const char* last_message;
5250void StoringErrorCallback(const char* location, const char* message) {
5251 if (last_location == NULL) {
5252 last_location = location;
5253 last_message = message;
5254 }
5255}
5256
5257
5258// ErrorReporting creates a circular extensions configuration and
5259// tests that the fatal error handler gets called. This renders V8
5260// unusable and therefore this test cannot be run in parallel.
5261TEST(ErrorReporting) {
5262 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5263 static const char* aDeps[] = { "B" };
5264 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5265 static const char* bDeps[] = { "A" };
5266 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5267 last_location = NULL;
5268 v8::ExtensionConfiguration config(1, bDeps);
5269 v8::Handle<Context> context = Context::New(&config);
5270 CHECK(context.IsEmpty());
5271 CHECK_NE(last_location, NULL);
5272}
5273
5274
ager@chromium.org7c537e22008-10-16 08:43:32 +00005275static const char* js_code_causing_huge_string_flattening =
5276 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00005277 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00005278 " str = str + str;"
5279 "}"
5280 "str.match(/X/);";
5281
5282
5283void OOMCallback(const char* location, const char* message) {
5284 exit(0);
5285}
5286
5287
5288TEST(RegexpOutOfMemory) {
5289 // Execute a script that causes out of memory when flattening a string.
5290 v8::HandleScope scope;
5291 v8::V8::SetFatalErrorHandler(OOMCallback);
5292 LocalContext context;
5293 Local<Script> script =
5294 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5295 last_location = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005296 script->Run();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005297
5298 CHECK(false); // Should not return.
5299}
5300
5301
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005302static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5303 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005304 CHECK(message->GetScriptResourceName()->IsUndefined());
5305 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005306 message->GetLineNumber();
5307 message->GetSourceLine();
5308}
5309
5310
5311THREADED_TEST(ErrorWithMissingScriptInfo) {
5312 v8::HandleScope scope;
5313 LocalContext context;
5314 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5315 Script::Compile(v8_str("throw Error()"))->Run();
5316 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5317}
5318
5319
5320int global_index = 0;
5321
5322class Snorkel {
5323 public:
5324 Snorkel() { index_ = global_index++; }
5325 int index_;
5326};
5327
5328class Whammy {
5329 public:
5330 Whammy() {
5331 cursor_ = 0;
5332 }
5333 ~Whammy() {
5334 script_.Dispose();
5335 }
5336 v8::Handle<Script> getScript() {
5337 if (script_.IsEmpty())
5338 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
5339 return Local<Script>(*script_);
5340 }
5341
5342 public:
5343 static const int kObjectCount = 256;
5344 int cursor_;
5345 v8::Persistent<v8::Object> objects_[kObjectCount];
5346 v8::Persistent<Script> script_;
5347};
5348
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005349static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005350 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5351 delete snorkel;
5352 obj.ClearWeak();
5353}
5354
5355v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5356 const AccessorInfo& info) {
5357 Whammy* whammy =
5358 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5359
5360 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5361
5362 v8::Handle<v8::Object> obj = v8::Object::New();
5363 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
5364 if (!prev.IsEmpty()) {
5365 prev->Set(v8_str("next"), obj);
5366 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
5367 whammy->objects_[whammy->cursor_].Clear();
5368 }
5369 whammy->objects_[whammy->cursor_] = global;
5370 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5371 return whammy->getScript()->Run();
5372}
5373
5374THREADED_TEST(WeakReference) {
5375 v8::HandleScope handle_scope;
5376 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005377 Whammy* whammy = new Whammy();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005378 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5379 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005380 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005381 const char* extension_list[] = { "v8/gc" };
5382 v8::ExtensionConfiguration extensions(1, extension_list);
5383 v8::Persistent<Context> context = Context::New(&extensions);
5384 Context::Scope context_scope(context);
5385
5386 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5387 context->Global()->Set(v8_str("whammy"), interceptor);
5388 const char* code =
5389 "var last;"
5390 "for (var i = 0; i < 10000; i++) {"
5391 " var obj = whammy.length;"
5392 " if (last) last.next = obj;"
5393 " last = obj;"
5394 "}"
5395 "gc();"
5396 "4";
5397 v8::Handle<Value> result = CompileRun(code);
5398 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005399 delete whammy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005400 context.Dispose();
5401}
5402
5403
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005404static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005405 obj.Dispose();
5406 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005407 *(reinterpret_cast<bool*>(data)) = true;
5408}
5409
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005410
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005411THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005412 v8::Persistent<Context> context = Context::New();
5413 Context::Scope context_scope(context);
5414
5415 v8::Persistent<v8::Object> object_a;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005416
5417 {
5418 v8::HandleScope handle_scope;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005419 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5420 }
5421
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005422 v8::Isolate* isolate = v8::Isolate::GetCurrent();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005423 bool object_a_disposed = false;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005424 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005425 CHECK(!object_a.IsIndependent());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005426 CHECK(!object_a.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005427 object_a.MarkIndependent();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005428 CHECK(object_a.IsIndependent());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005429 CHECK(object_a.IsIndependent(isolate));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005430 HEAP->PerformScavenge();
5431 CHECK(object_a_disposed);
5432}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005433
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005434
5435static void InvokeScavenge() {
5436 HEAP->PerformScavenge();
5437}
5438
5439
5440static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005441 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005442}
5443
5444
5445static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5446 obj.Dispose();
5447 obj.Clear();
5448 *(reinterpret_cast<bool*>(data)) = true;
5449 InvokeScavenge();
5450}
5451
5452
5453static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5454 obj.Dispose();
5455 obj.Clear();
5456 *(reinterpret_cast<bool*>(data)) = true;
5457 InvokeMarkSweep();
5458}
5459
5460
5461THREADED_TEST(GCFromWeakCallbacks) {
5462 v8::Persistent<Context> context = Context::New();
5463 Context::Scope context_scope(context);
5464
5465 static const int kNumberOfGCTypes = 2;
5466 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5467 {&ForceScavenge, &ForceMarkSweep};
5468
5469 typedef void (*GCInvoker)();
5470 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5471
5472 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5473 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5474 v8::Persistent<v8::Object> object;
5475 {
5476 v8::HandleScope handle_scope;
5477 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5478 }
5479 bool disposed = false;
5480 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5481 object.MarkIndependent();
5482 invoke_gc[outer_gc]();
5483 CHECK(disposed);
5484 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005485 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005486}
5487
5488
5489static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5490 obj.ClearWeak();
5491 *(reinterpret_cast<bool*>(data)) = true;
5492}
5493
5494
5495THREADED_TEST(IndependentHandleRevival) {
5496 v8::Persistent<Context> context = Context::New();
5497 Context::Scope context_scope(context);
5498
5499 v8::Persistent<v8::Object> object;
5500 {
5501 v8::HandleScope handle_scope;
5502 object = v8::Persistent<v8::Object>::New(v8::Object::New());
5503 object->Set(v8_str("x"), v8::Integer::New(1));
5504 v8::Local<String> y_str = v8_str("y");
5505 object->Set(y_str, y_str);
5506 }
5507 bool revived = false;
5508 object.MakeWeak(&revived, &RevivingCallback);
5509 object.MarkIndependent();
5510 HEAP->PerformScavenge();
5511 CHECK(revived);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00005512 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005513 {
5514 v8::HandleScope handle_scope;
5515 v8::Local<String> y_str = v8_str("y");
5516 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5517 CHECK(object->Get(y_str)->Equals(y_str));
5518 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005519}
5520
5521
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005522v8::Handle<Function> args_fun;
5523
5524
5525static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5526 ApiTestFuzzer::Fuzz();
5527 CHECK_EQ(args_fun, args.Callee());
5528 CHECK_EQ(3, args.Length());
5529 CHECK_EQ(v8::Integer::New(1), args[0]);
5530 CHECK_EQ(v8::Integer::New(2), args[1]);
5531 CHECK_EQ(v8::Integer::New(3), args[2]);
5532 CHECK_EQ(v8::Undefined(), args[3]);
5533 v8::HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005534 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005535 return v8::Undefined();
5536}
5537
5538
5539THREADED_TEST(Arguments) {
5540 v8::HandleScope scope;
5541 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5542 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5543 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005544 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005545 v8_compile("f(1, 2, 3)")->Run();
5546}
5547
5548
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005549static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5550 const AccessorInfo&) {
5551 return v8::Handle<Value>();
5552}
5553
5554
5555static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5556 const AccessorInfo&) {
5557 return v8::Handle<Value>();
5558}
5559
5560
5561static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5562 const AccessorInfo&) {
5563 if (!name->Equals(v8_str("foo"))) {
5564 return v8::Handle<v8::Boolean>(); // not intercepted
5565 }
5566
5567 return v8::False(); // intercepted, and don't delete the property
5568}
5569
5570
5571static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5572 if (index != 2) {
5573 return v8::Handle<v8::Boolean>(); // not intercepted
5574 }
5575
5576 return v8::False(); // intercepted, and don't delete the property
5577}
5578
5579
5580THREADED_TEST(Deleter) {
5581 v8::HandleScope scope;
5582 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5583 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5584 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5585 LocalContext context;
5586 context->Global()->Set(v8_str("k"), obj->NewInstance());
5587 CompileRun(
5588 "k.foo = 'foo';"
5589 "k.bar = 'bar';"
5590 "k[2] = 2;"
5591 "k[4] = 4;");
5592 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5593 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5594
5595 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5596 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5597
5598 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5599 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5600
5601 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5602 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5603}
5604
5605
5606static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5607 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005608 if (name->Equals(v8_str("foo")) ||
5609 name->Equals(v8_str("bar")) ||
5610 name->Equals(v8_str("baz"))) {
5611 return v8::Undefined();
5612 }
5613 return v8::Handle<Value>();
5614}
5615
5616
5617static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5618 ApiTestFuzzer::Fuzz();
5619 if (index == 0 || index == 1) return v8::Undefined();
5620 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005621}
5622
5623
5624static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5625 ApiTestFuzzer::Fuzz();
5626 v8::Handle<v8::Array> result = v8::Array::New(3);
5627 result->Set(v8::Integer::New(0), v8_str("foo"));
5628 result->Set(v8::Integer::New(1), v8_str("bar"));
5629 result->Set(v8::Integer::New(2), v8_str("baz"));
5630 return result;
5631}
5632
5633
5634static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5635 ApiTestFuzzer::Fuzz();
5636 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005637 result->Set(v8::Integer::New(0), v8_str("0"));
5638 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005639 return result;
5640}
5641
5642
5643THREADED_TEST(Enumerators) {
5644 v8::HandleScope scope;
5645 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5646 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005647 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648 LocalContext context;
5649 context->Global()->Set(v8_str("k"), obj->NewInstance());
5650 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005651 "k[10] = 0;"
5652 "k.a = 0;"
5653 "k[5] = 0;"
5654 "k.b = 0;"
5655 "k[4294967295] = 0;"
5656 "k.c = 0;"
5657 "k[4294967296] = 0;"
5658 "k.d = 0;"
5659 "k[140000] = 0;"
5660 "k.e = 0;"
5661 "k[30000000000] = 0;"
5662 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005663 "var result = [];"
5664 "for (var prop in k) {"
5665 " result.push(prop);"
5666 "}"
5667 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005668 // Check that we get all the property names returned including the
5669 // ones from the enumerators in the right order: indexed properties
5670 // in numerical order, indexed interceptor properties, named
5671 // properties in insertion order, named interceptor properties.
5672 // This order is not mandated by the spec, so this test is just
5673 // documenting our behavior.
5674 CHECK_EQ(17, result->Length());
5675 // Indexed properties in numerical order.
5676 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5677 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5678 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5679 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5680 // Indexed interceptor properties in the order they are returned
5681 // from the enumerator interceptor.
5682 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5683 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5684 // Named properties in insertion order.
5685 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5686 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5687 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5688 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5689 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5690 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5691 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5692 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5693 // Named interceptor properties.
5694 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5695 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5696 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005697}
5698
5699
5700int p_getter_count;
5701int p_getter_count2;
5702
5703
5704static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5705 ApiTestFuzzer::Fuzz();
5706 p_getter_count++;
5707 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5708 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5709 if (name->Equals(v8_str("p1"))) {
5710 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5711 } else if (name->Equals(v8_str("p2"))) {
5712 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5713 } else if (name->Equals(v8_str("p3"))) {
5714 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5715 } else if (name->Equals(v8_str("p4"))) {
5716 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5717 }
5718 return v8::Undefined();
5719}
5720
5721
5722static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5723 ApiTestFuzzer::Fuzz();
5724 LocalContext context;
5725 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5726 CompileRun(
5727 "o1.__proto__ = { };"
5728 "var o2 = { __proto__: o1 };"
5729 "var o3 = { __proto__: o2 };"
5730 "var o4 = { __proto__: o3 };"
5731 "for (var i = 0; i < 10; i++) o4.p4;"
5732 "for (var i = 0; i < 10; i++) o3.p3;"
5733 "for (var i = 0; i < 10; i++) o2.p2;"
5734 "for (var i = 0; i < 10; i++) o1.p1;");
5735}
5736
5737
5738static v8::Handle<Value> PGetter2(Local<String> name,
5739 const AccessorInfo& info) {
5740 ApiTestFuzzer::Fuzz();
5741 p_getter_count2++;
5742 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5743 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5744 if (name->Equals(v8_str("p1"))) {
5745 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5746 } else if (name->Equals(v8_str("p2"))) {
5747 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5748 } else if (name->Equals(v8_str("p3"))) {
5749 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5750 } else if (name->Equals(v8_str("p4"))) {
5751 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5752 }
5753 return v8::Undefined();
5754}
5755
5756
5757THREADED_TEST(GetterHolders) {
5758 v8::HandleScope scope;
5759 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5760 obj->SetAccessor(v8_str("p1"), PGetter);
5761 obj->SetAccessor(v8_str("p2"), PGetter);
5762 obj->SetAccessor(v8_str("p3"), PGetter);
5763 obj->SetAccessor(v8_str("p4"), PGetter);
5764 p_getter_count = 0;
5765 RunHolderTest(obj);
5766 CHECK_EQ(40, p_getter_count);
5767}
5768
5769
5770THREADED_TEST(PreInterceptorHolders) {
5771 v8::HandleScope scope;
5772 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5773 obj->SetNamedPropertyHandler(PGetter2);
5774 p_getter_count2 = 0;
5775 RunHolderTest(obj);
5776 CHECK_EQ(40, p_getter_count2);
5777}
5778
5779
5780THREADED_TEST(ObjectInstantiation) {
5781 v8::HandleScope scope;
5782 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5783 templ->SetAccessor(v8_str("t"), PGetter2);
5784 LocalContext context;
5785 context->Global()->Set(v8_str("o"), templ->NewInstance());
5786 for (int i = 0; i < 100; i++) {
5787 v8::HandleScope inner_scope;
5788 v8::Handle<v8::Object> obj = templ->NewInstance();
5789 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5790 context->Global()->Set(v8_str("o2"), obj);
5791 v8::Handle<Value> value =
5792 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5793 CHECK_EQ(v8::True(), value);
5794 context->Global()->Set(v8_str("o"), obj);
5795 }
5796}
5797
5798
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005799static int StrCmp16(uint16_t* a, uint16_t* b) {
5800 while (true) {
5801 if (*a == 0 && *b == 0) return 0;
5802 if (*a != *b) return 0 + *a - *b;
5803 a++;
5804 b++;
5805 }
5806}
5807
5808
5809static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5810 while (true) {
5811 if (n-- == 0) return 0;
5812 if (*a == 0 && *b == 0) return 0;
5813 if (*a != *b) return 0 + *a - *b;
5814 a++;
5815 b++;
5816 }
5817}
5818
5819
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005820int GetUtf8Length(Handle<String> str) {
5821 int len = str->Utf8Length();
5822 if (len < 0) {
5823 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5824 i::FlattenString(istr);
5825 len = str->Utf8Length();
5826 }
5827 return len;
5828}
5829
5830
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005831THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005832 LocalContext context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005833 v8::HandleScope scope;
5834 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005835 // abc<Icelandic eth><Unicode snowman>.
5836 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005837 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005838 const int kStride = 4; // Must match stride in for loops in JS below.
5839 CompileRun(
5840 "var left = '';"
5841 "for (var i = 0; i < 0xd800; i += 4) {"
5842 " left = left + String.fromCharCode(i);"
5843 "}");
5844 CompileRun(
5845 "var right = '';"
5846 "for (var i = 0; i < 0xd800; i += 4) {"
5847 " right = String.fromCharCode(i) + right;"
5848 "}");
5849 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5850 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5851 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005852
5853 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005854 CHECK_EQ(0xd800 / kStride, left_tree->Length());
5855 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005856
5857 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005858 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005859 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005860 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005861 int charlen;
5862
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005863 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005864 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005865 CHECK_EQ(9, len);
5866 CHECK_EQ(5, charlen);
5867 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005868
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005869 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005870 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005871 CHECK_EQ(8, len);
5872 CHECK_EQ(5, charlen);
5873 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005874
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005875 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005876 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005877 CHECK_EQ(5, len);
5878 CHECK_EQ(4, charlen);
5879 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005880
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005881 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005882 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005883 CHECK_EQ(5, len);
5884 CHECK_EQ(4, charlen);
5885 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005887 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005888 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005889 CHECK_EQ(5, len);
5890 CHECK_EQ(4, charlen);
5891 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005892
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005893 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005894 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005895 CHECK_EQ(3, len);
5896 CHECK_EQ(3, charlen);
5897 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005898
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005899 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005900 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005901 CHECK_EQ(3, len);
5902 CHECK_EQ(3, charlen);
5903 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005904
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005905 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005906 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005907 CHECK_EQ(2, len);
5908 CHECK_EQ(2, charlen);
5909 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005910
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005911 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005912 len = GetUtf8Length(left_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005913 int utf8_expected =
5914 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5915 CHECK_EQ(utf8_expected, len);
5916 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5917 CHECK_EQ(utf8_expected, len);
5918 CHECK_EQ(0xd800 / kStride, charlen);
5919 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5920 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5921 CHECK_EQ(0xc0 - kStride,
5922 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5923 CHECK_EQ(1, utf8buf[utf8_expected]);
5924
5925 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005926 len = GetUtf8Length(right_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005927 CHECK_EQ(utf8_expected, len);
5928 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5929 CHECK_EQ(utf8_expected, len);
5930 CHECK_EQ(0xd800 / kStride, charlen);
5931 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5932 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5933 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5934 CHECK_EQ(1, utf8buf[utf8_expected]);
5935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005936 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005937 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005938 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005939 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005940 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005941 CHECK_EQ(5, len);
5942 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005943 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005944 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005945
5946 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005947 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005948 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005949 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005950 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005951 CHECK_EQ(4, len);
5952 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005953 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005954 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005955
5956 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005957 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005958 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005959 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005960 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005961 CHECK_EQ(5, len);
5962 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005963 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005964 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005965
5966 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005967 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005968 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005969 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005970 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005971 CHECK_EQ(5, len);
5972 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005973 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005974 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005975
5976 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005977 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005978 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005979 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005980 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005981 CHECK_EQ(1, len);
5982 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005983 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005984 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985
5986 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005987 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005988 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005989 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005990 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005991 CHECK_EQ(1, len);
5992 CHECK_EQ(0, strcmp("e", buf));
5993 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005994
5995 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005996 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005997 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005998 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005999 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006000 CHECK_EQ(1, len);
6001 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006002 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006003 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006004
6005 memset(buf, 0x1, sizeof(buf));
6006 memset(wbuf, 0x1, sizeof(wbuf));
6007 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006008 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006009 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006010 CHECK_EQ(1, len);
6011 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006012 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006013 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006014
6015 memset(wbuf, 0x1, sizeof(wbuf));
6016 wbuf[5] = 'X';
6017 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
6018 CHECK_EQ(5, len);
6019 CHECK_EQ('X', wbuf[5]);
6020 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
6021 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6022 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
6023 CHECK_NE(0, StrCmp16(answer8b, wbuf));
6024 wbuf[5] = '\0';
6025 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
6026
6027 memset(buf, 0x1, sizeof(buf));
6028 buf[5] = 'X';
6029 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
6030 CHECK_EQ(5, len);
6031 CHECK_EQ('X', buf[5]);
6032 CHECK_EQ(0, strncmp("abcde", buf, 5));
6033 CHECK_NE(0, strcmp("abcde", buf));
6034 buf[5] = '\0';
6035 CHECK_EQ(0, strcmp("abcde", buf));
6036
6037 memset(utf8buf, 0x1, sizeof(utf8buf));
6038 utf8buf[8] = 'X';
6039 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6040 String::NO_NULL_TERMINATION);
6041 CHECK_EQ(8, len);
6042 CHECK_EQ('X', utf8buf[8]);
6043 CHECK_EQ(5, charlen);
6044 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
6045 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6046 utf8buf[8] = '\0';
6047 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006048
6049 memset(utf8buf, 0x1, sizeof(utf8buf));
6050 utf8buf[5] = 'X';
6051 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6052 String::NO_NULL_TERMINATION);
6053 CHECK_EQ(5, len);
6054 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
6055 CHECK_EQ(5, charlen);
6056 utf8buf[5] = '\0';
6057 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
6058
6059 memset(buf, 0x1, sizeof(buf));
6060 len = str3->WriteAscii(buf);
6061 CHECK_EQ(7, len);
6062 CHECK_EQ(0, strcmp("abc def", buf));
6063
6064 memset(buf, 0x1, sizeof(buf));
6065 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
6066 CHECK_EQ(7, len);
6067 CHECK_EQ(0, strcmp("abc", buf));
6068 CHECK_EQ(0, buf[3]);
6069 CHECK_EQ(0, strcmp("def", buf + 4));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006070}
6071
6072
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006073static void Utf16Helper(
6074 LocalContext& context,
6075 const char* name,
6076 const char* lengths_name,
6077 int len) {
6078 Local<v8::Array> a =
6079 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6080 Local<v8::Array> alens =
6081 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6082 for (int i = 0; i < len; i++) {
6083 Local<v8::String> string =
6084 Local<v8::String>::Cast(a->Get(i));
6085 Local<v8::Number> expected_len =
6086 Local<v8::Number>::Cast(alens->Get(i));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006087 CHECK_EQ(expected_len->Value() != string->Length(),
6088 string->MayContainNonAscii());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006089 int length = GetUtf8Length(string);
6090 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
6091 }
6092}
6093
6094
6095static uint16_t StringGet(Handle<String> str, int index) {
6096 i::Handle<i::String> istring =
6097 v8::Utils::OpenHandle(String::Cast(*str));
6098 return istring->Get(index);
6099}
6100
6101
6102static void WriteUtf8Helper(
6103 LocalContext& context,
6104 const char* name,
6105 const char* lengths_name,
6106 int len) {
6107 Local<v8::Array> b =
6108 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6109 Local<v8::Array> alens =
6110 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6111 char buffer[1000];
6112 char buffer2[1000];
6113 for (int i = 0; i < len; i++) {
6114 Local<v8::String> string =
6115 Local<v8::String>::Cast(b->Get(i));
6116 Local<v8::Number> expected_len =
6117 Local<v8::Number>::Cast(alens->Get(i));
6118 int utf8_length = static_cast<int>(expected_len->Value());
6119 for (int j = utf8_length + 1; j >= 0; j--) {
6120 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6121 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6122 int nchars;
6123 int utf8_written =
6124 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6125 int utf8_written2 =
6126 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6127 CHECK_GE(utf8_length + 1, utf8_written);
6128 CHECK_GE(utf8_length, utf8_written2);
6129 for (int k = 0; k < utf8_written2; k++) {
6130 CHECK_EQ(buffer[k], buffer2[k]);
6131 }
6132 CHECK(nchars * 3 >= utf8_written - 1);
6133 CHECK(nchars <= utf8_written);
6134 if (j == utf8_length + 1) {
6135 CHECK_EQ(utf8_written2, utf8_length);
6136 CHECK_EQ(utf8_written2 + 1, utf8_written);
6137 }
6138 CHECK_EQ(buffer[utf8_written], 42);
6139 if (j > utf8_length) {
6140 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6141 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6142 Handle<String> roundtrip = v8_str(buffer);
6143 CHECK(roundtrip->Equals(string));
6144 } else {
6145 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6146 }
6147 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6148 if (nchars >= 2) {
6149 uint16_t trail = StringGet(string, nchars - 1);
6150 uint16_t lead = StringGet(string, nchars - 2);
6151 if (((lead & 0xfc00) == 0xd800) &&
6152 ((trail & 0xfc00) == 0xdc00)) {
6153 unsigned char u1 = buffer2[utf8_written2 - 4];
6154 unsigned char u2 = buffer2[utf8_written2 - 3];
6155 unsigned char u3 = buffer2[utf8_written2 - 2];
6156 unsigned char u4 = buffer2[utf8_written2 - 1];
6157 CHECK_EQ((u1 & 0xf8), 0xf0);
6158 CHECK_EQ((u2 & 0xc0), 0x80);
6159 CHECK_EQ((u3 & 0xc0), 0x80);
6160 CHECK_EQ((u4 & 0xc0), 0x80);
6161 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6162 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6163 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6164 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6165 CHECK_EQ((u1 & 0x3), c >> 18);
6166 }
6167 }
6168 }
6169 }
6170}
6171
6172
6173THREADED_TEST(Utf16) {
6174 LocalContext context;
6175 v8::HandleScope scope;
6176 CompileRun(
6177 "var pad = '01234567890123456789';"
6178 "var p = [];"
6179 "var plens = [20, 3, 3];"
6180 "p.push('01234567890123456789');"
6181 "var lead = 0xd800;"
6182 "var trail = 0xdc00;"
6183 "p.push(String.fromCharCode(0xd800));"
6184 "p.push(String.fromCharCode(0xdc00));"
6185 "var a = [];"
6186 "var b = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006187 "var c = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006188 "var alens = [];"
6189 "for (var i = 0; i < 3; i++) {"
6190 " p[1] = String.fromCharCode(lead++);"
6191 " for (var j = 0; j < 3; j++) {"
6192 " p[2] = String.fromCharCode(trail++);"
6193 " a.push(p[i] + p[j]);"
6194 " b.push(p[i] + p[j]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006195 " c.push(p[i] + p[j]);"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006196 " alens.push(plens[i] + plens[j]);"
6197 " }"
6198 "}"
6199 "alens[5] -= 2;" // Here the surrogate pairs match up.
6200 "var a2 = [];"
6201 "var b2 = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006202 "var c2 = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006203 "var a2lens = [];"
6204 "for (var m = 0; m < 9; m++) {"
6205 " for (var n = 0; n < 9; n++) {"
6206 " a2.push(a[m] + a[n]);"
6207 " b2.push(b[m] + b[n]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006208 " var newc = 'x' + c[m] + c[n] + 'y';"
6209 " c2.push(newc.substring(1, newc.length - 1));"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006210 " var utf = alens[m] + alens[n];" // And here.
6211 // The 'n's that start with 0xdc.. are 6-8
6212 // The 'm's that end with 0xd8.. are 1, 4 and 7
6213 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6214 " a2lens.push(utf);"
6215 " }"
6216 "}");
6217 Utf16Helper(context, "a", "alens", 9);
6218 Utf16Helper(context, "a2", "a2lens", 81);
6219 WriteUtf8Helper(context, "b", "alens", 9);
6220 WriteUtf8Helper(context, "b2", "a2lens", 81);
danno@chromium.org88aa0582012-03-23 15:11:57 +00006221 WriteUtf8Helper(context, "c2", "a2lens", 81);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006222}
6223
6224
6225static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6226 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6227 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6228 return *is1 == *is2;
6229}
6230
6231
6232static void SameSymbolHelper(const char* a, const char* b) {
6233 Handle<String> symbol1 = v8::String::NewSymbol(a);
6234 Handle<String> symbol2 = v8::String::NewSymbol(b);
6235 CHECK(SameSymbol(symbol1, symbol2));
6236}
6237
6238
6239THREADED_TEST(Utf16Symbol) {
6240 LocalContext context;
6241 v8::HandleScope scope;
6242
6243 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6244 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6245 CHECK(SameSymbol(symbol1, symbol2));
6246
6247 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6248 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6249 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6250 "\360\220\220\206"); // 4 byte encoding.
6251 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6252 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6253 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6254 "x\360\220\220\206"); // 4 byte encoding.
6255 CompileRun(
6256 "var sym0 = 'benedictus';"
6257 "var sym0b = 'S\303\270ren';"
6258 "var sym1 = '\355\240\201\355\260\207';"
6259 "var sym2 = '\360\220\220\210';"
6260 "var sym3 = 'x\355\240\201\355\260\207';"
6261 "var sym4 = 'x\360\220\220\210';"
6262 "if (sym1.length != 2) throw sym1;"
6263 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6264 "if (sym2.length != 2) throw sym2;"
6265 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6266 "if (sym3.length != 3) throw sym3;"
6267 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6268 "if (sym4.length != 3) throw sym4;"
6269 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6270 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6271 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6272 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6273 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6274 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6275 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6276 v8::Local<v8::Object> global = context->Global();
6277 Local<Value> s0 = global->Get(v8_str("sym0"));
6278 Local<Value> s0b = global->Get(v8_str("sym0b"));
6279 Local<Value> s1 = global->Get(v8_str("sym1"));
6280 Local<Value> s2 = global->Get(v8_str("sym2"));
6281 Local<Value> s3 = global->Get(v8_str("sym3"));
6282 Local<Value> s4 = global->Get(v8_str("sym4"));
6283 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6284 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6285 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6286 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6287 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6288 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6289}
6290
6291
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006292THREADED_TEST(ToArrayIndex) {
6293 v8::HandleScope scope;
6294 LocalContext context;
6295
6296 v8::Handle<String> str = v8_str("42");
6297 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6298 CHECK(!index.IsEmpty());
6299 CHECK_EQ(42.0, index->Uint32Value());
6300 str = v8_str("42asdf");
6301 index = str->ToArrayIndex();
6302 CHECK(index.IsEmpty());
6303 str = v8_str("-42");
6304 index = str->ToArrayIndex();
6305 CHECK(index.IsEmpty());
6306 str = v8_str("4294967295");
6307 index = str->ToArrayIndex();
6308 CHECK(!index.IsEmpty());
6309 CHECK_EQ(4294967295.0, index->Uint32Value());
6310 v8::Handle<v8::Number> num = v8::Number::New(1);
6311 index = num->ToArrayIndex();
6312 CHECK(!index.IsEmpty());
6313 CHECK_EQ(1.0, index->Uint32Value());
6314 num = v8::Number::New(-1);
6315 index = num->ToArrayIndex();
6316 CHECK(index.IsEmpty());
6317 v8::Handle<v8::Object> obj = v8::Object::New();
6318 index = obj->ToArrayIndex();
6319 CHECK(index.IsEmpty());
6320}
6321
6322
6323THREADED_TEST(ErrorConstruction) {
6324 v8::HandleScope scope;
6325 LocalContext context;
6326
6327 v8::Handle<String> foo = v8_str("foo");
6328 v8::Handle<String> message = v8_str("message");
6329 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6330 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006331 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006332 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6333 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006334 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006335 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6336 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006337 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006338 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6339 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006340 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006341 v8::Handle<Value> error = v8::Exception::Error(foo);
6342 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006343 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006344}
6345
6346
6347static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6348 ApiTestFuzzer::Fuzz();
6349 return v8_num(10);
6350}
6351
6352
6353static void YSetter(Local<String> name,
6354 Local<Value> value,
6355 const AccessorInfo& info) {
6356 if (info.This()->Has(name)) {
6357 info.This()->Delete(name);
6358 }
6359 info.This()->Set(name, value);
6360}
6361
6362
6363THREADED_TEST(DeleteAccessor) {
6364 v8::HandleScope scope;
6365 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6366 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6367 LocalContext context;
6368 v8::Handle<v8::Object> holder = obj->NewInstance();
6369 context->Global()->Set(v8_str("holder"), holder);
6370 v8::Handle<Value> result = CompileRun(
6371 "holder.y = 11; holder.y = 12; holder.y");
6372 CHECK_EQ(12, result->Uint32Value());
6373}
6374
6375
6376THREADED_TEST(TypeSwitch) {
6377 v8::HandleScope scope;
6378 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6379 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6380 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6381 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6382 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6383 LocalContext context;
6384 v8::Handle<v8::Object> obj0 = v8::Object::New();
6385 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6386 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6387 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6388 for (int i = 0; i < 10; i++) {
6389 CHECK_EQ(0, type_switch->match(obj0));
6390 CHECK_EQ(1, type_switch->match(obj1));
6391 CHECK_EQ(2, type_switch->match(obj2));
6392 CHECK_EQ(3, type_switch->match(obj3));
6393 CHECK_EQ(3, type_switch->match(obj3));
6394 CHECK_EQ(2, type_switch->match(obj2));
6395 CHECK_EQ(1, type_switch->match(obj1));
6396 CHECK_EQ(0, type_switch->match(obj0));
6397 }
6398}
6399
6400
6401// For use within the TestSecurityHandler() test.
6402static bool g_security_callback_result = false;
6403static bool NamedSecurityTestCallback(Local<v8::Object> global,
6404 Local<Value> name,
6405 v8::AccessType type,
6406 Local<Value> data) {
6407 // Always allow read access.
6408 if (type == v8::ACCESS_GET)
6409 return true;
6410
6411 // Sometimes allow other access.
6412 return g_security_callback_result;
6413}
6414
6415
6416static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6417 uint32_t key,
6418 v8::AccessType type,
6419 Local<Value> data) {
6420 // Always allow read access.
6421 if (type == v8::ACCESS_GET)
6422 return true;
6423
6424 // Sometimes allow other access.
6425 return g_security_callback_result;
6426}
6427
6428
6429static int trouble_nesting = 0;
6430static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6431 ApiTestFuzzer::Fuzz();
6432 trouble_nesting++;
6433
6434 // Call a JS function that throws an uncaught exception.
6435 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6436 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6437 arg_this->Get(v8_str("trouble_callee")) :
6438 arg_this->Get(v8_str("trouble_caller"));
6439 CHECK(trouble_callee->IsFunction());
6440 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6441}
6442
6443
6444static int report_count = 0;
6445static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6446 v8::Handle<Value>) {
6447 report_count++;
6448}
6449
6450
6451// Counts uncaught exceptions, but other tests running in parallel
6452// also have uncaught exceptions.
6453TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006454 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006455 v8::HandleScope scope;
6456 LocalContext env;
6457 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6458
6459 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6460 v8::Local<v8::Object> global = env->Global();
6461 global->Set(v8_str("trouble"), fun->GetFunction());
6462
6463 Script::Compile(v8_str("function trouble_callee() {"
6464 " var x = null;"
6465 " return x.foo;"
6466 "};"
6467 "function trouble_caller() {"
6468 " trouble();"
6469 "};"))->Run();
6470 Local<Value> trouble = global->Get(v8_str("trouble"));
6471 CHECK(trouble->IsFunction());
6472 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6473 CHECK(trouble_callee->IsFunction());
6474 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6475 CHECK(trouble_caller->IsFunction());
6476 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6477 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006478 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6479}
6480
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006481static const char* script_resource_name = "ExceptionInNativeScript.js";
6482static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6483 v8::Handle<Value>) {
6484 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6485 CHECK(!name_val.IsEmpty() && name_val->IsString());
6486 v8::String::AsciiValue name(message->GetScriptResourceName());
6487 CHECK_EQ(script_resource_name, *name);
6488 CHECK_EQ(3, message->GetLineNumber());
6489 v8::String::AsciiValue source_line(message->GetSourceLine());
6490 CHECK_EQ(" new o.foo();", *source_line);
6491}
6492
6493TEST(ExceptionInNativeScript) {
6494 v8::HandleScope scope;
6495 LocalContext env;
6496 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6497
6498 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6499 v8::Local<v8::Object> global = env->Global();
6500 global->Set(v8_str("trouble"), fun->GetFunction());
6501
6502 Script::Compile(v8_str("function trouble() {\n"
6503 " var o = {};\n"
6504 " new o.foo();\n"
6505 "};"), v8::String::New(script_resource_name))->Run();
6506 Local<Value> trouble = global->Get(v8_str("trouble"));
6507 CHECK(trouble->IsFunction());
6508 Function::Cast(*trouble)->Call(global, 0, NULL);
6509 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6510}
6511
ager@chromium.org8bb60582008-12-11 12:02:20 +00006512
6513TEST(CompilationErrorUsingTryCatchHandler) {
6514 v8::HandleScope scope;
6515 LocalContext env;
6516 v8::TryCatch try_catch;
6517 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6518 CHECK_NE(NULL, *try_catch.Exception());
6519 CHECK(try_catch.HasCaught());
6520}
6521
6522
6523TEST(TryCatchFinallyUsingTryCatchHandler) {
6524 v8::HandleScope scope;
6525 LocalContext env;
6526 v8::TryCatch try_catch;
6527 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6528 CHECK(!try_catch.HasCaught());
6529 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6530 CHECK(try_catch.HasCaught());
6531 try_catch.Reset();
6532 Script::Compile(v8_str("(function() {"
6533 "try { throw ''; } finally { return; }"
6534 "})()"))->Run();
6535 CHECK(!try_catch.HasCaught());
6536 Script::Compile(v8_str("(function()"
6537 " { try { throw ''; } finally { throw 0; }"
6538 "})()"))->Run();
6539 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006540}
6541
6542
6543// SecurityHandler can't be run twice
6544TEST(SecurityHandler) {
6545 v8::HandleScope scope0;
6546 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6547 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6548 IndexedSecurityTestCallback);
6549 // Create an environment
6550 v8::Persistent<Context> context0 =
6551 Context::New(NULL, global_template);
6552 context0->Enter();
6553
6554 v8::Handle<v8::Object> global0 = context0->Global();
6555 v8::Handle<Script> script0 = v8_compile("foo = 111");
6556 script0->Run();
6557 global0->Set(v8_str("0"), v8_num(999));
6558 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6559 CHECK_EQ(111, foo0->Int32Value());
6560 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6561 CHECK_EQ(999, z0->Int32Value());
6562
6563 // Create another environment, should fail security checks.
6564 v8::HandleScope scope1;
6565
6566 v8::Persistent<Context> context1 =
6567 Context::New(NULL, global_template);
6568 context1->Enter();
6569
6570 v8::Handle<v8::Object> global1 = context1->Global();
6571 global1->Set(v8_str("othercontext"), global0);
6572 // This set will fail the security check.
6573 v8::Handle<Script> script1 =
6574 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6575 script1->Run();
6576 // This read will pass the security check.
6577 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6578 CHECK_EQ(111, foo1->Int32Value());
6579 // This read will pass the security check.
6580 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6581 CHECK_EQ(999, z1->Int32Value());
6582
6583 // Create another environment, should pass security checks.
6584 { g_security_callback_result = true; // allow security handler to pass.
6585 v8::HandleScope scope2;
6586 LocalContext context2;
6587 v8::Handle<v8::Object> global2 = context2->Global();
6588 global2->Set(v8_str("othercontext"), global0);
6589 v8::Handle<Script> script2 =
6590 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6591 script2->Run();
6592 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6593 CHECK_EQ(333, foo2->Int32Value());
6594 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6595 CHECK_EQ(888, z2->Int32Value());
6596 }
6597
6598 context1->Exit();
6599 context1.Dispose();
6600
6601 context0->Exit();
6602 context0.Dispose();
6603}
6604
6605
6606THREADED_TEST(SecurityChecks) {
6607 v8::HandleScope handle_scope;
6608 LocalContext env1;
6609 v8::Persistent<Context> env2 = Context::New();
6610
6611 Local<Value> foo = v8_str("foo");
6612 Local<Value> bar = v8_str("bar");
6613
6614 // Set to the same domain.
6615 env1->SetSecurityToken(foo);
6616
6617 // Create a function in env1.
6618 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6619 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6620 CHECK(spy->IsFunction());
6621
6622 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006623 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006624 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6625 CHECK(spy2->IsFunction());
6626
6627 // Switch to env2 in the same domain and invoke spy on env2.
6628 {
6629 env2->SetSecurityToken(foo);
6630 // Enter env2
6631 Context::Scope scope_env2(env2);
6632 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6633 CHECK(result->IsFunction());
6634 }
6635
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006636 {
6637 env2->SetSecurityToken(bar);
6638 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006639
6640 // Call cross_domain_call, it should throw an exception
6641 v8::TryCatch try_catch;
6642 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6643 CHECK(try_catch.HasCaught());
6644 }
6645
6646 env2.Dispose();
6647}
6648
6649
6650// Regression test case for issue 1183439.
6651THREADED_TEST(SecurityChecksForPrototypeChain) {
6652 v8::HandleScope scope;
6653 LocalContext current;
6654 v8::Persistent<Context> other = Context::New();
6655
6656 // Change context to be able to get to the Object function in the
6657 // other context without hitting the security checks.
6658 v8::Local<Value> other_object;
6659 { Context::Scope scope(other);
6660 other_object = other->Global()->Get(v8_str("Object"));
6661 other->Global()->Set(v8_num(42), v8_num(87));
6662 }
6663
6664 current->Global()->Set(v8_str("other"), other->Global());
6665 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6666
6667 // Make sure the security check fails here and we get an undefined
6668 // result instead of getting the Object function. Repeat in a loop
6669 // to make sure to exercise the IC code.
6670 v8::Local<Script> access_other0 = v8_compile("other.Object");
6671 v8::Local<Script> access_other1 = v8_compile("other[42]");
6672 for (int i = 0; i < 5; i++) {
6673 CHECK(!access_other0->Run()->Equals(other_object));
6674 CHECK(access_other0->Run()->IsUndefined());
6675 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6676 CHECK(access_other1->Run()->IsUndefined());
6677 }
6678
6679 // Create an object that has 'other' in its prototype chain and make
6680 // sure we cannot access the Object function indirectly through
6681 // that. Repeat in a loop to make sure to exercise the IC code.
6682 v8_compile("function F() { };"
6683 "F.prototype = other;"
6684 "var f = new F();")->Run();
6685 v8::Local<Script> access_f0 = v8_compile("f.Object");
6686 v8::Local<Script> access_f1 = v8_compile("f[42]");
6687 for (int j = 0; j < 5; j++) {
6688 CHECK(!access_f0->Run()->Equals(other_object));
6689 CHECK(access_f0->Run()->IsUndefined());
6690 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6691 CHECK(access_f1->Run()->IsUndefined());
6692 }
6693
6694 // Now it gets hairy: Set the prototype for the other global object
6695 // to be the current global object. The prototype chain for 'f' now
6696 // goes through 'other' but ends up in the current global object.
6697 { Context::Scope scope(other);
6698 other->Global()->Set(v8_str("__proto__"), current->Global());
6699 }
6700 // Set a named and an index property on the current global
6701 // object. To force the lookup to go through the other global object,
6702 // the properties must not exist in the other global object.
6703 current->Global()->Set(v8_str("foo"), v8_num(100));
6704 current->Global()->Set(v8_num(99), v8_num(101));
6705 // Try to read the properties from f and make sure that the access
6706 // gets stopped by the security checks on the other global object.
6707 Local<Script> access_f2 = v8_compile("f.foo");
6708 Local<Script> access_f3 = v8_compile("f[99]");
6709 for (int k = 0; k < 5; k++) {
6710 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6711 CHECK(access_f2->Run()->IsUndefined());
6712 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6713 CHECK(access_f3->Run()->IsUndefined());
6714 }
6715 other.Dispose();
6716}
6717
6718
6719THREADED_TEST(CrossDomainDelete) {
6720 v8::HandleScope handle_scope;
6721 LocalContext env1;
6722 v8::Persistent<Context> env2 = Context::New();
6723
6724 Local<Value> foo = v8_str("foo");
6725 Local<Value> bar = v8_str("bar");
6726
6727 // Set to the same domain.
6728 env1->SetSecurityToken(foo);
6729 env2->SetSecurityToken(foo);
6730
6731 env1->Global()->Set(v8_str("prop"), v8_num(3));
6732 env2->Global()->Set(v8_str("env1"), env1->Global());
6733
6734 // Change env2 to a different domain and delete env1.prop.
6735 env2->SetSecurityToken(bar);
6736 {
6737 Context::Scope scope_env2(env2);
6738 Local<Value> result =
6739 Script::Compile(v8_str("delete env1.prop"))->Run();
6740 CHECK(result->IsFalse());
6741 }
6742
6743 // Check that env1.prop still exists.
6744 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6745 CHECK(v->IsNumber());
6746 CHECK_EQ(3, v->Int32Value());
6747
6748 env2.Dispose();
6749}
6750
6751
ager@chromium.org870a0b62008-11-04 11:43:05 +00006752THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6753 v8::HandleScope handle_scope;
6754 LocalContext env1;
6755 v8::Persistent<Context> env2 = Context::New();
6756
6757 Local<Value> foo = v8_str("foo");
6758 Local<Value> bar = v8_str("bar");
6759
6760 // Set to the same domain.
6761 env1->SetSecurityToken(foo);
6762 env2->SetSecurityToken(foo);
6763
6764 env1->Global()->Set(v8_str("prop"), v8_num(3));
6765 env2->Global()->Set(v8_str("env1"), env1->Global());
6766
6767 // env1.prop is enumerable in env2.
6768 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6769 {
6770 Context::Scope scope_env2(env2);
6771 Local<Value> result = Script::Compile(test)->Run();
6772 CHECK(result->IsTrue());
6773 }
6774
6775 // Change env2 to a different domain and test again.
6776 env2->SetSecurityToken(bar);
6777 {
6778 Context::Scope scope_env2(env2);
6779 Local<Value> result = Script::Compile(test)->Run();
6780 CHECK(result->IsFalse());
6781 }
6782
6783 env2.Dispose();
6784}
6785
6786
ager@chromium.org236ad962008-09-25 09:45:57 +00006787THREADED_TEST(CrossDomainForIn) {
6788 v8::HandleScope handle_scope;
6789 LocalContext env1;
6790 v8::Persistent<Context> env2 = Context::New();
6791
6792 Local<Value> foo = v8_str("foo");
6793 Local<Value> bar = v8_str("bar");
6794
6795 // Set to the same domain.
6796 env1->SetSecurityToken(foo);
6797 env2->SetSecurityToken(foo);
6798
6799 env1->Global()->Set(v8_str("prop"), v8_num(3));
6800 env2->Global()->Set(v8_str("env1"), env1->Global());
6801
6802 // Change env2 to a different domain and set env1's global object
6803 // as the __proto__ of an object in env2 and enumerate properties
6804 // in for-in. It shouldn't enumerate properties on env1's global
6805 // object.
6806 env2->SetSecurityToken(bar);
6807 {
6808 Context::Scope scope_env2(env2);
6809 Local<Value> result =
6810 CompileRun("(function(){var obj = {'__proto__':env1};"
6811 "for (var p in obj)"
6812 " if (p == 'prop') return false;"
6813 "return true;})()");
6814 CHECK(result->IsTrue());
6815 }
6816 env2.Dispose();
6817}
6818
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006819
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006820TEST(ContextDetachGlobal) {
6821 v8::HandleScope handle_scope;
6822 LocalContext env1;
6823 v8::Persistent<Context> env2 = Context::New();
6824
6825 Local<v8::Object> global1 = env1->Global();
6826
6827 Local<Value> foo = v8_str("foo");
6828
6829 // Set to the same domain.
6830 env1->SetSecurityToken(foo);
6831 env2->SetSecurityToken(foo);
6832
6833 // Enter env2
6834 env2->Enter();
6835
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006836 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006837 Local<v8::Object> global2 = env2->Global();
6838 global2->Set(v8_str("prop"), v8::Integer::New(1));
6839 CompileRun("function getProp() {return prop;}");
6840
6841 env1->Global()->Set(v8_str("getProp"),
6842 global2->Get(v8_str("getProp")));
6843
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006844 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006845 env2->Exit();
6846 env2->DetachGlobal();
6847 // env2 has a new global object.
6848 CHECK(!env2->Global()->Equals(global2));
6849
6850 v8::Persistent<Context> env3 =
6851 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6852 env3->SetSecurityToken(v8_str("bar"));
6853 env3->Enter();
6854
6855 Local<v8::Object> global3 = env3->Global();
6856 CHECK_EQ(global2, global3);
6857 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6858 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6859 global3->Set(v8_str("prop"), v8::Integer::New(-1));
6860 global3->Set(v8_str("prop2"), v8::Integer::New(2));
6861 env3->Exit();
6862
6863 // Call getProp in env1, and it should return the value 1
6864 {
6865 Local<Value> get_prop = global1->Get(v8_str("getProp"));
6866 CHECK(get_prop->IsFunction());
6867 v8::TryCatch try_catch;
6868 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6869 CHECK(!try_catch.HasCaught());
6870 CHECK_EQ(1, r->Int32Value());
6871 }
6872
6873 // Check that env3 is not accessible from env1
6874 {
6875 Local<Value> r = global3->Get(v8_str("prop2"));
6876 CHECK(r->IsUndefined());
6877 }
6878
6879 env2.Dispose();
6880 env3.Dispose();
6881}
6882
6883
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00006884TEST(DetachAndReattachGlobal) {
6885 v8::HandleScope scope;
6886 LocalContext env1;
6887
6888 // Create second environment.
6889 v8::Persistent<Context> env2 = Context::New();
6890
6891 Local<Value> foo = v8_str("foo");
6892
6893 // Set same security token for env1 and env2.
6894 env1->SetSecurityToken(foo);
6895 env2->SetSecurityToken(foo);
6896
6897 // Create a property on the global object in env2.
6898 {
6899 v8::Context::Scope scope(env2);
6900 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6901 }
6902
6903 // Create a reference to env2 global from env1 global.
6904 env1->Global()->Set(v8_str("other"), env2->Global());
6905
6906 // Check that we have access to other.p in env2 from env1.
6907 Local<Value> result = CompileRun("other.p");
6908 CHECK(result->IsInt32());
6909 CHECK_EQ(42, result->Int32Value());
6910
6911 // Hold on to global from env2 and detach global from env2.
6912 Local<v8::Object> global2 = env2->Global();
6913 env2->DetachGlobal();
6914
6915 // Check that the global has been detached. No other.p property can
6916 // be found.
6917 result = CompileRun("other.p");
6918 CHECK(result->IsUndefined());
6919
6920 // Reuse global2 for env3.
6921 v8::Persistent<Context> env3 =
6922 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6923 CHECK_EQ(global2, env3->Global());
6924
6925 // Start by using the same security token for env3 as for env1 and env2.
6926 env3->SetSecurityToken(foo);
6927
6928 // Create a property on the global object in env3.
6929 {
6930 v8::Context::Scope scope(env3);
6931 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6932 }
6933
6934 // Check that other.p is now the property in env3 and that we have access.
6935 result = CompileRun("other.p");
6936 CHECK(result->IsInt32());
6937 CHECK_EQ(24, result->Int32Value());
6938
6939 // Change security token for env3 to something different from env1 and env2.
6940 env3->SetSecurityToken(v8_str("bar"));
6941
6942 // Check that we do not have access to other.p in env1. |other| is now
6943 // the global object for env3 which has a different security token,
6944 // so access should be blocked.
6945 result = CompileRun("other.p");
6946 CHECK(result->IsUndefined());
6947
6948 // Detach the global for env3 and reattach it to env2.
6949 env3->DetachGlobal();
6950 env2->ReattachGlobal(global2);
6951
6952 // Check that we have access to other.p again in env1. |other| is now
6953 // the global object for env2 which has the same security token as env1.
6954 result = CompileRun("other.p");
6955 CHECK(result->IsInt32());
6956 CHECK_EQ(42, result->Int32Value());
6957
6958 env2.Dispose();
6959 env3.Dispose();
6960}
6961
6962
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006963static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006964static bool NamedAccessBlocker(Local<v8::Object> global,
6965 Local<Value> name,
6966 v8::AccessType type,
6967 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006968 return Context::GetCurrent()->Global()->Equals(global) ||
6969 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006970}
6971
6972
6973static bool IndexedAccessBlocker(Local<v8::Object> global,
6974 uint32_t key,
6975 v8::AccessType type,
6976 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006977 return Context::GetCurrent()->Global()->Equals(global) ||
6978 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006979}
6980
6981
6982static int g_echo_value = -1;
6983static v8::Handle<Value> EchoGetter(Local<String> name,
6984 const AccessorInfo& info) {
6985 return v8_num(g_echo_value);
6986}
6987
6988
6989static void EchoSetter(Local<String> name,
6990 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006991 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006992 if (value->IsNumber())
6993 g_echo_value = value->Int32Value();
6994}
6995
6996
6997static v8::Handle<Value> UnreachableGetter(Local<String> name,
6998 const AccessorInfo& info) {
6999 CHECK(false); // This function should not be called..
7000 return v8::Undefined();
7001}
7002
7003
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007004static void UnreachableSetter(Local<String>, Local<Value>,
7005 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007006 CHECK(false); // This function should nto be called.
7007}
7008
7009
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007010TEST(AccessControl) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007011 v8::HandleScope handle_scope;
7012 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7013
7014 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7015 IndexedAccessBlocker);
7016
7017 // Add an accessor accessible by cross-domain JS code.
7018 global_template->SetAccessor(
7019 v8_str("accessible_prop"),
7020 EchoGetter, EchoSetter,
7021 v8::Handle<Value>(),
7022 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7023
7024 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00007025 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007026 UnreachableGetter, UnreachableSetter,
7027 v8::Handle<Value>(),
7028 v8::DEFAULT);
7029
7030 // Create an environment
7031 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7032 context0->Enter();
7033
7034 v8::Handle<v8::Object> global0 = context0->Global();
7035
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007036 // Define a property with JS getter and setter.
7037 CompileRun(
7038 "function getter() { return 'getter'; };\n"
7039 "function setter() { return 'setter'; }\n"
7040 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
7041
7042 Local<Value> getter = global0->Get(v8_str("getter"));
7043 Local<Value> setter = global0->Get(v8_str("setter"));
7044
7045 // And define normal element.
7046 global0->Set(239, v8_str("239"));
7047
7048 // Define an element with JS getter and setter.
7049 CompileRun(
7050 "function el_getter() { return 'el_getter'; };\n"
7051 "function el_setter() { return 'el_setter'; };\n"
7052 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
7053
7054 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
7055 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
7056
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007057 v8::HandleScope scope1;
7058
7059 v8::Persistent<Context> context1 = Context::New();
7060 context1->Enter();
7061
7062 v8::Handle<v8::Object> global1 = context1->Global();
7063 global1->Set(v8_str("other"), global0);
7064
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007065 // Access blocked property.
7066 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007067
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007068 ExpectUndefined("other.blocked_prop");
7069 ExpectUndefined(
7070 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7071 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007072
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007073 // Enable ACCESS_HAS
7074 allowed_access_type[v8::ACCESS_HAS] = true;
7075 ExpectUndefined("other.blocked_prop");
7076 // ... and now we can get the descriptor...
7077 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007078 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007079 // ... and enumerate the property.
7080 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
7081 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007082
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007083 // Access blocked element.
7084 CompileRun("other[239] = 1");
7085
7086 ExpectUndefined("other[239]");
7087 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
7088 ExpectFalse("propertyIsEnumerable.call(other, '239')");
7089
7090 // Enable ACCESS_HAS
7091 allowed_access_type[v8::ACCESS_HAS] = true;
7092 ExpectUndefined("other[239]");
7093 // ... and now we can get the descriptor...
7094 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
7095 // ... and enumerate the property.
7096 ExpectTrue("propertyIsEnumerable.call(other, '239')");
7097 allowed_access_type[v8::ACCESS_HAS] = false;
7098
7099 // Access a property with JS accessor.
7100 CompileRun("other.js_accessor_p = 2");
7101
7102 ExpectUndefined("other.js_accessor_p");
7103 ExpectUndefined(
7104 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7105
7106 // Enable ACCESS_HAS.
7107 allowed_access_type[v8::ACCESS_HAS] = true;
7108 ExpectUndefined("other.js_accessor_p");
7109 ExpectUndefined(
7110 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7111 ExpectUndefined(
7112 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7113 ExpectUndefined(
7114 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7115 allowed_access_type[v8::ACCESS_HAS] = false;
7116
7117 // Enable both ACCESS_HAS and ACCESS_GET.
7118 allowed_access_type[v8::ACCESS_HAS] = true;
7119 allowed_access_type[v8::ACCESS_GET] = true;
7120
7121 ExpectString("other.js_accessor_p", "getter");
7122 ExpectObject(
7123 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7124 ExpectUndefined(
7125 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7126 ExpectUndefined(
7127 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7128
7129 allowed_access_type[v8::ACCESS_GET] = false;
7130 allowed_access_type[v8::ACCESS_HAS] = false;
7131
7132 // Enable both ACCESS_HAS and ACCESS_SET.
7133 allowed_access_type[v8::ACCESS_HAS] = true;
7134 allowed_access_type[v8::ACCESS_SET] = true;
7135
7136 ExpectUndefined("other.js_accessor_p");
7137 ExpectUndefined(
7138 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7139 ExpectObject(
7140 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7141 ExpectUndefined(
7142 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7143
7144 allowed_access_type[v8::ACCESS_SET] = false;
7145 allowed_access_type[v8::ACCESS_HAS] = false;
7146
7147 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7148 allowed_access_type[v8::ACCESS_HAS] = true;
7149 allowed_access_type[v8::ACCESS_GET] = true;
7150 allowed_access_type[v8::ACCESS_SET] = true;
7151
7152 ExpectString("other.js_accessor_p", "getter");
7153 ExpectObject(
7154 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7155 ExpectObject(
7156 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7157 ExpectUndefined(
7158 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7159
7160 allowed_access_type[v8::ACCESS_SET] = false;
7161 allowed_access_type[v8::ACCESS_GET] = false;
7162 allowed_access_type[v8::ACCESS_HAS] = false;
7163
7164 // Access an element with JS accessor.
7165 CompileRun("other[42] = 2");
7166
7167 ExpectUndefined("other[42]");
7168 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7169
7170 // Enable ACCESS_HAS.
7171 allowed_access_type[v8::ACCESS_HAS] = true;
7172 ExpectUndefined("other[42]");
7173 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7174 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7175 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7176 allowed_access_type[v8::ACCESS_HAS] = false;
7177
7178 // Enable both ACCESS_HAS and ACCESS_GET.
7179 allowed_access_type[v8::ACCESS_HAS] = true;
7180 allowed_access_type[v8::ACCESS_GET] = true;
7181
7182 ExpectString("other[42]", "el_getter");
7183 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7184 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7185 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7186
7187 allowed_access_type[v8::ACCESS_GET] = false;
7188 allowed_access_type[v8::ACCESS_HAS] = false;
7189
7190 // Enable both ACCESS_HAS and ACCESS_SET.
7191 allowed_access_type[v8::ACCESS_HAS] = true;
7192 allowed_access_type[v8::ACCESS_SET] = true;
7193
7194 ExpectUndefined("other[42]");
7195 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7196 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7197 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7198
7199 allowed_access_type[v8::ACCESS_SET] = false;
7200 allowed_access_type[v8::ACCESS_HAS] = false;
7201
7202 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7203 allowed_access_type[v8::ACCESS_HAS] = true;
7204 allowed_access_type[v8::ACCESS_GET] = true;
7205 allowed_access_type[v8::ACCESS_SET] = true;
7206
7207 ExpectString("other[42]", "el_getter");
7208 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7209 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7210 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7211
7212 allowed_access_type[v8::ACCESS_SET] = false;
7213 allowed_access_type[v8::ACCESS_GET] = false;
7214 allowed_access_type[v8::ACCESS_HAS] = false;
7215
7216 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007217
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007218 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007219 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007220 CHECK(value->IsNumber());
7221 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007222 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007223
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007224 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007225 CHECK(value->IsNumber());
7226 CHECK_EQ(3, value->Int32Value());
7227
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007228 value = CompileRun(
7229 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7230 CHECK(value->IsNumber());
7231 CHECK_EQ(3, value->Int32Value());
7232
7233 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00007234 CHECK(value->IsTrue());
7235
7236 // Enumeration doesn't enumerate accessors from inaccessible objects in
7237 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007238 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00007239 CompileRun("(function(){var obj = {'__proto__':other};"
7240 "for (var p in obj)"
7241 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7242 " return false;"
7243 " }"
7244 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007245 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00007246
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007247 context1->Exit();
7248 context0->Exit();
7249 context1.Dispose();
7250 context0.Dispose();
7251}
7252
7253
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007254TEST(AccessControlES5) {
ricow@chromium.org65001782011-02-15 13:36:41 +00007255 v8::HandleScope handle_scope;
7256 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7257
7258 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7259 IndexedAccessBlocker);
7260
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007261 // Add accessible accessor.
7262 global_template->SetAccessor(
7263 v8_str("accessible_prop"),
7264 EchoGetter, EchoSetter,
7265 v8::Handle<Value>(),
7266 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7267
7268
ricow@chromium.org65001782011-02-15 13:36:41 +00007269 // Add an accessor that is not accessible by cross-domain JS code.
7270 global_template->SetAccessor(v8_str("blocked_prop"),
7271 UnreachableGetter, UnreachableSetter,
7272 v8::Handle<Value>(),
7273 v8::DEFAULT);
7274
7275 // Create an environment
7276 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7277 context0->Enter();
7278
7279 v8::Handle<v8::Object> global0 = context0->Global();
7280
7281 v8::Persistent<Context> context1 = Context::New();
7282 context1->Enter();
7283 v8::Handle<v8::Object> global1 = context1->Global();
7284 global1->Set(v8_str("other"), global0);
7285
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007286 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00007287 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007288
7289 ExpectUndefined("other.blocked_prop");
7290
7291 // Regression test for issue 1027.
7292 CompileRun("Object.defineProperty(\n"
7293 " other, 'blocked_prop', {configurable: false})");
7294 ExpectUndefined("other.blocked_prop");
7295 ExpectUndefined(
7296 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7297
7298 // Regression test for issue 1171.
7299 ExpectTrue("Object.isExtensible(other)");
7300 CompileRun("Object.preventExtensions(other)");
7301 ExpectTrue("Object.isExtensible(other)");
7302
7303 // Object.seal and Object.freeze.
7304 CompileRun("Object.freeze(other)");
7305 ExpectTrue("Object.isExtensible(other)");
7306
7307 CompileRun("Object.seal(other)");
7308 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007309
7310 // Regression test for issue 1250.
7311 // Make sure that we can set the accessible accessors value using normal
7312 // assignment.
7313 CompileRun("other.accessible_prop = 42");
7314 CHECK_EQ(42, g_echo_value);
7315
7316 v8::Handle<Value> value;
7317 // We follow Safari in ignoring assignments to host object accessors.
7318 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7319 value = CompileRun("other.accessible_prop == 42");
7320 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00007321}
7322
7323
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007324static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7325 Local<Value> name,
7326 v8::AccessType type,
7327 Local<Value> data) {
7328 return false;
7329}
7330
7331
7332static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7333 uint32_t key,
7334 v8::AccessType type,
7335 Local<Value> data) {
7336 return false;
7337}
7338
7339
7340THREADED_TEST(AccessControlGetOwnPropertyNames) {
7341 v8::HandleScope handle_scope;
7342 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7343
7344 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7345 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7346 GetOwnPropertyNamesIndexedBlocker);
7347
7348 // Create an environment
7349 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7350 context0->Enter();
7351
7352 v8::Handle<v8::Object> global0 = context0->Global();
7353
7354 v8::HandleScope scope1;
7355
7356 v8::Persistent<Context> context1 = Context::New();
7357 context1->Enter();
7358
7359 v8::Handle<v8::Object> global1 = context1->Global();
7360 global1->Set(v8_str("other"), global0);
7361 global1->Set(v8_str("object"), obj_template->NewInstance());
7362
7363 v8::Handle<Value> value;
7364
7365 // Attempt to get the property names of the other global object and
7366 // of an object that requires access checks. Accessing the other
7367 // global object should be blocked by access checks on the global
7368 // proxy object. Accessing the object that requires access checks
7369 // is blocked by the access checks on the object itself.
7370 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7371 CHECK(value->IsTrue());
7372
7373 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7374 CHECK(value->IsTrue());
7375
7376 context1->Exit();
7377 context0->Exit();
7378 context1.Dispose();
7379 context0.Dispose();
7380}
7381
7382
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007383static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
7384 v8::Handle<v8::Array> result = v8::Array::New(1);
7385 result->Set(0, v8_str("x"));
7386 return result;
7387}
7388
7389
7390THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
7391 v8::HandleScope handle_scope;
7392 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7393
7394 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7395 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7396 NamedPropertyEnumerator);
7397
7398 LocalContext context;
7399 v8::Handle<v8::Object> global = context->Global();
7400 global->Set(v8_str("object"), obj_template->NewInstance());
7401
7402 v8::Handle<Value> value =
7403 CompileRun("Object.getOwnPropertyNames(object).join(',')");
7404 CHECK_EQ(v8_str("x"), value);
7405}
7406
7407
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007408static v8::Handle<Value> ConstTenGetter(Local<String> name,
7409 const AccessorInfo& info) {
7410 return v8_num(10);
7411}
7412
7413
7414THREADED_TEST(CrossDomainAccessors) {
7415 v8::HandleScope handle_scope;
7416
7417 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7418
7419 v8::Handle<v8::ObjectTemplate> global_template =
7420 func_template->InstanceTemplate();
7421
7422 v8::Handle<v8::ObjectTemplate> proto_template =
7423 func_template->PrototypeTemplate();
7424
7425 // Add an accessor to proto that's accessible by cross-domain JS code.
7426 proto_template->SetAccessor(v8_str("accessible"),
7427 ConstTenGetter, 0,
7428 v8::Handle<Value>(),
7429 v8::ALL_CAN_READ);
7430
7431 // Add an accessor that is not accessible by cross-domain JS code.
7432 global_template->SetAccessor(v8_str("unreachable"),
7433 UnreachableGetter, 0,
7434 v8::Handle<Value>(),
7435 v8::DEFAULT);
7436
7437 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7438 context0->Enter();
7439
7440 Local<v8::Object> global = context0->Global();
7441 // Add a normal property that shadows 'accessible'
7442 global->Set(v8_str("accessible"), v8_num(11));
7443
7444 // Enter a new context.
7445 v8::HandleScope scope1;
7446 v8::Persistent<Context> context1 = Context::New();
7447 context1->Enter();
7448
7449 v8::Handle<v8::Object> global1 = context1->Global();
7450 global1->Set(v8_str("other"), global);
7451
7452 // Should return 10, instead of 11
7453 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7454 CHECK(value->IsNumber());
7455 CHECK_EQ(10, value->Int32Value());
7456
7457 value = v8_compile("other.unreachable")->Run();
7458 CHECK(value->IsUndefined());
7459
7460 context1->Exit();
7461 context0->Exit();
7462 context1.Dispose();
7463 context0.Dispose();
7464}
7465
7466
7467static int named_access_count = 0;
7468static int indexed_access_count = 0;
7469
7470static bool NamedAccessCounter(Local<v8::Object> global,
7471 Local<Value> name,
7472 v8::AccessType type,
7473 Local<Value> data) {
7474 named_access_count++;
7475 return true;
7476}
7477
7478
7479static bool IndexedAccessCounter(Local<v8::Object> global,
7480 uint32_t key,
7481 v8::AccessType type,
7482 Local<Value> data) {
7483 indexed_access_count++;
7484 return true;
7485}
7486
7487
7488// This one is too easily disturbed by other tests.
7489TEST(AccessControlIC) {
7490 named_access_count = 0;
7491 indexed_access_count = 0;
7492
7493 v8::HandleScope handle_scope;
7494
7495 // Create an environment.
7496 v8::Persistent<Context> context0 = Context::New();
7497 context0->Enter();
7498
7499 // Create an object that requires access-check functions to be
7500 // called for cross-domain access.
7501 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7502 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7503 IndexedAccessCounter);
7504 Local<v8::Object> object = object_template->NewInstance();
7505
7506 v8::HandleScope scope1;
7507
7508 // Create another environment.
7509 v8::Persistent<Context> context1 = Context::New();
7510 context1->Enter();
7511
7512 // Make easy access to the object from the other environment.
7513 v8::Handle<v8::Object> global1 = context1->Global();
7514 global1->Set(v8_str("obj"), object);
7515
7516 v8::Handle<Value> value;
7517
7518 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007519 CompileRun("function testProp(obj) {"
7520 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7521 " for (var j = 0; j < 10; j++) obj.prop;"
7522 " return obj.prop"
7523 "}");
7524 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007525 CHECK(value->IsNumber());
7526 CHECK_EQ(1, value->Int32Value());
7527 CHECK_EQ(21, named_access_count);
7528
7529 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007530 CompileRun("var p = 'prop';"
7531 "function testKeyed(obj) {"
7532 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7533 " for (var j = 0; j < 10; j++) obj[p];"
7534 " return obj[p];"
7535 "}");
7536 // Use obj which requires access checks. No inline caching is used
7537 // in that case.
7538 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007539 CHECK(value->IsNumber());
7540 CHECK_EQ(1, value->Int32Value());
7541 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007542 // Force the inline caches into generic state and try again.
7543 CompileRun("testKeyed({ a: 0 })");
7544 CompileRun("testKeyed({ b: 0 })");
7545 value = CompileRun("testKeyed(obj)");
7546 CHECK(value->IsNumber());
7547 CHECK_EQ(1, value->Int32Value());
7548 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007549
7550 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007551 CompileRun("function testIndexed(obj) {"
7552 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7553 " for (var j = 0; j < 10; j++) obj[0];"
7554 " return obj[0]"
7555 "}");
7556 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007557 CHECK(value->IsNumber());
7558 CHECK_EQ(1, value->Int32Value());
7559 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007560 // Force the inline caches into generic state.
7561 CompileRun("testIndexed(new Array(1))");
7562 // Test that the indexed access check is called.
7563 value = CompileRun("testIndexed(obj)");
7564 CHECK(value->IsNumber());
7565 CHECK_EQ(1, value->Int32Value());
7566 CHECK_EQ(42, indexed_access_count);
7567
7568 // Check that the named access check is called when invoking
7569 // functions on an object that requires access checks.
7570 CompileRun("obj.f = function() {}");
7571 CompileRun("function testCallNormal(obj) {"
7572 " for (var i = 0; i < 10; i++) obj.f();"
7573 "}");
7574 CompileRun("testCallNormal(obj)");
7575 CHECK_EQ(74, named_access_count);
7576
7577 // Force obj into slow case.
7578 value = CompileRun("delete obj.prop");
7579 CHECK(value->BooleanValue());
7580 // Force inline caches into dictionary probing mode.
7581 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7582 // Test that the named access check is called.
7583 value = CompileRun("testProp(obj);");
7584 CHECK(value->IsNumber());
7585 CHECK_EQ(1, value->Int32Value());
7586 CHECK_EQ(96, named_access_count);
7587
7588 // Force the call inline cache into dictionary probing mode.
7589 CompileRun("o.f = function() {}; testCallNormal(o)");
7590 // Test that the named access check is still called for each
7591 // invocation of the function.
7592 value = CompileRun("testCallNormal(obj)");
7593 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007594
7595 context1->Exit();
7596 context0->Exit();
7597 context1.Dispose();
7598 context0.Dispose();
7599}
7600
7601
7602static bool NamedAccessFlatten(Local<v8::Object> global,
7603 Local<Value> name,
7604 v8::AccessType type,
7605 Local<Value> data) {
7606 char buf[100];
7607 int len;
7608
7609 CHECK(name->IsString());
7610
7611 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007612 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007613 CHECK_EQ(4, len);
7614
7615 uint16_t buf2[100];
7616
7617 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007618 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007619 CHECK_EQ(4, len);
7620
7621 return true;
7622}
7623
7624
7625static bool IndexedAccessFlatten(Local<v8::Object> global,
7626 uint32_t key,
7627 v8::AccessType type,
7628 Local<Value> data) {
7629 return true;
7630}
7631
7632
7633// Regression test. In access checks, operations that may cause
7634// garbage collection are not allowed. It used to be the case that
7635// using the Write operation on a string could cause a garbage
7636// collection due to flattening of the string. This is no longer the
7637// case.
7638THREADED_TEST(AccessControlFlatten) {
7639 named_access_count = 0;
7640 indexed_access_count = 0;
7641
7642 v8::HandleScope handle_scope;
7643
7644 // Create an environment.
7645 v8::Persistent<Context> context0 = Context::New();
7646 context0->Enter();
7647
7648 // Create an object that requires access-check functions to be
7649 // called for cross-domain access.
7650 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7651 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7652 IndexedAccessFlatten);
7653 Local<v8::Object> object = object_template->NewInstance();
7654
7655 v8::HandleScope scope1;
7656
7657 // Create another environment.
7658 v8::Persistent<Context> context1 = Context::New();
7659 context1->Enter();
7660
7661 // Make easy access to the object from the other environment.
7662 v8::Handle<v8::Object> global1 = context1->Global();
7663 global1->Set(v8_str("obj"), object);
7664
7665 v8::Handle<Value> value;
7666
7667 value = v8_compile("var p = 'as' + 'df';")->Run();
7668 value = v8_compile("obj[p];")->Run();
7669
7670 context1->Exit();
7671 context0->Exit();
7672 context1.Dispose();
7673 context0.Dispose();
7674}
7675
7676
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007677static v8::Handle<Value> AccessControlNamedGetter(
7678 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007679 return v8::Integer::New(42);
7680}
7681
7682
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007683static v8::Handle<Value> AccessControlNamedSetter(
7684 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007685 return value;
7686}
7687
7688
7689static v8::Handle<Value> AccessControlIndexedGetter(
7690 uint32_t index,
7691 const AccessorInfo& info) {
7692 return v8_num(42);
7693}
7694
7695
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007696static v8::Handle<Value> AccessControlIndexedSetter(
7697 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007698 return value;
7699}
7700
7701
7702THREADED_TEST(AccessControlInterceptorIC) {
7703 named_access_count = 0;
7704 indexed_access_count = 0;
7705
7706 v8::HandleScope handle_scope;
7707
7708 // Create an environment.
7709 v8::Persistent<Context> context0 = Context::New();
7710 context0->Enter();
7711
7712 // Create an object that requires access-check functions to be
7713 // called for cross-domain access. The object also has interceptors
7714 // interceptor.
7715 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7716 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7717 IndexedAccessCounter);
7718 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7719 AccessControlNamedSetter);
7720 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7721 AccessControlIndexedSetter);
7722 Local<v8::Object> object = object_template->NewInstance();
7723
7724 v8::HandleScope scope1;
7725
7726 // Create another environment.
7727 v8::Persistent<Context> context1 = Context::New();
7728 context1->Enter();
7729
7730 // Make easy access to the object from the other environment.
7731 v8::Handle<v8::Object> global1 = context1->Global();
7732 global1->Set(v8_str("obj"), object);
7733
7734 v8::Handle<Value> value;
7735
7736 // Check that the named access-control function is called every time
7737 // eventhough there is an interceptor on the object.
7738 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7739 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7740 "obj.x")->Run();
7741 CHECK(value->IsNumber());
7742 CHECK_EQ(42, value->Int32Value());
7743 CHECK_EQ(21, named_access_count);
7744
7745 value = v8_compile("var p = 'x';")->Run();
7746 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7747 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7748 "obj[p]")->Run();
7749 CHECK(value->IsNumber());
7750 CHECK_EQ(42, value->Int32Value());
7751 CHECK_EQ(42, named_access_count);
7752
7753 // Check that the indexed access-control function is called every
7754 // time eventhough there is an interceptor on the object.
7755 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7756 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7757 "obj[0]")->Run();
7758 CHECK(value->IsNumber());
7759 CHECK_EQ(42, value->Int32Value());
7760 CHECK_EQ(21, indexed_access_count);
7761
7762 context1->Exit();
7763 context0->Exit();
7764 context1.Dispose();
7765 context0.Dispose();
7766}
7767
7768
7769THREADED_TEST(Version) {
7770 v8::V8::GetVersion();
7771}
7772
7773
7774static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7775 ApiTestFuzzer::Fuzz();
7776 return v8_num(12);
7777}
7778
7779
7780THREADED_TEST(InstanceProperties) {
7781 v8::HandleScope handle_scope;
7782 LocalContext context;
7783
7784 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7785 Local<ObjectTemplate> instance = t->InstanceTemplate();
7786
7787 instance->Set(v8_str("x"), v8_num(42));
7788 instance->Set(v8_str("f"),
7789 v8::FunctionTemplate::New(InstanceFunctionCallback));
7790
7791 Local<Value> o = t->GetFunction()->NewInstance();
7792
7793 context->Global()->Set(v8_str("i"), o);
7794 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7795 CHECK_EQ(42, value->Int32Value());
7796
7797 value = Script::Compile(v8_str("i.f()"))->Run();
7798 CHECK_EQ(12, value->Int32Value());
7799}
7800
7801
7802static v8::Handle<Value>
7803GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7804 ApiTestFuzzer::Fuzz();
7805 return v8::Handle<Value>();
7806}
7807
7808
7809THREADED_TEST(GlobalObjectInstanceProperties) {
7810 v8::HandleScope handle_scope;
7811
7812 Local<Value> global_object;
7813
7814 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7815 t->InstanceTemplate()->SetNamedPropertyHandler(
7816 GlobalObjectInstancePropertiesGet);
7817 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7818 instance_template->Set(v8_str("x"), v8_num(42));
7819 instance_template->Set(v8_str("f"),
7820 v8::FunctionTemplate::New(InstanceFunctionCallback));
7821
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007822 // The script to check how Crankshaft compiles missing global function
7823 // invocations. function g is not defined and should throw on call.
7824 const char* script =
7825 "function wrapper(call) {"
7826 " var x = 0, y = 1;"
7827 " for (var i = 0; i < 1000; i++) {"
7828 " x += i * 100;"
7829 " y += i * 100;"
7830 " }"
7831 " if (call) g();"
7832 "}"
7833 "for (var i = 0; i < 17; i++) wrapper(false);"
7834 "var thrown = 0;"
7835 "try { wrapper(true); } catch (e) { thrown = 1; };"
7836 "thrown";
7837
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007838 {
7839 LocalContext env(NULL, instance_template);
7840 // Hold on to the global object so it can be used again in another
7841 // environment initialization.
7842 global_object = env->Global();
7843
7844 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7845 CHECK_EQ(42, value->Int32Value());
7846 value = Script::Compile(v8_str("f()"))->Run();
7847 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007848 value = Script::Compile(v8_str(script))->Run();
7849 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007850 }
7851
7852 {
7853 // Create new environment reusing the global object.
7854 LocalContext env(NULL, instance_template, global_object);
7855 Local<Value> value = Script::Compile(v8_str("x"))->Run();
7856 CHECK_EQ(42, value->Int32Value());
7857 value = Script::Compile(v8_str("f()"))->Run();
7858 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007859 value = Script::Compile(v8_str(script))->Run();
7860 CHECK_EQ(1, value->Int32Value());
7861 }
7862}
7863
7864
7865THREADED_TEST(CallKnownGlobalReceiver) {
7866 v8::HandleScope handle_scope;
7867
7868 Local<Value> global_object;
7869
7870 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7871 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7872
7873 // The script to check that we leave global object not
7874 // global object proxy on stack when we deoptimize from inside
7875 // arguments evaluation.
7876 // To provoke error we need to both force deoptimization
7877 // from arguments evaluation and to force CallIC to take
7878 // CallIC_Miss code path that can't cope with global proxy.
7879 const char* script =
7880 "function bar(x, y) { try { } finally { } }"
7881 "function baz(x) { try { } finally { } }"
7882 "function bom(x) { try { } finally { } }"
7883 "function foo(x) { bar([x], bom(2)); }"
7884 "for (var i = 0; i < 10000; i++) foo(1);"
7885 "foo";
7886
7887 Local<Value> foo;
7888 {
7889 LocalContext env(NULL, instance_template);
7890 // Hold on to the global object so it can be used again in another
7891 // environment initialization.
7892 global_object = env->Global();
7893 foo = Script::Compile(v8_str(script))->Run();
7894 }
7895
7896 {
7897 // Create new environment reusing the global object.
7898 LocalContext env(NULL, instance_template, global_object);
7899 env->Global()->Set(v8_str("foo"), foo);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007900 Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007901 }
7902}
7903
7904
7905static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7906 ApiTestFuzzer::Fuzz();
7907 return v8_num(42);
7908}
7909
7910
7911static int shadow_y;
7912static int shadow_y_setter_call_count;
7913static int shadow_y_getter_call_count;
7914
7915
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007916static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007917 shadow_y_setter_call_count++;
7918 shadow_y = 42;
7919}
7920
7921
7922static v8::Handle<Value> ShadowYGetter(Local<String> name,
7923 const AccessorInfo& info) {
7924 ApiTestFuzzer::Fuzz();
7925 shadow_y_getter_call_count++;
7926 return v8_num(shadow_y);
7927}
7928
7929
7930static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7931 const AccessorInfo& info) {
7932 return v8::Handle<Value>();
7933}
7934
7935
7936static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7937 const AccessorInfo&) {
7938 return v8::Handle<Value>();
7939}
7940
7941
7942THREADED_TEST(ShadowObject) {
7943 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7944 v8::HandleScope handle_scope;
7945
7946 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7947 LocalContext context(NULL, global_template);
7948
7949 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7950 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7951 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7952 Local<ObjectTemplate> proto = t->PrototypeTemplate();
7953 Local<ObjectTemplate> instance = t->InstanceTemplate();
7954
7955 // Only allow calls of f on instances of t.
7956 Local<v8::Signature> signature = v8::Signature::New(t);
7957 proto->Set(v8_str("f"),
7958 v8::FunctionTemplate::New(ShadowFunctionCallback,
7959 Local<Value>(),
7960 signature));
7961 proto->Set(v8_str("x"), v8_num(12));
7962
7963 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7964
7965 Local<Value> o = t->GetFunction()->NewInstance();
7966 context->Global()->Set(v8_str("__proto__"), o);
7967
7968 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007969 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007970 CHECK(value->IsBoolean());
7971 CHECK(!value->BooleanValue());
7972
7973 value = Script::Compile(v8_str("x"))->Run();
7974 CHECK_EQ(12, value->Int32Value());
7975
7976 value = Script::Compile(v8_str("f()"))->Run();
7977 CHECK_EQ(42, value->Int32Value());
7978
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007979 Script::Compile(v8_str("y = 43"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007980 CHECK_EQ(1, shadow_y_setter_call_count);
7981 value = Script::Compile(v8_str("y"))->Run();
7982 CHECK_EQ(1, shadow_y_getter_call_count);
7983 CHECK_EQ(42, value->Int32Value());
7984}
7985
7986
7987THREADED_TEST(HiddenPrototype) {
7988 v8::HandleScope handle_scope;
7989 LocalContext context;
7990
7991 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7992 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7993 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7994 t1->SetHiddenPrototype(true);
7995 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7996 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7997 t2->SetHiddenPrototype(true);
7998 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7999 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8000 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8001
8002 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8003 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8004 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8005 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8006
8007 // Setting the prototype on an object skips hidden prototypes.
8008 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8009 o0->Set(v8_str("__proto__"), o1);
8010 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8011 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8012 o0->Set(v8_str("__proto__"), o2);
8013 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8014 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8015 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8016 o0->Set(v8_str("__proto__"), o3);
8017 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8018 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8019 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8020 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8021
8022 // Getting the prototype of o0 should get the first visible one
8023 // which is o3. Therefore, z should not be defined on the prototype
8024 // object.
8025 Local<Value> proto = o0->Get(v8_str("__proto__"));
8026 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008027 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008028}
8029
8030
ager@chromium.org5c838252010-02-19 08:53:10 +00008031THREADED_TEST(SetPrototype) {
8032 v8::HandleScope handle_scope;
8033 LocalContext context;
8034
8035 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8036 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8037 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8038 t1->SetHiddenPrototype(true);
8039 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8040 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8041 t2->SetHiddenPrototype(true);
8042 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8043 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8044 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8045
8046 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8047 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8048 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8049 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8050
8051 // Setting the prototype on an object does not skip hidden prototypes.
8052 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8053 CHECK(o0->SetPrototype(o1));
8054 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8055 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8056 CHECK(o1->SetPrototype(o2));
8057 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8058 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8059 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8060 CHECK(o2->SetPrototype(o3));
8061 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8062 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8063 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8064 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8065
8066 // Getting the prototype of o0 should get the first visible one
8067 // which is o3. Therefore, z should not be defined on the prototype
8068 // object.
8069 Local<Value> proto = o0->Get(v8_str("__proto__"));
8070 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008071 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008072
8073 // However, Object::GetPrototype ignores hidden prototype.
8074 Local<Value> proto0 = o0->GetPrototype();
8075 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008076 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00008077
8078 Local<Value> proto1 = o1->GetPrototype();
8079 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008080 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00008081
8082 Local<Value> proto2 = o2->GetPrototype();
8083 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008084 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008085}
8086
8087
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008088// Getting property names of an object with a prototype chain that
8089// triggers dictionary elements in GetLocalPropertyNames() shouldn't
8090// crash the runtime.
8091THREADED_TEST(Regress91517) {
8092 i::FLAG_allow_natives_syntax = true;
8093 v8::HandleScope handle_scope;
8094 LocalContext context;
8095
8096 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8097 t1->SetHiddenPrototype(true);
8098 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
8099 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8100 t2->SetHiddenPrototype(true);
8101 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
8102 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
8103 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
8104 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8105 t3->SetHiddenPrototype(true);
8106 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8107 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8108 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8109
8110 // Force dictionary-based properties.
8111 i::ScopedVector<char> name_buf(1024);
8112 for (int i = 1; i <= 1000; i++) {
8113 i::OS::SNPrintF(name_buf, "sdf%d", i);
8114 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8115 }
8116
8117 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8118 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8119 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8120 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8121
8122 // Create prototype chain of hidden prototypes.
8123 CHECK(o4->SetPrototype(o3));
8124 CHECK(o3->SetPrototype(o2));
8125 CHECK(o2->SetPrototype(o1));
8126
8127 // Call the runtime version of GetLocalPropertyNames() on the natively
8128 // created object through JavaScript.
8129 context->Global()->Set(v8_str("obj"), o4);
8130 CompileRun("var names = %GetLocalPropertyNames(obj);");
8131
8132 ExpectInt32("names.length", 1006);
8133 ExpectTrue("names.indexOf(\"baz\") >= 0");
8134 ExpectTrue("names.indexOf(\"boo\") >= 0");
8135 ExpectTrue("names.indexOf(\"foo\") >= 0");
8136 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8137 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8138 ExpectFalse("names[1005] == undefined");
8139}
8140
8141
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008142THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00008143 v8::HandleScope handle_scope;
8144 LocalContext context;
8145
8146 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008147 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8148 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00008149 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008150 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008151 CHECK(CompileRun(
8152 "(function() {"
8153 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008154 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008155 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008156 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8157 CHECK_EQ(42,
8158 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008159
8160 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008161 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00008162 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008163 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008164 CHECK(CompileRun(
8165 "(function() {"
8166 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008167 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008168 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008169 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008170}
8171
8172
ager@chromium.org5c838252010-02-19 08:53:10 +00008173THREADED_TEST(SetPrototypeThrows) {
8174 v8::HandleScope handle_scope;
8175 LocalContext context;
8176
8177 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8178
8179 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8180 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8181
8182 CHECK(o0->SetPrototype(o1));
8183 // If setting the prototype leads to the cycle, SetPrototype should
8184 // return false and keep VM in sane state.
8185 v8::TryCatch try_catch;
8186 CHECK(!o1->SetPrototype(o0));
8187 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008188 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00008189
8190 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8191}
8192
8193
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008194THREADED_TEST(GetterSetterExceptions) {
8195 v8::HandleScope handle_scope;
8196 LocalContext context;
8197 CompileRun(
8198 "function Foo() { };"
8199 "function Throw() { throw 5; };"
8200 "var x = { };"
8201 "x.__defineSetter__('set', Throw);"
8202 "x.__defineGetter__('get', Throw);");
8203 Local<v8::Object> x =
8204 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8205 v8::TryCatch try_catch;
8206 x->Set(v8_str("set"), v8::Integer::New(8));
8207 x->Get(v8_str("get"));
8208 x->Set(v8_str("set"), v8::Integer::New(8));
8209 x->Get(v8_str("get"));
8210 x->Set(v8_str("set"), v8::Integer::New(8));
8211 x->Get(v8_str("get"));
8212 x->Set(v8_str("set"), v8::Integer::New(8));
8213 x->Get(v8_str("get"));
8214}
8215
8216
8217THREADED_TEST(Constructor) {
8218 v8::HandleScope handle_scope;
8219 LocalContext context;
8220 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8221 templ->SetClassName(v8_str("Fun"));
8222 Local<Function> cons = templ->GetFunction();
8223 context->Global()->Set(v8_str("Fun"), cons);
8224 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008225 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008226 CHECK(obj->IsJSObject());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008227 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8228 CHECK(value->BooleanValue());
8229}
8230
lrn@chromium.org1c092762011-05-09 09:42:16 +00008231
8232static Handle<Value> ConstructorCallback(const Arguments& args) {
8233 ApiTestFuzzer::Fuzz();
8234 Local<Object> This;
8235
8236 if (args.IsConstructCall()) {
8237 Local<Object> Holder = args.Holder();
8238 This = Object::New();
8239 Local<Value> proto = Holder->GetPrototype();
8240 if (proto->IsObject()) {
8241 This->SetPrototype(proto);
8242 }
8243 } else {
8244 This = args.This();
8245 }
8246
8247 This->Set(v8_str("a"), args[0]);
8248 return This;
8249}
8250
8251
8252static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8253 ApiTestFuzzer::Fuzz();
8254 return args[0];
8255}
8256
8257
8258THREADED_TEST(ConstructorForObject) {
8259 v8::HandleScope handle_scope;
8260 LocalContext context;
8261
8262 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8263 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8264 Local<Object> instance = instance_template->NewInstance();
8265 context->Global()->Set(v8_str("obj"), instance);
8266 v8::TryCatch try_catch;
8267 Local<Value> value;
8268 CHECK(!try_catch.HasCaught());
8269
8270 // Call the Object's constructor with a 32-bit signed integer.
8271 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8272 CHECK(!try_catch.HasCaught());
8273 CHECK(value->IsInt32());
8274 CHECK_EQ(28, value->Int32Value());
8275
8276 Local<Value> args1[] = { v8_num(28) };
8277 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8278 CHECK(value_obj1->IsObject());
8279 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8280 value = object1->Get(v8_str("a"));
8281 CHECK(value->IsInt32());
8282 CHECK(!try_catch.HasCaught());
8283 CHECK_EQ(28, value->Int32Value());
8284
8285 // Call the Object's constructor with a String.
8286 value = CompileRun(
8287 "(function() { var o = new obj('tipli'); return o.a; })()");
8288 CHECK(!try_catch.HasCaught());
8289 CHECK(value->IsString());
8290 String::AsciiValue string_value1(value->ToString());
8291 CHECK_EQ("tipli", *string_value1);
8292
8293 Local<Value> args2[] = { v8_str("tipli") };
8294 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8295 CHECK(value_obj2->IsObject());
8296 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8297 value = object2->Get(v8_str("a"));
8298 CHECK(!try_catch.HasCaught());
8299 CHECK(value->IsString());
8300 String::AsciiValue string_value2(value->ToString());
8301 CHECK_EQ("tipli", *string_value2);
8302
8303 // Call the Object's constructor with a Boolean.
8304 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8305 CHECK(!try_catch.HasCaught());
8306 CHECK(value->IsBoolean());
8307 CHECK_EQ(true, value->BooleanValue());
8308
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008309 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00008310 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8311 CHECK(value_obj3->IsObject());
8312 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8313 value = object3->Get(v8_str("a"));
8314 CHECK(!try_catch.HasCaught());
8315 CHECK(value->IsBoolean());
8316 CHECK_EQ(true, value->BooleanValue());
8317
8318 // Call the Object's constructor with undefined.
8319 Handle<Value> args4[] = { v8::Undefined() };
8320 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8321 CHECK(value_obj4->IsObject());
8322 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8323 value = object4->Get(v8_str("a"));
8324 CHECK(!try_catch.HasCaught());
8325 CHECK(value->IsUndefined());
8326
8327 // Call the Object's constructor with null.
8328 Handle<Value> args5[] = { v8::Null() };
8329 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8330 CHECK(value_obj5->IsObject());
8331 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8332 value = object5->Get(v8_str("a"));
8333 CHECK(!try_catch.HasCaught());
8334 CHECK(value->IsNull());
8335 }
8336
8337 // Check exception handling when there is no constructor set for the Object.
8338 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8339 Local<Object> instance = instance_template->NewInstance();
8340 context->Global()->Set(v8_str("obj2"), instance);
8341 v8::TryCatch try_catch;
8342 Local<Value> value;
8343 CHECK(!try_catch.HasCaught());
8344
8345 value = CompileRun("new obj2(28)");
8346 CHECK(try_catch.HasCaught());
8347 String::AsciiValue exception_value1(try_catch.Exception());
8348 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8349 try_catch.Reset();
8350
8351 Local<Value> args[] = { v8_num(29) };
8352 value = instance->CallAsConstructor(1, args);
8353 CHECK(try_catch.HasCaught());
8354 String::AsciiValue exception_value2(try_catch.Exception());
8355 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8356 try_catch.Reset();
8357 }
8358
8359 // Check the case when constructor throws exception.
8360 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8361 instance_template->SetCallAsFunctionHandler(ThrowValue);
8362 Local<Object> instance = instance_template->NewInstance();
8363 context->Global()->Set(v8_str("obj3"), instance);
8364 v8::TryCatch try_catch;
8365 Local<Value> value;
8366 CHECK(!try_catch.HasCaught());
8367
8368 value = CompileRun("new obj3(22)");
8369 CHECK(try_catch.HasCaught());
8370 String::AsciiValue exception_value1(try_catch.Exception());
8371 CHECK_EQ("22", *exception_value1);
8372 try_catch.Reset();
8373
8374 Local<Value> args[] = { v8_num(23) };
8375 value = instance->CallAsConstructor(1, args);
8376 CHECK(try_catch.HasCaught());
8377 String::AsciiValue exception_value2(try_catch.Exception());
8378 CHECK_EQ("23", *exception_value2);
8379 try_catch.Reset();
8380 }
8381
8382 // Check whether constructor returns with an object or non-object.
8383 { Local<FunctionTemplate> function_template =
8384 FunctionTemplate::New(FakeConstructorCallback);
8385 Local<Function> function = function_template->GetFunction();
8386 Local<Object> instance1 = function;
8387 context->Global()->Set(v8_str("obj4"), instance1);
8388 v8::TryCatch try_catch;
8389 Local<Value> value;
8390 CHECK(!try_catch.HasCaught());
8391
8392 CHECK(instance1->IsObject());
8393 CHECK(instance1->IsFunction());
8394
8395 value = CompileRun("new obj4(28)");
8396 CHECK(!try_catch.HasCaught());
8397 CHECK(value->IsObject());
8398
8399 Local<Value> args1[] = { v8_num(28) };
8400 value = instance1->CallAsConstructor(1, args1);
8401 CHECK(!try_catch.HasCaught());
8402 CHECK(value->IsObject());
8403
8404 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8405 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8406 Local<Object> instance2 = instance_template->NewInstance();
8407 context->Global()->Set(v8_str("obj5"), instance2);
8408 CHECK(!try_catch.HasCaught());
8409
8410 CHECK(instance2->IsObject());
8411 CHECK(!instance2->IsFunction());
8412
8413 value = CompileRun("new obj5(28)");
8414 CHECK(!try_catch.HasCaught());
8415 CHECK(!value->IsObject());
8416
8417 Local<Value> args2[] = { v8_num(28) };
8418 value = instance2->CallAsConstructor(1, args2);
8419 CHECK(!try_catch.HasCaught());
8420 CHECK(!value->IsObject());
8421 }
8422}
8423
8424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008425THREADED_TEST(FunctionDescriptorException) {
8426 v8::HandleScope handle_scope;
8427 LocalContext context;
8428 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8429 templ->SetClassName(v8_str("Fun"));
8430 Local<Function> cons = templ->GetFunction();
8431 context->Global()->Set(v8_str("Fun"), cons);
8432 Local<Value> value = CompileRun(
8433 "function test() {"
8434 " try {"
8435 " (new Fun()).blah()"
8436 " } catch (e) {"
8437 " var str = String(e);"
8438 " if (str.indexOf('TypeError') == -1) return 1;"
8439 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00008440 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008441 " return 0;"
8442 " }"
8443 " return 4;"
8444 "}"
8445 "test();");
8446 CHECK_EQ(0, value->Int32Value());
8447}
8448
8449
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008450THREADED_TEST(EvalAliasedDynamic) {
8451 v8::HandleScope scope;
8452 LocalContext current;
8453
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008454 // Tests where aliased eval can only be resolved dynamically.
8455 Local<Script> script =
8456 Script::Compile(v8_str("function f(x) { "
8457 " var foo = 2;"
8458 " with (x) { return eval('foo'); }"
8459 "}"
8460 "foo = 0;"
8461 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008462 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008463 "var x = new Object();"
8464 "x.eval = function(x) { return 1; };"
8465 "result3 = f(x);"));
8466 script->Run();
8467 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8468 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8469 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8470
8471 v8::TryCatch try_catch;
8472 script =
8473 Script::Compile(v8_str("function f(x) { "
8474 " var bar = 2;"
8475 " with (x) { return eval('bar'); }"
8476 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008477 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008478 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008479 CHECK(!try_catch.HasCaught());
8480 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8481
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008482 try_catch.Reset();
8483}
8484
8485
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008486THREADED_TEST(CrossEval) {
8487 v8::HandleScope scope;
8488 LocalContext other;
8489 LocalContext current;
8490
8491 Local<String> token = v8_str("<security token>");
8492 other->SetSecurityToken(token);
8493 current->SetSecurityToken(token);
8494
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008495 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008496 current->Global()->Set(v8_str("other"), other->Global());
8497
8498 // Check that new variables are introduced in other context.
8499 Local<Script> script =
8500 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8501 script->Run();
8502 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8503 CHECK_EQ(1234, foo->Int32Value());
8504 CHECK(!current->Global()->Has(v8_str("foo")));
8505
8506 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008507 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008508 script =
8509 Script::Compile(v8_str("other.eval('na = 1234')"));
8510 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008511 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8512 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008513
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008514 // Check that global variables in current context are not visible in other
8515 // context.
8516 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008517 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008518 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008519 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008520 CHECK(try_catch.HasCaught());
8521 try_catch.Reset();
8522
8523 // Check that local variables in current context are not visible in other
8524 // context.
8525 script =
8526 Script::Compile(v8_str("(function() { "
8527 " var baz = 87;"
8528 " return other.eval('baz');"
8529 "})();"));
8530 result = script->Run();
8531 CHECK(try_catch.HasCaught());
8532 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008533
8534 // Check that global variables in the other environment are visible
8535 // when evaluting code.
8536 other->Global()->Set(v8_str("bis"), v8_num(1234));
8537 script = Script::Compile(v8_str("other.eval('bis')"));
8538 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008539 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008540
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008541 // Check that the 'this' pointer points to the global object evaluating
8542 // code.
8543 other->Global()->Set(v8_str("t"), other->Global());
8544 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008545 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008546 CHECK(result->IsTrue());
8547 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008548
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008549 // Check that variables introduced in with-statement are not visible in
8550 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008551 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008552 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008553 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008554 CHECK(try_catch.HasCaught());
8555 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008556
8557 // Check that you cannot use 'eval.call' with another object than the
8558 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008559 script =
8560 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8561 result = script->Run();
8562 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008563}
8564
8565
ager@chromium.orge2902be2009-06-08 12:21:35 +00008566// Test that calling eval in a context which has been detached from
8567// its global throws an exception. This behavior is consistent with
8568// other JavaScript implementations.
8569THREADED_TEST(EvalInDetachedGlobal) {
8570 v8::HandleScope scope;
8571
8572 v8::Persistent<Context> context0 = Context::New();
8573 v8::Persistent<Context> context1 = Context::New();
8574
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008575 // Set up function in context0 that uses eval from context0.
ager@chromium.orge2902be2009-06-08 12:21:35 +00008576 context0->Enter();
8577 v8::Handle<v8::Value> fun =
8578 CompileRun("var x = 42;"
8579 "(function() {"
8580 " var e = eval;"
8581 " return function(s) { return e(s); }"
8582 "})()");
8583 context0->Exit();
8584
8585 // Put the function into context1 and call it before and after
8586 // detaching the global. Before detaching, the call succeeds and
8587 // after detaching and exception is thrown.
8588 context1->Enter();
8589 context1->Global()->Set(v8_str("fun"), fun);
8590 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8591 CHECK_EQ(42, x_value->Int32Value());
8592 context0->DetachGlobal();
8593 v8::TryCatch catcher;
8594 x_value = CompileRun("fun('x')");
8595 CHECK(x_value.IsEmpty());
8596 CHECK(catcher.HasCaught());
8597 context1->Exit();
8598
8599 context1.Dispose();
8600 context0.Dispose();
8601}
8602
8603
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008604THREADED_TEST(CrossLazyLoad) {
8605 v8::HandleScope scope;
8606 LocalContext other;
8607 LocalContext current;
8608
8609 Local<String> token = v8_str("<security token>");
8610 other->SetSecurityToken(token);
8611 current->SetSecurityToken(token);
8612
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008613 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008614 current->Global()->Set(v8_str("other"), other->Global());
8615
8616 // Trigger lazy loading in other context.
8617 Local<Script> script =
8618 Script::Compile(v8_str("other.eval('new Date(42)')"));
8619 Local<Value> value = script->Run();
8620 CHECK_EQ(42.0, value->NumberValue());
8621}
8622
8623
8624static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8625 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008626 if (args.IsConstructCall()) {
8627 if (args[0]->IsInt32()) {
8628 return v8_num(-args[0]->Int32Value());
8629 }
8630 }
8631
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008632 return args[0];
8633}
8634
8635
8636// Test that a call handler can be set for objects which will allow
8637// non-function objects created through the API to be called as
8638// functions.
8639THREADED_TEST(CallAsFunction) {
8640 v8::HandleScope scope;
8641 LocalContext context;
8642
lrn@chromium.org1c092762011-05-09 09:42:16 +00008643 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8644 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8645 instance_template->SetCallAsFunctionHandler(call_as_function);
8646 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8647 context->Global()->Set(v8_str("obj"), instance);
8648 v8::TryCatch try_catch;
8649 Local<Value> value;
8650 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008651
lrn@chromium.org1c092762011-05-09 09:42:16 +00008652 value = CompileRun("obj(42)");
8653 CHECK(!try_catch.HasCaught());
8654 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008655
lrn@chromium.org1c092762011-05-09 09:42:16 +00008656 value = CompileRun("(function(o){return o(49)})(obj)");
8657 CHECK(!try_catch.HasCaught());
8658 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008659
lrn@chromium.org1c092762011-05-09 09:42:16 +00008660 // test special case of call as function
8661 value = CompileRun("[obj]['0'](45)");
8662 CHECK(!try_catch.HasCaught());
8663 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008664
lrn@chromium.org1c092762011-05-09 09:42:16 +00008665 value = CompileRun("obj.call = Function.prototype.call;"
8666 "obj.call(null, 87)");
8667 CHECK(!try_catch.HasCaught());
8668 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008669
lrn@chromium.org1c092762011-05-09 09:42:16 +00008670 // Regression tests for bug #1116356: Calling call through call/apply
8671 // must work for non-function receivers.
8672 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8673 value = CompileRun(apply_99);
8674 CHECK(!try_catch.HasCaught());
8675 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008676
lrn@chromium.org1c092762011-05-09 09:42:16 +00008677 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8678 value = CompileRun(call_17);
8679 CHECK(!try_catch.HasCaught());
8680 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008681
lrn@chromium.org1c092762011-05-09 09:42:16 +00008682 // Check that the call-as-function handler can be called through
8683 // new.
8684 value = CompileRun("new obj(43)");
8685 CHECK(!try_catch.HasCaught());
8686 CHECK_EQ(-43, value->Int32Value());
8687
8688 // Check that the call-as-function handler can be called through
8689 // the API.
8690 v8::Handle<Value> args[] = { v8_num(28) };
8691 value = instance->CallAsFunction(instance, 1, args);
8692 CHECK(!try_catch.HasCaught());
8693 CHECK_EQ(28, value->Int32Value());
8694 }
8695
8696 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008697 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008698 USE(instance_template);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008699 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8700 context->Global()->Set(v8_str("obj2"), instance);
8701 v8::TryCatch try_catch;
8702 Local<Value> value;
8703 CHECK(!try_catch.HasCaught());
8704
8705 // Call an object without call-as-function handler through the JS
8706 value = CompileRun("obj2(28)");
8707 CHECK(value.IsEmpty());
8708 CHECK(try_catch.HasCaught());
8709 String::AsciiValue exception_value1(try_catch.Exception());
8710 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8711 *exception_value1);
8712 try_catch.Reset();
8713
8714 // Call an object without call-as-function handler through the API
8715 value = CompileRun("obj2(28)");
8716 v8::Handle<Value> args[] = { v8_num(28) };
8717 value = instance->CallAsFunction(instance, 1, args);
8718 CHECK(value.IsEmpty());
8719 CHECK(try_catch.HasCaught());
8720 String::AsciiValue exception_value2(try_catch.Exception());
8721 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8722 try_catch.Reset();
8723 }
8724
8725 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8726 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8727 instance_template->SetCallAsFunctionHandler(ThrowValue);
8728 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8729 context->Global()->Set(v8_str("obj3"), instance);
8730 v8::TryCatch try_catch;
8731 Local<Value> value;
8732 CHECK(!try_catch.HasCaught());
8733
8734 // Catch the exception which is thrown by call-as-function handler
8735 value = CompileRun("obj3(22)");
8736 CHECK(try_catch.HasCaught());
8737 String::AsciiValue exception_value1(try_catch.Exception());
8738 CHECK_EQ("22", *exception_value1);
8739 try_catch.Reset();
8740
8741 v8::Handle<Value> args[] = { v8_num(23) };
8742 value = instance->CallAsFunction(instance, 1, args);
8743 CHECK(try_catch.HasCaught());
8744 String::AsciiValue exception_value2(try_catch.Exception());
8745 CHECK_EQ("23", *exception_value2);
8746 try_catch.Reset();
8747 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008748}
8749
8750
karlklose@chromium.org83a47282011-05-11 11:54:09 +00008751// Check whether a non-function object is callable.
8752THREADED_TEST(CallableObject) {
8753 v8::HandleScope scope;
8754 LocalContext context;
8755
8756 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8757 instance_template->SetCallAsFunctionHandler(call_as_function);
8758 Local<Object> instance = instance_template->NewInstance();
8759 v8::TryCatch try_catch;
8760
8761 CHECK(instance->IsCallable());
8762 CHECK(!try_catch.HasCaught());
8763 }
8764
8765 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8766 Local<Object> instance = instance_template->NewInstance();
8767 v8::TryCatch try_catch;
8768
8769 CHECK(!instance->IsCallable());
8770 CHECK(!try_catch.HasCaught());
8771 }
8772
8773 { Local<FunctionTemplate> function_template =
8774 FunctionTemplate::New(call_as_function);
8775 Local<Function> function = function_template->GetFunction();
8776 Local<Object> instance = function;
8777 v8::TryCatch try_catch;
8778
8779 CHECK(instance->IsCallable());
8780 CHECK(!try_catch.HasCaught());
8781 }
8782
8783 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8784 Local<Function> function = function_template->GetFunction();
8785 Local<Object> instance = function;
8786 v8::TryCatch try_catch;
8787
8788 CHECK(instance->IsCallable());
8789 CHECK(!try_catch.HasCaught());
8790 }
8791}
8792
8793
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008794static int CountHandles() {
8795 return v8::HandleScope::NumberOfHandles();
8796}
8797
8798
8799static int Recurse(int depth, int iterations) {
8800 v8::HandleScope scope;
8801 if (depth == 0) return CountHandles();
8802 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008803 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008804 }
8805 return Recurse(depth - 1, iterations);
8806}
8807
8808
8809THREADED_TEST(HandleIteration) {
8810 static const int kIterations = 500;
8811 static const int kNesting = 200;
8812 CHECK_EQ(0, CountHandles());
8813 {
8814 v8::HandleScope scope1;
8815 CHECK_EQ(0, CountHandles());
8816 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008817 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008818 CHECK_EQ(i + 1, CountHandles());
8819 }
8820
8821 CHECK_EQ(kIterations, CountHandles());
8822 {
8823 v8::HandleScope scope2;
8824 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008825 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008826 CHECK_EQ(j + 1 + kIterations, CountHandles());
8827 }
8828 }
8829 CHECK_EQ(kIterations, CountHandles());
8830 }
8831 CHECK_EQ(0, CountHandles());
8832 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8833}
8834
8835
8836static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8837 Local<String> name,
8838 const AccessorInfo& info) {
8839 ApiTestFuzzer::Fuzz();
8840 return v8::Handle<Value>();
8841}
8842
8843
8844THREADED_TEST(InterceptorHasOwnProperty) {
8845 v8::HandleScope scope;
8846 LocalContext context;
8847 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8848 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8849 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8850 Local<Function> function = fun_templ->GetFunction();
8851 context->Global()->Set(v8_str("constructor"), function);
8852 v8::Handle<Value> value = CompileRun(
8853 "var o = new constructor();"
8854 "o.hasOwnProperty('ostehaps');");
8855 CHECK_EQ(false, value->BooleanValue());
8856 value = CompileRun(
8857 "o.ostehaps = 42;"
8858 "o.hasOwnProperty('ostehaps');");
8859 CHECK_EQ(true, value->BooleanValue());
8860 value = CompileRun(
8861 "var p = new constructor();"
8862 "p.hasOwnProperty('ostehaps');");
8863 CHECK_EQ(false, value->BooleanValue());
8864}
8865
8866
ager@chromium.org9085a012009-05-11 19:22:57 +00008867static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8868 Local<String> name,
8869 const AccessorInfo& info) {
8870 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008871 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00008872 return v8::Handle<Value>();
8873}
8874
8875
8876THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8877 v8::HandleScope scope;
8878 LocalContext context;
8879 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8880 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8881 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8882 Local<Function> function = fun_templ->GetFunction();
8883 context->Global()->Set(v8_str("constructor"), function);
8884 // Let's first make some stuff so we can be sure to get a good GC.
8885 CompileRun(
8886 "function makestr(size) {"
8887 " switch (size) {"
8888 " case 1: return 'f';"
8889 " case 2: return 'fo';"
8890 " case 3: return 'foo';"
8891 " }"
8892 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
8893 "}"
8894 "var x = makestr(12345);"
8895 "x = makestr(31415);"
8896 "x = makestr(23456);");
8897 v8::Handle<Value> value = CompileRun(
8898 "var o = new constructor();"
8899 "o.__proto__ = new String(x);"
8900 "o.hasOwnProperty('ostehaps');");
8901 CHECK_EQ(false, value->BooleanValue());
8902}
8903
8904
ager@chromium.orge2902be2009-06-08 12:21:35 +00008905typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8906 const AccessorInfo& info);
8907
8908
8909static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8910 const char* source,
8911 int expected) {
8912 v8::HandleScope scope;
8913 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008914 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00008915 LocalContext context;
8916 context->Global()->Set(v8_str("o"), templ->NewInstance());
8917 v8::Handle<Value> value = CompileRun(source);
8918 CHECK_EQ(expected, value->Int32Value());
8919}
8920
8921
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008922static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8923 const AccessorInfo& info) {
8924 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00008925 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8926 CHECK_EQ(isolate, info.GetIsolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008927 CHECK_EQ(v8_str("data"), info.Data());
8928 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008929 return v8::Integer::New(42);
8930}
8931
8932
8933// This test should hit the load IC for the interceptor case.
8934THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00008935 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008936 "var result = 0;"
8937 "for (var i = 0; i < 1000; i++) {"
8938 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008939 "}",
8940 42);
8941}
8942
8943
8944// Below go several tests which verify that JITing for various
8945// configurations of interceptor and explicit fields works fine
8946// (those cases are special cased to get better performance).
8947
8948static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8949 const AccessorInfo& info) {
8950 ApiTestFuzzer::Fuzz();
8951 return v8_str("x")->Equals(name)
8952 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8953}
8954
8955
8956THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8957 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8958 "var result = 0;"
8959 "o.y = 239;"
8960 "for (var i = 0; i < 1000; i++) {"
8961 " result = o.y;"
8962 "}",
8963 239);
8964}
8965
8966
8967THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8968 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8969 "var result = 0;"
8970 "o.__proto__ = { 'y': 239 };"
8971 "for (var i = 0; i < 1000; i++) {"
8972 " result = o.y + o.x;"
8973 "}",
8974 239 + 42);
8975}
8976
8977
8978THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8979 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8980 "var result = 0;"
8981 "o.__proto__.y = 239;"
8982 "for (var i = 0; i < 1000; i++) {"
8983 " result = o.y + o.x;"
8984 "}",
8985 239 + 42);
8986}
8987
8988
8989THREADED_TEST(InterceptorLoadICUndefined) {
8990 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8991 "var result = 0;"
8992 "for (var i = 0; i < 1000; i++) {"
8993 " result = (o.y == undefined) ? 239 : 42;"
8994 "}",
8995 239);
8996}
8997
8998
8999THREADED_TEST(InterceptorLoadICWithOverride) {
9000 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9001 "fst = new Object(); fst.__proto__ = o;"
9002 "snd = new Object(); snd.__proto__ = fst;"
9003 "var result1 = 0;"
9004 "for (var i = 0; i < 1000; i++) {"
9005 " result1 = snd.x;"
9006 "}"
9007 "fst.x = 239;"
9008 "var result = 0;"
9009 "for (var i = 0; i < 1000; i++) {"
9010 " result = snd.x;"
9011 "}"
9012 "result + result1",
9013 239 + 42);
9014}
9015
9016
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009017// Test the case when we stored field into
9018// a stub, but interceptor produced value on its own.
9019THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
9020 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9021 "proto = new Object();"
9022 "o.__proto__ = proto;"
9023 "proto.x = 239;"
9024 "for (var i = 0; i < 1000; i++) {"
9025 " o.x;"
9026 // Now it should be ICed and keep a reference to x defined on proto
9027 "}"
9028 "var result = 0;"
9029 "for (var i = 0; i < 1000; i++) {"
9030 " result += o.x;"
9031 "}"
9032 "result;",
9033 42 * 1000);
9034}
9035
9036
9037// Test the case when we stored field into
9038// a stub, but it got invalidated later on.
9039THREADED_TEST(InterceptorLoadICInvalidatedField) {
9040 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9041 "proto1 = new Object();"
9042 "proto2 = new Object();"
9043 "o.__proto__ = proto1;"
9044 "proto1.__proto__ = proto2;"
9045 "proto2.y = 239;"
9046 "for (var i = 0; i < 1000; i++) {"
9047 " o.y;"
9048 // Now it should be ICed and keep a reference to y defined on proto2
9049 "}"
9050 "proto1.y = 42;"
9051 "var result = 0;"
9052 "for (var i = 0; i < 1000; i++) {"
9053 " result += o.y;"
9054 "}"
9055 "result;",
9056 42 * 1000);
9057}
9058
9059
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00009060static int interceptor_load_not_handled_calls = 0;
9061static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
9062 const AccessorInfo& info) {
9063 ++interceptor_load_not_handled_calls;
9064 return v8::Handle<v8::Value>();
9065}
9066
9067
9068// Test how post-interceptor lookups are done in the non-cacheable
9069// case: the interceptor should not be invoked during this lookup.
9070THREADED_TEST(InterceptorLoadICPostInterceptor) {
9071 interceptor_load_not_handled_calls = 0;
9072 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
9073 "receiver = new Object();"
9074 "receiver.__proto__ = o;"
9075 "proto = new Object();"
9076 "/* Make proto a slow-case object. */"
9077 "for (var i = 0; i < 1000; i++) {"
9078 " proto[\"xxxxxxxx\" + i] = [];"
9079 "}"
9080 "proto.x = 17;"
9081 "o.__proto__ = proto;"
9082 "var result = 0;"
9083 "for (var i = 0; i < 1000; i++) {"
9084 " result += receiver.x;"
9085 "}"
9086 "result;",
9087 17 * 1000);
9088 CHECK_EQ(1000, interceptor_load_not_handled_calls);
9089}
9090
9091
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009092// Test the case when we stored field into
9093// a stub, but it got invalidated later on due to override on
9094// global object which is between interceptor and fields' holders.
9095THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
9096 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9097 "o.__proto__ = this;" // set a global to be a proto of o.
9098 "this.__proto__.y = 239;"
9099 "for (var i = 0; i < 10; i++) {"
9100 " if (o.y != 239) throw 'oops: ' + o.y;"
9101 // Now it should be ICed and keep a reference to y defined on field_holder.
9102 "}"
9103 "this.y = 42;" // Assign on a global.
9104 "var result = 0;"
9105 "for (var i = 0; i < 10; i++) {"
9106 " result += o.y;"
9107 "}"
9108 "result;",
9109 42 * 10);
9110}
9111
9112
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009113static void SetOnThis(Local<String> name,
9114 Local<Value> value,
9115 const AccessorInfo& info) {
9116 info.This()->ForceSet(name, value);
9117}
9118
9119
9120THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
9121 v8::HandleScope scope;
9122 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9123 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9124 templ->SetAccessor(v8_str("y"), Return239);
9125 LocalContext context;
9126 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009127
9128 // Check the case when receiver and interceptor's holder
9129 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009130 v8::Handle<Value> value = CompileRun(
9131 "var result = 0;"
9132 "for (var i = 0; i < 7; i++) {"
9133 " result = o.y;"
9134 "}");
9135 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009136
9137 // Check the case when interceptor's holder is in proto chain
9138 // of receiver.
9139 value = CompileRun(
9140 "r = { __proto__: o };"
9141 "var result = 0;"
9142 "for (var i = 0; i < 7; i++) {"
9143 " result = r.y;"
9144 "}");
9145 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009146}
9147
9148
9149THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
9150 v8::HandleScope scope;
9151 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9152 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9153 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9154 templ_p->SetAccessor(v8_str("y"), Return239);
9155
9156 LocalContext context;
9157 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9158 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9159
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009160 // Check the case when receiver and interceptor's holder
9161 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009162 v8::Handle<Value> value = CompileRun(
9163 "o.__proto__ = p;"
9164 "var result = 0;"
9165 "for (var i = 0; i < 7; i++) {"
9166 " result = o.x + o.y;"
9167 "}");
9168 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009169
9170 // Check the case when interceptor's holder is in proto chain
9171 // of receiver.
9172 value = CompileRun(
9173 "r = { __proto__: o };"
9174 "var result = 0;"
9175 "for (var i = 0; i < 7; i++) {"
9176 " result = r.x + r.y;"
9177 "}");
9178 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009179}
9180
9181
9182THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
9183 v8::HandleScope scope;
9184 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9185 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9186 templ->SetAccessor(v8_str("y"), Return239);
9187
9188 LocalContext context;
9189 context->Global()->Set(v8_str("o"), templ->NewInstance());
9190
9191 v8::Handle<Value> value = CompileRun(
9192 "fst = new Object(); fst.__proto__ = o;"
9193 "snd = new Object(); snd.__proto__ = fst;"
9194 "var result1 = 0;"
9195 "for (var i = 0; i < 7; i++) {"
9196 " result1 = snd.x;"
9197 "}"
9198 "fst.x = 239;"
9199 "var result = 0;"
9200 "for (var i = 0; i < 7; i++) {"
9201 " result = snd.x;"
9202 "}"
9203 "result + result1");
9204 CHECK_EQ(239 + 42, value->Int32Value());
9205}
9206
9207
9208// Test the case when we stored callback into
9209// a stub, but interceptor produced value on its own.
9210THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
9211 v8::HandleScope scope;
9212 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9213 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9214 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9215 templ_p->SetAccessor(v8_str("y"), Return239);
9216
9217 LocalContext context;
9218 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9219 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9220
9221 v8::Handle<Value> value = CompileRun(
9222 "o.__proto__ = p;"
9223 "for (var i = 0; i < 7; i++) {"
9224 " o.x;"
9225 // Now it should be ICed and keep a reference to x defined on p
9226 "}"
9227 "var result = 0;"
9228 "for (var i = 0; i < 7; i++) {"
9229 " result += o.x;"
9230 "}"
9231 "result");
9232 CHECK_EQ(42 * 7, value->Int32Value());
9233}
9234
9235
9236// Test the case when we stored callback into
9237// a stub, but it got invalidated later on.
9238THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
9239 v8::HandleScope scope;
9240 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9241 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9242 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9243 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9244
9245 LocalContext context;
9246 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9247 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9248
9249 v8::Handle<Value> value = CompileRun(
9250 "inbetween = new Object();"
9251 "o.__proto__ = inbetween;"
9252 "inbetween.__proto__ = p;"
9253 "for (var i = 0; i < 10; i++) {"
9254 " o.y;"
9255 // Now it should be ICed and keep a reference to y defined on p
9256 "}"
9257 "inbetween.y = 42;"
9258 "var result = 0;"
9259 "for (var i = 0; i < 10; i++) {"
9260 " result += o.y;"
9261 "}"
9262 "result");
9263 CHECK_EQ(42 * 10, value->Int32Value());
9264}
9265
9266
9267// Test the case when we stored callback into
9268// a stub, but it got invalidated later on due to override on
9269// global object which is between interceptor and callbacks' holders.
9270THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
9271 v8::HandleScope scope;
9272 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9273 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9274 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9275 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9276
9277 LocalContext context;
9278 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9279 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9280
9281 v8::Handle<Value> value = CompileRun(
9282 "o.__proto__ = this;"
9283 "this.__proto__ = p;"
9284 "for (var i = 0; i < 10; i++) {"
9285 " if (o.y != 239) throw 'oops: ' + o.y;"
9286 // Now it should be ICed and keep a reference to y defined on p
9287 "}"
9288 "this.y = 42;"
9289 "var result = 0;"
9290 "for (var i = 0; i < 10; i++) {"
9291 " result += o.y;"
9292 "}"
9293 "result");
9294 CHECK_EQ(42 * 10, value->Int32Value());
9295}
9296
9297
ager@chromium.orge2902be2009-06-08 12:21:35 +00009298static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9299 const AccessorInfo& info) {
9300 ApiTestFuzzer::Fuzz();
9301 CHECK(v8_str("x")->Equals(name));
9302 return v8::Integer::New(0);
9303}
9304
9305
9306THREADED_TEST(InterceptorReturningZero) {
9307 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9308 "o.x == undefined ? 1 : 0",
9309 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009310}
9311
9312
9313static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009314 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009315 CHECK(v8_str("x")->Equals(key));
9316 CHECK_EQ(42, value->Int32Value());
9317 return value;
9318}
9319
9320
9321// This test should hit the store IC for the interceptor case.
9322THREADED_TEST(InterceptorStoreIC) {
9323 v8::HandleScope scope;
9324 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9325 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009326 InterceptorStoreICSetter,
9327 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009328 LocalContext context;
9329 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009330 CompileRun(
9331 "for (var i = 0; i < 1000; i++) {"
9332 " o.x = 42;"
9333 "}");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009334}
9335
9336
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009337THREADED_TEST(InterceptorStoreICWithNoSetter) {
9338 v8::HandleScope scope;
9339 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9340 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9341 LocalContext context;
9342 context->Global()->Set(v8_str("o"), templ->NewInstance());
9343 v8::Handle<Value> value = CompileRun(
9344 "for (var i = 0; i < 1000; i++) {"
9345 " o.y = 239;"
9346 "}"
9347 "42 + o.y");
9348 CHECK_EQ(239 + 42, value->Int32Value());
9349}
9350
9351
9352
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009353
9354v8::Handle<Value> call_ic_function;
9355v8::Handle<Value> call_ic_function2;
9356v8::Handle<Value> call_ic_function3;
9357
9358static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9359 const AccessorInfo& info) {
9360 ApiTestFuzzer::Fuzz();
9361 CHECK(v8_str("x")->Equals(name));
9362 return call_ic_function;
9363}
9364
9365
9366// This test should hit the call IC for the interceptor case.
9367THREADED_TEST(InterceptorCallIC) {
9368 v8::HandleScope scope;
9369 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9370 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9371 LocalContext context;
9372 context->Global()->Set(v8_str("o"), templ->NewInstance());
9373 call_ic_function =
9374 v8_compile("function f(x) { return x + 1; }; f")->Run();
9375 v8::Handle<Value> value = CompileRun(
9376 "var result = 0;"
9377 "for (var i = 0; i < 1000; i++) {"
9378 " result = o.x(41);"
9379 "}");
9380 CHECK_EQ(42, value->Int32Value());
9381}
9382
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009383
9384// This test checks that if interceptor doesn't provide
9385// a value, we can fetch regular value.
9386THREADED_TEST(InterceptorCallICSeesOthers) {
9387 v8::HandleScope scope;
9388 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9389 templ->SetNamedPropertyHandler(NoBlockGetterX);
9390 LocalContext context;
9391 context->Global()->Set(v8_str("o"), templ->NewInstance());
9392 v8::Handle<Value> value = CompileRun(
9393 "o.x = function f(x) { return x + 1; };"
9394 "var result = 0;"
9395 "for (var i = 0; i < 7; i++) {"
9396 " result = o.x(41);"
9397 "}");
9398 CHECK_EQ(42, value->Int32Value());
9399}
9400
9401
9402static v8::Handle<Value> call_ic_function4;
9403static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9404 const AccessorInfo& info) {
9405 ApiTestFuzzer::Fuzz();
9406 CHECK(v8_str("x")->Equals(name));
9407 return call_ic_function4;
9408}
9409
9410
9411// This test checks that if interceptor provides a function,
9412// even if we cached shadowed variant, interceptor's function
9413// is invoked
9414THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
9415 v8::HandleScope scope;
9416 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9417 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9418 LocalContext context;
9419 context->Global()->Set(v8_str("o"), templ->NewInstance());
9420 call_ic_function4 =
9421 v8_compile("function f(x) { return x - 1; }; f")->Run();
9422 v8::Handle<Value> value = CompileRun(
9423 "o.__proto__.x = function(x) { return x + 1; };"
9424 "var result = 0;"
9425 "for (var i = 0; i < 1000; i++) {"
9426 " result = o.x(42);"
9427 "}");
9428 CHECK_EQ(41, value->Int32Value());
9429}
9430
9431
9432// Test the case when we stored cacheable lookup into
9433// a stub, but it got invalidated later on
9434THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
9435 v8::HandleScope scope;
9436 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9437 templ->SetNamedPropertyHandler(NoBlockGetterX);
9438 LocalContext context;
9439 context->Global()->Set(v8_str("o"), templ->NewInstance());
9440 v8::Handle<Value> value = CompileRun(
9441 "proto1 = new Object();"
9442 "proto2 = new Object();"
9443 "o.__proto__ = proto1;"
9444 "proto1.__proto__ = proto2;"
9445 "proto2.y = function(x) { return x + 1; };"
9446 // Invoke it many times to compile a stub
9447 "for (var i = 0; i < 7; i++) {"
9448 " o.y(42);"
9449 "}"
9450 "proto1.y = function(x) { return x - 1; };"
9451 "var result = 0;"
9452 "for (var i = 0; i < 7; i++) {"
9453 " result += o.y(42);"
9454 "}");
9455 CHECK_EQ(41 * 7, value->Int32Value());
9456}
9457
9458
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009459// This test checks that if interceptor doesn't provide a function,
9460// cached constant function is used
9461THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
9462 v8::HandleScope scope;
9463 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9464 templ->SetNamedPropertyHandler(NoBlockGetterX);
9465 LocalContext context;
9466 context->Global()->Set(v8_str("o"), templ->NewInstance());
9467 v8::Handle<Value> value = CompileRun(
9468 "function inc(x) { return x + 1; };"
9469 "inc(1);"
9470 "o.x = inc;"
9471 "var result = 0;"
9472 "for (var i = 0; i < 1000; i++) {"
9473 " result = o.x(42);"
9474 "}");
9475 CHECK_EQ(43, value->Int32Value());
9476}
9477
9478
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009479static v8::Handle<Value> call_ic_function5;
9480static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9481 const AccessorInfo& info) {
9482 ApiTestFuzzer::Fuzz();
9483 if (v8_str("x")->Equals(name))
9484 return call_ic_function5;
9485 else
9486 return Local<Value>();
9487}
9488
9489
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009490// This test checks that if interceptor provides a function,
9491// even if we cached constant function, interceptor's function
9492// is invoked
9493THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
9494 v8::HandleScope scope;
9495 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9496 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9497 LocalContext context;
9498 context->Global()->Set(v8_str("o"), templ->NewInstance());
9499 call_ic_function5 =
9500 v8_compile("function f(x) { return x - 1; }; f")->Run();
9501 v8::Handle<Value> value = CompileRun(
9502 "function inc(x) { return x + 1; };"
9503 "inc(1);"
9504 "o.x = inc;"
9505 "var result = 0;"
9506 "for (var i = 0; i < 1000; i++) {"
9507 " result = o.x(42);"
9508 "}");
9509 CHECK_EQ(41, value->Int32Value());
9510}
9511
9512
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009513static v8::Handle<Value> call_ic_function6;
9514static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9515 const AccessorInfo& info) {
9516 ApiTestFuzzer::Fuzz();
9517 if (v8_str("x")->Equals(name))
9518 return call_ic_function6;
9519 else
9520 return Local<Value>();
9521}
9522
9523
9524// Same test as above, except the code is wrapped in a function
9525// to test the optimized compiler.
9526THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9527 i::FLAG_allow_natives_syntax = true;
9528 v8::HandleScope scope;
9529 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9530 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9531 LocalContext context;
9532 context->Global()->Set(v8_str("o"), templ->NewInstance());
9533 call_ic_function6 =
9534 v8_compile("function f(x) { return x - 1; }; f")->Run();
9535 v8::Handle<Value> value = CompileRun(
9536 "function inc(x) { return x + 1; };"
9537 "inc(1);"
9538 "o.x = inc;"
9539 "function test() {"
9540 " var result = 0;"
9541 " for (var i = 0; i < 1000; i++) {"
9542 " result = o.x(42);"
9543 " }"
9544 " return result;"
9545 "};"
9546 "test();"
9547 "test();"
9548 "test();"
9549 "%OptimizeFunctionOnNextCall(test);"
9550 "test()");
9551 CHECK_EQ(41, value->Int32Value());
9552}
9553
9554
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009555// Test the case when we stored constant function into
9556// a stub, but it got invalidated later on
9557THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
9558 v8::HandleScope scope;
9559 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9560 templ->SetNamedPropertyHandler(NoBlockGetterX);
9561 LocalContext context;
9562 context->Global()->Set(v8_str("o"), templ->NewInstance());
9563 v8::Handle<Value> value = CompileRun(
9564 "function inc(x) { return x + 1; };"
9565 "inc(1);"
9566 "proto1 = new Object();"
9567 "proto2 = new Object();"
9568 "o.__proto__ = proto1;"
9569 "proto1.__proto__ = proto2;"
9570 "proto2.y = inc;"
9571 // Invoke it many times to compile a stub
9572 "for (var i = 0; i < 7; i++) {"
9573 " o.y(42);"
9574 "}"
9575 "proto1.y = function(x) { return x - 1; };"
9576 "var result = 0;"
9577 "for (var i = 0; i < 7; i++) {"
9578 " result += o.y(42);"
9579 "}");
9580 CHECK_EQ(41 * 7, value->Int32Value());
9581}
9582
9583
9584// Test the case when we stored constant function into
9585// a stub, but it got invalidated later on due to override on
9586// global object which is between interceptor and constant function' holders.
9587THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
9588 v8::HandleScope scope;
9589 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9590 templ->SetNamedPropertyHandler(NoBlockGetterX);
9591 LocalContext context;
9592 context->Global()->Set(v8_str("o"), templ->NewInstance());
9593 v8::Handle<Value> value = CompileRun(
9594 "function inc(x) { return x + 1; };"
9595 "inc(1);"
9596 "o.__proto__ = this;"
9597 "this.__proto__.y = inc;"
9598 // Invoke it many times to compile a stub
9599 "for (var i = 0; i < 7; i++) {"
9600 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9601 "}"
9602 "this.y = function(x) { return x - 1; };"
9603 "var result = 0;"
9604 "for (var i = 0; i < 7; i++) {"
9605 " result += o.y(42);"
9606 "}");
9607 CHECK_EQ(41 * 7, value->Int32Value());
9608}
9609
9610
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009611// Test the case when actual function to call sits on global object.
9612THREADED_TEST(InterceptorCallICCachedFromGlobal) {
9613 v8::HandleScope scope;
9614 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9615 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9616
9617 LocalContext context;
9618 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9619
9620 v8::Handle<Value> value = CompileRun(
9621 "try {"
9622 " o.__proto__ = this;"
9623 " for (var i = 0; i < 10; i++) {"
9624 " var v = o.parseFloat('239');"
9625 " if (v != 239) throw v;"
9626 // Now it should be ICed and keep a reference to parseFloat.
9627 " }"
9628 " var result = 0;"
9629 " for (var i = 0; i < 10; i++) {"
9630 " result += o.parseFloat('239');"
9631 " }"
9632 " result"
9633 "} catch(e) {"
9634 " e"
9635 "};");
9636 CHECK_EQ(239 * 10, value->Int32Value());
9637}
9638
ager@chromium.org5c838252010-02-19 08:53:10 +00009639static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9640 const AccessorInfo& info) {
9641 ApiTestFuzzer::Fuzz();
9642 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
9643 ++(*call_count);
9644 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009645 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009646 }
9647 return v8::Handle<Value>();
9648}
9649
9650static v8::Handle<Value> FastApiCallback_TrivialSignature(
9651 const v8::Arguments& args) {
9652 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009653 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9654 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009655 CHECK_EQ(args.This(), args.Holder());
9656 CHECK(args.Data()->Equals(v8_str("method_data")));
9657 return v8::Integer::New(args[0]->Int32Value() + 1);
9658}
9659
9660static v8::Handle<Value> FastApiCallback_SimpleSignature(
9661 const v8::Arguments& args) {
9662 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009663 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9664 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009665 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9666 CHECK(args.Data()->Equals(v8_str("method_data")));
9667 // Note, we're using HasRealNamedProperty instead of Has to avoid
9668 // invoking the interceptor again.
9669 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9670 return v8::Integer::New(args[0]->Int32Value() + 1);
9671}
9672
9673// Helper to maximize the odds of object moving.
9674static void GenerateSomeGarbage() {
9675 CompileRun(
9676 "var garbage;"
9677 "for (var i = 0; i < 1000; i++) {"
9678 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9679 "}"
9680 "garbage = undefined;");
9681}
9682
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009684v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9685 static int count = 0;
9686 if (count++ % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009687 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9688 // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009689 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9690 }
9691 return v8::Handle<v8::Value>();
9692}
9693
9694
9695THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
9696 v8::HandleScope scope;
9697 LocalContext context;
9698 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9699 nativeobject_templ->Set("callback",
9700 v8::FunctionTemplate::New(DirectApiCallback));
9701 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9702 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9703 // call the api function multiple times to ensure direct call stub creation.
9704 CompileRun(
9705 "function f() {"
9706 " for (var i = 1; i <= 30; i++) {"
9707 " nativeobject.callback();"
9708 " }"
9709 "}"
9710 "f();");
9711}
9712
9713
9714v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9715 return v8::ThrowException(v8_str("g"));
9716}
9717
9718
9719THREADED_TEST(CallICFastApi_DirectCall_Throw) {
9720 v8::HandleScope scope;
9721 LocalContext context;
9722 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9723 nativeobject_templ->Set("callback",
9724 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9725 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9726 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9727 // call the api function multiple times to ensure direct call stub creation.
9728 v8::Handle<Value> result = CompileRun(
9729 "var result = '';"
9730 "function f() {"
9731 " for (var i = 1; i <= 5; i++) {"
9732 " try { nativeobject.callback(); } catch (e) { result += e; }"
9733 " }"
9734 "}"
9735 "f(); result;");
9736 CHECK_EQ(v8_str("ggggg"), result);
9737}
9738
9739
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009740v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9741 const v8::AccessorInfo& info) {
9742 if (++p_getter_count % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009743 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 GenerateSomeGarbage();
9745 }
9746 return v8::Handle<v8::Value>();
9747}
9748
9749
9750THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9751 v8::HandleScope scope;
9752 LocalContext context;
9753 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9754 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9755 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9756 p_getter_count = 0;
9757 CompileRun(
9758 "function f() {"
9759 " for (var i = 0; i < 30; i++) o1.p1;"
9760 "}"
9761 "f();");
9762 CHECK_EQ(30, p_getter_count);
9763}
9764
9765
9766v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9767 Local<String> name, const v8::AccessorInfo& info) {
9768 return v8::ThrowException(v8_str("g"));
9769}
9770
9771
9772THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9773 v8::HandleScope scope;
9774 LocalContext context;
9775 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9776 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9777 context->Global()->Set(v8_str("o1"), obj->NewInstance());
9778 v8::Handle<Value> result = CompileRun(
9779 "var result = '';"
9780 "for (var i = 0; i < 5; i++) {"
9781 " try { o1.p1; } catch (e) { result += e; }"
9782 "}"
9783 "result;");
9784 CHECK_EQ(v8_str("ggggg"), result);
9785}
9786
9787
ager@chromium.org5c838252010-02-19 08:53:10 +00009788THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9789 int interceptor_call_count = 0;
9790 v8::HandleScope scope;
9791 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9792 v8::Handle<v8::FunctionTemplate> method_templ =
9793 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9794 v8_str("method_data"),
9795 v8::Handle<v8::Signature>());
9796 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9797 proto_templ->Set(v8_str("method"), method_templ);
9798 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9799 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9800 NULL, NULL, NULL, NULL,
9801 v8::External::Wrap(&interceptor_call_count));
9802 LocalContext context;
9803 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9804 GenerateSomeGarbage();
9805 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009806 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009807 "var result = 0;"
9808 "for (var i = 0; i < 100; i++) {"
9809 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009810 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009811 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9812 CHECK_EQ(100, interceptor_call_count);
9813}
9814
9815THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9816 int interceptor_call_count = 0;
9817 v8::HandleScope scope;
9818 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9819 v8::Handle<v8::FunctionTemplate> method_templ =
9820 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9821 v8_str("method_data"),
9822 v8::Signature::New(fun_templ));
9823 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9824 proto_templ->Set(v8_str("method"), method_templ);
9825 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9826 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9827 NULL, NULL, NULL, NULL,
9828 v8::External::Wrap(&interceptor_call_count));
9829 LocalContext context;
9830 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9831 GenerateSomeGarbage();
9832 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009833 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009834 "o.foo = 17;"
9835 "var receiver = {};"
9836 "receiver.__proto__ = o;"
9837 "var result = 0;"
9838 "for (var i = 0; i < 100; i++) {"
9839 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009840 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009841 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9842 CHECK_EQ(100, interceptor_call_count);
9843}
9844
9845THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9846 int interceptor_call_count = 0;
9847 v8::HandleScope scope;
9848 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9849 v8::Handle<v8::FunctionTemplate> method_templ =
9850 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9851 v8_str("method_data"),
9852 v8::Signature::New(fun_templ));
9853 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9854 proto_templ->Set(v8_str("method"), method_templ);
9855 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9856 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9857 NULL, NULL, NULL, NULL,
9858 v8::External::Wrap(&interceptor_call_count));
9859 LocalContext context;
9860 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9861 GenerateSomeGarbage();
9862 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009863 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009864 "o.foo = 17;"
9865 "var receiver = {};"
9866 "receiver.__proto__ = o;"
9867 "var result = 0;"
9868 "var saved_result = 0;"
9869 "for (var i = 0; i < 100; i++) {"
9870 " result = receiver.method(41);"
9871 " if (i == 50) {"
9872 " saved_result = result;"
9873 " receiver = {method: function(x) { return x - 1 }};"
9874 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009875 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009876 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9877 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9878 CHECK_GE(interceptor_call_count, 50);
9879}
9880
9881THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9882 int interceptor_call_count = 0;
9883 v8::HandleScope scope;
9884 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9885 v8::Handle<v8::FunctionTemplate> method_templ =
9886 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9887 v8_str("method_data"),
9888 v8::Signature::New(fun_templ));
9889 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9890 proto_templ->Set(v8_str("method"), method_templ);
9891 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9892 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9893 NULL, NULL, NULL, NULL,
9894 v8::External::Wrap(&interceptor_call_count));
9895 LocalContext context;
9896 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9897 GenerateSomeGarbage();
9898 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009899 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009900 "o.foo = 17;"
9901 "var receiver = {};"
9902 "receiver.__proto__ = o;"
9903 "var result = 0;"
9904 "var saved_result = 0;"
9905 "for (var i = 0; i < 100; i++) {"
9906 " result = receiver.method(41);"
9907 " if (i == 50) {"
9908 " saved_result = result;"
9909 " o.method = function(x) { return x - 1 };"
9910 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009911 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009912 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9913 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9914 CHECK_GE(interceptor_call_count, 50);
9915}
9916
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009917THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9918 int interceptor_call_count = 0;
9919 v8::HandleScope scope;
9920 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9921 v8::Handle<v8::FunctionTemplate> method_templ =
9922 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9923 v8_str("method_data"),
9924 v8::Signature::New(fun_templ));
9925 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9926 proto_templ->Set(v8_str("method"), method_templ);
9927 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9928 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9929 NULL, NULL, NULL, NULL,
9930 v8::External::Wrap(&interceptor_call_count));
9931 LocalContext context;
9932 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9933 GenerateSomeGarbage();
9934 context->Global()->Set(v8_str("o"), fun->NewInstance());
9935 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009936 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009937 "o.foo = 17;"
9938 "var receiver = {};"
9939 "receiver.__proto__ = o;"
9940 "var result = 0;"
9941 "var saved_result = 0;"
9942 "for (var i = 0; i < 100; i++) {"
9943 " result = receiver.method(41);"
9944 " if (i == 50) {"
9945 " saved_result = result;"
9946 " receiver = 333;"
9947 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009948 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +00009949 CHECK(try_catch.HasCaught());
9950 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9951 try_catch.Exception()->ToString());
9952 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9953 CHECK_GE(interceptor_call_count, 50);
9954}
9955
ager@chromium.org5c838252010-02-19 08:53:10 +00009956THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9957 int interceptor_call_count = 0;
9958 v8::HandleScope scope;
9959 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9960 v8::Handle<v8::FunctionTemplate> method_templ =
9961 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9962 v8_str("method_data"),
9963 v8::Signature::New(fun_templ));
9964 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9965 proto_templ->Set(v8_str("method"), method_templ);
9966 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9967 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9968 NULL, NULL, NULL, NULL,
9969 v8::External::Wrap(&interceptor_call_count));
9970 LocalContext context;
9971 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9972 GenerateSomeGarbage();
9973 context->Global()->Set(v8_str("o"), fun->NewInstance());
9974 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009975 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +00009976 "o.foo = 17;"
9977 "var receiver = {};"
9978 "receiver.__proto__ = o;"
9979 "var result = 0;"
9980 "var saved_result = 0;"
9981 "for (var i = 0; i < 100; i++) {"
9982 " result = receiver.method(41);"
9983 " if (i == 50) {"
9984 " saved_result = result;"
9985 " receiver = {method: receiver.method};"
9986 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009987 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +00009988 CHECK(try_catch.HasCaught());
9989 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9990 try_catch.Exception()->ToString());
9991 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9992 CHECK_GE(interceptor_call_count, 50);
9993}
9994
9995THREADED_TEST(CallICFastApi_TrivialSignature) {
9996 v8::HandleScope scope;
9997 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9998 v8::Handle<v8::FunctionTemplate> method_templ =
9999 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10000 v8_str("method_data"),
10001 v8::Handle<v8::Signature>());
10002 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10003 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010004 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010005 USE(templ);
ager@chromium.org5c838252010-02-19 08:53:10 +000010006 LocalContext context;
10007 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10008 GenerateSomeGarbage();
10009 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010010 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010011 "var result = 0;"
10012 "for (var i = 0; i < 100; i++) {"
10013 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010014 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010015
10016 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10017}
10018
10019THREADED_TEST(CallICFastApi_SimpleSignature) {
10020 v8::HandleScope scope;
10021 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10022 v8::Handle<v8::FunctionTemplate> method_templ =
10023 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10024 v8_str("method_data"),
10025 v8::Signature::New(fun_templ));
10026 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10027 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010028 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010029 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010030 LocalContext context;
10031 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10032 GenerateSomeGarbage();
10033 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010034 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010035 "o.foo = 17;"
10036 "var receiver = {};"
10037 "receiver.__proto__ = o;"
10038 "var result = 0;"
10039 "for (var i = 0; i < 100; i++) {"
10040 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010041 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010042
10043 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10044}
10045
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010046THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010047 v8::HandleScope scope;
10048 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10049 v8::Handle<v8::FunctionTemplate> method_templ =
10050 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10051 v8_str("method_data"),
10052 v8::Signature::New(fun_templ));
10053 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10054 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010055 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010056 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010057 LocalContext context;
10058 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10059 GenerateSomeGarbage();
10060 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010061 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010062 "o.foo = 17;"
10063 "var receiver = {};"
10064 "receiver.__proto__ = o;"
10065 "var result = 0;"
10066 "var saved_result = 0;"
10067 "for (var i = 0; i < 100; i++) {"
10068 " result = receiver.method(41);"
10069 " if (i == 50) {"
10070 " saved_result = result;"
10071 " receiver = {method: function(x) { return x - 1 }};"
10072 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010073 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010074 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10075 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10076}
10077
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010078THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10079 v8::HandleScope scope;
10080 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10081 v8::Handle<v8::FunctionTemplate> method_templ =
10082 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10083 v8_str("method_data"),
10084 v8::Signature::New(fun_templ));
10085 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10086 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010087 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010088 CHECK(!templ.IsEmpty());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010089 LocalContext context;
10090 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10091 GenerateSomeGarbage();
10092 context->Global()->Set(v8_str("o"), fun->NewInstance());
10093 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010094 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010095 "o.foo = 17;"
10096 "var receiver = {};"
10097 "receiver.__proto__ = o;"
10098 "var result = 0;"
10099 "var saved_result = 0;"
10100 "for (var i = 0; i < 100; i++) {"
10101 " result = receiver.method(41);"
10102 " if (i == 50) {"
10103 " saved_result = result;"
10104 " receiver = 333;"
10105 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010106 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010107 CHECK(try_catch.HasCaught());
10108 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10109 try_catch.Exception()->ToString());
10110 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10111}
10112
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010113
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010114v8::Handle<Value> keyed_call_ic_function;
10115
10116static v8::Handle<Value> InterceptorKeyedCallICGetter(
10117 Local<String> name, const AccessorInfo& info) {
10118 ApiTestFuzzer::Fuzz();
10119 if (v8_str("x")->Equals(name)) {
10120 return keyed_call_ic_function;
10121 }
10122 return v8::Handle<Value>();
10123}
10124
10125
10126// Test the case when we stored cacheable lookup into
10127// a stub, but the function name changed (to another cacheable function).
10128THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
10129 v8::HandleScope scope;
10130 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10131 templ->SetNamedPropertyHandler(NoBlockGetterX);
10132 LocalContext context;
10133 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010134 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010135 "proto = new Object();"
10136 "proto.y = function(x) { return x + 1; };"
10137 "proto.z = function(x) { return x - 1; };"
10138 "o.__proto__ = proto;"
10139 "var result = 0;"
10140 "var method = 'y';"
10141 "for (var i = 0; i < 10; i++) {"
10142 " if (i == 5) { method = 'z'; };"
10143 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010144 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010145 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10146}
10147
10148
10149// Test the case when we stored cacheable lookup into
10150// a stub, but the function name changed (and the new function is present
10151// both before and after the interceptor in the prototype chain).
10152THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
10153 v8::HandleScope scope;
10154 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10155 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10156 LocalContext context;
10157 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10158 keyed_call_ic_function =
10159 v8_compile("function f(x) { return x - 1; }; f")->Run();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010160 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010161 "o = new Object();"
10162 "proto2 = new Object();"
10163 "o.y = function(x) { return x + 1; };"
10164 "proto2.y = function(x) { return x + 2; };"
10165 "o.__proto__ = proto1;"
10166 "proto1.__proto__ = proto2;"
10167 "var result = 0;"
10168 "var method = 'x';"
10169 "for (var i = 0; i < 10; i++) {"
10170 " if (i == 5) { method = 'y'; };"
10171 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010172 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010173 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10174}
10175
10176
10177// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10178// on the global object.
10179THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
10180 v8::HandleScope scope;
10181 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10182 templ->SetNamedPropertyHandler(NoBlockGetterX);
10183 LocalContext context;
10184 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010185 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010186 "function inc(x) { return x + 1; };"
10187 "inc(1);"
10188 "function dec(x) { return x - 1; };"
10189 "dec(1);"
10190 "o.__proto__ = this;"
10191 "this.__proto__.x = inc;"
10192 "this.__proto__.y = dec;"
10193 "var result = 0;"
10194 "var method = 'x';"
10195 "for (var i = 0; i < 10; i++) {"
10196 " if (i == 5) { method = 'y'; };"
10197 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010198 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010199 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10200}
10201
10202
10203// Test the case when actual function to call sits on global object.
10204THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
10205 v8::HandleScope scope;
10206 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10207 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10208 LocalContext context;
10209 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10210
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010211 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010212 "function len(x) { return x.length; };"
10213 "o.__proto__ = this;"
10214 "var m = 'parseFloat';"
10215 "var result = 0;"
10216 "for (var i = 0; i < 10; i++) {"
10217 " if (i == 5) {"
10218 " m = 'len';"
10219 " saved_result = result;"
10220 " };"
10221 " result = o[m]('239');"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010222 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010223 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10224 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10225}
10226
10227// Test the map transition before the interceptor.
10228THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
10229 v8::HandleScope scope;
10230 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10231 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10232 LocalContext context;
10233 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10234
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010235 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010236 "var o = new Object();"
10237 "o.__proto__ = proto;"
10238 "o.method = function(x) { return x + 1; };"
10239 "var m = 'method';"
10240 "var result = 0;"
10241 "for (var i = 0; i < 10; i++) {"
10242 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10243 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010244 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010245 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10246}
10247
10248
10249// Test the map transition after the interceptor.
10250THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
10251 v8::HandleScope scope;
10252 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10253 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10254 LocalContext context;
10255 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10256
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010257 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010258 "var proto = new Object();"
10259 "o.__proto__ = proto;"
10260 "proto.method = function(x) { return x + 1; };"
10261 "var m = 'method';"
10262 "var result = 0;"
10263 "for (var i = 0; i < 10; i++) {"
10264 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10265 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010266 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010267 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10268}
10269
10270
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010271static int interceptor_call_count = 0;
10272
10273static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10274 const AccessorInfo& info) {
10275 ApiTestFuzzer::Fuzz();
10276 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10277 return call_ic_function2;
10278 }
10279 return v8::Handle<Value>();
10280}
10281
10282
10283// This test should hit load and call ICs for the interceptor case.
10284// Once in a while, the interceptor will reply that a property was not
10285// found in which case we should get a reference error.
10286THREADED_TEST(InterceptorICReferenceErrors) {
10287 v8::HandleScope scope;
10288 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10289 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10290 LocalContext context(0, templ, v8::Handle<Value>());
10291 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10292 v8::Handle<Value> value = CompileRun(
10293 "function f() {"
10294 " for (var i = 0; i < 1000; i++) {"
10295 " try { x; } catch(e) { return true; }"
10296 " }"
10297 " return false;"
10298 "};"
10299 "f();");
10300 CHECK_EQ(true, value->BooleanValue());
10301 interceptor_call_count = 0;
10302 value = CompileRun(
10303 "function g() {"
10304 " for (var i = 0; i < 1000; i++) {"
10305 " try { x(42); } catch(e) { return true; }"
10306 " }"
10307 " return false;"
10308 "};"
10309 "g();");
10310 CHECK_EQ(true, value->BooleanValue());
10311}
10312
10313
10314static int interceptor_ic_exception_get_count = 0;
10315
10316static v8::Handle<Value> InterceptorICExceptionGetter(
10317 Local<String> name,
10318 const AccessorInfo& info) {
10319 ApiTestFuzzer::Fuzz();
10320 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10321 return call_ic_function3;
10322 }
10323 if (interceptor_ic_exception_get_count == 20) {
10324 return v8::ThrowException(v8_num(42));
10325 }
10326 // Do not handle get for properties other than x.
10327 return v8::Handle<Value>();
10328}
10329
10330// Test interceptor load/call IC where the interceptor throws an
10331// exception once in a while.
10332THREADED_TEST(InterceptorICGetterExceptions) {
10333 interceptor_ic_exception_get_count = 0;
10334 v8::HandleScope scope;
10335 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10336 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10337 LocalContext context(0, templ, v8::Handle<Value>());
10338 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10339 v8::Handle<Value> value = CompileRun(
10340 "function f() {"
10341 " for (var i = 0; i < 100; i++) {"
10342 " try { x; } catch(e) { return true; }"
10343 " }"
10344 " return false;"
10345 "};"
10346 "f();");
10347 CHECK_EQ(true, value->BooleanValue());
10348 interceptor_ic_exception_get_count = 0;
10349 value = CompileRun(
10350 "function f() {"
10351 " for (var i = 0; i < 100; i++) {"
10352 " try { x(42); } catch(e) { return true; }"
10353 " }"
10354 " return false;"
10355 "};"
10356 "f();");
10357 CHECK_EQ(true, value->BooleanValue());
10358}
10359
10360
10361static int interceptor_ic_exception_set_count = 0;
10362
10363static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010364 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010365 ApiTestFuzzer::Fuzz();
10366 if (++interceptor_ic_exception_set_count > 20) {
10367 return v8::ThrowException(v8_num(42));
10368 }
10369 // Do not actually handle setting.
10370 return v8::Handle<Value>();
10371}
10372
10373// Test interceptor store IC where the interceptor throws an exception
10374// once in a while.
10375THREADED_TEST(InterceptorICSetterExceptions) {
10376 interceptor_ic_exception_set_count = 0;
10377 v8::HandleScope scope;
10378 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10379 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10380 LocalContext context(0, templ, v8::Handle<Value>());
10381 v8::Handle<Value> value = CompileRun(
10382 "function f() {"
10383 " for (var i = 0; i < 100; i++) {"
10384 " try { x = 42; } catch(e) { return true; }"
10385 " }"
10386 " return false;"
10387 "};"
10388 "f();");
10389 CHECK_EQ(true, value->BooleanValue());
10390}
10391
10392
10393// Test that we ignore null interceptors.
10394THREADED_TEST(NullNamedInterceptor) {
10395 v8::HandleScope scope;
10396 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10397 templ->SetNamedPropertyHandler(0);
10398 LocalContext context;
10399 templ->Set("x", v8_num(42));
10400 v8::Handle<v8::Object> obj = templ->NewInstance();
10401 context->Global()->Set(v8_str("obj"), obj);
10402 v8::Handle<Value> value = CompileRun("obj.x");
10403 CHECK(value->IsInt32());
10404 CHECK_EQ(42, value->Int32Value());
10405}
10406
10407
10408// Test that we ignore null interceptors.
10409THREADED_TEST(NullIndexedInterceptor) {
10410 v8::HandleScope scope;
10411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10412 templ->SetIndexedPropertyHandler(0);
10413 LocalContext context;
10414 templ->Set("42", v8_num(42));
10415 v8::Handle<v8::Object> obj = templ->NewInstance();
10416 context->Global()->Set(v8_str("obj"), obj);
10417 v8::Handle<Value> value = CompileRun("obj[42]");
10418 CHECK(value->IsInt32());
10419 CHECK_EQ(42, value->Int32Value());
10420}
10421
10422
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010423THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
10424 v8::HandleScope scope;
10425 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10426 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10427 LocalContext env;
10428 env->Global()->Set(v8_str("obj"),
10429 templ->GetFunction()->NewInstance());
10430 ExpectTrue("obj.x === 42");
10431 ExpectTrue("!obj.propertyIsEnumerable('x')");
10432}
10433
10434
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010435static Handle<Value> ThrowingGetter(Local<String> name,
10436 const AccessorInfo& info) {
10437 ApiTestFuzzer::Fuzz();
10438 ThrowException(Handle<Value>());
10439 return Undefined();
10440}
10441
10442
10443THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10444 HandleScope scope;
10445 LocalContext context;
10446
10447 Local<FunctionTemplate> templ = FunctionTemplate::New();
10448 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10449 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10450
10451 Local<Object> instance = templ->GetFunction()->NewInstance();
10452
10453 Local<Object> another = Object::New();
10454 another->SetPrototype(instance);
10455
10456 Local<Object> with_js_getter = CompileRun(
10457 "o = {};\n"
10458 "o.__defineGetter__('f', function() { throw undefined; });\n"
10459 "o\n").As<Object>();
10460 CHECK(!with_js_getter.IsEmpty());
10461
10462 TryCatch try_catch;
10463
10464 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10465 CHECK(try_catch.HasCaught());
10466 try_catch.Reset();
10467 CHECK(result.IsEmpty());
10468
10469 result = another->GetRealNamedProperty(v8_str("f"));
10470 CHECK(try_catch.HasCaught());
10471 try_catch.Reset();
10472 CHECK(result.IsEmpty());
10473
10474 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10475 CHECK(try_catch.HasCaught());
10476 try_catch.Reset();
10477 CHECK(result.IsEmpty());
10478
10479 result = another->Get(v8_str("f"));
10480 CHECK(try_catch.HasCaught());
10481 try_catch.Reset();
10482 CHECK(result.IsEmpty());
10483
10484 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10485 CHECK(try_catch.HasCaught());
10486 try_catch.Reset();
10487 CHECK(result.IsEmpty());
10488
10489 result = with_js_getter->Get(v8_str("f"));
10490 CHECK(try_catch.HasCaught());
10491 try_catch.Reset();
10492 CHECK(result.IsEmpty());
10493}
10494
10495
10496static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10497 TryCatch try_catch;
10498 // Verboseness is important: it triggers message delivery which can call into
10499 // external code.
10500 try_catch.SetVerbose(true);
10501 CompileRun("throw 'from JS';");
10502 CHECK(try_catch.HasCaught());
10503 CHECK(!i::Isolate::Current()->has_pending_exception());
10504 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10505 return Undefined();
10506}
10507
10508
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010509static int call_depth;
10510
10511
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010512static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10513 TryCatch try_catch;
10514}
10515
10516
10517static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010518 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010519}
10520
10521
10522static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010523 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010524}
10525
10526
10527static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10528 Handle<String> errorMessageString = message->Get();
10529 CHECK(!errorMessageString.IsEmpty());
10530 message->GetStackTrace();
10531 message->GetScriptResourceName();
10532}
10533
10534THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10535 HandleScope scope;
10536 LocalContext context;
10537
10538 Local<Function> func =
10539 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10540 context->Global()->Set(v8_str("func"), func);
10541
10542 MessageCallback callbacks[] =
10543 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10544 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10545 MessageCallback callback = callbacks[i];
10546 if (callback != NULL) {
10547 V8::AddMessageListener(callback);
10548 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +000010549 // Some small number to control number of times message handler should
10550 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010551 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010552 ExpectFalse(
10553 "var thrown = false;\n"
10554 "try { func(); } catch(e) { thrown = true; }\n"
10555 "thrown\n");
10556 if (callback != NULL) {
10557 V8::RemoveMessageListeners(callback);
10558 }
10559 }
10560}
10561
10562
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010563static v8::Handle<Value> ParentGetter(Local<String> name,
10564 const AccessorInfo& info) {
10565 ApiTestFuzzer::Fuzz();
10566 return v8_num(1);
10567}
10568
10569
10570static v8::Handle<Value> ChildGetter(Local<String> name,
10571 const AccessorInfo& info) {
10572 ApiTestFuzzer::Fuzz();
10573 return v8_num(42);
10574}
10575
10576
10577THREADED_TEST(Overriding) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010578 i::FLAG_es5_readonly = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010579 v8::HandleScope scope;
10580 LocalContext context;
10581
10582 // Parent template.
10583 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10584 Local<ObjectTemplate> parent_instance_templ =
10585 parent_templ->InstanceTemplate();
10586 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10587
10588 // Template that inherits from the parent template.
10589 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10590 Local<ObjectTemplate> child_instance_templ =
10591 child_templ->InstanceTemplate();
10592 child_templ->Inherit(parent_templ);
10593 // Override 'f'. The child version of 'f' should get called for child
10594 // instances.
10595 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10596 // Add 'g' twice. The 'g' added last should get called for instances.
10597 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10598 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10599
10600 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10601 // so 'h' can be shadowed on the instance object.
10602 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10603 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10604 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10605
10606 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10607 // but the attribute does not have effect because it is duplicated with
10608 // NULL setter.
10609 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10610 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10611
10612
10613
10614 // Instantiate the child template.
10615 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10616
10617 // Check that the child function overrides the parent one.
10618 context->Global()->Set(v8_str("o"), instance);
10619 Local<Value> value = v8_compile("o.f")->Run();
10620 // Check that the 'g' that was added last is hit.
10621 CHECK_EQ(42, value->Int32Value());
10622 value = v8_compile("o.g")->Run();
10623 CHECK_EQ(42, value->Int32Value());
10624
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010625 // Check that 'h' cannot be shadowed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010626 value = v8_compile("o.h = 3; o.h")->Run();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010627 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010628
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010629 // Check that 'i' cannot be shadowed or changed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010630 value = v8_compile("o.i = 3; o.i")->Run();
10631 CHECK_EQ(42, value->Int32Value());
10632}
10633
10634
10635static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10636 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010637 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010638}
10639
10640
10641THREADED_TEST(IsConstructCall) {
10642 v8::HandleScope scope;
10643
10644 // Function template with call handler.
10645 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10646 templ->SetCallHandler(IsConstructHandler);
10647
10648 LocalContext context;
10649
10650 context->Global()->Set(v8_str("f"), templ->GetFunction());
10651 Local<Value> value = v8_compile("f()")->Run();
10652 CHECK(!value->BooleanValue());
10653 value = v8_compile("new f()")->Run();
10654 CHECK(value->BooleanValue());
10655}
10656
10657
10658THREADED_TEST(ObjectProtoToString) {
10659 v8::HandleScope scope;
10660 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10661 templ->SetClassName(v8_str("MyClass"));
10662
10663 LocalContext context;
10664
10665 Local<String> customized_tostring = v8_str("customized toString");
10666
10667 // Replace Object.prototype.toString
10668 v8_compile("Object.prototype.toString = function() {"
10669 " return 'customized toString';"
10670 "}")->Run();
10671
10672 // Normal ToString call should call replaced Object.prototype.toString
10673 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10674 Local<String> value = instance->ToString();
10675 CHECK(value->IsString() && value->Equals(customized_tostring));
10676
10677 // ObjectProtoToString should not call replace toString function.
10678 value = instance->ObjectProtoToString();
10679 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10680
10681 // Check global
10682 value = context->Global()->ObjectProtoToString();
10683 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10684
10685 // Check ordinary object
10686 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010687 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010688 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10689}
10690
10691
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010692THREADED_TEST(ObjectGetConstructorName) {
10693 v8::HandleScope scope;
10694 LocalContext context;
10695 v8_compile("function Parent() {};"
10696 "function Child() {};"
10697 "Child.prototype = new Parent();"
10698 "var outer = { inner: function() { } };"
10699 "var p = new Parent();"
10700 "var c = new Child();"
10701 "var x = new outer.inner();")->Run();
10702
10703 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10704 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10705 v8_str("Parent")));
10706
10707 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
10708 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
10709 v8_str("Child")));
10710
10711 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
10712 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
10713 v8_str("outer.inner")));
10714}
10715
10716
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010717bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010718i::Semaphore* ApiTestFuzzer::all_tests_done_=
10719 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010720int ApiTestFuzzer::active_tests_;
10721int ApiTestFuzzer::tests_being_run_;
10722int ApiTestFuzzer::current_;
10723
10724
10725// We are in a callback and want to switch to another thread (if we
10726// are currently running the thread fuzzing test).
10727void ApiTestFuzzer::Fuzz() {
10728 if (!fuzzing_) return;
10729 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
10730 test->ContextSwitch();
10731}
10732
10733
10734// Let the next thread go. Since it is also waiting on the V8 lock it may
10735// not start immediately.
10736bool ApiTestFuzzer::NextThread() {
10737 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010738 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010739 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010740 if (kLogThreading)
10741 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010742 return false;
10743 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010744 if (kLogThreading) {
10745 printf("Switch from %s to %s\n",
10746 test_name,
10747 RegisterThreadedTest::nth(test_position)->name());
10748 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010749 current_ = test_position;
10750 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10751 return true;
10752}
10753
10754
10755void ApiTestFuzzer::Run() {
10756 // When it is our turn...
10757 gate_->Wait();
10758 {
10759 // ... get the V8 lock and start running the test.
10760 v8::Locker locker;
10761 CallTest();
10762 }
10763 // This test finished.
10764 active_ = false;
10765 active_tests_--;
10766 // If it was the last then signal that fact.
10767 if (active_tests_ == 0) {
10768 all_tests_done_->Signal();
10769 } else {
10770 // Otherwise select a new test and start that.
10771 NextThread();
10772 }
10773}
10774
10775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010776static unsigned linear_congruential_generator;
10777
10778
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010779void ApiTestFuzzer::SetUp(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010780 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010781 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000010782 int count = RegisterThreadedTest::count();
10783 int start = count * part / (LAST_PART + 1);
10784 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10785 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010786 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010787 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010788 }
10789 for (int i = 0; i < active_tests_; i++) {
10790 RegisterThreadedTest::nth(i)->fuzzer_->Start();
10791 }
10792}
10793
10794
10795static void CallTestNumber(int test_number) {
10796 (RegisterThreadedTest::nth(test_number)->callback())();
10797}
10798
10799
10800void ApiTestFuzzer::RunAllTests() {
10801 // Set off the first test.
10802 current_ = -1;
10803 NextThread();
10804 // Wait till they are all done.
10805 all_tests_done_->Wait();
10806}
10807
10808
10809int ApiTestFuzzer::GetNextTestNumber() {
10810 int next_test;
10811 do {
10812 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10813 linear_congruential_generator *= 1664525u;
10814 linear_congruential_generator += 1013904223u;
10815 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10816 return next_test;
10817}
10818
10819
10820void ApiTestFuzzer::ContextSwitch() {
10821 // If the new thread is the same as the current thread there is nothing to do.
10822 if (NextThread()) {
10823 // Now it can start.
10824 v8::Unlocker unlocker;
10825 // Wait till someone starts us again.
10826 gate_->Wait();
10827 // And we're off.
10828 }
10829}
10830
10831
10832void ApiTestFuzzer::TearDown() {
10833 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000010834 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10835 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10836 if (fuzzer != NULL) fuzzer->Join();
10837 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010838}
10839
10840
10841// Lets not be needlessly self-referential.
10842TEST(Threading) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010843 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010844 ApiTestFuzzer::RunAllTests();
10845 ApiTestFuzzer::TearDown();
10846}
10847
10848TEST(Threading2) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010849 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010850 ApiTestFuzzer::RunAllTests();
10851 ApiTestFuzzer::TearDown();
10852}
10853
lrn@chromium.org1c092762011-05-09 09:42:16 +000010854TEST(Threading3) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010855 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010856 ApiTestFuzzer::RunAllTests();
10857 ApiTestFuzzer::TearDown();
10858}
10859
10860TEST(Threading4) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010861 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000010862 ApiTestFuzzer::RunAllTests();
10863 ApiTestFuzzer::TearDown();
10864}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010865
10866void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010867 if (kLogThreading)
10868 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010869 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010870 if (kLogThreading)
10871 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010872}
10873
10874
10875static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010876 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010877 ApiTestFuzzer::Fuzz();
10878 v8::Unlocker unlocker;
10879 const char* code = "throw 7;";
10880 {
10881 v8::Locker nested_locker;
10882 v8::HandleScope scope;
10883 v8::Handle<Value> exception;
10884 { v8::TryCatch try_catch;
10885 v8::Handle<Value> value = CompileRun(code);
10886 CHECK(value.IsEmpty());
10887 CHECK(try_catch.HasCaught());
10888 // Make sure to wrap the exception in a new handle because
10889 // the handle returned from the TryCatch is destroyed
10890 // when the TryCatch is destroyed.
10891 exception = Local<Value>::New(try_catch.Exception());
10892 }
10893 return v8::ThrowException(exception);
10894 }
10895}
10896
10897
10898static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010899 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010900 ApiTestFuzzer::Fuzz();
10901 v8::Unlocker unlocker;
10902 const char* code = "throw 7;";
10903 {
10904 v8::Locker nested_locker;
10905 v8::HandleScope scope;
10906 v8::Handle<Value> value = CompileRun(code);
10907 CHECK(value.IsEmpty());
10908 return v8_str("foo");
10909 }
10910}
10911
10912
10913// These are locking tests that don't need to be run again
10914// as part of the locking aggregation tests.
10915TEST(NestedLockers) {
10916 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010917 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010918 v8::HandleScope scope;
10919 LocalContext env;
10920 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10921 Local<Function> fun = fun_templ->GetFunction();
10922 env->Global()->Set(v8_str("throw_in_js"), fun);
10923 Local<Script> script = v8_compile("(function () {"
10924 " try {"
10925 " throw_in_js();"
10926 " return 42;"
10927 " } catch (e) {"
10928 " return e * 13;"
10929 " }"
10930 "})();");
10931 CHECK_EQ(91, script->Run()->Int32Value());
10932}
10933
10934
10935// These are locking tests that don't need to be run again
10936// as part of the locking aggregation tests.
10937TEST(NestedLockersNoTryCatch) {
10938 v8::Locker locker;
10939 v8::HandleScope scope;
10940 LocalContext env;
10941 Local<v8::FunctionTemplate> fun_templ =
10942 v8::FunctionTemplate::New(ThrowInJSNoCatch);
10943 Local<Function> fun = fun_templ->GetFunction();
10944 env->Global()->Set(v8_str("throw_in_js"), fun);
10945 Local<Script> script = v8_compile("(function () {"
10946 " try {"
10947 " throw_in_js();"
10948 " return 42;"
10949 " } catch (e) {"
10950 " return e * 13;"
10951 " }"
10952 "})();");
10953 CHECK_EQ(91, script->Run()->Int32Value());
10954}
10955
10956
10957THREADED_TEST(RecursiveLocking) {
10958 v8::Locker locker;
10959 {
10960 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010961 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010962 }
10963}
10964
10965
10966static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10967 ApiTestFuzzer::Fuzz();
10968 v8::Unlocker unlocker;
10969 return v8::Undefined();
10970}
10971
10972
10973THREADED_TEST(LockUnlockLock) {
10974 {
10975 v8::Locker locker;
10976 v8::HandleScope scope;
10977 LocalContext env;
10978 Local<v8::FunctionTemplate> fun_templ =
10979 v8::FunctionTemplate::New(UnlockForAMoment);
10980 Local<Function> fun = fun_templ->GetFunction();
10981 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10982 Local<Script> script = v8_compile("(function () {"
10983 " unlock_for_a_moment();"
10984 " return 42;"
10985 "})();");
10986 CHECK_EQ(42, script->Run()->Int32Value());
10987 }
10988 {
10989 v8::Locker locker;
10990 v8::HandleScope scope;
10991 LocalContext env;
10992 Local<v8::FunctionTemplate> fun_templ =
10993 v8::FunctionTemplate::New(UnlockForAMoment);
10994 Local<Function> fun = fun_templ->GetFunction();
10995 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10996 Local<Script> script = v8_compile("(function () {"
10997 " unlock_for_a_moment();"
10998 " return 42;"
10999 "})();");
11000 CHECK_EQ(42, script->Run()->Int32Value());
11001 }
11002}
11003
11004
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011005static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011006 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011007 int count = 0;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011008 i::HeapIterator it;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011009 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11010 if (object->IsJSGlobalObject()) count++;
11011 return count;
11012}
11013
11014
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011015static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011016 // We need to collect all garbage twice to be sure that everything
11017 // has been collected. This is because inline caches are cleared in
11018 // the first garbage collection but some of the maps have already
11019 // been marked at that point. Therefore some of the maps are not
11020 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011021 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11022 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011023 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011024#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011026#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011027 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011028}
11029
11030
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011031TEST(DontLeakGlobalObjects) {
11032 // Regression test for issues 1139850 and 1174891.
11033
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011034 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011035
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011036 for (int i = 0; i < 5; i++) {
11037 { v8::HandleScope scope;
11038 LocalContext context;
11039 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011040 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011041 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011042
11043 { v8::HandleScope scope;
11044 LocalContext context;
11045 v8_compile("Date")->Run();
11046 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011047 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011048 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011049
11050 { v8::HandleScope scope;
11051 LocalContext context;
11052 v8_compile("/aaa/")->Run();
11053 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011054 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011055 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011056
11057 { v8::HandleScope scope;
11058 const char* extension_list[] = { "v8/gc" };
11059 v8::ExtensionConfiguration extensions(1, extension_list);
11060 LocalContext context(&extensions);
11061 v8_compile("gc();")->Run();
11062 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011063 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011064 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011065 }
11066}
11067
11068
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011069v8::Persistent<v8::Object> some_object;
11070v8::Persistent<v8::Object> bad_handle;
11071
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011072void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011073 v8::HandleScope scope;
11074 bad_handle = v8::Persistent<v8::Object>::New(some_object);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011075 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011076}
11077
11078
11079THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11080 LocalContext context;
11081
11082 v8::Persistent<v8::Object> handle1, handle2;
11083 {
11084 v8::HandleScope scope;
11085 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
11086 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11087 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11088 }
11089 // Note: order is implementation dependent alas: currently
11090 // global handle nodes are processed by PostGarbageCollectionProcessing
11091 // in reverse allocation order, so if second allocated handle is deleted,
11092 // weak callback of the first handle would be able to 'reallocate' it.
11093 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
11094 handle2.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011095 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011096}
11097
11098
11099v8::Persistent<v8::Object> to_be_disposed;
11100
11101void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
11102 to_be_disposed.Dispose();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011103 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011104 handle.Dispose();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011105}
11106
11107
11108THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11109 LocalContext context;
11110
11111 v8::Persistent<v8::Object> handle1, handle2;
11112 {
11113 v8::HandleScope scope;
11114 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11115 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11116 }
11117 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
11118 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011119 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011120}
11121
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011122void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
11123 handle.Dispose();
11124}
11125
11126void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
11127 v8::HandleScope scope;
11128 v8::Persistent<v8::Object>::New(v8::Object::New());
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +000011129 handle.Dispose();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011130}
11131
11132
11133THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11134 LocalContext context;
11135
11136 v8::Persistent<v8::Object> handle1, handle2, handle3;
11137 {
11138 v8::HandleScope scope;
11139 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
11140 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
11141 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
11142 }
11143 handle2.MakeWeak(NULL, DisposingCallback);
11144 handle3.MakeWeak(NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011145 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011146}
11147
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011148
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011149THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011150 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011151
11152 const int nof = 2;
11153 const char* sources[nof] = {
11154 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11155 "Object()"
11156 };
11157
11158 for (int i = 0; i < nof; i++) {
11159 const char* source = sources[i];
11160 { v8::HandleScope scope;
11161 LocalContext context;
11162 CompileRun(source);
11163 }
11164 { v8::HandleScope scope;
11165 LocalContext context;
11166 CompileRun(source);
11167 }
11168 }
11169}
11170
11171
11172static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
11173 v8::HandleScope inner;
11174 env->Enter();
11175 v8::Handle<Value> three = v8_num(3);
11176 v8::Handle<Value> value = inner.Close(three);
11177 env->Exit();
11178 return value;
11179}
11180
11181
11182THREADED_TEST(NestedHandleScopeAndContexts) {
11183 v8::HandleScope outer;
11184 v8::Persistent<Context> env = Context::New();
11185 env->Enter();
11186 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011187 v8::Handle<String> str(value->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011188 CHECK(!str.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011189 env->Exit();
11190 env.Dispose();
11191}
11192
11193
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011194static i::Handle<i::JSFunction>* foo_ptr = NULL;
11195static int foo_count = 0;
11196static i::Handle<i::JSFunction>* bar_ptr = NULL;
11197static int bar_count = 0;
11198
11199
11200static void entry_hook(uintptr_t function,
11201 uintptr_t return_addr_location) {
11202 i::Code* code = i::Code::GetCodeFromTargetAddress(
11203 reinterpret_cast<i::Address>(function));
11204 CHECK(code != NULL);
11205
11206 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11207 ++bar_count;
11208
11209 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11210 ++foo_count;
11211
11212 // TODO(siggi): Verify return_addr_location.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011213 // This can be done by capturing JitCodeEvents, but requires an ordered
11214 // collection.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011215}
11216
11217
11218static void RunLoopInNewEnv() {
11219 bar_ptr = NULL;
11220 foo_ptr = NULL;
11221
11222 v8::HandleScope outer;
11223 v8::Persistent<Context> env = Context::New();
11224 env->Enter();
11225
11226 const char* script =
11227 "function bar() {"
11228 " var sum = 0;"
11229 " for (i = 0; i < 100; ++i)"
11230 " sum = foo(i);"
11231 " return sum;"
11232 "}"
11233 "function foo(i) { return i * i; }";
11234 CompileRun(script);
11235 i::Handle<i::JSFunction> bar =
11236 i::Handle<i::JSFunction>::cast(
11237 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11238 ASSERT(*bar);
11239
11240 i::Handle<i::JSFunction> foo =
11241 i::Handle<i::JSFunction>::cast(
11242 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11243 ASSERT(*foo);
11244
11245 bar_ptr = &bar;
11246 foo_ptr = &foo;
11247
11248 v8::Handle<v8::Value> value = CompileRun("bar();");
11249 CHECK(value->IsNumber());
11250 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11251
11252 // Test the optimized codegen path.
11253 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11254 "bar();");
11255 CHECK(value->IsNumber());
11256 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11257
11258 env->Exit();
11259}
11260
11261
11262TEST(SetFunctionEntryHook) {
11263 i::FLAG_allow_natives_syntax = true;
11264
11265 // Test setting and resetting the entry hook.
11266 // Nulling it should always succeed.
11267 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11268
11269 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11270 // Setting a hook while one's active should fail.
11271 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11272
11273 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11274
11275 // Reset the entry count to zero and set the entry hook.
11276 bar_count = 0;
11277 foo_count = 0;
11278 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11279 RunLoopInNewEnv();
11280
11281 CHECK_EQ(2, bar_count);
11282 CHECK_EQ(200, foo_count);
11283
11284 // Clear the entry hook and count.
11285 bar_count = 0;
11286 foo_count = 0;
11287 v8::V8::SetFunctionEntryHook(NULL);
11288
11289 // Clear the compilation cache to make sure we don't reuse the
11290 // functions from the previous invocation.
11291 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11292
11293 // Verify that entry hooking is now disabled.
11294 RunLoopInNewEnv();
11295 CHECK_EQ(0u, bar_count);
11296 CHECK_EQ(0u, foo_count);
11297}
11298
11299
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011300static i::HashMap* code_map = NULL;
11301static int saw_bar = 0;
11302static int move_events = 0;
11303
11304
11305static bool FunctionNameIs(const char* expected,
11306 const v8::JitCodeEvent* event) {
11307 // Log lines for functions are of the general form:
11308 // "LazyCompile:<type><function_name>", where the type is one of
11309 // "*", "~" or "".
11310 static const char kPreamble[] = "LazyCompile:";
11311 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11312
11313 if (event->name.len < sizeof(kPreamble) - 1 ||
11314 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11315 return false;
11316 }
11317
11318 const char* tail = event->name.str + kPreambleLen;
11319 size_t tail_len = event->name.len - kPreambleLen;
11320 size_t expected_len = strlen(expected);
11321 if (tail_len == expected_len + 1) {
11322 if (*tail == '*' || *tail == '~') {
11323 --tail_len;
11324 ++tail;
11325 } else {
11326 return false;
11327 }
11328 }
11329
11330 if (tail_len != expected_len)
11331 return false;
11332
11333 return strncmp(tail, expected, expected_len) == 0;
11334}
11335
11336
11337static void event_handler(const v8::JitCodeEvent* event) {
11338 CHECK(event != NULL);
11339 CHECK(code_map != NULL);
11340
11341 switch (event->type) {
11342 case v8::JitCodeEvent::CODE_ADDED: {
11343 CHECK(event->code_start != NULL);
11344 CHECK_NE(0, static_cast<int>(event->code_len));
11345 CHECK(event->name.str != NULL);
11346 i::HashMap::Entry* entry =
11347 code_map->Lookup(event->code_start,
11348 i::ComputePointerHash(event->code_start),
11349 true);
11350 entry->value = reinterpret_cast<void*>(event->code_len);
11351
11352 if (FunctionNameIs("bar", event)) {
11353 ++saw_bar;
11354 }
11355 }
11356 break;
11357
11358 case v8::JitCodeEvent::CODE_MOVED: {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011359 uint32_t hash = i::ComputePointerHash(event->code_start);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011360 // We would like to never see code move that we haven't seen before,
11361 // but the code creation event does not happen until the line endings
11362 // have been calculated (this is so that we can report the line in the
11363 // script at which the function source is found, see
11364 // Compiler::RecordFunctionCompilation) and the line endings
11365 // calculations can cause a GC, which can move the newly created code
11366 // before its existence can be logged.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011367 i::HashMap::Entry* entry =
11368 code_map->Lookup(event->code_start, hash, false);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011369 if (entry != NULL) {
11370 ++move_events;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011371
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011372 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11373 code_map->Remove(event->code_start, hash);
11374
11375 entry = code_map->Lookup(event->new_code_start,
11376 i::ComputePointerHash(event->new_code_start),
11377 true);
11378 CHECK(entry != NULL);
11379 entry->value = reinterpret_cast<void*>(event->code_len);
11380 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011381 }
11382 break;
11383
11384 case v8::JitCodeEvent::CODE_REMOVED:
11385 // Object/code removal events are currently not dispatched from the GC.
11386 CHECK(false);
11387 break;
11388 default:
11389 // Impossible event.
11390 CHECK(false);
11391 break;
11392 }
11393}
11394
11395
11396// Implemented in the test-alloc.cc test suite.
11397void SimulateFullSpace(i::PagedSpace* space);
11398
11399
11400static bool MatchPointers(void* key1, void* key2) {
11401 return key1 == key2;
11402}
11403
11404
11405TEST(SetJitCodeEventHandler) {
11406 const char* script =
11407 "function bar() {"
11408 " var sum = 0;"
11409 " for (i = 0; i < 100; ++i)"
11410 " sum = foo(i);"
11411 " return sum;"
11412 "}"
11413 "function foo(i) { return i * i; };"
11414 "bar();";
11415
11416 // Run this test in a new isolate to make sure we don't
11417 // have remnants of state from other code.
11418 v8::Isolate* isolate = v8::Isolate::New();
11419 isolate->Enter();
11420
11421 {
11422 i::HashMap code(MatchPointers);
11423 code_map = &code;
11424
11425 saw_bar = 0;
11426 move_events = 0;
11427
11428 i::FLAG_stress_compaction = true;
11429 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11430
11431 v8::HandleScope scope;
11432 // Generate new code objects sparsely distributed across several
11433 // different fragmented code-space pages.
11434 const int kIterations = 10;
11435 for (int i = 0; i < kIterations; ++i) {
11436 LocalContext env;
11437
11438 v8::Handle<v8::Script> compiled_script;
11439 {
11440 i::AlwaysAllocateScope always_allocate;
11441 SimulateFullSpace(HEAP->code_space());
11442 compiled_script = v8_compile(script);
11443 }
11444 compiled_script->Run();
11445
11446 // Clear the compilation cache to get more wastage.
11447 ISOLATE->compilation_cache()->Clear();
11448 }
11449
11450 // Force code movement.
11451 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11452
11453 CHECK_LE(kIterations, saw_bar);
11454 CHECK_NE(0, move_events);
11455
11456 code_map = NULL;
11457 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11458 }
11459
11460 isolate->Exit();
11461 isolate->Dispose();
11462
11463 // Do this in a new isolate.
11464 isolate = v8::Isolate::New();
11465 isolate->Enter();
11466
11467 // Verify that we get callbacks for existing code objects when we
11468 // request enumeration of existing code.
11469 {
11470 v8::HandleScope scope;
11471 LocalContext env;
11472 CompileRun(script);
11473
11474 // Now get code through initial iteration.
11475 i::HashMap code(MatchPointers);
11476 code_map = &code;
11477
11478 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11479 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11480
11481 code_map = NULL;
11482
11483 // We expect that we got some events. Note that if we could get code removal
11484 // notifications, we could compare two collections, one created by listening
11485 // from the time of creation of an isolate, and the other by subscribing
11486 // with EnumExisting.
11487 CHECK_NE(0, code.occupancy());
11488 }
11489
11490 isolate->Exit();
11491 isolate->Dispose();
11492}
11493
11494
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011495static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11496
11497
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011498THREADED_TEST(ExternalAllocatedMemory) {
11499 v8::HandleScope outer;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011500 v8::Persistent<Context> env(Context::New());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011501 CHECK(!env.IsEmpty());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011502 const intptr_t kSize = 1024*1024;
11503 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize)),
11504 cast(kSize));
11505 CHECK_EQ(cast(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize)),
11506 cast(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011507}
11508
11509
11510THREADED_TEST(DisposeEnteredContext) {
11511 v8::HandleScope scope;
11512 LocalContext outer;
11513 { v8::Persistent<v8::Context> inner = v8::Context::New();
11514 inner->Enter();
11515 inner.Dispose();
11516 inner.Clear();
11517 inner->Exit();
11518 }
11519}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011520
11521
11522// Regression test for issue 54, object templates with internal fields
11523// but no accessors or interceptors did not get their internal field
11524// count set on instances.
11525THREADED_TEST(Regress54) {
11526 v8::HandleScope outer;
11527 LocalContext context;
11528 static v8::Persistent<v8::ObjectTemplate> templ;
11529 if (templ.IsEmpty()) {
11530 v8::HandleScope inner;
11531 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11532 local->SetInternalFieldCount(1);
11533 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
11534 }
11535 v8::Handle<v8::Object> result = templ->NewInstance();
11536 CHECK_EQ(1, result->InternalFieldCount());
11537}
11538
11539
11540// If part of the threaded tests, this test makes ThreadingTest fail
11541// on mac.
11542TEST(CatchStackOverflow) {
11543 v8::HandleScope scope;
11544 LocalContext context;
11545 v8::TryCatch try_catch;
11546 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11547 "function f() {"
11548 " return f();"
11549 "}"
11550 ""
11551 "f();"));
11552 v8::Handle<v8::Value> result = script->Run();
11553 CHECK(result.IsEmpty());
11554}
11555
11556
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011557static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11558 const char* resource_name,
11559 int line_offset) {
11560 v8::HandleScope scope;
11561 v8::TryCatch try_catch;
11562 v8::Handle<v8::Value> result = script->Run();
11563 CHECK(result.IsEmpty());
11564 CHECK(try_catch.HasCaught());
11565 v8::Handle<v8::Message> message = try_catch.Message();
11566 CHECK(!message.IsEmpty());
11567 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11568 CHECK_EQ(91, message->GetStartPosition());
11569 CHECK_EQ(92, message->GetEndPosition());
11570 CHECK_EQ(2, message->GetStartColumn());
11571 CHECK_EQ(3, message->GetEndColumn());
11572 v8::String::AsciiValue line(message->GetSourceLine());
11573 CHECK_EQ(" throw 'nirk';", *line);
11574 v8::String::AsciiValue name(message->GetScriptResourceName());
11575 CHECK_EQ(resource_name, *name);
11576}
11577
11578
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011579THREADED_TEST(TryCatchSourceInfo) {
11580 v8::HandleScope scope;
11581 LocalContext context;
11582 v8::Handle<v8::String> source = v8::String::New(
11583 "function Foo() {\n"
11584 " return Bar();\n"
11585 "}\n"
11586 "\n"
11587 "function Bar() {\n"
11588 " return Baz();\n"
11589 "}\n"
11590 "\n"
11591 "function Baz() {\n"
11592 " throw 'nirk';\n"
11593 "}\n"
11594 "\n"
11595 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011596
11597 const char* resource_name;
11598 v8::Handle<v8::Script> script;
11599 resource_name = "test.js";
11600 script = v8::Script::Compile(source, v8::String::New(resource_name));
11601 CheckTryCatchSourceInfo(script, resource_name, 0);
11602
11603 resource_name = "test1.js";
11604 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11605 script = v8::Script::Compile(source, &origin1);
11606 CheckTryCatchSourceInfo(script, resource_name, 0);
11607
11608 resource_name = "test2.js";
11609 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11610 script = v8::Script::Compile(source, &origin2);
11611 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011612}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011613
11614
11615THREADED_TEST(CompilationCache) {
11616 v8::HandleScope scope;
11617 LocalContext context;
11618 v8::Handle<v8::String> source0 = v8::String::New("1234");
11619 v8::Handle<v8::String> source1 = v8::String::New("1234");
11620 v8::Handle<v8::Script> script0 =
11621 v8::Script::Compile(source0, v8::String::New("test.js"));
11622 v8::Handle<v8::Script> script1 =
11623 v8::Script::Compile(source1, v8::String::New("test.js"));
11624 v8::Handle<v8::Script> script2 =
11625 v8::Script::Compile(source0); // different origin
11626 CHECK_EQ(1234, script0->Run()->Int32Value());
11627 CHECK_EQ(1234, script1->Run()->Int32Value());
11628 CHECK_EQ(1234, script2->Run()->Int32Value());
11629}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011630
11631
11632static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11633 ApiTestFuzzer::Fuzz();
11634 return v8_num(42);
11635}
11636
11637
11638THREADED_TEST(CallbackFunctionName) {
11639 v8::HandleScope scope;
11640 LocalContext context;
11641 Local<ObjectTemplate> t = ObjectTemplate::New();
11642 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
11643 context->Global()->Set(v8_str("obj"), t->NewInstance());
11644 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
11645 CHECK(value->IsString());
11646 v8::String::AsciiValue name(value);
11647 CHECK_EQ("asdf", *name);
11648}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011649
11650
11651THREADED_TEST(DateAccess) {
11652 v8::HandleScope scope;
11653 LocalContext context;
11654 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
11655 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011656 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011657}
11658
11659
11660void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011661 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011662 v8::Handle<v8::Array> props = obj->GetPropertyNames();
11663 CHECK_EQ(elmc, props->Length());
11664 for (int i = 0; i < elmc; i++) {
11665 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11666 CHECK_EQ(elmv[i], *elm);
11667 }
11668}
11669
11670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011671void CheckOwnProperties(v8::Handle<v8::Value> val,
11672 int elmc,
11673 const char* elmv[]) {
11674 v8::Handle<v8::Object> obj = val.As<v8::Object>();
11675 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
11676 CHECK_EQ(elmc, props->Length());
11677 for (int i = 0; i < elmc; i++) {
11678 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
11679 CHECK_EQ(elmv[i], *elm);
11680 }
11681}
11682
11683
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011684THREADED_TEST(PropertyEnumeration) {
11685 v8::HandleScope scope;
11686 LocalContext context;
11687 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11688 "var result = [];"
11689 "result[0] = {};"
11690 "result[1] = {a: 1, b: 2};"
11691 "result[2] = [1, 2, 3];"
11692 "var proto = {x: 1, y: 2, z: 3};"
11693 "var x = { __proto__: proto, w: 0, z: 1 };"
11694 "result[3] = x;"
11695 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011696 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011697 CHECK_EQ(4, elms->Length());
11698 int elmc0 = 0;
11699 const char** elmv0 = NULL;
11700 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011701 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011702 int elmc1 = 2;
11703 const char* elmv1[] = {"a", "b"};
11704 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011705 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011706 int elmc2 = 3;
11707 const char* elmv2[] = {"0", "1", "2"};
11708 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011709 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011710 int elmc3 = 4;
11711 const char* elmv3[] = {"w", "z", "x", "y"};
11712 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011713 int elmc4 = 2;
11714 const char* elmv4[] = {"w", "z"};
11715 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011716}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718THREADED_TEST(PropertyEnumeration2) {
11719 v8::HandleScope scope;
11720 LocalContext context;
11721 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
11722 "var result = [];"
11723 "result[0] = {};"
11724 "result[1] = {a: 1, b: 2};"
11725 "result[2] = [1, 2, 3];"
11726 "var proto = {x: 1, y: 2, z: 3};"
11727 "var x = { __proto__: proto, w: 0, z: 1 };"
11728 "result[3] = x;"
11729 "result;"))->Run();
11730 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
11731 CHECK_EQ(4, elms->Length());
11732 int elmc0 = 0;
11733 const char** elmv0 = NULL;
11734 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
11735
11736 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
11737 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
11738 CHECK_EQ(0, props->Length());
11739 for (uint32_t i = 0; i < props->Length(); i++) {
11740 printf("p[%d]\n", i);
11741 }
11742}
ager@chromium.org870a0b62008-11-04 11:43:05 +000011743
ager@chromium.org870a0b62008-11-04 11:43:05 +000011744static bool NamedSetAccessBlocker(Local<v8::Object> obj,
11745 Local<Value> name,
11746 v8::AccessType type,
11747 Local<Value> data) {
11748 return type != v8::ACCESS_SET;
11749}
11750
11751
11752static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
11753 uint32_t key,
11754 v8::AccessType type,
11755 Local<Value> data) {
11756 return type != v8::ACCESS_SET;
11757}
11758
11759
11760THREADED_TEST(DisableAccessChecksWhileConfiguring) {
11761 v8::HandleScope scope;
11762 LocalContext context;
11763 Local<ObjectTemplate> templ = ObjectTemplate::New();
11764 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11765 IndexedSetAccessBlocker);
11766 templ->Set(v8_str("x"), v8::True());
11767 Local<v8::Object> instance = templ->NewInstance();
11768 context->Global()->Set(v8_str("obj"), instance);
11769 Local<Value> value = CompileRun("obj.x");
11770 CHECK(value->BooleanValue());
11771}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011772
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011773
ager@chromium.org32912102009-01-16 10:38:43 +000011774static bool NamedGetAccessBlocker(Local<v8::Object> obj,
11775 Local<Value> name,
11776 v8::AccessType type,
11777 Local<Value> data) {
11778 return false;
11779}
11780
11781
11782static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
11783 uint32_t key,
11784 v8::AccessType type,
11785 Local<Value> data) {
11786 return false;
11787}
11788
11789
11790
11791THREADED_TEST(AccessChecksReenabledCorrectly) {
11792 v8::HandleScope scope;
11793 LocalContext context;
11794 Local<ObjectTemplate> templ = ObjectTemplate::New();
11795 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11796 IndexedGetAccessBlocker);
11797 templ->Set(v8_str("a"), v8_str("a"));
11798 // Add more than 8 (see kMaxFastProperties) properties
11799 // so that the constructor will force copying map.
11800 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011801 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000011802 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011803 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000011804 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011805 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000011806 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011807 buf[2] = k;
11808 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000011809 templ->Set(v8_str(buf), v8::Number::New(k));
11810 }
11811 }
11812 }
11813
11814 Local<v8::Object> instance_1 = templ->NewInstance();
11815 context->Global()->Set(v8_str("obj_1"), instance_1);
11816
11817 Local<Value> value_1 = CompileRun("obj_1.a");
11818 CHECK(value_1->IsUndefined());
11819
11820 Local<v8::Object> instance_2 = templ->NewInstance();
11821 context->Global()->Set(v8_str("obj_2"), instance_2);
11822
11823 Local<Value> value_2 = CompileRun("obj_2.a");
11824 CHECK(value_2->IsUndefined());
11825}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011826
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011827
ager@chromium.org8bb60582008-12-11 12:02:20 +000011828// This tests that access check information remains on the global
11829// object template when creating contexts.
11830THREADED_TEST(AccessControlRepeatedContextCreation) {
11831 v8::HandleScope handle_scope;
11832 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11833 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
11834 IndexedSetAccessBlocker);
11835 i::Handle<i::ObjectTemplateInfo> internal_template =
11836 v8::Utils::OpenHandle(*global_template);
11837 CHECK(!internal_template->constructor()->IsUndefined());
11838 i::Handle<i::FunctionTemplateInfo> constructor(
11839 i::FunctionTemplateInfo::cast(internal_template->constructor()));
11840 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011841 v8::Persistent<Context> context0(Context::New(NULL, global_template));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011842 CHECK(!context0.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +000011843 CHECK(!constructor->access_check_info()->IsUndefined());
11844}
11845
11846
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011847THREADED_TEST(TurnOnAccessCheck) {
11848 v8::HandleScope handle_scope;
11849
11850 // Create an environment with access check to the global object disabled by
11851 // default.
11852 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11853 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11854 IndexedGetAccessBlocker,
11855 v8::Handle<v8::Value>(),
11856 false);
11857 v8::Persistent<Context> context = Context::New(NULL, global_template);
11858 Context::Scope context_scope(context);
11859
11860 // Set up a property and a number of functions.
11861 context->Global()->Set(v8_str("a"), v8_num(1));
11862 CompileRun("function f1() {return a;}"
11863 "function f2() {return a;}"
11864 "function g1() {return h();}"
11865 "function g2() {return h();}"
11866 "function h() {return 1;}");
11867 Local<Function> f1 =
11868 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11869 Local<Function> f2 =
11870 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11871 Local<Function> g1 =
11872 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11873 Local<Function> g2 =
11874 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11875 Local<Function> h =
11876 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11877
11878 // Get the global object.
11879 v8::Handle<v8::Object> global = context->Global();
11880
11881 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11882 // uses the runtime system to retreive property a whereas f2 uses global load
11883 // inline cache.
11884 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11885 for (int i = 0; i < 4; i++) {
11886 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11887 }
11888
11889 // Same for g1 and g2.
11890 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11891 for (int i = 0; i < 4; i++) {
11892 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11893 }
11894
11895 // Detach the global and turn on access check.
11896 context->DetachGlobal();
11897 context->Global()->TurnOnAccessCheck();
11898
11899 // Failing access check to property get results in undefined.
11900 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11901 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11902
11903 // Failing access check to function call results in exception.
11904 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11905 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11906
11907 // No failing access check when just returning a constant.
11908 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11909}
11910
11911
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011912static const char* kPropertyA = "a";
11913static const char* kPropertyH = "h";
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011914
11915static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
11916 Local<Value> name,
11917 v8::AccessType type,
11918 Local<Value> data) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011919 if (!name->IsString()) return false;
11920 i::Handle<i::String> name_handle =
11921 v8::Utils::OpenHandle(String::Cast(*name));
11922 return !name_handle->IsEqualTo(i::CStrVector(kPropertyA))
11923 && !name_handle->IsEqualTo(i::CStrVector(kPropertyH));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011924}
11925
11926
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011927THREADED_TEST(TurnOnAccessCheckAndRecompile) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011928 v8::HandleScope handle_scope;
11929
11930 // Create an environment with access check to the global object disabled by
11931 // default. When the registered access checker will block access to properties
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011932 // a and h.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011933 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11934 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
11935 IndexedGetAccessBlocker,
11936 v8::Handle<v8::Value>(),
11937 false);
11938 v8::Persistent<Context> context = Context::New(NULL, global_template);
11939 Context::Scope context_scope(context);
11940
11941 // Set up a property and a number of functions.
11942 context->Global()->Set(v8_str("a"), v8_num(1));
11943 static const char* source = "function f1() {return a;}"
11944 "function f2() {return a;}"
11945 "function g1() {return h();}"
11946 "function g2() {return h();}"
11947 "function h() {return 1;}";
11948
11949 CompileRun(source);
11950 Local<Function> f1;
11951 Local<Function> f2;
11952 Local<Function> g1;
11953 Local<Function> g2;
11954 Local<Function> h;
11955 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11956 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11957 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
11958 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
11959 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
11960
11961 // Get the global object.
11962 v8::Handle<v8::Object> global = context->Global();
11963
11964 // Call f1 one time and f2 a number of times. This will ensure that f1 still
11965 // uses the runtime system to retreive property a whereas f2 uses global load
11966 // inline cache.
11967 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
11968 for (int i = 0; i < 4; i++) {
11969 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
11970 }
11971
11972 // Same for g1 and g2.
11973 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
11974 for (int i = 0; i < 4; i++) {
11975 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
11976 }
11977
11978 // Detach the global and turn on access check now blocking access to property
11979 // a and function h.
11980 context->DetachGlobal();
11981 context->Global()->TurnOnAccessCheck();
11982
11983 // Failing access check to property get results in undefined.
11984 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
11985 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
11986
11987 // Failing access check to function call results in exception.
11988 CHECK(g1->Call(global, 0, NULL).IsEmpty());
11989 CHECK(g2->Call(global, 0, NULL).IsEmpty());
11990
11991 // No failing access check when just returning a constant.
11992 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
11993
11994 // Now compile the source again. And get the newly compiled functions, except
11995 // for h for which access is blocked.
11996 CompileRun(source);
11997 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
11998 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
11999 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12000 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12001 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
12002
12003 // Failing access check to property get results in undefined.
12004 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12005 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12006
12007 // Failing access check to function call results in exception.
12008 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12009 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12010}
12011
12012
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012013// This test verifies that pre-compilation (aka preparsing) can be called
12014// without initializing the whole VM. Thus we cannot run this test in a
12015// multi-threaded setup.
12016TEST(PreCompile) {
12017 // TODO(155): This test would break without the initialization of V8. This is
12018 // a workaround for now to make this test not fail.
12019 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012020 const char* script = "function foo(a) { return a+1; }";
12021 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012022 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012023 CHECK_NE(sd->Length(), 0);
12024 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012025 CHECK(!sd->HasError());
12026 delete sd;
12027}
12028
12029
12030TEST(PreCompileWithError) {
12031 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012032 const char* script = "function foo(a) { return 1 * * 2; }";
12033 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012034 v8::ScriptData::PreCompile(script, i::StrLength(script));
12035 CHECK(sd->HasError());
12036 delete sd;
12037}
12038
12039
12040TEST(Regress31661) {
12041 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012042 const char* script = " The Definintive Guide";
12043 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012044 v8::ScriptData::PreCompile(script, i::StrLength(script));
12045 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012046 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012047}
12048
12049
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012050// Tests that ScriptData can be serialized and deserialized.
12051TEST(PreCompileSerialization) {
12052 v8::V8::Initialize();
12053 const char* script = "function foo(a) { return a+1; }";
12054 v8::ScriptData* sd =
12055 v8::ScriptData::PreCompile(script, i::StrLength(script));
12056
12057 // Serialize.
12058 int serialized_data_length = sd->Length();
12059 char* serialized_data = i::NewArray<char>(serialized_data_length);
12060 memcpy(serialized_data, sd->Data(), serialized_data_length);
12061
12062 // Deserialize.
12063 v8::ScriptData* deserialized_sd =
12064 v8::ScriptData::New(serialized_data, serialized_data_length);
12065
12066 // Verify that the original is the same as the deserialized.
12067 CHECK_EQ(sd->Length(), deserialized_sd->Length());
12068 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
12069 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
12070
12071 delete sd;
12072 delete deserialized_sd;
12073}
12074
12075
12076// Attempts to deserialize bad data.
12077TEST(PreCompileDeserializationError) {
12078 v8::V8::Initialize();
12079 const char* data = "DONT CARE";
12080 int invalid_size = 3;
12081 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
12082
12083 CHECK_EQ(0, sd->Length());
12084
12085 delete sd;
12086}
12087
12088
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012089// Attempts to deserialize bad data.
12090TEST(PreCompileInvalidPreparseDataError) {
12091 v8::V8::Initialize();
12092 v8::HandleScope scope;
12093 LocalContext context;
12094
12095 const char* script = "function foo(){ return 5;}\n"
12096 "function bar(){ return 6 + 7;} foo();";
12097 v8::ScriptData* sd =
12098 v8::ScriptData::PreCompile(script, i::StrLength(script));
12099 CHECK(!sd->HasError());
12100 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000012101 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000012102 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012103 const int kFunctionEntryStartOffset = 0;
12104 const int kFunctionEntryEndOffset = 1;
12105 unsigned* sd_data =
12106 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012107
12108 // Overwrite function bar's end position with 0.
12109 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12110 v8::TryCatch try_catch;
12111
12112 Local<String> source = String::New(script);
12113 Local<Script> compiled_script = Script::New(source, NULL, sd);
12114 CHECK(try_catch.HasCaught());
12115 String::AsciiValue exception_value(try_catch.Message()->Get());
12116 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12117 *exception_value);
12118
12119 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012120
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012121 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012122 // will not be found when searching for it by position and we should fall
12123 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000012124 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12125 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012126 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12127 200;
12128 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012129 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012130
12131 delete sd;
12132}
12133
12134
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012135// Verifies that the Handle<String> and const char* versions of the API produce
12136// the same results (at least for one trivial case).
12137TEST(PreCompileAPIVariationsAreSame) {
12138 v8::V8::Initialize();
12139 v8::HandleScope scope;
12140
12141 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012142
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012143 v8::ScriptData* sd_from_cstring =
12144 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12145
12146 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012147 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012148 v8::String::NewExternal(resource));
12149
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012150 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12151 v8::String::New(cstring));
12152
12153 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012154 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012155 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012156 sd_from_cstring->Length()));
12157
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012158 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12159 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12160 sd_from_string->Data(),
12161 sd_from_cstring->Length()));
12162
12163
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012164 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012165 delete sd_from_external_string;
12166 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012167}
12168
12169
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012170// This tests that we do not allow dictionary load/call inline caches
12171// to use functions that have not yet been compiled. The potential
12172// problem of loading a function that has not yet been compiled can
12173// arise because we share code between contexts via the compilation
12174// cache.
12175THREADED_TEST(DictionaryICLoadedFunction) {
12176 v8::HandleScope scope;
12177 // Test LoadIC.
12178 for (int i = 0; i < 2; i++) {
12179 LocalContext context;
12180 context->Global()->Set(v8_str("tmp"), v8::True());
12181 context->Global()->Delete(v8_str("tmp"));
12182 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12183 }
12184 // Test CallIC.
12185 for (int i = 0; i < 2; i++) {
12186 LocalContext context;
12187 context->Global()->Set(v8_str("tmp"), v8::True());
12188 context->Global()->Delete(v8_str("tmp"));
12189 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12190 }
12191}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012192
12193
12194// Test that cross-context new calls use the context of the callee to
12195// create the new JavaScript object.
12196THREADED_TEST(CrossContextNew) {
12197 v8::HandleScope scope;
12198 v8::Persistent<Context> context0 = Context::New();
12199 v8::Persistent<Context> context1 = Context::New();
12200
12201 // Allow cross-domain access.
12202 Local<String> token = v8_str("<security token>");
12203 context0->SetSecurityToken(token);
12204 context1->SetSecurityToken(token);
12205
12206 // Set an 'x' property on the Object prototype and define a
12207 // constructor function in context0.
12208 context0->Enter();
12209 CompileRun("Object.prototype.x = 42; function C() {};");
12210 context0->Exit();
12211
12212 // Call the constructor function from context0 and check that the
12213 // result has the 'x' property.
12214 context1->Enter();
12215 context1->Global()->Set(v8_str("other"), context0->Global());
12216 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12217 CHECK(value->IsInt32());
12218 CHECK_EQ(42, value->Int32Value());
12219 context1->Exit();
12220
12221 // Dispose the contexts to allow them to be garbage collected.
12222 context0.Dispose();
12223 context1.Dispose();
12224}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012225
12226
12227class RegExpInterruptTest {
12228 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012229 RegExpInterruptTest() : block_(NULL) {}
12230 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012231 void RunTest() {
12232 block_ = i::OS::CreateSemaphore(0);
12233 gc_count_ = 0;
12234 gc_during_regexp_ = 0;
12235 regexp_success_ = false;
12236 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012237 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012238 gc_thread.Start();
12239 v8::Locker::StartPreemption(1);
12240
12241 LongRunningRegExp();
12242 {
12243 v8::Unlocker unlock;
12244 gc_thread.Join();
12245 }
12246 v8::Locker::StopPreemption();
12247 CHECK(regexp_success_);
12248 CHECK(gc_success_);
12249 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012250
ager@chromium.org381abbb2009-02-25 13:23:22 +000012251 private:
12252 // Number of garbage collections required.
12253 static const int kRequiredGCs = 5;
12254
12255 class GCThread : public i::Thread {
12256 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012257 explicit GCThread(RegExpInterruptTest* test)
12258 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012259 virtual void Run() {
12260 test_->CollectGarbage();
12261 }
12262 private:
12263 RegExpInterruptTest* test_;
12264 };
12265
12266 void CollectGarbage() {
12267 block_->Wait();
12268 while (gc_during_regexp_ < kRequiredGCs) {
12269 {
12270 v8::Locker lock;
12271 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012272 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012273 gc_count_++;
12274 }
12275 i::OS::Sleep(1);
12276 }
12277 gc_success_ = true;
12278 }
12279
12280 void LongRunningRegExp() {
12281 block_->Signal(); // Enable garbage collection thread on next preemption.
12282 int rounds = 0;
12283 while (gc_during_regexp_ < kRequiredGCs) {
12284 int gc_before = gc_count_;
12285 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012286 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012287 const char* c_source =
12288 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12289 ".exec('aaaaaaaaaaaaaaab') === null";
12290 Local<String> source = String::New(c_source);
12291 Local<Script> script = Script::Compile(source);
12292 Local<Value> result = script->Run();
12293 if (!result->BooleanValue()) {
12294 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12295 return;
12296 }
12297 }
12298 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012299 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012300 const char* c_source =
12301 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12302 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12303 Local<String> source = String::New(c_source);
12304 Local<Script> script = Script::Compile(source);
12305 Local<Value> result = script->Run();
12306 if (!result->BooleanValue()) {
12307 gc_during_regexp_ = kRequiredGCs;
12308 return;
12309 }
12310 }
12311 int gc_after = gc_count_;
12312 gc_during_regexp_ += gc_after - gc_before;
12313 rounds++;
12314 i::OS::Sleep(1);
12315 }
12316 regexp_success_ = true;
12317 }
12318
12319 i::Semaphore* block_;
12320 int gc_count_;
12321 int gc_during_regexp_;
12322 bool regexp_success_;
12323 bool gc_success_;
12324};
12325
12326
12327// Test that a regular expression execution can be interrupted and
12328// survive a garbage collection.
12329TEST(RegExpInterruption) {
12330 v8::Locker lock;
12331 v8::V8::Initialize();
12332 v8::HandleScope scope;
12333 Local<Context> local_env;
12334 {
12335 LocalContext env;
12336 local_env = env.local();
12337 }
12338
12339 // Local context should still be live.
12340 CHECK(!local_env.IsEmpty());
12341 local_env->Enter();
12342
12343 // Should complete without problems.
12344 RegExpInterruptTest().RunTest();
12345
12346 local_env->Exit();
12347}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012348
12349
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012350class ApplyInterruptTest {
12351 public:
12352 ApplyInterruptTest() : block_(NULL) {}
12353 ~ApplyInterruptTest() { delete block_; }
12354 void RunTest() {
12355 block_ = i::OS::CreateSemaphore(0);
12356 gc_count_ = 0;
12357 gc_during_apply_ = 0;
12358 apply_success_ = false;
12359 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012360 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012361 gc_thread.Start();
12362 v8::Locker::StartPreemption(1);
12363
12364 LongRunningApply();
12365 {
12366 v8::Unlocker unlock;
12367 gc_thread.Join();
12368 }
12369 v8::Locker::StopPreemption();
12370 CHECK(apply_success_);
12371 CHECK(gc_success_);
12372 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012373
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012374 private:
12375 // Number of garbage collections required.
12376 static const int kRequiredGCs = 2;
12377
12378 class GCThread : public i::Thread {
12379 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012380 explicit GCThread(ApplyInterruptTest* test)
12381 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012382 virtual void Run() {
12383 test_->CollectGarbage();
12384 }
12385 private:
12386 ApplyInterruptTest* test_;
12387 };
12388
12389 void CollectGarbage() {
12390 block_->Wait();
12391 while (gc_during_apply_ < kRequiredGCs) {
12392 {
12393 v8::Locker lock;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012394 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012395 gc_count_++;
12396 }
12397 i::OS::Sleep(1);
12398 }
12399 gc_success_ = true;
12400 }
12401
12402 void LongRunningApply() {
12403 block_->Signal();
12404 int rounds = 0;
12405 while (gc_during_apply_ < kRequiredGCs) {
12406 int gc_before = gc_count_;
12407 {
12408 const char* c_source =
12409 "function do_very_little(bar) {"
12410 " this.foo = bar;"
12411 "}"
12412 "for (var i = 0; i < 100000; i++) {"
12413 " do_very_little.apply(this, ['bar']);"
12414 "}";
12415 Local<String> source = String::New(c_source);
12416 Local<Script> script = Script::Compile(source);
12417 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000012418 // Check that no exception was thrown.
12419 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012420 }
12421 int gc_after = gc_count_;
12422 gc_during_apply_ += gc_after - gc_before;
12423 rounds++;
12424 }
12425 apply_success_ = true;
12426 }
12427
12428 i::Semaphore* block_;
12429 int gc_count_;
12430 int gc_during_apply_;
12431 bool apply_success_;
12432 bool gc_success_;
12433};
12434
12435
12436// Test that nothing bad happens if we get a preemption just when we were
12437// about to do an apply().
12438TEST(ApplyInterruption) {
12439 v8::Locker lock;
12440 v8::V8::Initialize();
12441 v8::HandleScope scope;
12442 Local<Context> local_env;
12443 {
12444 LocalContext env;
12445 local_env = env.local();
12446 }
12447
12448 // Local context should still be live.
12449 CHECK(!local_env.IsEmpty());
12450 local_env->Enter();
12451
12452 // Should complete without problems.
12453 ApplyInterruptTest().RunTest();
12454
12455 local_env->Exit();
12456}
12457
12458
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012459// Verify that we can clone an object
12460TEST(ObjectClone) {
12461 v8::HandleScope scope;
12462 LocalContext env;
12463
12464 const char* sample =
12465 "var rv = {};" \
12466 "rv.alpha = 'hello';" \
12467 "rv.beta = 123;" \
12468 "rv;";
12469
12470 // Create an object, verify basics.
12471 Local<Value> val = CompileRun(sample);
12472 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012473 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012474 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12475
12476 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12477 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12478 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12479
12480 // Clone it.
12481 Local<v8::Object> clone = obj->Clone();
12482 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12483 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12484 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12485
12486 // Set a property on the clone, verify each object.
12487 clone->Set(v8_str("beta"), v8::Integer::New(456));
12488 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12489 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12490}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012491
12492
ager@chromium.org5ec48922009-05-05 07:25:34 +000012493class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12494 public:
12495 explicit AsciiVectorResource(i::Vector<const char> vector)
12496 : data_(vector) {}
12497 virtual ~AsciiVectorResource() {}
12498 virtual size_t length() const { return data_.length(); }
12499 virtual const char* data() const { return data_.start(); }
12500 private:
12501 i::Vector<const char> data_;
12502};
12503
12504
12505class UC16VectorResource : public v8::String::ExternalStringResource {
12506 public:
12507 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12508 : data_(vector) {}
12509 virtual ~UC16VectorResource() {}
12510 virtual size_t length() const { return data_.length(); }
12511 virtual const i::uc16* data() const { return data_.start(); }
12512 private:
12513 i::Vector<const i::uc16> data_;
12514};
12515
12516
12517static void MorphAString(i::String* string,
12518 AsciiVectorResource* ascii_resource,
12519 UC16VectorResource* uc16_resource) {
12520 CHECK(i::StringShape(string).IsExternal());
12521 if (string->IsAsciiRepresentation()) {
12522 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012523 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012524 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012526 i::ExternalTwoByteString* morphed =
12527 i::ExternalTwoByteString::cast(string);
12528 morphed->set_resource(uc16_resource);
12529 } else {
12530 // Check old map is not symbol or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012531 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012532 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012533 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012534 i::ExternalAsciiString* morphed =
12535 i::ExternalAsciiString::cast(string);
12536 morphed->set_resource(ascii_resource);
12537 }
12538}
12539
12540
12541// Test that we can still flatten a string if the components it is built up
12542// from have been turned into 16 bit strings in the mean time.
12543THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012544 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000012545 const char* c_string = "Now is the time for all good men"
12546 " to come to the aid of the party";
12547 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12548 {
12549 v8::HandleScope scope;
12550 LocalContext env;
12551 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012552 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012553 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012554 i::Vector<const uint16_t>(two_byte_string,
12555 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012556
12557 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012559 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012560 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012561
12562 env->Global()->Set(v8_str("lhs"), lhs);
12563 env->Global()->Set(v8_str("rhs"), rhs);
12564
12565 CompileRun(
12566 "var cons = lhs + rhs;"
12567 "var slice = lhs.substring(1, lhs.length - 1);"
12568 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12569
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012570 CHECK(!lhs->MayContainNonAscii());
12571 CHECK(!rhs->MayContainNonAscii());
12572
ager@chromium.org5ec48922009-05-05 07:25:34 +000012573 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12574 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12575
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012576 // This should UTF-8 without flattening, since everything is ASCII.
12577 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12578 CHECK_EQ(128, cons->Utf8Length());
12579 int nchars = -1;
12580 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12581 CHECK_EQ(128, nchars);
12582 CHECK_EQ(0, strcmp(
12583 utf_buffer,
12584 "Now is the time for all good men to come to the aid of the party"
12585 "Now is the time for all good men to come to the aid of the party"));
12586
ager@chromium.org5ec48922009-05-05 07:25:34 +000012587 // Now do some stuff to make sure the strings are flattened, etc.
12588 CompileRun(
12589 "/[^a-z]/.test(cons);"
12590 "/[^a-z]/.test(slice);"
12591 "/[^a-z]/.test(slice_on_cons);");
12592 const char* expected_cons =
12593 "Now is the time for all good men to come to the aid of the party"
12594 "Now is the time for all good men to come to the aid of the party";
12595 const char* expected_slice =
12596 "ow is the time for all good men to come to the aid of the part";
12597 const char* expected_slice_on_cons =
12598 "ow is the time for all good men to come to the aid of the party"
12599 "Now is the time for all good men to come to the aid of the part";
12600 CHECK_EQ(String::New(expected_cons),
12601 env->Global()->Get(v8_str("cons")));
12602 CHECK_EQ(String::New(expected_slice),
12603 env->Global()->Get(v8_str("slice")));
12604 CHECK_EQ(String::New(expected_slice_on_cons),
12605 env->Global()->Get(v8_str("slice_on_cons")));
12606 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012607 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000012608}
12609
12610
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012611TEST(CompileExternalTwoByteSource) {
12612 v8::HandleScope scope;
12613 LocalContext context;
12614
12615 // This is a very short list of sources, which currently is to check for a
12616 // regression caused by r2703.
12617 const char* ascii_sources[] = {
12618 "0.5",
12619 "-0.5", // This mainly testes PushBack in the Scanner.
12620 "--0.5", // This mainly testes PushBack in the Scanner.
12621 NULL
12622 };
12623
12624 // Compile the sources as external two byte strings.
12625 for (int i = 0; ascii_sources[i] != NULL; i++) {
12626 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12627 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012628 i::Vector<const uint16_t>(two_byte_string,
12629 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012630 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12631 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012632 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012633 }
12634}
12635
12636
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012637class RegExpStringModificationTest {
12638 public:
12639 RegExpStringModificationTest()
12640 : block_(i::OS::CreateSemaphore(0)),
12641 morphs_(0),
12642 morphs_during_regexp_(0),
12643 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
12644 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
12645 ~RegExpStringModificationTest() { delete block_; }
12646 void RunTest() {
12647 regexp_success_ = false;
12648 morph_success_ = false;
12649
12650 // Initialize the contents of two_byte_content_ to be a uc16 representation
12651 // of "aaaaaaaaaaaaaab".
12652 for (int i = 0; i < 14; i++) {
12653 two_byte_content_[i] = 'a';
12654 }
12655 two_byte_content_[14] = 'b';
12656
12657 // Create the input string for the regexp - the one we are going to change
12658 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012660
12661 // Inject the input as a global variable.
12662 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012663 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012664 i::Isolate::Current()->native_context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012665 *input_name,
12666 *input_,
12667 NONE,
12668 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012669
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012670 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012671 morph_thread.Start();
12672 v8::Locker::StartPreemption(1);
12673 LongRunningRegExp();
12674 {
12675 v8::Unlocker unlock;
12676 morph_thread.Join();
12677 }
12678 v8::Locker::StopPreemption();
12679 CHECK(regexp_success_);
12680 CHECK(morph_success_);
12681 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012682
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012683 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012684 // Number of string modifications required.
12685 static const int kRequiredModifications = 5;
12686 static const int kMaxModifications = 100;
12687
12688 class MorphThread : public i::Thread {
12689 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012690 explicit MorphThread(RegExpStringModificationTest* test)
12691 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012692 virtual void Run() {
12693 test_->MorphString();
12694 }
12695 private:
12696 RegExpStringModificationTest* test_;
12697 };
12698
12699 void MorphString() {
12700 block_->Wait();
12701 while (morphs_during_regexp_ < kRequiredModifications &&
12702 morphs_ < kMaxModifications) {
12703 {
12704 v8::Locker lock;
12705 // Swap string between ascii and two-byte representation.
12706 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000012707 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012708 morphs_++;
12709 }
12710 i::OS::Sleep(1);
12711 }
12712 morph_success_ = true;
12713 }
12714
12715 void LongRunningRegExp() {
12716 block_->Signal(); // Enable morphing thread on next preemption.
12717 while (morphs_during_regexp_ < kRequiredModifications &&
12718 morphs_ < kMaxModifications) {
12719 int morphs_before = morphs_;
12720 {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000012721 v8::HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012722 // Match 15-30 "a"'s against 14 and a "b".
12723 const char* c_source =
12724 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12725 ".exec(input) === null";
12726 Local<String> source = String::New(c_source);
12727 Local<Script> script = Script::Compile(source);
12728 Local<Value> result = script->Run();
12729 CHECK(result->IsTrue());
12730 }
12731 int morphs_after = morphs_;
12732 morphs_during_regexp_ += morphs_after - morphs_before;
12733 }
12734 regexp_success_ = true;
12735 }
12736
12737 i::uc16 two_byte_content_[15];
12738 i::Semaphore* block_;
12739 int morphs_;
12740 int morphs_during_regexp_;
12741 bool regexp_success_;
12742 bool morph_success_;
12743 i::Handle<i::String> input_;
12744 AsciiVectorResource ascii_resource_;
12745 UC16VectorResource uc16_resource_;
12746};
12747
12748
12749// Test that a regular expression execution can be interrupted and
12750// the string changed without failing.
12751TEST(RegExpStringModification) {
12752 v8::Locker lock;
12753 v8::V8::Initialize();
12754 v8::HandleScope scope;
12755 Local<Context> local_env;
12756 {
12757 LocalContext env;
12758 local_env = env.local();
12759 }
12760
12761 // Local context should still be live.
12762 CHECK(!local_env.IsEmpty());
12763 local_env->Enter();
12764
12765 // Should complete without problems.
12766 RegExpStringModificationTest().RunTest();
12767
12768 local_env->Exit();
12769}
12770
12771
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012772// Test that we cannot set a property on the global object if there
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012773// is a read-only property in the prototype chain.
12774TEST(ReadOnlyPropertyInGlobalProto) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012775 i::FLAG_es5_readonly = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012776 v8::HandleScope scope;
12777 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12778 LocalContext context(0, templ);
12779 v8::Handle<v8::Object> global = context->Global();
12780 v8::Handle<v8::Object> global_proto =
12781 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
12782 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
12783 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
12784 // Check without 'eval' or 'with'.
12785 v8::Handle<v8::Value> res =
12786 CompileRun("function f() { x = 42; return x; }; f()");
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012787 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012788 // Check with 'eval'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012789 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
12790 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012791 // Check with 'with'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012792 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
12793 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012794}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012795
12796static int force_set_set_count = 0;
12797static int force_set_get_count = 0;
12798bool pass_on_get = false;
12799
12800static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
12801 const v8::AccessorInfo& info) {
12802 force_set_get_count++;
12803 if (pass_on_get) {
12804 return v8::Handle<v8::Value>();
12805 } else {
12806 return v8::Int32::New(3);
12807 }
12808}
12809
12810static void ForceSetSetter(v8::Local<v8::String> name,
12811 v8::Local<v8::Value> value,
12812 const v8::AccessorInfo& info) {
12813 force_set_set_count++;
12814}
12815
12816static v8::Handle<v8::Value> ForceSetInterceptSetter(
12817 v8::Local<v8::String> name,
12818 v8::Local<v8::Value> value,
12819 const v8::AccessorInfo& info) {
12820 force_set_set_count++;
12821 return v8::Undefined();
12822}
12823
12824TEST(ForceSet) {
12825 force_set_get_count = 0;
12826 force_set_set_count = 0;
12827 pass_on_get = false;
12828
12829 v8::HandleScope scope;
12830 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12831 v8::Handle<v8::String> access_property = v8::String::New("a");
12832 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
12833 LocalContext context(NULL, templ);
12834 v8::Handle<v8::Object> global = context->Global();
12835
12836 // Ordinary properties
12837 v8::Handle<v8::String> simple_property = v8::String::New("p");
12838 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
12839 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12840 // This should fail because the property is read-only
12841 global->Set(simple_property, v8::Int32::New(5));
12842 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12843 // This should succeed even though the property is read-only
12844 global->ForceSet(simple_property, v8::Int32::New(6));
12845 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
12846
12847 // Accessors
12848 CHECK_EQ(0, force_set_set_count);
12849 CHECK_EQ(0, force_set_get_count);
12850 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12851 // CHECK_EQ the property shouldn't override it, just call the setter
12852 // which in this case does nothing.
12853 global->Set(access_property, v8::Int32::New(7));
12854 CHECK_EQ(3, global->Get(access_property)->Int32Value());
12855 CHECK_EQ(1, force_set_set_count);
12856 CHECK_EQ(2, force_set_get_count);
12857 // Forcing the property to be set should override the accessor without
12858 // calling it
12859 global->ForceSet(access_property, v8::Int32::New(8));
12860 CHECK_EQ(8, global->Get(access_property)->Int32Value());
12861 CHECK_EQ(1, force_set_set_count);
12862 CHECK_EQ(2, force_set_get_count);
12863}
12864
12865TEST(ForceSetWithInterceptor) {
12866 force_set_get_count = 0;
12867 force_set_set_count = 0;
12868 pass_on_get = false;
12869
12870 v8::HandleScope scope;
12871 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12872 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
12873 LocalContext context(NULL, templ);
12874 v8::Handle<v8::Object> global = context->Global();
12875
12876 v8::Handle<v8::String> some_property = v8::String::New("a");
12877 CHECK_EQ(0, force_set_set_count);
12878 CHECK_EQ(0, force_set_get_count);
12879 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12880 // Setting the property shouldn't override it, just call the setter
12881 // which in this case does nothing.
12882 global->Set(some_property, v8::Int32::New(7));
12883 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12884 CHECK_EQ(1, force_set_set_count);
12885 CHECK_EQ(2, force_set_get_count);
12886 // Getting the property when the interceptor returns an empty handle
12887 // should yield undefined, since the property isn't present on the
12888 // object itself yet.
12889 pass_on_get = true;
12890 CHECK(global->Get(some_property)->IsUndefined());
12891 CHECK_EQ(1, force_set_set_count);
12892 CHECK_EQ(3, force_set_get_count);
12893 // Forcing the property to be set should cause the value to be
12894 // set locally without calling the interceptor.
12895 global->ForceSet(some_property, v8::Int32::New(8));
12896 CHECK_EQ(8, global->Get(some_property)->Int32Value());
12897 CHECK_EQ(1, force_set_set_count);
12898 CHECK_EQ(4, force_set_get_count);
12899 // Reenabling the interceptor should cause it to take precedence over
12900 // the property
12901 pass_on_get = false;
12902 CHECK_EQ(3, global->Get(some_property)->Int32Value());
12903 CHECK_EQ(1, force_set_set_count);
12904 CHECK_EQ(5, force_set_get_count);
12905 // The interceptor should also work for other properties
12906 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
12907 CHECK_EQ(1, force_set_set_count);
12908 CHECK_EQ(6, force_set_get_count);
12909}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000012910
12911
ager@chromium.orge2902be2009-06-08 12:21:35 +000012912THREADED_TEST(ForceDelete) {
12913 v8::HandleScope scope;
12914 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12915 LocalContext context(NULL, templ);
12916 v8::Handle<v8::Object> global = context->Global();
12917
12918 // Ordinary properties
12919 v8::Handle<v8::String> simple_property = v8::String::New("p");
12920 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
12921 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12922 // This should fail because the property is dont-delete.
12923 CHECK(!global->Delete(simple_property));
12924 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
12925 // This should succeed even though the property is dont-delete.
12926 CHECK(global->ForceDelete(simple_property));
12927 CHECK(global->Get(simple_property)->IsUndefined());
12928}
12929
12930
12931static int force_delete_interceptor_count = 0;
12932static bool pass_on_delete = false;
12933
12934
12935static v8::Handle<v8::Boolean> ForceDeleteDeleter(
12936 v8::Local<v8::String> name,
12937 const v8::AccessorInfo& info) {
12938 force_delete_interceptor_count++;
12939 if (pass_on_delete) {
12940 return v8::Handle<v8::Boolean>();
12941 } else {
12942 return v8::True();
12943 }
12944}
12945
12946
12947THREADED_TEST(ForceDeleteWithInterceptor) {
12948 force_delete_interceptor_count = 0;
12949 pass_on_delete = false;
12950
12951 v8::HandleScope scope;
12952 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12953 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
12954 LocalContext context(NULL, templ);
12955 v8::Handle<v8::Object> global = context->Global();
12956
12957 v8::Handle<v8::String> some_property = v8::String::New("a");
12958 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
12959
12960 // Deleting a property should get intercepted and nothing should
12961 // happen.
12962 CHECK_EQ(0, force_delete_interceptor_count);
12963 CHECK(global->Delete(some_property));
12964 CHECK_EQ(1, force_delete_interceptor_count);
12965 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12966 // Deleting the property when the interceptor returns an empty
12967 // handle should not delete the property since it is DontDelete.
12968 pass_on_delete = true;
12969 CHECK(!global->Delete(some_property));
12970 CHECK_EQ(2, force_delete_interceptor_count);
12971 CHECK_EQ(42, global->Get(some_property)->Int32Value());
12972 // Forcing the property to be deleted should delete the value
12973 // without calling the interceptor.
12974 CHECK(global->ForceDelete(some_property));
12975 CHECK(global->Get(some_property)->IsUndefined());
12976 CHECK_EQ(2, force_delete_interceptor_count);
12977}
12978
12979
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000012980// Make sure that forcing a delete invalidates any IC stubs, so we
12981// don't read the hole value.
12982THREADED_TEST(ForceDeleteIC) {
12983 v8::HandleScope scope;
12984 LocalContext context;
12985 // Create a DontDelete variable on the global object.
12986 CompileRun("this.__proto__ = { foo: 'horse' };"
12987 "var foo = 'fish';"
12988 "function f() { return foo.length; }");
12989 // Initialize the IC for foo in f.
12990 CompileRun("for (var i = 0; i < 4; i++) f();");
12991 // Make sure the value of foo is correct before the deletion.
12992 CHECK_EQ(4, CompileRun("f()")->Int32Value());
12993 // Force the deletion of foo.
12994 CHECK(context->Global()->ForceDelete(v8_str("foo")));
12995 // Make sure the value for foo is read from the prototype, and that
12996 // we don't get in trouble with reading the deleted cell value
12997 // sentinel.
12998 CHECK_EQ(5, CompileRun("f()")->Int32Value());
12999}
13000
13001
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013002TEST(InlinedFunctionAcrossContexts) {
13003 i::FLAG_allow_natives_syntax = true;
13004 v8::HandleScope outer_scope;
13005 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
13006 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
13007 ctx1->Enter();
13008
13009 {
13010 v8::HandleScope inner_scope;
13011 CompileRun("var G = 42; function foo() { return G; }");
13012 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
13013 ctx2->Enter();
13014 ctx2->Global()->Set(v8_str("o"), foo);
13015 v8::Local<v8::Value> res = CompileRun(
13016 "function f() { return o(); }"
13017 "for (var i = 0; i < 10; ++i) f();"
13018 "%OptimizeFunctionOnNextCall(f);"
13019 "f();");
13020 CHECK_EQ(42, res->Int32Value());
13021 ctx2->Exit();
13022 v8::Handle<v8::String> G_property = v8::String::New("G");
13023 CHECK(ctx1->Global()->ForceDelete(G_property));
13024 ctx2->Enter();
13025 ExpectString(
13026 "(function() {"
13027 " try {"
13028 " return f();"
13029 " } catch(e) {"
13030 " return e.toString();"
13031 " }"
13032 " })()",
13033 "ReferenceError: G is not defined");
13034 ctx2->Exit();
13035 ctx1->Exit();
13036 ctx1.Dispose();
13037 }
13038 ctx2.Dispose();
13039}
13040
13041
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013042v8::Persistent<Context> calling_context0;
13043v8::Persistent<Context> calling_context1;
13044v8::Persistent<Context> calling_context2;
13045
13046
13047// Check that the call to the callback is initiated in
13048// calling_context2, the directly calling context is calling_context1
13049// and the callback itself is in calling_context0.
13050static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
13051 ApiTestFuzzer::Fuzz();
13052 CHECK(Context::GetCurrent() == calling_context0);
13053 CHECK(Context::GetCalling() == calling_context1);
13054 CHECK(Context::GetEntered() == calling_context2);
13055 return v8::Integer::New(42);
13056}
13057
13058
13059THREADED_TEST(GetCallingContext) {
13060 v8::HandleScope scope;
13061
13062 calling_context0 = Context::New();
13063 calling_context1 = Context::New();
13064 calling_context2 = Context::New();
13065
13066 // Allow cross-domain access.
13067 Local<String> token = v8_str("<security token>");
13068 calling_context0->SetSecurityToken(token);
13069 calling_context1->SetSecurityToken(token);
13070 calling_context2->SetSecurityToken(token);
13071
13072 // Create an object with a C++ callback in context0.
13073 calling_context0->Enter();
13074 Local<v8::FunctionTemplate> callback_templ =
13075 v8::FunctionTemplate::New(GetCallingContextCallback);
13076 calling_context0->Global()->Set(v8_str("callback"),
13077 callback_templ->GetFunction());
13078 calling_context0->Exit();
13079
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013080 // Expose context0 in context1 and set up a function that calls the
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013081 // callback function.
13082 calling_context1->Enter();
13083 calling_context1->Global()->Set(v8_str("context0"),
13084 calling_context0->Global());
13085 CompileRun("function f() { context0.callback() }");
13086 calling_context1->Exit();
13087
13088 // Expose context1 in context2 and call the callback function in
13089 // context0 indirectly through f in context1.
13090 calling_context2->Enter();
13091 calling_context2->Global()->Set(v8_str("context1"),
13092 calling_context1->Global());
13093 CompileRun("context1.f()");
13094 calling_context2->Exit();
13095
13096 // Dispose the contexts to allow them to be garbage collected.
13097 calling_context0.Dispose();
13098 calling_context1.Dispose();
13099 calling_context2.Dispose();
13100 calling_context0.Clear();
13101 calling_context1.Clear();
13102 calling_context2.Clear();
13103}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013104
13105
13106// Check that a variable declaration with no explicit initialization
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013107// value does shadow an existing property in the prototype chain.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013108THREADED_TEST(InitGlobalVarInProtoChain) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013109 i::FLAG_es52_globals = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013110 v8::HandleScope scope;
13111 LocalContext context;
13112 // Introduce a variable in the prototype chain.
13113 CompileRun("__proto__.x = 42");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013114 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013115 CHECK(!result->IsUndefined());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013116 CHECK_EQ(43, result->Int32Value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013117}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013118
13119
13120// Regression test for issue 398.
13121// If a function is added to an object, creating a constant function
13122// field, and the result is cloned, replacing the constant function on the
13123// original should not affect the clone.
13124// See http://code.google.com/p/v8/issues/detail?id=398
13125THREADED_TEST(ReplaceConstantFunction) {
13126 v8::HandleScope scope;
13127 LocalContext context;
13128 v8::Handle<v8::Object> obj = v8::Object::New();
13129 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13130 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13131 obj->Set(foo_string, func_templ->GetFunction());
13132 v8::Handle<v8::Object> obj_clone = obj->Clone();
13133 obj_clone->Set(foo_string, v8::String::New("Hello"));
13134 CHECK(!obj->Get(foo_string)->IsUndefined());
13135}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013136
13137
13138// Regression test for http://crbug.com/16276.
13139THREADED_TEST(Regress16276) {
13140 v8::HandleScope scope;
13141 LocalContext context;
13142 // Force the IC in f to be a dictionary load IC.
13143 CompileRun("function f(obj) { return obj.x; }\n"
13144 "var obj = { x: { foo: 42 }, y: 87 };\n"
13145 "var x = obj.x;\n"
13146 "delete obj.y;\n"
13147 "for (var i = 0; i < 5; i++) f(obj);");
13148 // Detach the global object to make 'this' refer directly to the
13149 // global object (not the proxy), and make sure that the dictionary
13150 // load IC doesn't mess up loading directly from the global object.
13151 context->DetachGlobal();
13152 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13153}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013154
13155
13156THREADED_TEST(PixelArray) {
13157 v8::HandleScope scope;
13158 LocalContext context;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013159 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013160 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013161 i::Handle<i::ExternalPixelArray> pixels =
13162 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013163 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013164 v8::kExternalPixelArray,
13165 pixel_data));
13166 // Force GC to trigger verification.
13167 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013168 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013169 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013170 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013171 // Force GC to trigger verification.
13172 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013173 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013174 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013175 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013176 }
13177
13178 v8::Handle<v8::Object> obj = v8::Object::New();
13179 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13180 // Set the elements to be the pixels.
13181 // jsobj->set_elements(*pixels);
13182 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013183 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013184 obj->Set(v8_str("field"), v8::Int32::New(1503));
13185 context->Global()->Set(v8_str("pixels"), obj);
13186 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13187 CHECK_EQ(1503, result->Int32Value());
13188 result = CompileRun("pixels[1]");
13189 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013190
13191 result = CompileRun("var sum = 0;"
13192 "for (var i = 0; i < 8; i++) {"
13193 " sum += pixels[i] = pixels[i] = -i;"
13194 "}"
13195 "sum;");
13196 CHECK_EQ(-28, result->Int32Value());
13197
13198 result = CompileRun("var sum = 0;"
13199 "for (var i = 0; i < 8; i++) {"
13200 " sum += pixels[i] = pixels[i] = 0;"
13201 "}"
13202 "sum;");
13203 CHECK_EQ(0, result->Int32Value());
13204
13205 result = CompileRun("var sum = 0;"
13206 "for (var i = 0; i < 8; i++) {"
13207 " sum += pixels[i] = pixels[i] = 255;"
13208 "}"
13209 "sum;");
13210 CHECK_EQ(8 * 255, result->Int32Value());
13211
13212 result = CompileRun("var sum = 0;"
13213 "for (var i = 0; i < 8; i++) {"
13214 " sum += pixels[i] = pixels[i] = 256 + i;"
13215 "}"
13216 "sum;");
13217 CHECK_EQ(2076, result->Int32Value());
13218
13219 result = CompileRun("var sum = 0;"
13220 "for (var i = 0; i < 8; i++) {"
13221 " sum += pixels[i] = pixels[i] = i;"
13222 "}"
13223 "sum;");
13224 CHECK_EQ(28, result->Int32Value());
13225
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013226 result = CompileRun("var sum = 0;"
13227 "for (var i = 0; i < 8; i++) {"
13228 " sum += pixels[i];"
13229 "}"
13230 "sum;");
13231 CHECK_EQ(28, result->Int32Value());
13232
13233 i::Handle<i::Smi> value(i::Smi::FromInt(2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013234 i::Handle<i::Object> no_failure;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013235 no_failure =
13236 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013237 ASSERT(!no_failure.is_null());
13238 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013239 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013240 *value.location() = i::Smi::FromInt(256);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013241 no_failure =
13242 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013243 ASSERT(!no_failure.is_null());
13244 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013245 CHECK_EQ(255,
13246 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013247 *value.location() = i::Smi::FromInt(-1);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013248 no_failure =
13249 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013250 ASSERT(!no_failure.is_null());
13251 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013252 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013253
13254 result = CompileRun("for (var i = 0; i < 8; i++) {"
13255 " pixels[i] = (i * 65) - 109;"
13256 "}"
13257 "pixels[1] + pixels[6];");
13258 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013259 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13260 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13261 CHECK_EQ(21,
13262 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13263 CHECK_EQ(86,
13264 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13265 CHECK_EQ(151,
13266 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13267 CHECK_EQ(216,
13268 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13269 CHECK_EQ(255,
13270 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13271 CHECK_EQ(255,
13272 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013273 result = CompileRun("var sum = 0;"
13274 "for (var i = 0; i < 8; i++) {"
13275 " sum += pixels[i];"
13276 "}"
13277 "sum;");
13278 CHECK_EQ(984, result->Int32Value());
13279
13280 result = CompileRun("for (var i = 0; i < 8; i++) {"
13281 " pixels[i] = (i * 1.1);"
13282 "}"
13283 "pixels[1] + pixels[6];");
13284 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013285 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13286 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13287 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13288 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13289 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13290 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13291 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13292 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013293
13294 result = CompileRun("for (var i = 0; i < 8; i++) {"
13295 " pixels[7] = undefined;"
13296 "}"
13297 "pixels[7];");
13298 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013299 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013300
13301 result = CompileRun("for (var i = 0; i < 8; i++) {"
13302 " pixels[6] = '2.3';"
13303 "}"
13304 "pixels[6];");
13305 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013306 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013307
13308 result = CompileRun("for (var i = 0; i < 8; i++) {"
13309 " pixels[5] = NaN;"
13310 "}"
13311 "pixels[5];");
13312 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013313 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013314
13315 result = CompileRun("for (var i = 0; i < 8; i++) {"
13316 " pixels[8] = Infinity;"
13317 "}"
13318 "pixels[8];");
13319 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013320 CHECK_EQ(255,
13321 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013322
13323 result = CompileRun("for (var i = 0; i < 8; i++) {"
13324 " pixels[9] = -Infinity;"
13325 "}"
13326 "pixels[9];");
13327 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013328 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013329
13330 result = CompileRun("pixels[3] = 33;"
13331 "delete pixels[3];"
13332 "pixels[3];");
13333 CHECK_EQ(33, result->Int32Value());
13334
13335 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13336 "pixels[2] = 12; pixels[3] = 13;"
13337 "pixels.__defineGetter__('2',"
13338 "function() { return 120; });"
13339 "pixels[2];");
13340 CHECK_EQ(12, result->Int32Value());
13341
13342 result = CompileRun("var js_array = new Array(40);"
13343 "js_array[0] = 77;"
13344 "js_array;");
13345 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13346
13347 result = CompileRun("pixels[1] = 23;"
13348 "pixels.__proto__ = [];"
13349 "js_array.__proto__ = pixels;"
13350 "js_array.concat(pixels);");
13351 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13352 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13353
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013354 result = CompileRun("pixels[1] = 23;");
13355 CHECK_EQ(23, result->Int32Value());
13356
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013357 // Test for index greater than 255. Regression test for:
13358 // http://code.google.com/p/chromium/issues/detail?id=26337.
13359 result = CompileRun("pixels[256] = 255;");
13360 CHECK_EQ(255, result->Int32Value());
13361 result = CompileRun("var i = 0;"
13362 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13363 "i");
13364 CHECK_EQ(255, result->Int32Value());
13365
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013366 // Make sure that pixel array ICs recognize when a non-pixel array
13367 // is passed to it.
13368 result = CompileRun("function pa_load(p) {"
13369 " var sum = 0;"
13370 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13371 " return sum;"
13372 "}"
13373 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13374 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13375 "just_ints = new Object();"
13376 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13377 "for (var i = 0; i < 10; ++i) {"
13378 " result = pa_load(just_ints);"
13379 "}"
13380 "result");
13381 CHECK_EQ(32640, result->Int32Value());
13382
13383 // Make sure that pixel array ICs recognize out-of-bound accesses.
13384 result = CompileRun("function pa_load(p, start) {"
13385 " var sum = 0;"
13386 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13387 " return sum;"
13388 "}"
13389 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13390 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13391 "for (var i = 0; i < 10; ++i) {"
13392 " result = pa_load(pixels,-10);"
13393 "}"
13394 "result");
13395 CHECK_EQ(0, result->Int32Value());
13396
13397 // Make sure that generic ICs properly handles a pixel array.
13398 result = CompileRun("function pa_load(p) {"
13399 " var sum = 0;"
13400 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13401 " return sum;"
13402 "}"
13403 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13404 "just_ints = new Object();"
13405 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13406 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13407 "for (var i = 0; i < 10; ++i) {"
13408 " result = pa_load(pixels);"
13409 "}"
13410 "result");
13411 CHECK_EQ(32640, result->Int32Value());
13412
13413 // Make sure that generic load ICs recognize out-of-bound accesses in
13414 // pixel arrays.
13415 result = CompileRun("function pa_load(p, start) {"
13416 " var sum = 0;"
13417 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13418 " return sum;"
13419 "}"
13420 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13421 "just_ints = new Object();"
13422 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13423 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13424 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13425 "for (var i = 0; i < 10; ++i) {"
13426 " result = pa_load(pixels,-10);"
13427 "}"
13428 "result");
13429 CHECK_EQ(0, result->Int32Value());
13430
13431 // Make sure that generic ICs properly handles other types than pixel
13432 // arrays (that the inlined fast pixel array test leaves the right information
13433 // in the right registers).
13434 result = CompileRun("function pa_load(p) {"
13435 " var sum = 0;"
13436 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13437 " return sum;"
13438 "}"
13439 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13440 "just_ints = new Object();"
13441 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13442 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13443 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13444 "sparse_array = new Object();"
13445 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13446 "sparse_array[1000000] = 3;"
13447 "for (var i = 0; i < 10; ++i) {"
13448 " result = pa_load(sparse_array);"
13449 "}"
13450 "result");
13451 CHECK_EQ(32640, result->Int32Value());
13452
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013453 // Make sure that pixel array store ICs clamp values correctly.
13454 result = CompileRun("function pa_store(p) {"
13455 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13456 "}"
13457 "pa_store(pixels);"
13458 "var sum = 0;"
13459 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13460 "sum");
13461 CHECK_EQ(48896, result->Int32Value());
13462
13463 // Make sure that pixel array stores correctly handle accesses outside
13464 // of the pixel array..
13465 result = CompileRun("function pa_store(p,start) {"
13466 " for (var j = 0; j < 256; j++) {"
13467 " p[j+start] = j * 2;"
13468 " }"
13469 "}"
13470 "pa_store(pixels,0);"
13471 "pa_store(pixels,-128);"
13472 "var sum = 0;"
13473 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13474 "sum");
13475 CHECK_EQ(65280, result->Int32Value());
13476
13477 // Make sure that the generic store stub correctly handle accesses outside
13478 // of the pixel array..
13479 result = CompileRun("function pa_store(p,start) {"
13480 " for (var j = 0; j < 256; j++) {"
13481 " p[j+start] = j * 2;"
13482 " }"
13483 "}"
13484 "pa_store(pixels,0);"
13485 "just_ints = new Object();"
13486 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13487 "pa_store(just_ints, 0);"
13488 "pa_store(pixels,-128);"
13489 "var sum = 0;"
13490 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13491 "sum");
13492 CHECK_EQ(65280, result->Int32Value());
13493
13494 // Make sure that the generic keyed store stub clamps pixel array values
13495 // correctly.
13496 result = CompileRun("function pa_store(p) {"
13497 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13498 "}"
13499 "pa_store(pixels);"
13500 "just_ints = new Object();"
13501 "pa_store(just_ints);"
13502 "pa_store(pixels);"
13503 "var sum = 0;"
13504 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13505 "sum");
13506 CHECK_EQ(48896, result->Int32Value());
13507
13508 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013509 result = CompileRun("function pa_load(p) {"
13510 " var sum = 0;"
13511 " for (var i=0; i<256; ++i) {"
13512 " sum += p[i];"
13513 " }"
13514 " return sum; "
13515 "}"
13516 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013517 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013518 " result = pa_load(pixels);"
13519 "}"
13520 "result");
13521 CHECK_EQ(32640, result->Int32Value());
13522
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013523 // Make sure that pixel array stores are optimized by crankshaft.
13524 result = CompileRun("function pa_init(p) {"
13525 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13526 "}"
13527 "function pa_load(p) {"
13528 " var sum = 0;"
13529 " for (var i=0; i<256; ++i) {"
13530 " sum += p[i];"
13531 " }"
13532 " return sum; "
13533 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013534 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013535 " pa_init(pixels);"
13536 "}"
13537 "result = pa_load(pixels);"
13538 "result");
13539 CHECK_EQ(32640, result->Int32Value());
13540
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013541 free(pixel_data);
13542}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013543
ager@chromium.org96c75b52009-08-26 09:13:16 +000013544
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013545THREADED_TEST(PixelArrayInfo) {
13546 v8::HandleScope scope;
13547 LocalContext context;
13548 for (int size = 0; size < 100; size += 10) {
13549 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13550 v8::Handle<v8::Object> obj = v8::Object::New();
13551 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13552 CHECK(obj->HasIndexedPropertiesInPixelData());
13553 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13554 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13555 free(pixel_data);
13556 }
13557}
13558
13559
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013560static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13561 uint32_t index,
13562 const AccessorInfo& info) {
13563 ApiTestFuzzer::Fuzz();
13564 return v8::Handle<Value>();
13565}
13566
13567
13568static v8::Handle<Value> NotHandledIndexedPropertySetter(
13569 uint32_t index,
13570 Local<Value> value,
13571 const AccessorInfo& info) {
13572 ApiTestFuzzer::Fuzz();
13573 return v8::Handle<Value>();
13574}
13575
13576
13577THREADED_TEST(PixelArrayWithInterceptor) {
13578 v8::HandleScope scope;
13579 LocalContext context;
13580 const int kElementCount = 260;
13581 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013582 i::Handle<i::ExternalPixelArray> pixels =
13583 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013584 FACTORY->NewExternalArray(kElementCount,
13585 v8::kExternalPixelArray,
13586 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013587 for (int i = 0; i < kElementCount; i++) {
13588 pixels->set(i, i % 256);
13589 }
13590 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13591 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13592 NotHandledIndexedPropertySetter);
13593 v8::Handle<v8::Object> obj = templ->NewInstance();
13594 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13595 context->Global()->Set(v8_str("pixels"), obj);
13596 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13597 CHECK_EQ(1, result->Int32Value());
13598 result = CompileRun("var sum = 0;"
13599 "for (var i = 0; i < 8; i++) {"
13600 " sum += pixels[i] = pixels[i] = -i;"
13601 "}"
13602 "sum;");
13603 CHECK_EQ(-28, result->Int32Value());
13604 result = CompileRun("pixels.hasOwnProperty('1')");
13605 CHECK(result->BooleanValue());
13606 free(pixel_data);
13607}
13608
13609
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013610static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13611 switch (array_type) {
13612 case v8::kExternalByteArray:
13613 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013614 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013615 return 1;
13616 break;
13617 case v8::kExternalShortArray:
13618 case v8::kExternalUnsignedShortArray:
13619 return 2;
13620 break;
13621 case v8::kExternalIntArray:
13622 case v8::kExternalUnsignedIntArray:
13623 case v8::kExternalFloatArray:
13624 return 4;
13625 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013626 case v8::kExternalDoubleArray:
13627 return 8;
13628 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013629 default:
13630 UNREACHABLE();
13631 return -1;
13632 }
13633 UNREACHABLE();
13634 return -1;
13635}
13636
13637
ager@chromium.org3811b432009-10-28 14:53:37 +000013638template <class ExternalArrayClass, class ElementType>
13639static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
13640 int64_t low,
13641 int64_t high) {
13642 v8::HandleScope scope;
13643 LocalContext context;
13644 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013645 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000013646 ElementType* array_data =
13647 static_cast<ElementType*>(malloc(kElementCount * element_size));
13648 i::Handle<ExternalArrayClass> array =
13649 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013650 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013651 // Force GC to trigger verification.
13652 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013653 for (int i = 0; i < kElementCount; i++) {
13654 array->set(i, static_cast<ElementType>(i));
13655 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013656 // Force GC to trigger verification.
13657 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013658 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013659 CHECK_EQ(static_cast<int64_t>(i),
13660 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000013661 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
13662 }
13663
13664 v8::Handle<v8::Object> obj = v8::Object::New();
13665 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13666 // Set the elements to be the external array.
13667 obj->SetIndexedPropertiesToExternalArrayData(array_data,
13668 array_type,
13669 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013670 CHECK_EQ(
13671 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013672 obj->Set(v8_str("field"), v8::Int32::New(1503));
13673 context->Global()->Set(v8_str("ext_array"), obj);
13674 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13675 CHECK_EQ(1503, result->Int32Value());
13676 result = CompileRun("ext_array[1]");
13677 CHECK_EQ(1, result->Int32Value());
13678
13679 // Check pass through of assigned smis
13680 result = CompileRun("var sum = 0;"
13681 "for (var i = 0; i < 8; i++) {"
13682 " sum += ext_array[i] = ext_array[i] = -i;"
13683 "}"
13684 "sum;");
13685 CHECK_EQ(-28, result->Int32Value());
13686
13687 // Check assigned smis
13688 result = CompileRun("for (var i = 0; i < 8; i++) {"
13689 " ext_array[i] = i;"
13690 "}"
13691 "var sum = 0;"
13692 "for (var i = 0; i < 8; i++) {"
13693 " sum += ext_array[i];"
13694 "}"
13695 "sum;");
13696 CHECK_EQ(28, result->Int32Value());
13697
13698 // Check assigned smis in reverse order
13699 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13700 " ext_array[i] = i;"
13701 "}"
13702 "var sum = 0;"
13703 "for (var i = 0; i < 8; i++) {"
13704 " sum += ext_array[i];"
13705 "}"
13706 "sum;");
13707 CHECK_EQ(28, result->Int32Value());
13708
13709 // Check pass through of assigned HeapNumbers
13710 result = CompileRun("var sum = 0;"
13711 "for (var i = 0; i < 16; i+=2) {"
13712 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13713 "}"
13714 "sum;");
13715 CHECK_EQ(-28, result->Int32Value());
13716
13717 // Check assigned HeapNumbers
13718 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13719 " ext_array[i] = (i * 0.5);"
13720 "}"
13721 "var sum = 0;"
13722 "for (var i = 0; i < 16; i+=2) {"
13723 " sum += ext_array[i];"
13724 "}"
13725 "sum;");
13726 CHECK_EQ(28, result->Int32Value());
13727
13728 // Check assigned HeapNumbers in reverse order
13729 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13730 " ext_array[i] = (i * 0.5);"
13731 "}"
13732 "var sum = 0;"
13733 "for (var i = 0; i < 16; i+=2) {"
13734 " sum += ext_array[i];"
13735 "}"
13736 "sum;");
13737 CHECK_EQ(28, result->Int32Value());
13738
13739 i::ScopedVector<char> test_buf(1024);
13740
13741 // Check legal boundary conditions.
13742 // The repeated loads and stores ensure the ICs are exercised.
13743 const char* boundary_program =
13744 "var res = 0;"
13745 "for (var i = 0; i < 16; i++) {"
13746 " ext_array[i] = %lld;"
13747 " if (i > 8) {"
13748 " res = ext_array[i];"
13749 " }"
13750 "}"
13751 "res;";
13752 i::OS::SNPrintF(test_buf,
13753 boundary_program,
13754 low);
13755 result = CompileRun(test_buf.start());
13756 CHECK_EQ(low, result->IntegerValue());
13757
13758 i::OS::SNPrintF(test_buf,
13759 boundary_program,
13760 high);
13761 result = CompileRun(test_buf.start());
13762 CHECK_EQ(high, result->IntegerValue());
13763
13764 // Check misprediction of type in IC.
13765 result = CompileRun("var tmp_array = ext_array;"
13766 "var sum = 0;"
13767 "for (var i = 0; i < 8; i++) {"
13768 " tmp_array[i] = i;"
13769 " sum += tmp_array[i];"
13770 " if (i == 4) {"
13771 " tmp_array = {};"
13772 " }"
13773 "}"
13774 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013775 // Force GC to trigger verification.
13776 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000013777 CHECK_EQ(28, result->Int32Value());
13778
13779 // Make sure out-of-range loads do not throw.
13780 i::OS::SNPrintF(test_buf,
13781 "var caught_exception = false;"
13782 "try {"
13783 " ext_array[%d];"
13784 "} catch (e) {"
13785 " caught_exception = true;"
13786 "}"
13787 "caught_exception;",
13788 kElementCount);
13789 result = CompileRun(test_buf.start());
13790 CHECK_EQ(false, result->BooleanValue());
13791
13792 // Make sure out-of-range stores do not throw.
13793 i::OS::SNPrintF(test_buf,
13794 "var caught_exception = false;"
13795 "try {"
13796 " ext_array[%d] = 1;"
13797 "} catch (e) {"
13798 " caught_exception = true;"
13799 "}"
13800 "caught_exception;",
13801 kElementCount);
13802 result = CompileRun(test_buf.start());
13803 CHECK_EQ(false, result->BooleanValue());
13804
13805 // Check other boundary conditions, values and operations.
13806 result = CompileRun("for (var i = 0; i < 8; i++) {"
13807 " ext_array[7] = undefined;"
13808 "}"
13809 "ext_array[7];");
13810 CHECK_EQ(0, result->Int32Value());
yangguo@chromium.org56454712012-02-16 15:33:53 +000013811 if (array_type == v8::kExternalDoubleArray ||
13812 array_type == v8::kExternalFloatArray) {
13813 CHECK_EQ(
ulan@chromium.org812308e2012-02-29 15:58:45 +000013814 static_cast<int>(i::OS::nan_value()),
yangguo@chromium.org56454712012-02-16 15:33:53 +000013815 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
13816 } else {
13817 CHECK_EQ(0, static_cast<int>(
13818 jsobj->GetElement(7)->ToObjectChecked()->Number()));
13819 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013820
13821 result = CompileRun("for (var i = 0; i < 8; i++) {"
13822 " ext_array[6] = '2.3';"
13823 "}"
13824 "ext_array[6];");
13825 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013826 CHECK_EQ(
13827 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000013828
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013829 if (array_type != v8::kExternalFloatArray &&
13830 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013831 // Though the specification doesn't state it, be explicit about
13832 // converting NaNs and +/-Infinity to zero.
13833 result = CompileRun("for (var i = 0; i < 8; i++) {"
13834 " ext_array[i] = 5;"
13835 "}"
13836 "for (var i = 0; i < 8; i++) {"
13837 " ext_array[i] = NaN;"
13838 "}"
13839 "ext_array[5];");
13840 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013841 CHECK_EQ(0,
13842 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013843
13844 result = CompileRun("for (var i = 0; i < 8; i++) {"
13845 " ext_array[i] = 5;"
13846 "}"
13847 "for (var i = 0; i < 8; i++) {"
13848 " ext_array[i] = Infinity;"
13849 "}"
13850 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013851 int expected_value =
13852 (array_type == v8::kExternalPixelArray) ? 255 : 0;
13853 CHECK_EQ(expected_value, result->Int32Value());
13854 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013855 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000013856
13857 result = CompileRun("for (var i = 0; i < 8; i++) {"
13858 " ext_array[i] = 5;"
13859 "}"
13860 "for (var i = 0; i < 8; i++) {"
13861 " ext_array[i] = -Infinity;"
13862 "}"
13863 "ext_array[5];");
13864 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013865 CHECK_EQ(0,
13866 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013867
13868 // Check truncation behavior of integral arrays.
13869 const char* unsigned_data =
13870 "var source_data = [0.6, 10.6];"
13871 "var expected_results = [0, 10];";
13872 const char* signed_data =
13873 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13874 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013875 const char* pixel_data =
13876 "var source_data = [0.6, 10.6];"
13877 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013878 bool is_unsigned =
13879 (array_type == v8::kExternalUnsignedByteArray ||
13880 array_type == v8::kExternalUnsignedShortArray ||
13881 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013882 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013883
13884 i::OS::SNPrintF(test_buf,
13885 "%s"
13886 "var all_passed = true;"
13887 "for (var i = 0; i < source_data.length; i++) {"
13888 " for (var j = 0; j < 8; j++) {"
13889 " ext_array[j] = source_data[i];"
13890 " }"
13891 " all_passed = all_passed &&"
13892 " (ext_array[5] == expected_results[i]);"
13893 "}"
13894 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013895 (is_unsigned ?
13896 unsigned_data :
13897 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000013898 result = CompileRun(test_buf.start());
13899 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000013900 }
13901
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000013902 for (int i = 0; i < kElementCount; i++) {
13903 array->set(i, static_cast<ElementType>(i));
13904 }
13905 // Test complex assignments
13906 result = CompileRun("function ee_op_test_complex_func(sum) {"
13907 " for (var i = 0; i < 40; ++i) {"
13908 " sum += (ext_array[i] += 1);"
13909 " sum += (ext_array[i] -= 1);"
13910 " } "
13911 " return sum;"
13912 "}"
13913 "sum=0;"
13914 "for (var i=0;i<10000;++i) {"
13915 " sum=ee_op_test_complex_func(sum);"
13916 "}"
13917 "sum;");
13918 CHECK_EQ(16000000, result->Int32Value());
13919
13920 // Test count operations
13921 result = CompileRun("function ee_op_test_count_func(sum) {"
13922 " for (var i = 0; i < 40; ++i) {"
13923 " sum += (++ext_array[i]);"
13924 " sum += (--ext_array[i]);"
13925 " } "
13926 " return sum;"
13927 "}"
13928 "sum=0;"
13929 "for (var i=0;i<10000;++i) {"
13930 " sum=ee_op_test_count_func(sum);"
13931 "}"
13932 "sum;");
13933 CHECK_EQ(16000000, result->Int32Value());
13934
ager@chromium.org3811b432009-10-28 14:53:37 +000013935 result = CompileRun("ext_array[3] = 33;"
13936 "delete ext_array[3];"
13937 "ext_array[3];");
13938 CHECK_EQ(33, result->Int32Value());
13939
13940 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13941 "ext_array[2] = 12; ext_array[3] = 13;"
13942 "ext_array.__defineGetter__('2',"
13943 "function() { return 120; });"
13944 "ext_array[2];");
13945 CHECK_EQ(12, result->Int32Value());
13946
13947 result = CompileRun("var js_array = new Array(40);"
13948 "js_array[0] = 77;"
13949 "js_array;");
13950 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13951
13952 result = CompileRun("ext_array[1] = 23;"
13953 "ext_array.__proto__ = [];"
13954 "js_array.__proto__ = ext_array;"
13955 "js_array.concat(ext_array);");
13956 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13957 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13958
13959 result = CompileRun("ext_array[1] = 23;");
13960 CHECK_EQ(23, result->Int32Value());
13961
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013962 // Test more complex manipulations which cause eax to contain values
13963 // that won't be completely overwritten by loads from the arrays.
13964 // This catches bugs in the instructions used for the KeyedLoadIC
13965 // for byte and word types.
13966 {
13967 const int kXSize = 300;
13968 const int kYSize = 300;
13969 const int kLargeElementCount = kXSize * kYSize * 4;
13970 ElementType* large_array_data =
13971 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013972 v8::Handle<v8::Object> large_obj = v8::Object::New();
13973 // Set the elements to be the external array.
13974 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
13975 array_type,
13976 kLargeElementCount);
13977 context->Global()->Set(v8_str("large_array"), large_obj);
13978 // Initialize contents of a few rows.
13979 for (int x = 0; x < 300; x++) {
13980 int row = 0;
13981 int offset = row * 300 * 4;
13982 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13983 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13984 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13985 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13986 row = 150;
13987 offset = row * 300 * 4;
13988 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13989 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13990 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13991 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13992 row = 298;
13993 offset = row * 300 * 4;
13994 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
13995 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
13996 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
13997 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
13998 }
13999 // The goal of the code below is to make "offset" large enough
14000 // that the computation of the index (which goes into eax) has
14001 // high bits set which will not be overwritten by a byte or short
14002 // load.
14003 result = CompileRun("var failed = false;"
14004 "var offset = 0;"
14005 "for (var i = 0; i < 300; i++) {"
14006 " if (large_array[4 * i] != 127 ||"
14007 " large_array[4 * i + 1] != 0 ||"
14008 " large_array[4 * i + 2] != 0 ||"
14009 " large_array[4 * i + 3] != 127) {"
14010 " failed = true;"
14011 " }"
14012 "}"
14013 "offset = 150 * 300 * 4;"
14014 "for (var i = 0; i < 300; i++) {"
14015 " if (large_array[offset + 4 * i] != 127 ||"
14016 " large_array[offset + 4 * i + 1] != 0 ||"
14017 " large_array[offset + 4 * i + 2] != 0 ||"
14018 " large_array[offset + 4 * i + 3] != 127) {"
14019 " failed = true;"
14020 " }"
14021 "}"
14022 "offset = 298 * 300 * 4;"
14023 "for (var i = 0; i < 300; i++) {"
14024 " if (large_array[offset + 4 * i] != 127 ||"
14025 " large_array[offset + 4 * i + 1] != 0 ||"
14026 " large_array[offset + 4 * i + 2] != 0 ||"
14027 " large_array[offset + 4 * i + 3] != 127) {"
14028 " failed = true;"
14029 " }"
14030 "}"
14031 "!failed;");
14032 CHECK_EQ(true, result->BooleanValue());
14033 free(large_array_data);
14034 }
14035
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014036 // The "" property descriptor is overloaded to store information about
14037 // the external array. Ensure that setting and accessing the "" property
14038 // works (it should overwrite the information cached about the external
14039 // array in the DescriptorArray) in various situations.
14040 result = CompileRun("ext_array[''] = 23; ext_array['']");
14041 CHECK_EQ(23, result->Int32Value());
14042
14043 // Property "" set after the external array is associated with the object.
14044 {
14045 v8::Handle<v8::Object> obj2 = v8::Object::New();
14046 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
14047 obj2->Set(v8_str(""), v8::Int32::New(1503));
14048 // Set the elements to be the external array.
14049 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14050 array_type,
14051 kElementCount);
14052 context->Global()->Set(v8_str("ext_array"), obj2);
14053 result = CompileRun("ext_array['']");
14054 CHECK_EQ(1503, result->Int32Value());
14055 }
14056
14057 // Property "" set after the external array is associated with the object.
14058 {
14059 v8::Handle<v8::Object> obj2 = v8::Object::New();
14060 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14061 // Set the elements to be the external array.
14062 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14063 array_type,
14064 kElementCount);
14065 obj2->Set(v8_str(""), v8::Int32::New(1503));
14066 context->Global()->Set(v8_str("ext_array"), obj2);
14067 result = CompileRun("ext_array['']");
14068 CHECK_EQ(1503, result->Int32Value());
14069 }
14070
14071 // Should reuse the map from previous test.
14072 {
14073 v8::Handle<v8::Object> obj2 = v8::Object::New();
14074 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14075 // Set the elements to be the external array. Should re-use the map
14076 // from previous test.
14077 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14078 array_type,
14079 kElementCount);
14080 context->Global()->Set(v8_str("ext_array"), obj2);
14081 result = CompileRun("ext_array['']");
14082 }
14083
14084 // Property "" is a constant function that shouldn't not be interfered with
14085 // when an external array is set.
14086 {
14087 v8::Handle<v8::Object> obj2 = v8::Object::New();
14088 // Start
14089 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14090
14091 // Add a constant function to an object.
14092 context->Global()->Set(v8_str("ext_array"), obj2);
14093 result = CompileRun("ext_array[''] = function() {return 1503;};"
14094 "ext_array['']();");
14095
14096 // Add an external array transition to the same map that
14097 // has the constant transition.
14098 v8::Handle<v8::Object> obj3 = v8::Object::New();
14099 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14100 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14101 array_type,
14102 kElementCount);
14103 context->Global()->Set(v8_str("ext_array"), obj3);
14104 }
14105
14106 // If a external array transition is in the map, it should get clobbered
14107 // by a constant function.
14108 {
14109 // Add an external array transition.
14110 v8::Handle<v8::Object> obj3 = v8::Object::New();
14111 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14112 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14113 array_type,
14114 kElementCount);
14115
14116 // Add a constant function to the same map that just got an external array
14117 // transition.
14118 v8::Handle<v8::Object> obj2 = v8::Object::New();
14119 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14120 context->Global()->Set(v8_str("ext_array"), obj2);
14121 result = CompileRun("ext_array[''] = function() {return 1503;};"
14122 "ext_array['']();");
14123 }
14124
ager@chromium.org3811b432009-10-28 14:53:37 +000014125 free(array_data);
14126}
14127
14128
14129THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014130 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014131 v8::kExternalByteArray,
14132 -128,
14133 127);
14134}
14135
14136
14137THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014138 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014139 v8::kExternalUnsignedByteArray,
14140 0,
14141 255);
14142}
14143
14144
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014145THREADED_TEST(ExternalPixelArray) {
14146 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14147 v8::kExternalPixelArray,
14148 0,
14149 255);
14150}
14151
14152
ager@chromium.org3811b432009-10-28 14:53:37 +000014153THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014154 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014155 v8::kExternalShortArray,
14156 -32768,
14157 32767);
14158}
14159
14160
14161THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014162 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014163 v8::kExternalUnsignedShortArray,
14164 0,
14165 65535);
14166}
14167
14168
14169THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014170 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014171 v8::kExternalIntArray,
14172 INT_MIN, // -2147483648
14173 INT_MAX); // 2147483647
14174}
14175
14176
14177THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014178 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014179 v8::kExternalUnsignedIntArray,
14180 0,
14181 UINT_MAX); // 4294967295
14182}
14183
14184
14185THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014186 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014187 v8::kExternalFloatArray,
14188 -500,
14189 500);
14190}
14191
14192
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014193THREADED_TEST(ExternalDoubleArray) {
14194 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14195 v8::kExternalDoubleArray,
14196 -500,
14197 500);
14198}
14199
14200
ager@chromium.org3811b432009-10-28 14:53:37 +000014201THREADED_TEST(ExternalArrays) {
14202 TestExternalByteArray();
14203 TestExternalUnsignedByteArray();
14204 TestExternalShortArray();
14205 TestExternalUnsignedShortArray();
14206 TestExternalIntArray();
14207 TestExternalUnsignedIntArray();
14208 TestExternalFloatArray();
14209}
14210
14211
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014212void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14213 v8::HandleScope scope;
14214 LocalContext context;
14215 for (int size = 0; size < 100; size += 10) {
14216 int element_size = ExternalArrayElementSize(array_type);
14217 void* external_data = malloc(size * element_size);
14218 v8::Handle<v8::Object> obj = v8::Object::New();
14219 obj->SetIndexedPropertiesToExternalArrayData(
14220 external_data, array_type, size);
14221 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14222 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14223 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14224 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14225 free(external_data);
14226 }
14227}
14228
14229
14230THREADED_TEST(ExternalArrayInfo) {
14231 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14232 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14233 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14234 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14235 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14236 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14237 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014238 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014239 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014240}
14241
14242
danno@chromium.org412fa512012-09-14 13:28:26 +000014243void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14244 v8::Handle<v8::Object> obj = v8::Object::New();
14245 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14246 last_location = last_message = NULL;
14247 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14248 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14249 CHECK_NE(NULL, last_location);
14250 CHECK_NE(NULL, last_message);
14251}
14252
14253
14254TEST(ExternalArrayLimits) {
14255 v8::HandleScope scope;
14256 LocalContext context;
14257 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14258 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14259 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14260 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14261 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14262 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14263 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14264 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14265 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14266 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14267 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14268 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14269 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14270 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14271 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14272 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14273 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14274 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14275}
14276
14277
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014278THREADED_TEST(ScriptContextDependence) {
14279 v8::HandleScope scope;
14280 LocalContext c1;
14281 const char *source = "foo";
14282 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14283 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14284 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14285 CHECK_EQ(dep->Run()->Int32Value(), 100);
14286 CHECK_EQ(indep->Run()->Int32Value(), 100);
14287 LocalContext c2;
14288 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14289 CHECK_EQ(dep->Run()->Int32Value(), 100);
14290 CHECK_EQ(indep->Run()->Int32Value(), 101);
14291}
14292
ager@chromium.org96c75b52009-08-26 09:13:16 +000014293
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014294THREADED_TEST(StackTrace) {
14295 v8::HandleScope scope;
14296 LocalContext context;
14297 v8::TryCatch try_catch;
14298 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14299 v8::Handle<v8::String> src = v8::String::New(source);
14300 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14301 v8::Script::New(src, origin)->Run();
14302 CHECK(try_catch.HasCaught());
14303 v8::String::Utf8Value stack(try_catch.StackTrace());
14304 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14305}
ager@chromium.org96c75b52009-08-26 09:13:16 +000014306
14307
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014308// Checks that a StackFrame has certain expected values.
14309void checkStackFrame(const char* expected_script_name,
14310 const char* expected_func_name, int expected_line_number,
14311 int expected_column, bool is_eval, bool is_constructor,
14312 v8::Handle<v8::StackFrame> frame) {
14313 v8::HandleScope scope;
14314 v8::String::Utf8Value func_name(frame->GetFunctionName());
14315 v8::String::Utf8Value script_name(frame->GetScriptName());
14316 if (*script_name == NULL) {
14317 // The situation where there is no associated script, like for evals.
14318 CHECK(expected_script_name == NULL);
14319 } else {
14320 CHECK(strstr(*script_name, expected_script_name) != NULL);
14321 }
14322 CHECK(strstr(*func_name, expected_func_name) != NULL);
14323 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14324 CHECK_EQ(expected_column, frame->GetColumn());
14325 CHECK_EQ(is_eval, frame->IsEval());
14326 CHECK_EQ(is_constructor, frame->IsConstructor());
14327}
14328
14329
14330v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
14331 v8::HandleScope scope;
14332 const char* origin = "capture-stack-trace-test";
14333 const int kOverviewTest = 1;
14334 const int kDetailedTest = 2;
14335
14336 ASSERT(args.Length() == 1);
14337
14338 int testGroup = args[0]->Int32Value();
14339 if (testGroup == kOverviewTest) {
14340 v8::Handle<v8::StackTrace> stackTrace =
14341 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14342 CHECK_EQ(4, stackTrace->GetFrameCount());
14343 checkStackFrame(origin, "bar", 2, 10, false, false,
14344 stackTrace->GetFrame(0));
14345 checkStackFrame(origin, "foo", 6, 3, false, false,
14346 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014347 // This is the source string inside the eval which has the call to foo.
14348 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014349 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014350 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014351 checkStackFrame(origin, "", 8, 7, false, false,
14352 stackTrace->GetFrame(3));
14353
14354 CHECK(stackTrace->AsArray()->IsArray());
14355 } else if (testGroup == kDetailedTest) {
14356 v8::Handle<v8::StackTrace> stackTrace =
14357 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14358 CHECK_EQ(4, stackTrace->GetFrameCount());
14359 checkStackFrame(origin, "bat", 4, 22, false, false,
14360 stackTrace->GetFrame(0));
14361 checkStackFrame(origin, "baz", 8, 3, false, true,
14362 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014363#ifdef ENABLE_DEBUGGER_SUPPORT
14364 bool is_eval = true;
14365#else // ENABLE_DEBUGGER_SUPPORT
14366 bool is_eval = false;
14367#endif // ENABLE_DEBUGGER_SUPPORT
14368
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014369 // This is the source string inside the eval which has the call to baz.
14370 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014371 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014372 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014373 checkStackFrame(origin, "", 10, 1, false, false,
14374 stackTrace->GetFrame(3));
14375
14376 CHECK(stackTrace->AsArray()->IsArray());
14377 }
14378 return v8::Undefined();
14379}
14380
14381
14382// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014383// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14384// THREADED_TEST(CaptureStackTrace) {
14385TEST(CaptureStackTrace) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014386 v8::HandleScope scope;
14387 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14388 Local<ObjectTemplate> templ = ObjectTemplate::New();
14389 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14390 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14391 LocalContext context(0, templ);
14392
14393 // Test getting OVERVIEW information. Should ignore information that is not
14394 // script name, function name, line number, and column offset.
14395 const char *overview_source =
14396 "function bar() {\n"
14397 " var y; AnalyzeStackInNativeCode(1);\n"
14398 "}\n"
14399 "function foo() {\n"
14400 "\n"
14401 " bar();\n"
14402 "}\n"
14403 "var x;eval('new foo();');";
14404 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014405 v8::Handle<Value> overview_result(
14406 v8::Script::New(overview_src, origin)->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014407 CHECK(!overview_result.IsEmpty());
14408 CHECK(overview_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014409
14410 // Test getting DETAILED information.
14411 const char *detailed_source =
14412 "function bat() {AnalyzeStackInNativeCode(2);\n"
14413 "}\n"
14414 "\n"
14415 "function baz() {\n"
14416 " bat();\n"
14417 "}\n"
14418 "eval('new baz();');";
14419 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14420 // Make the script using a non-zero line and column offset.
14421 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14422 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14423 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14424 v8::Handle<v8::Script> detailed_script(
14425 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014426 v8::Handle<Value> detailed_result(detailed_script->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014427 CHECK(!detailed_result.IsEmpty());
14428 CHECK(detailed_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014429}
14430
14431
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014432static void StackTraceForUncaughtExceptionListener(
14433 v8::Handle<v8::Message> message,
14434 v8::Handle<Value>) {
14435 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14436 CHECK_EQ(2, stack_trace->GetFrameCount());
14437 checkStackFrame("origin", "foo", 2, 3, false, false,
14438 stack_trace->GetFrame(0));
14439 checkStackFrame("origin", "bar", 5, 3, false, false,
14440 stack_trace->GetFrame(1));
14441}
14442
14443TEST(CaptureStackTraceForUncaughtException) {
14444 report_count = 0;
14445 v8::HandleScope scope;
14446 LocalContext env;
14447 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14448 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14449
14450 Script::Compile(v8_str("function foo() {\n"
14451 " throw 1;\n"
14452 "};\n"
14453 "function bar() {\n"
14454 " foo();\n"
14455 "};"),
14456 v8_str("origin"))->Run();
14457 v8::Local<v8::Object> global = env->Global();
14458 Local<Value> trouble = global->Get(v8_str("bar"));
14459 CHECK(trouble->IsFunction());
14460 Function::Cast(*trouble)->Call(global, 0, NULL);
14461 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14462 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14463}
14464
14465
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014466TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14467 v8::HandleScope scope;
14468 LocalContext env;
14469 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14470 1024,
14471 v8::StackTrace::kDetailed);
14472
14473 CompileRun(
14474 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14475 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14476 " 'isConstructor'];\n"
14477 "for (var i = 0; i < setters.length; i++) {\n"
14478 " var prop = setters[i];\n"
14479 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14480 "}\n");
14481 CompileRun("throw 'exception';");
14482 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14483}
14484
14485
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014486static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14487 v8::Handle<v8::Value> data) {
14488 // Use the frame where JavaScript is called from.
14489 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14490 CHECK(!stack_trace.IsEmpty());
14491 int frame_count = stack_trace->GetFrameCount();
14492 CHECK_EQ(3, frame_count);
14493 int line_number[] = {1, 2, 5};
14494 for (int i = 0; i < frame_count; i++) {
14495 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14496 }
14497}
14498
14499
14500// Test that we only return the stack trace at the site where the exception
14501// is first thrown (not where it is rethrown).
14502TEST(RethrowStackTrace) {
14503 v8::HandleScope scope;
14504 LocalContext env;
14505 // We make sure that
14506 // - the stack trace of the ReferenceError in g() is reported.
14507 // - the stack trace is not overwritten when e1 is rethrown by t().
14508 // - the stack trace of e2 does not overwrite that of e1.
14509 const char* source =
14510 "function g() { error; } \n"
14511 "function f() { g(); } \n"
14512 "function t(e) { throw e; } \n"
14513 "try { \n"
14514 " f(); \n"
14515 "} catch (e1) { \n"
14516 " try { \n"
14517 " error; \n"
14518 " } catch (e2) { \n"
14519 " t(e1); \n"
14520 " } \n"
14521 "} \n";
14522 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14523 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14524 CompileRun(source);
14525 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14526 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14527}
14528
14529
14530static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14531 v8::Handle<v8::Value> data) {
14532 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14533 CHECK(!stack_trace.IsEmpty());
14534 int frame_count = stack_trace->GetFrameCount();
14535 CHECK_EQ(2, frame_count);
14536 int line_number[] = {3, 7};
14537 for (int i = 0; i < frame_count; i++) {
14538 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14539 }
14540}
14541
14542
14543// Test that we do not recognize identity for primitive exceptions.
14544TEST(RethrowPrimitiveStackTrace) {
14545 v8::HandleScope scope;
14546 LocalContext env;
14547 // We do not capture stack trace for non Error objects on creation time.
14548 // Instead, we capture the stack trace on last throw.
14549 const char* source =
14550 "function g() { throw 404; } \n"
14551 "function f() { g(); } \n"
14552 "function t(e) { throw e; } \n"
14553 "try { \n"
14554 " f(); \n"
14555 "} catch (e1) { \n"
14556 " t(e1) \n"
14557 "} \n";
14558 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14559 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14560 CompileRun(source);
14561 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14562 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14563}
14564
14565
14566static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14567 v8::Handle<v8::Value> data) {
14568 // Use the frame where JavaScript is called from.
14569 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14570 CHECK(!stack_trace.IsEmpty());
14571 CHECK_EQ(1, stack_trace->GetFrameCount());
14572 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14573}
14574
14575
14576// Test that the stack trace is captured when the error object is created and
14577// not where it is thrown.
14578TEST(RethrowExistingStackTrace) {
14579 v8::HandleScope scope;
14580 LocalContext env;
14581 const char* source =
14582 "var e = new Error(); \n"
14583 "throw e; \n";
14584 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14585 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14586 CompileRun(source);
14587 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14588 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14589}
14590
14591
14592static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14593 v8::Handle<v8::Value> data) {
14594 // Use the frame where JavaScript is called from.
14595 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14596 CHECK(!stack_trace.IsEmpty());
14597 CHECK_EQ(1, stack_trace->GetFrameCount());
14598 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14599}
14600
14601
14602// Test that the stack trace is captured where the bogus Error object is thrown.
14603TEST(RethrowBogusErrorStackTrace) {
14604 v8::HandleScope scope;
14605 LocalContext env;
14606 const char* source =
14607 "var e = {__proto__: new Error()} \n"
14608 "throw e; \n";
14609 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14610 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14611 CompileRun(source);
14612 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14613 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14614}
14615
14616
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014617v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
14618 v8::HandleScope scope;
14619 v8::Handle<v8::StackTrace> stackTrace =
14620 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14621 CHECK_EQ(5, stackTrace->GetFrameCount());
14622 v8::Handle<v8::String> url = v8_str("eval_url");
14623 for (int i = 0; i < 3; i++) {
14624 v8::Handle<v8::String> name =
14625 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14626 CHECK(!name.IsEmpty());
14627 CHECK_EQ(url, name);
14628 }
14629 return v8::Undefined();
14630}
14631
14632
14633TEST(SourceURLInStackTrace) {
14634 v8::HandleScope scope;
14635 Local<ObjectTemplate> templ = ObjectTemplate::New();
14636 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14637 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14638 LocalContext context(0, templ);
14639
14640 const char *source =
14641 "function outer() {\n"
14642 "function bar() {\n"
14643 " AnalyzeStackOfEvalWithSourceURL();\n"
14644 "}\n"
14645 "function foo() {\n"
14646 "\n"
14647 " bar();\n"
14648 "}\n"
14649 "foo();\n"
14650 "}\n"
14651 "eval('(' + outer +')()//@ sourceURL=eval_url');";
14652 CHECK(CompileRun(source)->IsUndefined());
14653}
14654
14655
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000014656v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
14657 const v8::Arguments& args) {
14658 v8::HandleScope scope;
14659 v8::Handle<v8::StackTrace> stackTrace =
14660 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14661 CHECK_EQ(4, stackTrace->GetFrameCount());
14662 v8::Handle<v8::String> url = v8_str("url");
14663 for (int i = 0; i < 3; i++) {
14664 v8::Handle<v8::String> name =
14665 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14666 CHECK(!name.IsEmpty());
14667 CHECK_EQ(url, name);
14668 }
14669 return v8::Undefined();
14670}
14671
14672
14673TEST(InlineScriptWithSourceURLInStackTrace) {
14674 v8::HandleScope scope;
14675 Local<ObjectTemplate> templ = ObjectTemplate::New();
14676 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
14677 v8::FunctionTemplate::New(
14678 AnalyzeStackOfInlineScriptWithSourceURL));
14679 LocalContext context(0, templ);
14680
14681 const char *source =
14682 "function outer() {\n"
14683 "function bar() {\n"
14684 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
14685 "}\n"
14686 "function foo() {\n"
14687 "\n"
14688 " bar();\n"
14689 "}\n"
14690 "foo();\n"
14691 "}\n"
14692 "outer()\n"
14693 "//@ sourceURL=source_url";
14694 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
14695}
14696
14697
14698v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
14699 const v8::Arguments& args) {
14700 v8::HandleScope scope;
14701 v8::Handle<v8::StackTrace> stackTrace =
14702 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14703 CHECK_EQ(4, stackTrace->GetFrameCount());
14704 v8::Handle<v8::String> url = v8_str("source_url");
14705 for (int i = 0; i < 3; i++) {
14706 v8::Handle<v8::String> name =
14707 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14708 CHECK(!name.IsEmpty());
14709 CHECK_EQ(url, name);
14710 }
14711 return v8::Undefined();
14712}
14713
14714
14715TEST(DynamicWithSourceURLInStackTrace) {
14716 v8::HandleScope scope;
14717 Local<ObjectTemplate> templ = ObjectTemplate::New();
14718 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
14719 v8::FunctionTemplate::New(
14720 AnalyzeStackOfDynamicScriptWithSourceURL));
14721 LocalContext context(0, templ);
14722
14723 const char *source =
14724 "function outer() {\n"
14725 "function bar() {\n"
14726 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
14727 "}\n"
14728 "function foo() {\n"
14729 "\n"
14730 " bar();\n"
14731 "}\n"
14732 "foo();\n"
14733 "}\n"
14734 "outer()\n"
14735 "//@ sourceURL=source_url";
14736 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
14737}
14738
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014739static void CreateGarbageInOldSpace() {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014740 v8::HandleScope scope;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014741 i::AlwaysAllocateScope always_allocate;
14742 for (int i = 0; i < 1000; i++) {
14743 FACTORY->NewFixedArray(1000, i::TENURED);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014744 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014745}
14746
14747// Test that idle notification can be handled and eventually returns true.
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014748TEST(IdleNotification) {
14749 const intptr_t MB = 1024 * 1024;
14750 v8::HandleScope scope;
14751 LocalContext env;
14752 intptr_t initial_size = HEAP->SizeOfObjects();
14753 CreateGarbageInOldSpace();
14754 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14755 CHECK_GT(size_with_garbage, initial_size + MB);
14756 bool finished = false;
14757 for (int i = 0; i < 200 && !finished; i++) {
14758 finished = v8::V8::IdleNotification();
14759 }
14760 intptr_t final_size = HEAP->SizeOfObjects();
14761 CHECK(finished);
14762 CHECK_LT(final_size, initial_size + 1);
14763}
14764
14765
14766// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014767TEST(IdleNotificationWithSmallHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014768 const intptr_t MB = 1024 * 1024;
14769 const int IdlePauseInMs = 900;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000014770 v8::HandleScope scope;
14771 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014772 intptr_t initial_size = HEAP->SizeOfObjects();
14773 CreateGarbageInOldSpace();
14774 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14775 CHECK_GT(size_with_garbage, initial_size + MB);
14776 bool finished = false;
14777 for (int i = 0; i < 200 && !finished; i++) {
14778 finished = v8::V8::IdleNotification(IdlePauseInMs);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014779 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014780 intptr_t final_size = HEAP->SizeOfObjects();
14781 CHECK(finished);
14782 CHECK_LT(final_size, initial_size + 1);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014783}
14784
14785
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014786// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000014787TEST(IdleNotificationWithLargeHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014788 const intptr_t MB = 1024 * 1024;
14789 const int IdlePauseInMs = 900;
yangguo@chromium.org56454712012-02-16 15:33:53 +000014790 v8::HandleScope scope;
14791 LocalContext env;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014792 intptr_t initial_size = HEAP->SizeOfObjects();
14793 CreateGarbageInOldSpace();
14794 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14795 CHECK_GT(size_with_garbage, initial_size + MB);
14796 bool finished = false;
14797 for (int i = 0; i < 200 && !finished; i++) {
14798 finished = v8::V8::IdleNotification(IdlePauseInMs);
yangguo@chromium.org56454712012-02-16 15:33:53 +000014799 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014800 intptr_t final_size = HEAP->SizeOfObjects();
14801 CHECK(finished);
14802 CHECK_LT(final_size, initial_size + 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014803}
14804
14805
danno@chromium.org2c26cb12012-05-03 09:06:43 +000014806TEST(Regress2107) {
14807 const intptr_t MB = 1024 * 1024;
14808 const int kShortIdlePauseInMs = 100;
14809 const int kLongIdlePauseInMs = 1000;
14810 v8::HandleScope scope;
14811 LocalContext env;
14812 intptr_t initial_size = HEAP->SizeOfObjects();
14813 // Send idle notification to start a round of incremental GCs.
14814 v8::V8::IdleNotification(kShortIdlePauseInMs);
14815 // Emulate 7 page reloads.
14816 for (int i = 0; i < 7; i++) {
14817 v8::Persistent<v8::Context> ctx = v8::Context::New();
14818 ctx->Enter();
14819 CreateGarbageInOldSpace();
14820 ctx->Exit();
14821 ctx.Dispose();
14822 v8::V8::ContextDisposedNotification();
14823 v8::V8::IdleNotification(kLongIdlePauseInMs);
14824 }
14825 // Create garbage and check that idle notification still collects it.
14826 CreateGarbageInOldSpace();
14827 intptr_t size_with_garbage = HEAP->SizeOfObjects();
14828 CHECK_GT(size_with_garbage, initial_size + MB);
14829 bool finished = false;
14830 for (int i = 0; i < 200 && !finished; i++) {
14831 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
14832 }
14833 intptr_t final_size = HEAP->SizeOfObjects();
14834 CHECK_LT(final_size, initial_size + 1);
14835}
14836
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014837static uint32_t* stack_limit;
14838
14839static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014840 stack_limit = reinterpret_cast<uint32_t*>(
14841 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000014842 return v8::Undefined();
14843}
14844
14845
14846// Uses the address of a local variable to determine the stack top now.
14847// Given a size, returns an address that is that far from the current
14848// top of stack.
14849static uint32_t* ComputeStackLimit(uint32_t size) {
14850 uint32_t* answer = &size - (size / sizeof(size));
14851 // If the size is very large and the stack is very near the bottom of
14852 // memory then the calculation above may wrap around and give an address
14853 // that is above the (downwards-growing) stack. In that case we return
14854 // a very low address.
14855 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
14856 return answer;
14857}
14858
14859
14860TEST(SetResourceConstraints) {
14861 static const int K = 1024;
14862 uint32_t* set_limit = ComputeStackLimit(128 * K);
14863
14864 // Set stack limit.
14865 v8::ResourceConstraints constraints;
14866 constraints.set_stack_limit(set_limit);
14867 CHECK(v8::SetResourceConstraints(&constraints));
14868
14869 // Execute a script.
14870 v8::HandleScope scope;
14871 LocalContext env;
14872 Local<v8::FunctionTemplate> fun_templ =
14873 v8::FunctionTemplate::New(GetStackLimitCallback);
14874 Local<Function> fun = fun_templ->GetFunction();
14875 env->Global()->Set(v8_str("get_stack_limit"), fun);
14876 CompileRun("get_stack_limit();");
14877
14878 CHECK(stack_limit == set_limit);
14879}
14880
14881
14882TEST(SetResourceConstraintsInThread) {
14883 uint32_t* set_limit;
14884 {
14885 v8::Locker locker;
14886 static const int K = 1024;
14887 set_limit = ComputeStackLimit(128 * K);
14888
14889 // Set stack limit.
14890 v8::ResourceConstraints constraints;
14891 constraints.set_stack_limit(set_limit);
14892 CHECK(v8::SetResourceConstraints(&constraints));
14893
14894 // Execute a script.
14895 v8::HandleScope scope;
14896 LocalContext env;
14897 Local<v8::FunctionTemplate> fun_templ =
14898 v8::FunctionTemplate::New(GetStackLimitCallback);
14899 Local<Function> fun = fun_templ->GetFunction();
14900 env->Global()->Set(v8_str("get_stack_limit"), fun);
14901 CompileRun("get_stack_limit();");
14902
14903 CHECK(stack_limit == set_limit);
14904 }
14905 {
14906 v8::Locker locker;
14907 CHECK(stack_limit == set_limit);
14908 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000014909}
ager@chromium.org3811b432009-10-28 14:53:37 +000014910
14911
14912THREADED_TEST(GetHeapStatistics) {
14913 v8::HandleScope scope;
14914 LocalContext c1;
14915 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000014916 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
14917 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000014918 v8::V8::GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000014919 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
14920 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000014921}
14922
14923
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014924class VisitorImpl : public v8::ExternalResourceVisitor {
14925 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014926 explicit VisitorImpl(TestResource** resource) {
14927 for (int i = 0; i < 4; i++) {
14928 resource_[i] = resource[i];
14929 found_resource_[i] = false;
14930 }
14931 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014932 virtual ~VisitorImpl() {}
14933 virtual void VisitExternalString(v8::Handle<v8::String> string) {
14934 if (!string->IsExternal()) {
14935 CHECK(string->IsExternalAscii());
14936 return;
14937 }
14938 v8::String::ExternalStringResource* resource =
14939 string->GetExternalStringResource();
14940 CHECK(resource);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014941 for (int i = 0; i < 4; i++) {
14942 if (resource_[i] == resource) {
14943 CHECK(!found_resource_[i]);
14944 found_resource_[i] = true;
14945 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014946 }
14947 }
14948 void CheckVisitedResources() {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014949 for (int i = 0; i < 4; i++) {
14950 CHECK(found_resource_[i]);
14951 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014952 }
14953
14954 private:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014955 v8::String::ExternalStringResource* resource_[4];
14956 bool found_resource_[4];
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014957};
14958
14959TEST(VisitExternalStrings) {
14960 v8::HandleScope scope;
14961 LocalContext env;
14962 const char* string = "Some string";
14963 uint16_t* two_byte_string = AsciiToTwoByteString(string);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014964 TestResource* resource[4];
14965 resource[0] = new TestResource(two_byte_string);
14966 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
14967 resource[1] = new TestResource(two_byte_string);
14968 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014969
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014970 // Externalized symbol.
14971 resource[2] = new TestResource(two_byte_string);
14972 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
14973 CHECK(string2->MakeExternal(resource[2]));
14974
14975 // Symbolized External.
14976 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
14977 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
14978 HEAP->CollectAllAvailableGarbage(); // Tenure string.
14979 // Turn into a symbol.
14980 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
14981 CHECK(!HEAP->LookupSymbol(*string3_i)->IsFailure());
14982 CHECK(string3_i->IsSymbol());
14983
14984 // We need to add usages for string* to avoid warnings in GCC 4.7
14985 CHECK(string0->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000014986 CHECK(string1->IsExternal());
14987 CHECK(string2->IsExternal());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014988 CHECK(string3->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000014989
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000014990 VisitorImpl visitor(resource);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014991 v8::V8::VisitExternalResources(&visitor);
14992 visitor.CheckVisitedResources();
14993}
14994
14995
ager@chromium.org3811b432009-10-28 14:53:37 +000014996static double DoubleFromBits(uint64_t value) {
14997 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000014998 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000014999 return target;
15000}
15001
15002
15003static uint64_t DoubleToBits(double value) {
15004 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015005 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015006 return target;
15007}
15008
15009
15010static double DoubleToDateTime(double input) {
15011 double date_limit = 864e13;
15012 if (IsNaN(input) || input < -date_limit || input > date_limit) {
15013 return i::OS::nan_value();
15014 }
15015 return (input < 0) ? -(floor(-input)) : floor(input);
15016}
15017
15018// We don't have a consistent way to write 64-bit constants syntactically, so we
15019// split them into two 32-bit constants and combine them programmatically.
15020static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15021 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15022}
15023
15024
15025THREADED_TEST(QuietSignalingNaNs) {
15026 v8::HandleScope scope;
15027 LocalContext context;
15028 v8::TryCatch try_catch;
15029
15030 // Special double values.
15031 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15032 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15033 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15034 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15035 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15036 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15037 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15038
15039 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15040 // on either side of the epoch.
15041 double date_limit = 864e13;
15042
15043 double test_values[] = {
15044 snan,
15045 qnan,
15046 infinity,
15047 max_normal,
15048 date_limit + 1,
15049 date_limit,
15050 min_normal,
15051 max_denormal,
15052 min_denormal,
15053 0,
15054 -0,
15055 -min_denormal,
15056 -max_denormal,
15057 -min_normal,
15058 -date_limit,
15059 -date_limit - 1,
15060 -max_normal,
15061 -infinity,
15062 -qnan,
15063 -snan
15064 };
15065 int num_test_values = 20;
15066
15067 for (int i = 0; i < num_test_values; i++) {
15068 double test_value = test_values[i];
15069
15070 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15071 v8::Handle<v8::Value> number = v8::Number::New(test_value);
15072 double stored_number = number->NumberValue();
15073 if (!IsNaN(test_value)) {
15074 CHECK_EQ(test_value, stored_number);
15075 } else {
15076 uint64_t stored_bits = DoubleToBits(stored_number);
15077 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015078#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15079 // Most significant fraction bit for quiet nan is set to 0
15080 // on MIPS architecture. Allowed by IEEE-754.
15081 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15082#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015083 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015084#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015085 }
15086
15087 // Check that Date::New preserves non-NaNs in the date range and
15088 // quiets SNaNs.
15089 v8::Handle<v8::Value> date = v8::Date::New(test_value);
15090 double expected_stored_date = DoubleToDateTime(test_value);
15091 double stored_date = date->NumberValue();
15092 if (!IsNaN(expected_stored_date)) {
15093 CHECK_EQ(expected_stored_date, stored_date);
15094 } else {
15095 uint64_t stored_bits = DoubleToBits(stored_date);
15096 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015097#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15098 // Most significant fraction bit for quiet nan is set to 0
15099 // on MIPS architecture. Allowed by IEEE-754.
15100 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15101#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015102 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015103#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015104 }
15105 }
15106}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015107
15108
15109static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
15110 v8::HandleScope scope;
15111 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015112 v8::Handle<v8::String> str(args[0]->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015113 USE(str);
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015114 if (tc.HasCaught())
15115 return tc.ReThrow();
15116 return v8::Undefined();
15117}
15118
15119
15120// Test that an exception can be propagated down through a spaghetti
15121// stack using ReThrow.
15122THREADED_TEST(SpaghettiStackReThrow) {
15123 v8::HandleScope scope;
15124 LocalContext context;
15125 context->Global()->Set(
15126 v8::String::New("s"),
15127 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15128 v8::TryCatch try_catch;
15129 CompileRun(
15130 "var i = 0;"
15131 "var o = {"
15132 " toString: function () {"
15133 " if (i == 10) {"
15134 " throw 'Hey!';"
15135 " } else {"
15136 " i++;"
15137 " return s(o);"
15138 " }"
15139 " }"
15140 "};"
15141 "s(o);");
15142 CHECK(try_catch.HasCaught());
15143 v8::String::Utf8Value value(try_catch.Exception());
15144 CHECK_EQ(0, strcmp(*value, "Hey!"));
15145}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015146
15147
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015148TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015149 v8::V8::Initialize();
15150
15151 v8::HandleScope scope;
15152 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000015153 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015154 int gc_count;
15155
ager@chromium.org60121232009-12-03 11:25:37 +000015156 // Create a context used to keep the code from aging in the compilation
15157 // cache.
15158 other_context = Context::New();
15159
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015160 // Context-dependent context data creates reference from the compilation
15161 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015162 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015163 context = Context::New();
15164 {
15165 v8::HandleScope scope;
15166
15167 context->Enter();
15168 Local<v8::String> obj = v8::String::New("");
15169 context->SetData(obj);
ager@chromium.org60121232009-12-03 11:25:37 +000015170 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015171 context->Exit();
15172 }
15173 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015174 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015175 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015176 other_context->Enter();
15177 CompileRun(source_simple);
15178 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015179 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015180 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015181 }
ager@chromium.org60121232009-12-03 11:25:37 +000015182 CHECK_GE(2, gc_count);
15183 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015184
15185 // Eval in a function creates reference from the compilation cache to the
15186 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015187 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015188 context = Context::New();
15189 {
15190 v8::HandleScope scope;
15191
15192 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000015193 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015194 context->Exit();
15195 }
15196 context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015197 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015198 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015199 other_context->Enter();
15200 CompileRun(source_eval);
15201 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015202 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015203 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015204 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000015205 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015206 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015207
15208 // Looking up the line number for an exception creates reference from the
15209 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015210 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015211 context = Context::New();
15212 {
15213 v8::HandleScope scope;
15214
15215 context->Enter();
15216 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000015217 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015218 CHECK(try_catch.HasCaught());
15219 v8::Handle<v8::Message> message = try_catch.Message();
15220 CHECK(!message.IsEmpty());
15221 CHECK_EQ(1, message->GetLineNumber());
15222 context->Exit();
15223 }
15224 context.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000015225 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015226 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015227 other_context->Enter();
15228 CompileRun(source_exception);
15229 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015230 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015231 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015232 }
ager@chromium.org60121232009-12-03 11:25:37 +000015233 CHECK_GE(2, gc_count);
15234 CHECK_EQ(1, GetGlobalObjectsCount());
15235
15236 other_context.Dispose();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015237 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015238}
ager@chromium.org5c838252010-02-19 08:53:10 +000015239
15240
15241THREADED_TEST(ScriptOrigin) {
15242 v8::HandleScope scope;
15243 LocalContext env;
15244 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15245 v8::Handle<v8::String> script = v8::String::New(
15246 "function f() {}\n\nfunction g() {}");
15247 v8::Script::Compile(script, &origin)->Run();
15248 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15249 env->Global()->Get(v8::String::New("f")));
15250 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15251 env->Global()->Get(v8::String::New("g")));
15252
15253 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15254 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15255 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15256
15257 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15258 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15259 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15260}
15261
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015262THREADED_TEST(FunctionGetInferredName) {
15263 v8::HandleScope scope;
15264 LocalContext env;
15265 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15266 v8::Handle<v8::String> script = v8::String::New(
15267 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15268 v8::Script::Compile(script, &origin)->Run();
15269 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15270 env->Global()->Get(v8::String::New("f")));
15271 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15272}
ager@chromium.org5c838252010-02-19 08:53:10 +000015273
15274THREADED_TEST(ScriptLineNumber) {
15275 v8::HandleScope scope;
15276 LocalContext env;
15277 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15278 v8::Handle<v8::String> script = v8::String::New(
15279 "function f() {}\n\nfunction g() {}");
15280 v8::Script::Compile(script, &origin)->Run();
15281 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15282 env->Global()->Get(v8::String::New("f")));
15283 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15284 env->Global()->Get(v8::String::New("g")));
15285 CHECK_EQ(0, f->GetScriptLineNumber());
15286 CHECK_EQ(2, g->GetScriptLineNumber());
15287}
15288
15289
danno@chromium.orgc612e022011-11-10 11:38:15 +000015290THREADED_TEST(ScriptColumnNumber) {
15291 v8::HandleScope scope;
15292 LocalContext env;
15293 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15294 v8::Integer::New(3), v8::Integer::New(2));
15295 v8::Handle<v8::String> script = v8::String::New(
15296 "function foo() {}\n\n function bar() {}");
15297 v8::Script::Compile(script, &origin)->Run();
15298 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15299 env->Global()->Get(v8::String::New("foo")));
15300 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15301 env->Global()->Get(v8::String::New("bar")));
15302 CHECK_EQ(14, foo->GetScriptColumnNumber());
15303 CHECK_EQ(17, bar->GetScriptColumnNumber());
15304}
15305
15306
15307THREADED_TEST(FunctionGetScriptId) {
15308 v8::HandleScope scope;
15309 LocalContext env;
15310 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15311 v8::Integer::New(3), v8::Integer::New(2));
15312 v8::Handle<v8::String> scriptSource = v8::String::New(
15313 "function foo() {}\n\n function bar() {}");
15314 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15315 script->Run();
15316 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15317 env->Global()->Get(v8::String::New("foo")));
15318 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15319 env->Global()->Get(v8::String::New("bar")));
15320 CHECK_EQ(script->Id(), foo->GetScriptId());
15321 CHECK_EQ(script->Id(), bar->GetScriptId());
15322}
15323
15324
ager@chromium.org5c838252010-02-19 08:53:10 +000015325static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15326 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015327 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15328 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015329 return v8_num(42);
15330}
15331
15332
15333static void SetterWhichSetsYOnThisTo23(Local<String> name,
15334 Local<Value> value,
15335 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015336 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15337 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015338 info.This()->Set(v8_str("y"), v8_num(23));
15339}
15340
15341
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015342Handle<Value> FooGetInterceptor(Local<String> name,
15343 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015344 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15345 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015346 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15347 return v8_num(42);
15348}
15349
15350
15351Handle<Value> FooSetInterceptor(Local<String> name,
15352 Local<Value> value,
15353 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015354 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15355 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015356 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15357 info.This()->Set(v8_str("y"), v8_num(23));
15358 return v8_num(23);
15359}
15360
15361
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015362TEST(SetterOnConstructorPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015363 v8::HandleScope scope;
15364 Local<ObjectTemplate> templ = ObjectTemplate::New();
15365 templ->SetAccessor(v8_str("x"),
15366 GetterWhichReturns42,
15367 SetterWhichSetsYOnThisTo23);
15368 LocalContext context;
15369 context->Global()->Set(v8_str("P"), templ->NewInstance());
15370 CompileRun("function C1() {"
15371 " this.x = 23;"
15372 "};"
15373 "C1.prototype = P;"
15374 "function C2() {"
15375 " this.x = 23"
15376 "};"
15377 "C2.prototype = { };"
15378 "C2.prototype.__proto__ = P;");
15379
15380 v8::Local<v8::Script> script;
15381 script = v8::Script::Compile(v8_str("new C1();"));
15382 for (int i = 0; i < 10; i++) {
15383 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15384 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15385 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15386 }
15387
15388 script = v8::Script::Compile(v8_str("new C2();"));
15389 for (int i = 0; i < 10; i++) {
15390 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15391 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15392 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15393 }
15394}
15395
15396
15397static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15398 Local<String> name, const AccessorInfo& info) {
15399 return v8_num(42);
15400}
15401
15402
15403static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15404 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15405 if (name->Equals(v8_str("x"))) {
15406 info.This()->Set(v8_str("y"), v8_num(23));
15407 }
15408 return v8::Handle<Value>();
15409}
15410
15411
15412THREADED_TEST(InterceptorOnConstructorPrototype) {
15413 v8::HandleScope scope;
15414 Local<ObjectTemplate> templ = ObjectTemplate::New();
15415 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15416 NamedPropertySetterWhichSetsYOnThisTo23);
15417 LocalContext context;
15418 context->Global()->Set(v8_str("P"), templ->NewInstance());
15419 CompileRun("function C1() {"
15420 " this.x = 23;"
15421 "};"
15422 "C1.prototype = P;"
15423 "function C2() {"
15424 " this.x = 23"
15425 "};"
15426 "C2.prototype = { };"
15427 "C2.prototype.__proto__ = P;");
15428
15429 v8::Local<v8::Script> script;
15430 script = v8::Script::Compile(v8_str("new C1();"));
15431 for (int i = 0; i < 10; i++) {
15432 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15433 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15434 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15435 }
15436
15437 script = v8::Script::Compile(v8_str("new C2();"));
15438 for (int i = 0; i < 10; i++) {
15439 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15440 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15441 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15442 }
15443}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015444
15445
15446TEST(Bug618) {
15447 const char* source = "function C1() {"
15448 " this.x = 23;"
15449 "};"
15450 "C1.prototype = P;";
15451
15452 v8::HandleScope scope;
15453 LocalContext context;
15454 v8::Local<v8::Script> script;
15455
15456 // Use a simple object as prototype.
15457 v8::Local<v8::Object> prototype = v8::Object::New();
15458 prototype->Set(v8_str("y"), v8_num(42));
15459 context->Global()->Set(v8_str("P"), prototype);
15460
15461 // This compile will add the code to the compilation cache.
15462 CompileRun(source);
15463
15464 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015465 // Allow enough iterations for the inobject slack tracking logic
15466 // to finalize instance size and install the fast construct stub.
15467 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015468 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15469 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15470 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15471 }
15472
15473 // Use an API object with accessors as prototype.
15474 Local<ObjectTemplate> templ = ObjectTemplate::New();
15475 templ->SetAccessor(v8_str("x"),
15476 GetterWhichReturns42,
15477 SetterWhichSetsYOnThisTo23);
15478 context->Global()->Set(v8_str("P"), templ->NewInstance());
15479
15480 // This compile will get the code from the compilation cache.
15481 CompileRun(source);
15482
15483 script = v8::Script::Compile(v8_str("new C1();"));
15484 for (int i = 0; i < 10; i++) {
15485 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15486 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15487 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15488 }
15489}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015490
15491int prologue_call_count = 0;
15492int epilogue_call_count = 0;
15493int prologue_call_count_second = 0;
15494int epilogue_call_count_second = 0;
15495
15496void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15497 ++prologue_call_count;
15498}
15499
15500void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15501 ++epilogue_call_count;
15502}
15503
15504void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15505 ++prologue_call_count_second;
15506}
15507
15508void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15509 ++epilogue_call_count_second;
15510}
15511
15512TEST(GCCallbacks) {
15513 LocalContext context;
15514
15515 v8::V8::AddGCPrologueCallback(PrologueCallback);
15516 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15517 CHECK_EQ(0, prologue_call_count);
15518 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015519 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015520 CHECK_EQ(1, prologue_call_count);
15521 CHECK_EQ(1, epilogue_call_count);
15522 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15523 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015524 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015525 CHECK_EQ(2, prologue_call_count);
15526 CHECK_EQ(2, epilogue_call_count);
15527 CHECK_EQ(1, prologue_call_count_second);
15528 CHECK_EQ(1, epilogue_call_count_second);
15529 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15530 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015531 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015532 CHECK_EQ(2, prologue_call_count);
15533 CHECK_EQ(2, epilogue_call_count);
15534 CHECK_EQ(2, prologue_call_count_second);
15535 CHECK_EQ(2, epilogue_call_count_second);
15536 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15537 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015538 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015539 CHECK_EQ(2, prologue_call_count);
15540 CHECK_EQ(2, epilogue_call_count);
15541 CHECK_EQ(2, prologue_call_count_second);
15542 CHECK_EQ(2, epilogue_call_count_second);
15543}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015544
15545
15546THREADED_TEST(AddToJSFunctionResultCache) {
15547 i::FLAG_allow_natives_syntax = true;
15548 v8::HandleScope scope;
15549
15550 LocalContext context;
15551
15552 const char* code =
15553 "(function() {"
15554 " var key0 = 'a';"
15555 " var key1 = 'b';"
15556 " var r0 = %_GetFromCache(0, key0);"
15557 " var r1 = %_GetFromCache(0, key1);"
15558 " var r0_ = %_GetFromCache(0, key0);"
15559 " if (r0 !== r0_)"
15560 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15561 " var r1_ = %_GetFromCache(0, key1);"
15562 " if (r1 !== r1_)"
15563 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15564 " return 'PASSED';"
15565 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015566 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015567 ExpectString(code, "PASSED");
15568}
15569
15570
15571static const int k0CacheSize = 16;
15572
15573THREADED_TEST(FillJSFunctionResultCache) {
15574 i::FLAG_allow_natives_syntax = true;
15575 v8::HandleScope scope;
15576
15577 LocalContext context;
15578
15579 const char* code =
15580 "(function() {"
15581 " var k = 'a';"
15582 " var r = %_GetFromCache(0, k);"
15583 " for (var i = 0; i < 16; i++) {"
15584 " %_GetFromCache(0, 'a' + i);"
15585 " };"
15586 " if (r === %_GetFromCache(0, k))"
15587 " return 'FAILED: k0CacheSize is too small';"
15588 " return 'PASSED';"
15589 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015590 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015591 ExpectString(code, "PASSED");
15592}
15593
15594
15595THREADED_TEST(RoundRobinGetFromCache) {
15596 i::FLAG_allow_natives_syntax = true;
15597 v8::HandleScope scope;
15598
15599 LocalContext context;
15600
15601 const char* code =
15602 "(function() {"
15603 " var keys = [];"
15604 " for (var i = 0; i < 16; i++) keys.push(i);"
15605 " var values = [];"
15606 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15607 " for (var i = 0; i < 16; i++) {"
15608 " var v = %_GetFromCache(0, keys[i]);"
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000015609 " if (v.toString() !== values[i].toString())"
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015610 " return 'Wrong value for ' + "
15611 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15612 " };"
15613 " return 'PASSED';"
15614 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015615 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015616 ExpectString(code, "PASSED");
15617}
15618
15619
15620THREADED_TEST(ReverseGetFromCache) {
15621 i::FLAG_allow_natives_syntax = true;
15622 v8::HandleScope scope;
15623
15624 LocalContext context;
15625
15626 const char* code =
15627 "(function() {"
15628 " var keys = [];"
15629 " for (var i = 0; i < 16; i++) keys.push(i);"
15630 " var values = [];"
15631 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15632 " for (var i = 15; i >= 16; i--) {"
15633 " var v = %_GetFromCache(0, keys[i]);"
15634 " if (v !== values[i])"
15635 " return 'Wrong value for ' + "
15636 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15637 " };"
15638 " return 'PASSED';"
15639 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015640 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015641 ExpectString(code, "PASSED");
15642}
15643
15644
15645THREADED_TEST(TestEviction) {
15646 i::FLAG_allow_natives_syntax = true;
15647 v8::HandleScope scope;
15648
15649 LocalContext context;
15650
15651 const char* code =
15652 "(function() {"
15653 " for (var i = 0; i < 2*16; i++) {"
15654 " %_GetFromCache(0, 'a' + i);"
15655 " };"
15656 " return 'PASSED';"
15657 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015658 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015659 ExpectString(code, "PASSED");
15660}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015661
15662
15663THREADED_TEST(TwoByteStringInAsciiCons) {
15664 // See Chromium issue 47824.
15665 v8::HandleScope scope;
15666
15667 LocalContext context;
15668 const char* init_code =
15669 "var str1 = 'abelspendabel';"
15670 "var str2 = str1 + str1 + str1;"
15671 "str2;";
15672 Local<Value> result = CompileRun(init_code);
15673
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015674 Local<Value> indexof = CompileRun("str2.indexOf('els')");
15675 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
15676
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015677 CHECK(result->IsString());
15678 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
15679 int length = string->length();
15680 CHECK(string->IsAsciiRepresentation());
15681
15682 FlattenString(string);
15683 i::Handle<i::String> flat_string = FlattenGetString(string);
15684
15685 CHECK(string->IsAsciiRepresentation());
15686 CHECK(flat_string->IsAsciiRepresentation());
15687
15688 // Create external resource.
15689 uint16_t* uc16_buffer = new uint16_t[length + 1];
15690
15691 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
15692 uc16_buffer[length] = 0;
15693
15694 TestResource resource(uc16_buffer);
15695
15696 flat_string->MakeExternal(&resource);
15697
15698 CHECK(flat_string->IsTwoByteRepresentation());
15699
15700 // At this point, we should have a Cons string which is flat and ASCII,
15701 // with a first half that is a two-byte string (although it only contains
15702 // ASCII characters). This is a valid sequence of steps, and it can happen
15703 // in real pages.
15704
15705 CHECK(string->IsAsciiRepresentation());
15706 i::ConsString* cons = i::ConsString::cast(*string);
15707 CHECK_EQ(0, cons->second()->length());
15708 CHECK(cons->first()->IsTwoByteRepresentation());
15709
15710 // Check that some string operations work.
15711
15712 // Atom RegExp.
15713 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
15714 CHECK_EQ(6, reresult->Int32Value());
15715
15716 // Nonatom RegExp.
15717 reresult = CompileRun("str2.match(/abe./g).length;");
15718 CHECK_EQ(6, reresult->Int32Value());
15719
15720 reresult = CompileRun("str2.search(/bel/g);");
15721 CHECK_EQ(1, reresult->Int32Value());
15722
15723 reresult = CompileRun("str2.search(/be./g);");
15724 CHECK_EQ(1, reresult->Int32Value());
15725
15726 ExpectTrue("/bel/g.test(str2);");
15727
15728 ExpectTrue("/be./g.test(str2);");
15729
15730 reresult = CompileRun("/bel/g.exec(str2);");
15731 CHECK(!reresult->IsNull());
15732
15733 reresult = CompileRun("/be./g.exec(str2);");
15734 CHECK(!reresult->IsNull());
15735
15736 ExpectString("str2.substring(2, 10);", "elspenda");
15737
15738 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
15739
15740 ExpectString("str2.charAt(2);", "e");
15741
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000015742 ExpectObject("str2.indexOf('els');", indexof);
15743
15744 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
15745
lrn@chromium.org32d961d2010-06-30 09:09:34 +000015746 reresult = CompileRun("str2.charCodeAt(2);");
15747 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
15748}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015749
15750
15751// Failed access check callback that performs a GC on each invocation.
15752void FailedAccessCheckCallbackGC(Local<v8::Object> target,
15753 v8::AccessType type,
15754 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015755 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000015756}
15757
15758
15759TEST(GCInFailedAccessCheckCallback) {
15760 // Install a failed access check callback that performs a GC on each
15761 // invocation. Then force the callback to be called from va
15762
15763 v8::V8::Initialize();
15764 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
15765
15766 v8::HandleScope scope;
15767
15768 // Create an ObjectTemplate for global objects and install access
15769 // check callbacks that will block access.
15770 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
15771 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15772 IndexedGetAccessBlocker,
15773 v8::Handle<v8::Value>(),
15774 false);
15775
15776 // Create a context and set an x property on it's global object.
15777 LocalContext context0(NULL, global_template);
15778 context0->Global()->Set(v8_str("x"), v8_num(42));
15779 v8::Handle<v8::Object> global0 = context0->Global();
15780
15781 // Create a context with a different security token so that the
15782 // failed access check callback will be called on each access.
15783 LocalContext context1(NULL, global_template);
15784 context1->Global()->Set(v8_str("other"), global0);
15785
15786 // Get property with failed access check.
15787 ExpectUndefined("other.x");
15788
15789 // Get element with failed access check.
15790 ExpectUndefined("other[0]");
15791
15792 // Set property with failed access check.
15793 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
15794 CHECK(result->IsObject());
15795
15796 // Set element with failed access check.
15797 result = CompileRun("other[0] = new Object()");
15798 CHECK(result->IsObject());
15799
15800 // Get property attribute with failed access check.
15801 ExpectFalse("\'x\' in other");
15802
15803 // Get property attribute for element with failed access check.
15804 ExpectFalse("0 in other");
15805
15806 // Delete property.
15807 ExpectFalse("delete other.x");
15808
15809 // Delete element.
15810 CHECK_EQ(false, global0->Delete(0));
15811
15812 // DefineAccessor.
15813 CHECK_EQ(false,
15814 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
15815
15816 // Define JavaScript accessor.
15817 ExpectUndefined("Object.prototype.__defineGetter__.call("
15818 " other, \'x\', function() { return 42; })");
15819
15820 // LookupAccessor.
15821 ExpectUndefined("Object.prototype.__lookupGetter__.call("
15822 " other, \'x\')");
15823
15824 // HasLocalElement.
15825 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
15826
15827 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
15828 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
15829 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
15830
15831 // Reset the failed access check callback so it does not influence
15832 // the other tests.
15833 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
15834}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000015835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015836TEST(DefaultIsolateGetCurrent) {
15837 CHECK(v8::Isolate::GetCurrent() != NULL);
15838 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15839 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15840 printf("*** %s\n", "DefaultIsolateGetCurrent success");
15841}
15842
15843TEST(IsolateNewDispose) {
15844 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15845 v8::Isolate* isolate = v8::Isolate::New();
15846 CHECK(isolate != NULL);
15847 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15848 CHECK(current_isolate != isolate);
15849 CHECK(current_isolate == v8::Isolate::GetCurrent());
15850
15851 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15852 last_location = last_message = NULL;
15853 isolate->Dispose();
15854 CHECK_EQ(last_location, NULL);
15855 CHECK_EQ(last_message, NULL);
15856}
15857
15858TEST(IsolateEnterExitDefault) {
15859 v8::HandleScope scope;
15860 LocalContext context;
15861 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
15862 CHECK(current_isolate != NULL); // Default isolate.
15863 ExpectString("'hello'", "hello");
15864 current_isolate->Enter();
15865 ExpectString("'still working'", "still working");
15866 current_isolate->Exit();
15867 ExpectString("'still working 2'", "still working 2");
15868 current_isolate->Exit();
15869 // Default isolate is always, well, 'default current'.
15870 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
15871 // Still working since default isolate is auto-entering any thread
15872 // that has no isolate and attempts to execute V8 APIs.
15873 ExpectString("'still working 3'", "still working 3");
15874}
15875
15876TEST(DisposeDefaultIsolate) {
15877 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15878
15879 // Run some V8 code to trigger default isolate to become 'current'.
15880 v8::HandleScope scope;
15881 LocalContext context;
15882 ExpectString("'run some V8'", "run some V8");
15883
15884 v8::Isolate* isolate = v8::Isolate::GetCurrent();
15885 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
15886 last_location = last_message = NULL;
15887 isolate->Dispose();
15888 // It is not possible to dispose default isolate via Isolate API.
15889 CHECK_NE(last_location, NULL);
15890 CHECK_NE(last_message, NULL);
15891}
15892
15893TEST(RunDefaultAndAnotherIsolate) {
15894 v8::HandleScope scope;
15895 LocalContext context;
15896
15897 // Enter new isolate.
15898 v8::Isolate* isolate = v8::Isolate::New();
15899 CHECK(isolate);
15900 isolate->Enter();
15901 { // Need this block because subsequent Exit() will deallocate Heap,
15902 // so we need all scope objects to be deconstructed when it happens.
15903 v8::HandleScope scope_new;
15904 LocalContext context_new;
15905
15906 // Run something in new isolate.
15907 CompileRun("var foo = 153;");
15908 ExpectTrue("function f() { return foo == 153; }; f()");
15909 }
15910 isolate->Exit();
15911
15912 // This runs automatically in default isolate.
15913 // Variables in another isolate should be not available.
15914 ExpectTrue("function f() {"
15915 " try {"
15916 " foo;"
15917 " return false;"
15918 " } catch(e) {"
15919 " return true;"
15920 " }"
15921 "};"
15922 "var bar = 371;"
15923 "f()");
15924
15925 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15926 last_location = last_message = NULL;
15927 isolate->Dispose();
15928 CHECK_EQ(last_location, NULL);
15929 CHECK_EQ(last_message, NULL);
15930
15931 // Check that default isolate still runs.
15932 ExpectTrue("function f() { return bar == 371; }; f()");
15933}
15934
15935TEST(DisposeIsolateWhenInUse) {
15936 v8::Isolate* isolate = v8::Isolate::New();
15937 CHECK(isolate);
15938 isolate->Enter();
15939 v8::HandleScope scope;
15940 LocalContext context;
15941 // Run something in this isolate.
15942 ExpectTrue("true");
15943 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15944 last_location = last_message = NULL;
15945 // Still entered, should fail.
15946 isolate->Dispose();
15947 CHECK_NE(last_location, NULL);
15948 CHECK_NE(last_message, NULL);
15949}
15950
15951TEST(RunTwoIsolatesOnSingleThread) {
15952 // Run isolate 1.
15953 v8::Isolate* isolate1 = v8::Isolate::New();
15954 isolate1->Enter();
15955 v8::Persistent<v8::Context> context1 = v8::Context::New();
15956
15957 {
15958 v8::Context::Scope cscope(context1);
15959 v8::HandleScope scope;
15960 // Run something in new isolate.
15961 CompileRun("var foo = 'isolate 1';");
15962 ExpectString("function f() { return foo; }; f()", "isolate 1");
15963 }
15964
15965 // Run isolate 2.
15966 v8::Isolate* isolate2 = v8::Isolate::New();
15967 v8::Persistent<v8::Context> context2;
15968
15969 {
15970 v8::Isolate::Scope iscope(isolate2);
15971 context2 = v8::Context::New();
15972 v8::Context::Scope cscope(context2);
15973 v8::HandleScope scope;
15974
15975 // Run something in new isolate.
15976 CompileRun("var foo = 'isolate 2';");
15977 ExpectString("function f() { return foo; }; f()", "isolate 2");
15978 }
15979
15980 {
15981 v8::Context::Scope cscope(context1);
15982 v8::HandleScope scope;
15983 // Now again in isolate 1
15984 ExpectString("function f() { return foo; }; f()", "isolate 1");
15985 }
15986
15987 isolate1->Exit();
15988
15989 // Run some stuff in default isolate.
15990 v8::Persistent<v8::Context> context_default = v8::Context::New();
15991
15992 {
15993 v8::Context::Scope cscope(context_default);
15994 v8::HandleScope scope;
15995 // Variables in other isolates should be not available, verify there
15996 // is an exception.
15997 ExpectTrue("function f() {"
15998 " try {"
15999 " foo;"
16000 " return false;"
16001 " } catch(e) {"
16002 " return true;"
16003 " }"
16004 "};"
16005 "var isDefaultIsolate = true;"
16006 "f()");
16007 }
16008
16009 isolate1->Enter();
16010
16011 {
16012 v8::Isolate::Scope iscope(isolate2);
16013 v8::Context::Scope cscope(context2);
16014 v8::HandleScope scope;
16015 ExpectString("function f() { return foo; }; f()", "isolate 2");
16016 }
16017
16018 {
16019 v8::Context::Scope cscope(context1);
16020 v8::HandleScope scope;
16021 ExpectString("function f() { return foo; }; f()", "isolate 1");
16022 }
16023
16024 {
16025 v8::Isolate::Scope iscope(isolate2);
16026 context2.Dispose();
16027 }
16028
16029 context1.Dispose();
16030 isolate1->Exit();
16031
16032 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16033 last_location = last_message = NULL;
16034
16035 isolate1->Dispose();
16036 CHECK_EQ(last_location, NULL);
16037 CHECK_EQ(last_message, NULL);
16038
16039 isolate2->Dispose();
16040 CHECK_EQ(last_location, NULL);
16041 CHECK_EQ(last_message, NULL);
16042
16043 // Check that default isolate still runs.
16044 {
16045 v8::Context::Scope cscope(context_default);
16046 v8::HandleScope scope;
16047 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
16048 }
16049}
16050
16051static int CalcFibonacci(v8::Isolate* isolate, int limit) {
16052 v8::Isolate::Scope isolate_scope(isolate);
16053 v8::HandleScope scope;
16054 LocalContext context;
16055 i::ScopedVector<char> code(1024);
16056 i::OS::SNPrintF(code, "function fib(n) {"
16057 " if (n <= 2) return 1;"
16058 " return fib(n-1) + fib(n-2);"
16059 "}"
16060 "fib(%d)", limit);
16061 Local<Value> value = CompileRun(code.start());
16062 CHECK(value->IsNumber());
16063 return static_cast<int>(value->NumberValue());
16064}
16065
16066class IsolateThread : public v8::internal::Thread {
16067 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016068 IsolateThread(v8::Isolate* isolate, int fib_limit)
16069 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016070 isolate_(isolate),
16071 fib_limit_(fib_limit),
16072 result_(0) { }
16073
16074 void Run() {
16075 result_ = CalcFibonacci(isolate_, fib_limit_);
16076 }
16077
16078 int result() { return result_; }
16079
16080 private:
16081 v8::Isolate* isolate_;
16082 int fib_limit_;
16083 int result_;
16084};
16085
16086TEST(MultipleIsolatesOnIndividualThreads) {
16087 v8::Isolate* isolate1 = v8::Isolate::New();
16088 v8::Isolate* isolate2 = v8::Isolate::New();
16089
16090 IsolateThread thread1(isolate1, 21);
16091 IsolateThread thread2(isolate2, 12);
16092
16093 // Compute some fibonacci numbers on 3 threads in 3 isolates.
16094 thread1.Start();
16095 thread2.Start();
16096
16097 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
16098 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
16099
16100 thread1.Join();
16101 thread2.Join();
16102
16103 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
16104 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
16105 CHECK_EQ(result1, 10946);
16106 CHECK_EQ(result2, 144);
16107 CHECK_EQ(result1, thread1.result());
16108 CHECK_EQ(result2, thread2.result());
16109
16110 isolate1->Dispose();
16111 isolate2->Dispose();
16112}
16113
lrn@chromium.org1c092762011-05-09 09:42:16 +000016114TEST(IsolateDifferentContexts) {
16115 v8::Isolate* isolate = v8::Isolate::New();
16116 Persistent<v8::Context> context;
16117 {
16118 v8::Isolate::Scope isolate_scope(isolate);
16119 v8::HandleScope handle_scope;
16120 context = v8::Context::New();
16121 v8::Context::Scope context_scope(context);
16122 Local<Value> v = CompileRun("2");
16123 CHECK(v->IsNumber());
16124 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16125 }
16126 {
16127 v8::Isolate::Scope isolate_scope(isolate);
16128 v8::HandleScope handle_scope;
16129 context = v8::Context::New();
16130 v8::Context::Scope context_scope(context);
16131 Local<Value> v = CompileRun("22");
16132 CHECK(v->IsNumber());
16133 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16134 }
16135}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016136
16137class InitDefaultIsolateThread : public v8::internal::Thread {
16138 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016139 enum TestCase {
16140 IgnoreOOM,
16141 SetResourceConstraints,
16142 SetFatalHandler,
16143 SetCounterFunction,
16144 SetCreateHistogramFunction,
16145 SetAddHistogramSampleFunction
16146 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016147
16148 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016149 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016150 testCase_(testCase),
16151 result_(false) { }
16152
16153 void Run() {
16154 switch (testCase_) {
16155 case IgnoreOOM:
16156 v8::V8::IgnoreOutOfMemoryException();
16157 break;
16158
16159 case SetResourceConstraints: {
16160 static const int K = 1024;
16161 v8::ResourceConstraints constraints;
16162 constraints.set_max_young_space_size(256 * K);
16163 constraints.set_max_old_space_size(4 * K * K);
16164 v8::SetResourceConstraints(&constraints);
16165 break;
16166 }
16167
16168 case SetFatalHandler:
16169 v8::V8::SetFatalErrorHandler(NULL);
16170 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016171
16172 case SetCounterFunction:
16173 v8::V8::SetCounterFunction(NULL);
16174 break;
16175
16176 case SetCreateHistogramFunction:
16177 v8::V8::SetCreateHistogramFunction(NULL);
16178 break;
16179
16180 case SetAddHistogramSampleFunction:
16181 v8::V8::SetAddHistogramSampleFunction(NULL);
16182 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016183 }
16184 result_ = true;
16185 }
16186
16187 bool result() { return result_; }
16188
16189 private:
16190 TestCase testCase_;
16191 bool result_;
16192};
16193
16194
16195static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16196 InitDefaultIsolateThread thread(testCase);
16197 thread.Start();
16198 thread.Join();
16199 CHECK_EQ(thread.result(), true);
16200}
16201
16202TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16203 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16204}
16205
16206TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16207 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16208}
16209
16210TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16211 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16212}
16213
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016214TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16215 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16216}
16217
16218TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16219 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16220}
16221
16222TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16223 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16224}
16225
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016226
16227TEST(StringCheckMultipleContexts) {
16228 const char* code =
16229 "(function() { return \"a\".charAt(0); })()";
16230
16231 {
16232 // Run the code twice in the first context to initialize the call IC.
16233 v8::HandleScope scope;
16234 LocalContext context1;
16235 ExpectString(code, "a");
16236 ExpectString(code, "a");
16237 }
16238
16239 {
16240 // Change the String.prototype in the second context and check
16241 // that the right function gets called.
16242 v8::HandleScope scope;
16243 LocalContext context2;
16244 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16245 ExpectString(code, "not a");
16246 }
16247}
16248
16249
16250TEST(NumberCheckMultipleContexts) {
16251 const char* code =
16252 "(function() { return (42).toString(); })()";
16253
16254 {
16255 // Run the code twice in the first context to initialize the call IC.
16256 v8::HandleScope scope;
16257 LocalContext context1;
16258 ExpectString(code, "42");
16259 ExpectString(code, "42");
16260 }
16261
16262 {
16263 // Change the Number.prototype in the second context and check
16264 // that the right function gets called.
16265 v8::HandleScope scope;
16266 LocalContext context2;
16267 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16268 ExpectString(code, "not 42");
16269 }
16270}
16271
16272
16273TEST(BooleanCheckMultipleContexts) {
16274 const char* code =
16275 "(function() { return true.toString(); })()";
16276
16277 {
16278 // Run the code twice in the first context to initialize the call IC.
16279 v8::HandleScope scope;
16280 LocalContext context1;
16281 ExpectString(code, "true");
16282 ExpectString(code, "true");
16283 }
16284
16285 {
16286 // Change the Boolean.prototype in the second context and check
16287 // that the right function gets called.
16288 v8::HandleScope scope;
16289 LocalContext context2;
16290 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16291 ExpectString(code, "");
16292 }
16293}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016294
16295
16296TEST(DontDeleteCellLoadIC) {
16297 const char* function_code =
16298 "function readCell() { while (true) { return cell; } }";
16299
16300 {
16301 // Run the code twice in the first context to initialize the load
16302 // IC for a don't delete cell.
16303 v8::HandleScope scope;
16304 LocalContext context1;
16305 CompileRun("var cell = \"first\";");
16306 ExpectBoolean("delete cell", false);
16307 CompileRun(function_code);
16308 ExpectString("readCell()", "first");
16309 ExpectString("readCell()", "first");
16310 }
16311
16312 {
16313 // Use a deletable cell in the second context.
16314 v8::HandleScope scope;
16315 LocalContext context2;
16316 CompileRun("cell = \"second\";");
16317 CompileRun(function_code);
16318 ExpectString("readCell()", "second");
16319 ExpectBoolean("delete cell", true);
16320 ExpectString("(function() {"
16321 " try {"
16322 " return readCell();"
16323 " } catch(e) {"
16324 " return e.toString();"
16325 " }"
16326 "})()",
16327 "ReferenceError: cell is not defined");
16328 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016329 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016330 ExpectString("readCell()", "new_second");
16331 ExpectString("readCell()", "new_second");
16332 }
16333}
16334
16335
16336TEST(DontDeleteCellLoadICForceDelete) {
16337 const char* function_code =
16338 "function readCell() { while (true) { return cell; } }";
16339
16340 // Run the code twice to initialize the load IC for a don't delete
16341 // cell.
16342 v8::HandleScope scope;
16343 LocalContext context;
16344 CompileRun("var cell = \"value\";");
16345 ExpectBoolean("delete cell", false);
16346 CompileRun(function_code);
16347 ExpectString("readCell()", "value");
16348 ExpectString("readCell()", "value");
16349
16350 // Delete the cell using the API and check the inlined code works
16351 // correctly.
16352 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16353 ExpectString("(function() {"
16354 " try {"
16355 " return readCell();"
16356 " } catch(e) {"
16357 " return e.toString();"
16358 " }"
16359 "})()",
16360 "ReferenceError: cell is not defined");
16361}
16362
16363
16364TEST(DontDeleteCellLoadICAPI) {
16365 const char* function_code =
16366 "function readCell() { while (true) { return cell; } }";
16367
16368 // Run the code twice to initialize the load IC for a don't delete
16369 // cell created using the API.
16370 v8::HandleScope scope;
16371 LocalContext context;
16372 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16373 ExpectBoolean("delete cell", false);
16374 CompileRun(function_code);
16375 ExpectString("readCell()", "value");
16376 ExpectString("readCell()", "value");
16377
16378 // Delete the cell using the API and check the inlined code works
16379 // correctly.
16380 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16381 ExpectString("(function() {"
16382 " try {"
16383 " return readCell();"
16384 " } catch(e) {"
16385 " return e.toString();"
16386 " }"
16387 "})()",
16388 "ReferenceError: cell is not defined");
16389}
16390
16391
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016392class Visitor42 : public v8::PersistentHandleVisitor {
16393 public:
16394 explicit Visitor42(v8::Persistent<v8::Object> object)
16395 : counter_(0), object_(object) { }
16396
16397 virtual void VisitPersistentHandle(Persistent<Value> value,
16398 uint16_t class_id) {
16399 if (class_id == 42) {
16400 CHECK(value->IsObject());
16401 v8::Persistent<v8::Object> visited =
16402 v8::Persistent<v8::Object>::Cast(value);
16403 CHECK_EQ(42, visited.WrapperClassId());
16404 CHECK_EQ(object_, visited);
16405 ++counter_;
16406 }
16407 }
16408
16409 int counter_;
16410 v8::Persistent<v8::Object> object_;
16411};
16412
16413
16414TEST(PersistentHandleVisitor) {
16415 v8::HandleScope scope;
16416 LocalContext context;
16417 v8::Persistent<v8::Object> object =
16418 v8::Persistent<v8::Object>::New(v8::Object::New());
16419 CHECK_EQ(0, object.WrapperClassId());
16420 object.SetWrapperClassId(42);
16421 CHECK_EQ(42, object.WrapperClassId());
16422
16423 Visitor42 visitor(object);
16424 v8::V8::VisitHandlesWithClassIds(&visitor);
16425 CHECK_EQ(1, visitor.counter_);
16426
16427 object.Dispose();
16428}
16429
16430
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016431TEST(RegExp) {
16432 v8::HandleScope scope;
16433 LocalContext context;
16434
16435 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16436 CHECK(re->IsRegExp());
16437 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016438 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016439
16440 re = v8::RegExp::New(v8_str("bar"),
16441 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16442 v8::RegExp::kGlobal));
16443 CHECK(re->IsRegExp());
16444 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016445 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16446 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016447
16448 re = v8::RegExp::New(v8_str("baz"),
16449 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16450 v8::RegExp::kMultiline));
16451 CHECK(re->IsRegExp());
16452 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016453 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16454 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016455
16456 re = CompileRun("/quux/").As<v8::RegExp>();
16457 CHECK(re->IsRegExp());
16458 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016459 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016460
16461 re = CompileRun("/quux/gm").As<v8::RegExp>();
16462 CHECK(re->IsRegExp());
16463 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016464 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16465 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016466
16467 // Override the RegExp constructor and check the API constructor
16468 // still works.
16469 CompileRun("RegExp = function() {}");
16470
16471 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16472 CHECK(re->IsRegExp());
16473 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016474 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016475
16476 re = v8::RegExp::New(v8_str("foobarbaz"),
16477 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16478 v8::RegExp::kMultiline));
16479 CHECK(re->IsRegExp());
16480 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016481 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16482 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016483
16484 context->Global()->Set(v8_str("re"), re);
16485 ExpectTrue("re.test('FoobarbaZ')");
16486
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016487 // RegExps are objects on which you can set properties.
16488 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016489 v8::Handle<v8::Value> value(CompileRun("re.property"));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000016490 CHECK_EQ(32, value->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016491
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016492 v8::TryCatch try_catch;
16493 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16494 CHECK(re.IsEmpty());
16495 CHECK(try_catch.HasCaught());
16496 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16497 ExpectTrue("ex instanceof SyntaxError");
16498}
16499
16500
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016501THREADED_TEST(Equals) {
16502 v8::HandleScope handleScope;
16503 LocalContext localContext;
16504
16505 v8::Handle<v8::Object> globalProxy = localContext->Global();
16506 v8::Handle<Value> global = globalProxy->GetPrototype();
16507
16508 CHECK(global->StrictEquals(global));
16509 CHECK(!global->StrictEquals(globalProxy));
16510 CHECK(!globalProxy->StrictEquals(global));
16511 CHECK(globalProxy->StrictEquals(globalProxy));
16512
16513 CHECK(global->Equals(global));
16514 CHECK(!global->Equals(globalProxy));
16515 CHECK(!globalProxy->Equals(global));
16516 CHECK(globalProxy->Equals(globalProxy));
16517}
16518
16519
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016520static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16521 const v8::AccessorInfo& info ) {
16522 return v8_str("42!");
16523}
16524
16525
16526static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16527 v8::Handle<v8::Array> result = v8::Array::New();
16528 result->Set(0, v8_str("universalAnswer"));
16529 return result;
16530}
16531
16532
16533TEST(NamedEnumeratorAndForIn) {
16534 v8::HandleScope handle_scope;
16535 LocalContext context;
16536 v8::Context::Scope context_scope(context.local());
16537
16538 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16539 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16540 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16541 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16542 "var result = []; for (var k in o) result.push(k); result"));
16543 CHECK_EQ(1, result->Length());
16544 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16545}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016546
16547
16548TEST(DefinePropertyPostDetach) {
16549 v8::HandleScope scope;
16550 LocalContext context;
16551 v8::Handle<v8::Object> proxy = context->Global();
16552 v8::Handle<v8::Function> define_property =
16553 CompileRun("(function() {"
16554 " Object.defineProperty("
16555 " this,"
16556 " 1,"
16557 " { configurable: true, enumerable: true, value: 3 });"
16558 "})").As<Function>();
16559 context->DetachGlobal();
16560 define_property->Call(proxy, 0, NULL);
16561}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016562
16563
16564static void InstallContextId(v8::Handle<Context> context, int id) {
16565 Context::Scope scope(context);
16566 CompileRun("Object.prototype").As<Object>()->
16567 Set(v8_str("context_id"), v8::Integer::New(id));
16568}
16569
16570
16571static void CheckContextId(v8::Handle<Object> object, int expected) {
16572 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16573}
16574
16575
16576THREADED_TEST(CreationContext) {
16577 HandleScope handle_scope;
16578 Persistent<Context> context1 = Context::New();
16579 InstallContextId(context1, 1);
16580 Persistent<Context> context2 = Context::New();
16581 InstallContextId(context2, 2);
16582 Persistent<Context> context3 = Context::New();
16583 InstallContextId(context3, 3);
16584
16585 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16586
16587 Local<Object> object1;
16588 Local<Function> func1;
16589 {
16590 Context::Scope scope(context1);
16591 object1 = Object::New();
16592 func1 = tmpl->GetFunction();
16593 }
16594
16595 Local<Object> object2;
16596 Local<Function> func2;
16597 {
16598 Context::Scope scope(context2);
16599 object2 = Object::New();
16600 func2 = tmpl->GetFunction();
16601 }
16602
16603 Local<Object> instance1;
16604 Local<Object> instance2;
16605
16606 {
16607 Context::Scope scope(context3);
16608 instance1 = func1->NewInstance();
16609 instance2 = func2->NewInstance();
16610 }
16611
16612 CHECK(object1->CreationContext() == context1);
16613 CheckContextId(object1, 1);
16614 CHECK(func1->CreationContext() == context1);
16615 CheckContextId(func1, 1);
16616 CHECK(instance1->CreationContext() == context1);
16617 CheckContextId(instance1, 1);
16618 CHECK(object2->CreationContext() == context2);
16619 CheckContextId(object2, 2);
16620 CHECK(func2->CreationContext() == context2);
16621 CheckContextId(func2, 2);
16622 CHECK(instance2->CreationContext() == context2);
16623 CheckContextId(instance2, 2);
16624
16625 {
16626 Context::Scope scope(context1);
16627 CHECK(object1->CreationContext() == context1);
16628 CheckContextId(object1, 1);
16629 CHECK(func1->CreationContext() == context1);
16630 CheckContextId(func1, 1);
16631 CHECK(instance1->CreationContext() == context1);
16632 CheckContextId(instance1, 1);
16633 CHECK(object2->CreationContext() == context2);
16634 CheckContextId(object2, 2);
16635 CHECK(func2->CreationContext() == context2);
16636 CheckContextId(func2, 2);
16637 CHECK(instance2->CreationContext() == context2);
16638 CheckContextId(instance2, 2);
16639 }
16640
16641 {
16642 Context::Scope scope(context2);
16643 CHECK(object1->CreationContext() == context1);
16644 CheckContextId(object1, 1);
16645 CHECK(func1->CreationContext() == context1);
16646 CheckContextId(func1, 1);
16647 CHECK(instance1->CreationContext() == context1);
16648 CheckContextId(instance1, 1);
16649 CHECK(object2->CreationContext() == context2);
16650 CheckContextId(object2, 2);
16651 CHECK(func2->CreationContext() == context2);
16652 CheckContextId(func2, 2);
16653 CHECK(instance2->CreationContext() == context2);
16654 CheckContextId(instance2, 2);
16655 }
16656
16657 context1.Dispose();
16658 context2.Dispose();
16659 context3.Dispose();
16660}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016661
16662
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000016663THREADED_TEST(CreationContextOfJsFunction) {
16664 HandleScope handle_scope;
16665 Persistent<Context> context = Context::New();
16666 InstallContextId(context, 1);
16667
16668 Local<Object> function;
16669 {
16670 Context::Scope scope(context);
16671 function = CompileRun("function foo() {}; foo").As<Object>();
16672 }
16673
16674 CHECK(function->CreationContext() == context);
16675 CheckContextId(function, 1);
16676
16677 context.Dispose();
16678}
16679
16680
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000016681Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
16682 const AccessorInfo& info) {
16683 if (index == 42) return v8_str("yes");
16684 return Handle<v8::Integer>();
16685}
16686
16687
16688Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
16689 const AccessorInfo& info) {
16690 if (property->Equals(v8_str("foo"))) return v8_str("yes");
16691 return Handle<Value>();
16692}
16693
16694
16695Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
16696 uint32_t index, const AccessorInfo& info) {
16697 if (index == 42) return v8_num(1).As<v8::Integer>();
16698 return Handle<v8::Integer>();
16699}
16700
16701
16702Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
16703 Local<String> property, const AccessorInfo& info) {
16704 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
16705 return Handle<v8::Integer>();
16706}
16707
16708
16709Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
16710 Local<String> property, const AccessorInfo& info) {
16711 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
16712 return Handle<v8::Integer>();
16713}
16714
16715
16716Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
16717 const AccessorInfo& info) {
16718 return v8_str("yes");
16719}
16720
16721
16722TEST(HasOwnProperty) {
16723 v8::HandleScope scope;
16724 LocalContext env;
16725 { // Check normal properties and defined getters.
16726 Handle<Value> value = CompileRun(
16727 "function Foo() {"
16728 " this.foo = 11;"
16729 " this.__defineGetter__('baz', function() { return 1; });"
16730 "};"
16731 "function Bar() { "
16732 " this.bar = 13;"
16733 " this.__defineGetter__('bla', function() { return 2; });"
16734 "};"
16735 "Bar.prototype = new Foo();"
16736 "new Bar();");
16737 CHECK(value->IsObject());
16738 Handle<Object> object = value->ToObject();
16739 CHECK(object->Has(v8_str("foo")));
16740 CHECK(!object->HasOwnProperty(v8_str("foo")));
16741 CHECK(object->HasOwnProperty(v8_str("bar")));
16742 CHECK(object->Has(v8_str("baz")));
16743 CHECK(!object->HasOwnProperty(v8_str("baz")));
16744 CHECK(object->HasOwnProperty(v8_str("bla")));
16745 }
16746 { // Check named getter interceptors.
16747 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16748 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
16749 Handle<Object> instance = templ->NewInstance();
16750 CHECK(!instance->HasOwnProperty(v8_str("42")));
16751 CHECK(instance->HasOwnProperty(v8_str("foo")));
16752 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16753 }
16754 { // Check indexed getter interceptors.
16755 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16756 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
16757 Handle<Object> instance = templ->NewInstance();
16758 CHECK(instance->HasOwnProperty(v8_str("42")));
16759 CHECK(!instance->HasOwnProperty(v8_str("43")));
16760 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16761 }
16762 { // Check named query interceptors.
16763 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16764 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
16765 Handle<Object> instance = templ->NewInstance();
16766 CHECK(instance->HasOwnProperty(v8_str("foo")));
16767 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16768 }
16769 { // Check indexed query interceptors.
16770 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16771 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
16772 Handle<Object> instance = templ->NewInstance();
16773 CHECK(instance->HasOwnProperty(v8_str("42")));
16774 CHECK(!instance->HasOwnProperty(v8_str("41")));
16775 }
16776 { // Check callbacks.
16777 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16778 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
16779 Handle<Object> instance = templ->NewInstance();
16780 CHECK(instance->HasOwnProperty(v8_str("foo")));
16781 CHECK(!instance->HasOwnProperty(v8_str("bar")));
16782 }
16783 { // Check that query wins on disagreement.
16784 Handle<ObjectTemplate> templ = ObjectTemplate::New();
16785 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
16786 0,
16787 HasOwnPropertyNamedPropertyQuery2);
16788 Handle<Object> instance = templ->NewInstance();
16789 CHECK(!instance->HasOwnProperty(v8_str("foo")));
16790 CHECK(instance->HasOwnProperty(v8_str("bar")));
16791 }
16792}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016793
16794
16795void CheckCodeGenerationAllowed() {
16796 Handle<Value> result = CompileRun("eval('42')");
16797 CHECK_EQ(42, result->Int32Value());
16798 result = CompileRun("(function(e) { return e('42'); })(eval)");
16799 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016800 result = CompileRun("var f = new Function('return 42'); f()");
16801 CHECK_EQ(42, result->Int32Value());
16802}
16803
16804
16805void CheckCodeGenerationDisallowed() {
16806 TryCatch try_catch;
16807
16808 Handle<Value> result = CompileRun("eval('42')");
16809 CHECK(result.IsEmpty());
16810 CHECK(try_catch.HasCaught());
16811 try_catch.Reset();
16812
16813 result = CompileRun("(function(e) { return e('42'); })(eval)");
16814 CHECK(result.IsEmpty());
16815 CHECK(try_catch.HasCaught());
16816 try_catch.Reset();
16817
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016818 result = CompileRun("var f = new Function('return 42'); f()");
16819 CHECK(result.IsEmpty());
16820 CHECK(try_catch.HasCaught());
16821}
16822
16823
16824bool CodeGenerationAllowed(Local<Context> context) {
16825 ApiTestFuzzer::Fuzz();
16826 return true;
16827}
16828
16829
16830bool CodeGenerationDisallowed(Local<Context> context) {
16831 ApiTestFuzzer::Fuzz();
16832 return false;
16833}
16834
16835
16836THREADED_TEST(AllowCodeGenFromStrings) {
16837 v8::HandleScope scope;
16838 LocalContext context;
16839
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016840 // eval and the Function constructor allowed by default.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016841 CHECK(context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016842 CheckCodeGenerationAllowed();
16843
ager@chromium.orgea91cc52011-05-23 06:06:11 +000016844 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016845 context->AllowCodeGenerationFromStrings(false);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016846 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016847 CheckCodeGenerationDisallowed();
16848
16849 // Allow again.
16850 context->AllowCodeGenerationFromStrings(true);
16851 CheckCodeGenerationAllowed();
16852
16853 // Disallow but setting a global callback that will allow the calls.
16854 context->AllowCodeGenerationFromStrings(false);
16855 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016856 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016857 CheckCodeGenerationAllowed();
16858
16859 // Set a callback that disallows the code generation.
16860 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000016861 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016862 CheckCodeGenerationDisallowed();
16863}
lrn@chromium.org1c092762011-05-09 09:42:16 +000016864
16865
ulan@chromium.org56c14af2012-09-20 12:51:09 +000016866TEST(SetErrorMessageForCodeGenFromStrings) {
16867 v8::HandleScope scope;
16868 LocalContext context;
16869 TryCatch try_catch;
16870
16871 Handle<String> message = v8_str("Message") ;
16872 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
16873 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
16874 context->AllowCodeGenerationFromStrings(false);
16875 context->SetErrorMessageForCodeGenerationFromStrings(message);
16876 Handle<Value> result = CompileRun("eval('42')");
16877 CHECK(result.IsEmpty());
16878 CHECK(try_catch.HasCaught());
16879 Handle<String> actual_message = try_catch.Message()->Get();
16880 CHECK(expected_message->Equals(actual_message));
16881}
16882
16883
lrn@chromium.org1c092762011-05-09 09:42:16 +000016884static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
16885 return v8::Undefined();
16886}
16887
16888
16889THREADED_TEST(CallAPIFunctionOnNonObject) {
16890 v8::HandleScope scope;
16891 LocalContext context;
16892 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
16893 Handle<Function> function = templ->GetFunction();
16894 context->Global()->Set(v8_str("f"), function);
16895 TryCatch try_catch;
16896 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000016897}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016898
16899
16900// Regression test for issue 1470.
16901THREADED_TEST(ReadOnlyIndexedProperties) {
16902 v8::HandleScope scope;
16903 Local<ObjectTemplate> templ = ObjectTemplate::New();
16904
16905 LocalContext context;
16906 Local<v8::Object> obj = templ->NewInstance();
16907 context->Global()->Set(v8_str("obj"), obj);
16908 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16909 obj->Set(v8_str("1"), v8_str("foobar"));
16910 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
16911 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
16912 obj->Set(v8_num(2), v8_str("foobar"));
16913 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
16914
16915 // Test non-smi case.
16916 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
16917 obj->Set(v8_str("2000000000"), v8_str("foobar"));
16918 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
16919}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000016920
16921
16922THREADED_TEST(Regress1516) {
16923 v8::HandleScope scope;
16924
16925 LocalContext context;
16926 { v8::HandleScope temp_scope;
16927 CompileRun("({'a': 0})");
16928 }
16929
16930 int elements;
16931 { i::MapCache* map_cache =
16932 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
16933 elements = map_cache->NumberOfElements();
16934 CHECK_LE(1, elements);
16935 }
16936
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +000016937 i::Isolate::Current()->heap()->CollectAllGarbage(
16938 i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000016939 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
16940 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
16941 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
16942 CHECK_GT(elements, map_cache->NumberOfElements());
16943 }
16944 }
16945}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016946
16947
16948static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
16949 Local<Value> name,
16950 v8::AccessType type,
16951 Local<Value> data) {
16952 // Only block read access to __proto__.
16953 if (type == v8::ACCESS_GET &&
16954 name->IsString() &&
16955 name->ToString()->Length() == 9 &&
16956 name->ToString()->Utf8Length() == 9) {
16957 char buffer[10];
16958 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
16959 return strncmp(buffer, "__proto__", 9) != 0;
16960 }
16961
16962 return true;
16963}
16964
16965
16966THREADED_TEST(Regress93759) {
16967 HandleScope scope;
16968
16969 // Template for object with security check.
16970 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
16971 // We don't do indexing, so any callback can be used for that.
16972 no_proto_template->SetAccessCheckCallbacks(
16973 BlockProtoNamedSecurityTestCallback,
16974 IndexedSecurityTestCallback);
16975
16976 // Templates for objects with hidden prototypes and possibly security check.
16977 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
16978 hidden_proto_template->SetHiddenPrototype(true);
16979
16980 Local<FunctionTemplate> protected_hidden_proto_template =
16981 v8::FunctionTemplate::New();
16982 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
16983 BlockProtoNamedSecurityTestCallback,
16984 IndexedSecurityTestCallback);
16985 protected_hidden_proto_template->SetHiddenPrototype(true);
16986
16987 // Context for "foreign" objects used in test.
16988 Persistent<Context> context = v8::Context::New();
16989 context->Enter();
16990
16991 // Plain object, no security check.
16992 Local<Object> simple_object = Object::New();
16993
16994 // Object with explicit security check.
16995 Local<Object> protected_object =
16996 no_proto_template->NewInstance();
16997
16998 // JSGlobalProxy object, always have security check.
16999 Local<Object> proxy_object =
17000 context->Global();
17001
17002 // Global object, the prototype of proxy_object. No security checks.
17003 Local<Object> global_object =
17004 proxy_object->GetPrototype()->ToObject();
17005
17006 // Hidden prototype without security check.
17007 Local<Object> hidden_prototype =
17008 hidden_proto_template->GetFunction()->NewInstance();
17009 Local<Object> object_with_hidden =
17010 Object::New();
17011 object_with_hidden->SetPrototype(hidden_prototype);
17012
17013 // Hidden prototype with security check on the hidden prototype.
17014 Local<Object> protected_hidden_prototype =
17015 protected_hidden_proto_template->GetFunction()->NewInstance();
17016 Local<Object> object_with_protected_hidden =
17017 Object::New();
17018 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
17019
17020 context->Exit();
17021
17022 // Template for object for second context. Values to test are put on it as
17023 // properties.
17024 Local<ObjectTemplate> global_template = ObjectTemplate::New();
17025 global_template->Set(v8_str("simple"), simple_object);
17026 global_template->Set(v8_str("protected"), protected_object);
17027 global_template->Set(v8_str("global"), global_object);
17028 global_template->Set(v8_str("proxy"), proxy_object);
17029 global_template->Set(v8_str("hidden"), object_with_hidden);
17030 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
17031
17032 LocalContext context2(NULL, global_template);
17033
17034 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
17035 CHECK(result1->Equals(simple_object->GetPrototype()));
17036
17037 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
17038 CHECK(result2->Equals(Undefined()));
17039
17040 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
17041 CHECK(result3->Equals(global_object->GetPrototype()));
17042
17043 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
17044 CHECK(result4->Equals(Undefined()));
17045
17046 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
17047 CHECK(result5->Equals(
17048 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
17049
17050 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
17051 CHECK(result6->Equals(Undefined()));
17052
17053 context.Dispose();
17054}
17055
17056
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017057THREADED_TEST(Regress125988) {
17058 v8::HandleScope scope;
17059 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
17060 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
17061 LocalContext env;
17062 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
17063 CompileRun("var a = new Object();"
17064 "var b = new Intercept();"
17065 "var c = new Object();"
17066 "c.__proto__ = b;"
17067 "b.__proto__ = a;"
17068 "a.x = 23;"
17069 "for (var i = 0; i < 3; i++) c.x;");
17070 ExpectBoolean("c.hasOwnProperty('x')", false);
17071 ExpectInt32("c.x", 23);
17072 CompileRun("a.y = 42;"
17073 "for (var i = 0; i < 3; i++) c.x;");
17074 ExpectBoolean("c.hasOwnProperty('x')", false);
17075 ExpectInt32("c.x", 23);
17076 ExpectBoolean("c.hasOwnProperty('y')", false);
17077 ExpectInt32("c.y", 42);
17078}
17079
17080
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017081static void TestReceiver(Local<Value> expected_result,
17082 Local<Value> expected_receiver,
17083 const char* code) {
17084 Local<Value> result = CompileRun(code);
17085 CHECK(result->IsObject());
17086 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
17087 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
17088}
17089
17090
17091THREADED_TEST(ForeignFunctionReceiver) {
17092 HandleScope scope;
17093
17094 // Create two contexts with different "id" properties ('i' and 'o').
17095 // Call a function both from its own context and from a the foreign
17096 // context, and see what "this" is bound to (returning both "this"
17097 // and "this.id" for comparison).
17098
17099 Persistent<Context> foreign_context = v8::Context::New();
17100 foreign_context->Enter();
17101 Local<Value> foreign_function =
17102 CompileRun("function func() { return { 0: this.id, "
17103 " 1: this, "
17104 " toString: function() { "
17105 " return this[0];"
17106 " }"
17107 " };"
17108 "}"
17109 "var id = 'i';"
17110 "func;");
17111 CHECK(foreign_function->IsFunction());
17112 foreign_context->Exit();
17113
17114 LocalContext context;
17115
17116 Local<String> password = v8_str("Password");
17117 // Don't get hit by security checks when accessing foreign_context's
17118 // global receiver (aka. global proxy).
17119 context->SetSecurityToken(password);
17120 foreign_context->SetSecurityToken(password);
17121
17122 Local<String> i = v8_str("i");
17123 Local<String> o = v8_str("o");
17124 Local<String> id = v8_str("id");
17125
17126 CompileRun("function ownfunc() { return { 0: this.id, "
17127 " 1: this, "
17128 " toString: function() { "
17129 " return this[0];"
17130 " }"
17131 " };"
17132 "}"
17133 "var id = 'o';"
17134 "ownfunc");
17135 context->Global()->Set(v8_str("func"), foreign_function);
17136
17137 // Sanity check the contexts.
17138 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17139 CHECK(o->Equals(context->Global()->Get(id)));
17140
17141 // Checking local function's receiver.
17142 // Calling function using its call/apply methods.
17143 TestReceiver(o, context->Global(), "ownfunc.call()");
17144 TestReceiver(o, context->Global(), "ownfunc.apply()");
17145 // Making calls through built-in functions.
17146 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17147 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17148 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17149 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17150 // Calling with environment record as base.
17151 TestReceiver(o, context->Global(), "ownfunc()");
17152 // Calling with no base.
17153 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17154
17155 // Checking foreign function return value.
17156 // Calling function using its call/apply methods.
17157 TestReceiver(i, foreign_context->Global(), "func.call()");
17158 TestReceiver(i, foreign_context->Global(), "func.apply()");
17159 // Calling function using another context's call/apply methods.
17160 TestReceiver(i, foreign_context->Global(),
17161 "Function.prototype.call.call(func)");
17162 TestReceiver(i, foreign_context->Global(),
17163 "Function.prototype.call.apply(func)");
17164 TestReceiver(i, foreign_context->Global(),
17165 "Function.prototype.apply.call(func)");
17166 TestReceiver(i, foreign_context->Global(),
17167 "Function.prototype.apply.apply(func)");
17168 // Making calls through built-in functions.
17169 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17170 // ToString(func()) is func()[0], i.e., the returned this.id.
17171 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17172 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17173 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17174
17175 // TODO(1547): Make the following also return "i".
17176 // Calling with environment record as base.
17177 TestReceiver(o, context->Global(), "func()");
17178 // Calling with no base.
17179 TestReceiver(o, context->Global(), "(1,func)()");
17180
17181 foreign_context.Dispose();
17182}
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017183
17184
17185uint8_t callback_fired = 0;
17186
17187
17188void CallCompletedCallback1() {
17189 i::OS::Print("Firing callback 1.\n");
17190 callback_fired ^= 1; // Toggle first bit.
17191}
17192
17193
17194void CallCompletedCallback2() {
17195 i::OS::Print("Firing callback 2.\n");
17196 callback_fired ^= 2; // Toggle second bit.
17197}
17198
17199
17200Handle<Value> RecursiveCall(const Arguments& args) {
17201 int32_t level = args[0]->Int32Value();
17202 if (level < 3) {
17203 level++;
17204 i::OS::Print("Entering recursion level %d.\n", level);
17205 char script[64];
17206 i::Vector<char> script_vector(script, sizeof(script));
17207 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17208 CompileRun(script_vector.start());
17209 i::OS::Print("Leaving recursion level %d.\n", level);
17210 CHECK_EQ(0, callback_fired);
17211 } else {
17212 i::OS::Print("Recursion ends.\n");
17213 CHECK_EQ(0, callback_fired);
17214 }
17215 return Undefined();
17216}
17217
17218
17219TEST(CallCompletedCallback) {
17220 v8::HandleScope scope;
17221 LocalContext env;
17222 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17223 v8::FunctionTemplate::New(RecursiveCall);
17224 env->Global()->Set(v8_str("recursion"),
17225 recursive_runtime->GetFunction());
17226 // Adding the same callback a second time has no effect.
17227 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17228 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17229 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17230 i::OS::Print("--- Script (1) ---\n");
17231 Local<Script> script =
17232 v8::Script::Compile(v8::String::New("recursion(0)"));
17233 script->Run();
17234 CHECK_EQ(3, callback_fired);
17235
17236 i::OS::Print("\n--- Script (2) ---\n");
17237 callback_fired = 0;
17238 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17239 script->Run();
17240 CHECK_EQ(2, callback_fired);
17241
17242 i::OS::Print("\n--- Function ---\n");
17243 callback_fired = 0;
17244 Local<Function> recursive_function =
17245 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17246 v8::Handle<Value> args[] = { v8_num(0) };
17247 recursive_function->Call(env->Global(), 1, args);
17248 CHECK_EQ(2, callback_fired);
17249}
17250
17251
17252void CallCompletedCallbackNoException() {
17253 v8::HandleScope scope;
17254 CompileRun("1+1;");
17255}
17256
17257
17258void CallCompletedCallbackException() {
17259 v8::HandleScope scope;
17260 CompileRun("throw 'second exception';");
17261}
17262
17263
17264TEST(CallCompletedCallbackOneException) {
17265 v8::HandleScope scope;
17266 LocalContext env;
17267 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17268 CompileRun("throw 'exception';");
17269}
17270
17271
17272TEST(CallCompletedCallbackTwoExceptions) {
17273 v8::HandleScope scope;
17274 LocalContext env;
17275 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17276 CompileRun("throw 'first exception';");
17277}
ulan@chromium.org812308e2012-02-29 15:58:45 +000017278
17279
17280static int probes_counter = 0;
17281static int misses_counter = 0;
17282static int updates_counter = 0;
17283
17284
17285static int* LookupCounter(const char* name) {
17286 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17287 return &probes_counter;
17288 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17289 return &misses_counter;
17290 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17291 return &updates_counter;
17292 }
17293 return NULL;
17294}
17295
17296
17297static const char* kMegamorphicTestProgram =
17298 "function ClassA() { };"
17299 "function ClassB() { };"
17300 "ClassA.prototype.foo = function() { };"
17301 "ClassB.prototype.foo = function() { };"
17302 "function fooify(obj) { obj.foo(); };"
17303 "var a = new ClassA();"
17304 "var b = new ClassB();"
17305 "for (var i = 0; i < 10000; i++) {"
17306 " fooify(a);"
17307 " fooify(b);"
17308 "}";
17309
17310
17311static void StubCacheHelper(bool primary) {
17312 V8::SetCounterFunction(LookupCounter);
17313 USE(kMegamorphicTestProgram);
17314#ifdef DEBUG
17315 i::FLAG_native_code_counters = true;
17316 if (primary) {
17317 i::FLAG_test_primary_stub_cache = true;
17318 } else {
17319 i::FLAG_test_secondary_stub_cache = true;
17320 }
17321 i::FLAG_crankshaft = false;
17322 v8::HandleScope scope;
17323 LocalContext env;
17324 int initial_probes = probes_counter;
17325 int initial_misses = misses_counter;
17326 int initial_updates = updates_counter;
17327 CompileRun(kMegamorphicTestProgram);
17328 int probes = probes_counter - initial_probes;
17329 int misses = misses_counter - initial_misses;
17330 int updates = updates_counter - initial_updates;
17331 CHECK_LT(updates, 10);
17332 CHECK_LT(misses, 10);
17333 CHECK_GE(probes, 10000);
17334#endif
17335}
17336
17337
17338TEST(SecondaryStubCache) {
17339 StubCacheHelper(true);
17340}
17341
17342
17343TEST(PrimaryStubCache) {
17344 StubCacheHelper(false);
17345}
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017346
17347
17348static int fatal_error_callback_counter = 0;
17349static void CountingErrorCallback(const char* location, const char* message) {
17350 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17351 fatal_error_callback_counter++;
17352}
17353
17354
17355TEST(StaticGetters) {
17356 v8::HandleScope scope;
17357 LocalContext context;
17358 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17359 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17360 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17361 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17362 i::Handle<i::Object> null_value = FACTORY->null_value();
17363 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17364 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17365 i::Handle<i::Object> true_value = FACTORY->true_value();
17366 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17367 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17368 i::Handle<i::Object> false_value = FACTORY->false_value();
17369 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17370 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17371
17372 // Test after-death behavior.
17373 CHECK(i::Internals::IsInitialized(isolate));
17374 CHECK_EQ(0, fatal_error_callback_counter);
17375 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17376 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17377 i::Isolate::Current()->TearDown();
17378 CHECK(!i::Internals::IsInitialized(isolate));
17379 CHECK_EQ(1, fatal_error_callback_counter);
17380 CHECK(v8::Undefined().IsEmpty());
17381 CHECK_EQ(2, fatal_error_callback_counter);
17382 CHECK(v8::Undefined(isolate).IsEmpty());
17383 CHECK_EQ(3, fatal_error_callback_counter);
17384 CHECK(v8::Null().IsEmpty());
17385 CHECK_EQ(4, fatal_error_callback_counter);
17386 CHECK(v8::Null(isolate).IsEmpty());
17387 CHECK_EQ(5, fatal_error_callback_counter);
17388 CHECK(v8::True().IsEmpty());
17389 CHECK_EQ(6, fatal_error_callback_counter);
17390 CHECK(v8::True(isolate).IsEmpty());
17391 CHECK_EQ(7, fatal_error_callback_counter);
17392 CHECK(v8::False().IsEmpty());
17393 CHECK_EQ(8, fatal_error_callback_counter);
17394 CHECK(v8::False(isolate).IsEmpty());
17395 CHECK_EQ(9, fatal_error_callback_counter);
17396}
17397
17398
17399TEST(IsolateEmbedderData) {
17400 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17401 CHECK_EQ(NULL, isolate->GetData());
17402 CHECK_EQ(NULL, ISOLATE->GetData());
17403 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17404 isolate->SetData(data1);
17405 CHECK_EQ(data1, isolate->GetData());
17406 CHECK_EQ(data1, ISOLATE->GetData());
17407 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17408 ISOLATE->SetData(data2);
17409 CHECK_EQ(data2, isolate->GetData());
17410 CHECK_EQ(data2, ISOLATE->GetData());
17411 ISOLATE->TearDown();
17412 CHECK_EQ(data2, isolate->GetData());
17413 CHECK_EQ(data2, ISOLATE->GetData());
17414}
17415
17416
17417TEST(StringEmpty) {
17418 v8::HandleScope scope;
17419 LocalContext context;
17420 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17421 i::Handle<i::Object> empty_string = FACTORY->empty_symbol();
17422 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17423 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17424
17425 // Test after-death behavior.
17426 CHECK(i::Internals::IsInitialized(isolate));
17427 CHECK_EQ(0, fatal_error_callback_counter);
17428 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17429 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17430 i::Isolate::Current()->TearDown();
17431 CHECK(!i::Internals::IsInitialized(isolate));
17432 CHECK_EQ(1, fatal_error_callback_counter);
17433 CHECK(v8::String::Empty().IsEmpty());
17434 CHECK_EQ(2, fatal_error_callback_counter);
17435 CHECK(v8::String::Empty(isolate).IsEmpty());
17436 CHECK_EQ(3, fatal_error_callback_counter);
17437}
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017438
17439
17440static int instance_checked_getter_count = 0;
17441static Handle<Value> InstanceCheckedGetter(Local<String> name,
17442 const AccessorInfo& info) {
17443 CHECK_EQ(name, v8_str("foo"));
17444 instance_checked_getter_count++;
17445 return v8_num(11);
17446}
17447
17448
17449static int instance_checked_setter_count = 0;
17450static void InstanceCheckedSetter(Local<String> name,
17451 Local<Value> value,
17452 const AccessorInfo& info) {
17453 CHECK_EQ(name, v8_str("foo"));
17454 CHECK_EQ(value, v8_num(23));
17455 instance_checked_setter_count++;
17456}
17457
17458
17459static void CheckInstanceCheckedResult(int getters,
17460 int setters,
17461 bool expects_callbacks,
17462 TryCatch* try_catch) {
17463 if (expects_callbacks) {
17464 CHECK(!try_catch->HasCaught());
17465 CHECK_EQ(getters, instance_checked_getter_count);
17466 CHECK_EQ(setters, instance_checked_setter_count);
17467 } else {
17468 CHECK(try_catch->HasCaught());
17469 CHECK_EQ(0, instance_checked_getter_count);
17470 CHECK_EQ(0, instance_checked_setter_count);
17471 }
17472 try_catch->Reset();
17473}
17474
17475
17476static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17477 instance_checked_getter_count = 0;
17478 instance_checked_setter_count = 0;
17479 TryCatch try_catch;
17480
17481 // Test path through generic runtime code.
17482 CompileRun("obj.foo");
17483 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17484 CompileRun("obj.foo = 23");
17485 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17486
17487 // Test path through generated LoadIC and StoredIC.
17488 CompileRun("function test_get(o) { o.foo; }"
17489 "test_get(obj);");
17490 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17491 CompileRun("test_get(obj);");
17492 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17493 CompileRun("test_get(obj);");
17494 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17495 CompileRun("function test_set(o) { o.foo = 23; }"
17496 "test_set(obj);");
17497 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17498 CompileRun("test_set(obj);");
17499 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17500 CompileRun("test_set(obj);");
17501 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17502
17503 // Test path through optimized code.
17504 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17505 "test_get(obj);");
17506 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17507 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17508 "test_set(obj);");
17509 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17510
17511 // Cleanup so that closures start out fresh in next check.
17512 CompileRun("%DeoptimizeFunction(test_get);"
17513 "%ClearFunctionTypeFeedback(test_get);"
17514 "%DeoptimizeFunction(test_set);"
17515 "%ClearFunctionTypeFeedback(test_set);");
17516}
17517
17518
17519THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17520 v8::internal::FLAG_allow_natives_syntax = true;
17521 v8::HandleScope scope;
17522 LocalContext context;
17523
17524 Local<FunctionTemplate> templ = FunctionTemplate::New();
17525 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17526 inst->SetAccessor(v8_str("foo"),
17527 InstanceCheckedGetter, InstanceCheckedSetter,
17528 Handle<Value>(),
17529 v8::DEFAULT,
17530 v8::None,
17531 v8::AccessorSignature::New(templ));
17532 context->Global()->Set(v8_str("f"), templ->GetFunction());
17533
17534 printf("Testing positive ...\n");
17535 CompileRun("var obj = new f();");
17536 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17537 CheckInstanceCheckedAccessors(true);
17538
17539 printf("Testing negative ...\n");
17540 CompileRun("var obj = {};"
17541 "obj.__proto__ = new f();");
17542 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17543 CheckInstanceCheckedAccessors(false);
17544}
17545
17546
17547THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17548 v8::internal::FLAG_allow_natives_syntax = true;
17549 v8::HandleScope scope;
17550 LocalContext context;
17551
17552 Local<FunctionTemplate> templ = FunctionTemplate::New();
17553 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17554 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17555 inst->SetAccessor(v8_str("foo"),
17556 InstanceCheckedGetter, InstanceCheckedSetter,
17557 Handle<Value>(),
17558 v8::DEFAULT,
17559 v8::None,
17560 v8::AccessorSignature::New(templ));
17561 context->Global()->Set(v8_str("f"), templ->GetFunction());
17562
17563 printf("Testing positive ...\n");
17564 CompileRun("var obj = new f();");
17565 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17566 CheckInstanceCheckedAccessors(true);
17567
17568 printf("Testing negative ...\n");
17569 CompileRun("var obj = {};"
17570 "obj.__proto__ = new f();");
17571 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17572 CheckInstanceCheckedAccessors(false);
17573}
17574
17575
17576THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17577 v8::internal::FLAG_allow_natives_syntax = true;
17578 v8::HandleScope scope;
17579 LocalContext context;
17580
17581 Local<FunctionTemplate> templ = FunctionTemplate::New();
17582 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
17583 proto->SetAccessor(v8_str("foo"),
17584 InstanceCheckedGetter, InstanceCheckedSetter,
17585 Handle<Value>(),
17586 v8::DEFAULT,
17587 v8::None,
17588 v8::AccessorSignature::New(templ));
17589 context->Global()->Set(v8_str("f"), templ->GetFunction());
17590
17591 printf("Testing positive ...\n");
17592 CompileRun("var obj = new f();");
17593 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17594 CheckInstanceCheckedAccessors(true);
17595
17596 printf("Testing negative ...\n");
17597 CompileRun("var obj = {};"
17598 "obj.__proto__ = new f();");
17599 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17600 CheckInstanceCheckedAccessors(false);
17601
17602 printf("Testing positive with modified prototype chain ...\n");
17603 CompileRun("var obj = new f();"
17604 "var pro = {};"
17605 "pro.__proto__ = obj.__proto__;"
17606 "obj.__proto__ = pro;");
17607 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17608 CheckInstanceCheckedAccessors(true);
17609}
17610
17611
17612TEST(TryFinallyMessage) {
17613 v8::HandleScope scope;
17614 LocalContext context;
17615 {
17616 // Test that the original error message is not lost if there is a
17617 // recursive call into Javascript is done in the finally block, e.g. to
17618 // initialize an IC. (crbug.com/129171)
17619 TryCatch try_catch;
17620 const char* trigger_ic =
17621 "try { \n"
17622 " throw new Error('test'); \n"
17623 "} finally { \n"
17624 " var x = 0; \n"
17625 " x++; \n" // Trigger an IC initialization here.
17626 "} \n";
17627 CompileRun(trigger_ic);
17628 CHECK(try_catch.HasCaught());
17629 Local<Message> message = try_catch.Message();
17630 CHECK(!message.IsEmpty());
17631 CHECK_EQ(2, message->GetLineNumber());
17632 }
17633
17634 {
17635 // Test that the original exception message is indeed overwritten if
17636 // a new error is thrown in the finally block.
17637 TryCatch try_catch;
17638 const char* throw_again =
17639 "try { \n"
17640 " throw new Error('test'); \n"
17641 "} finally { \n"
17642 " var x = 0; \n"
17643 " x++; \n"
17644 " throw new Error('again'); \n" // This is the new uncaught error.
17645 "} \n";
17646 CompileRun(throw_again);
17647 CHECK(try_catch.HasCaught());
17648 Local<Message> message = try_catch.Message();
17649 CHECK(!message.IsEmpty());
17650 CHECK_EQ(6, message->GetLineNumber());
17651 }
17652}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017653
17654
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017655static void Helper137002(bool do_store,
17656 bool polymorphic,
17657 bool remove_accessor,
17658 bool interceptor) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017659 LocalContext context;
17660 Local<ObjectTemplate> templ = ObjectTemplate::New();
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017661 if (interceptor) {
17662 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
17663 } else {
17664 templ->SetAccessor(v8_str("foo"),
17665 GetterWhichReturns42,
17666 SetterWhichSetsYOnThisTo23);
17667 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017668 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17669
17670 // Turn monomorphic on slow object with native accessor, then turn
17671 // polymorphic, finally optimize to create negative lookup and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017672 CompileRun(do_store ?
17673 "function f(x) { x.foo = void 0; }" :
17674 "function f(x) { return x.foo; }");
17675 CompileRun("obj.y = void 0;");
17676 if (!interceptor) {
17677 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
17678 }
17679 CompileRun("obj.__proto__ = null;"
17680 "f(obj); f(obj); f(obj);");
17681 if (polymorphic) {
17682 CompileRun("f({});");
17683 }
17684 CompileRun("obj.y = void 0;"
17685 "%OptimizeFunctionOnNextCall(f);");
17686 if (remove_accessor) {
17687 CompileRun("delete obj.foo;");
17688 }
17689 CompileRun("var result = f(obj);");
17690 if (do_store) {
17691 CompileRun("result = obj.y;");
17692 }
17693 if (remove_accessor && !interceptor) {
17694 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
17695 } else {
17696 CHECK_EQ(do_store ? 23 : 42,
17697 context->Global()->Get(v8_str("result"))->Int32Value());
17698 }
17699}
17700
17701
17702THREADED_TEST(Regress137002a) {
17703 i::FLAG_allow_natives_syntax = true;
17704 i::FLAG_compilation_cache = false;
17705 v8::HandleScope scope;
17706 for (int i = 0; i < 16; i++) {
17707 Helper137002(i & 8, i & 4, i & 2, i & 1);
17708 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017709}
17710
17711
17712THREADED_TEST(Regress137002b) {
17713 i::FLAG_allow_natives_syntax = true;
17714 v8::HandleScope scope;
17715 LocalContext context;
17716 Local<ObjectTemplate> templ = ObjectTemplate::New();
17717 templ->SetAccessor(v8_str("foo"),
17718 GetterWhichReturns42,
17719 SetterWhichSetsYOnThisTo23);
17720 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17721
17722 // Turn monomorphic on slow object with native accessor, then just
17723 // delete the property and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017724 CompileRun("function load(x) { return x.foo; }"
17725 "function store(x) { x.foo = void 0; }"
17726 "function keyed_load(x, key) { return x[key]; }"
17727 // Second version of function has a different source (add void 0)
17728 // so that it does not share code with the first version. This
17729 // ensures that the ICs are monomorphic.
17730 "function load2(x) { void 0; return x.foo; }"
17731 "function store2(x) { void 0; x.foo = void 0; }"
17732 "function keyed_load2(x, key) { void 0; return x[key]; }"
17733
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017734 "obj.y = void 0;"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017735 "obj.__proto__ = null;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017736 "var subobj = {};"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017737 "subobj.y = void 0;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017738 "subobj.__proto__ = obj;"
17739 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17740
17741 // Make the ICs monomorphic.
17742 "load(obj); load(obj);"
17743 "load2(subobj); load2(subobj);"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017744 "store(obj); store(obj);"
17745 "store2(subobj); store2(subobj);"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017746 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
17747 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
17748
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017749 // Actually test the shiny new ICs and better not crash. This
17750 // serves as a regression test for issue 142088 as well.
17751 "load(obj);"
17752 "load2(subobj);"
17753 "store(obj);"
17754 "store2(subobj);"
17755 "keyed_load(obj, 'foo');"
17756 "keyed_load2(subobj, 'foo');"
17757
erik.corry@gmail.com88767242012-08-08 14:43:45 +000017758 // Delete the accessor. It better not be called any more now.
17759 "delete obj.foo;"
17760 "obj.y = void 0;"
17761 "subobj.y = void 0;"
17762
17763 "var load_result = load(obj);"
17764 "var load_result2 = load2(subobj);"
17765 "var keyed_load_result = keyed_load(obj, 'foo');"
17766 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
17767 "store(obj);"
17768 "store2(subobj);"
17769 "var y_from_obj = obj.y;"
17770 "var y_from_subobj = subobj.y;");
17771 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
17772 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
17773 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
17774 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
17775 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
17776 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000017777}
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017778
17779
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000017780THREADED_TEST(Regress142088) {
17781 i::FLAG_allow_natives_syntax = true;
17782 v8::HandleScope scope;
17783 LocalContext context;
17784 Local<ObjectTemplate> templ = ObjectTemplate::New();
17785 templ->SetAccessor(v8_str("foo"),
17786 GetterWhichReturns42,
17787 SetterWhichSetsYOnThisTo23);
17788 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17789
17790 CompileRun("function load(x) { return x.foo; }"
17791 "var o = Object.create(obj);"
17792 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
17793 "load(o); load(o); load(o); load(o);");
17794}
17795
17796
verwaest@chromium.org753aee42012-07-17 16:15:42 +000017797THREADED_TEST(Regress137496) {
17798 i::FLAG_expose_gc = true;
17799 v8::HandleScope scope;
17800 LocalContext context;
17801
17802 // Compile a try-finally clause where the finally block causes a GC
17803 // while there still is a message pending for external reporting.
17804 TryCatch try_catch;
17805 try_catch.SetVerbose(true);
17806 CompileRun("try { throw new Error(); } finally { gc(); }");
17807 CHECK(try_catch.HasCaught());
17808}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017809
17810
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000017811THREADED_TEST(Regress149912) {
17812 v8::HandleScope scope;
17813 LocalContext context;
17814 Handle<FunctionTemplate> templ = FunctionTemplate::New();
17815 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17816 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
17817 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
17818}
17819
17820
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000017821THREADED_TEST(Regress157124) {
17822 v8::HandleScope scope;
17823 LocalContext context;
17824 Local<ObjectTemplate> templ = ObjectTemplate::New();
17825 Local<Object> obj = templ->NewInstance();
17826 obj->GetIdentityHash();
17827 obj->DeleteHiddenValue(v8_str("Bug"));
17828}
17829
17830
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000017831#ifndef WIN32
17832class ThreadInterruptTest {
17833 public:
17834 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
17835 ~ThreadInterruptTest() { delete sem_; }
17836
17837 void RunTest() {
17838 sem_ = i::OS::CreateSemaphore(0);
17839
17840 InterruptThread i_thread(this);
17841 i_thread.Start();
17842
17843 sem_->Wait();
17844 CHECK_EQ(kExpectedValue, sem_value_);
17845 }
17846
17847 private:
17848 static const int kExpectedValue = 1;
17849
17850 class InterruptThread : public i::Thread {
17851 public:
17852 explicit InterruptThread(ThreadInterruptTest* test)
17853 : Thread("InterruptThread"), test_(test) {}
17854
17855 virtual void Run() {
17856 struct sigaction action;
17857
17858 // Ensure that we'll enter waiting condition
17859 i::OS::Sleep(100);
17860
17861 // Setup signal handler
17862 memset(&action, 0, sizeof(action));
17863 action.sa_handler = SignalHandler;
17864 sigaction(SIGCHLD, &action, NULL);
17865
17866 // Send signal
17867 kill(getpid(), SIGCHLD);
17868
17869 // Ensure that if wait has returned because of error
17870 i::OS::Sleep(100);
17871
17872 // Set value and signal semaphore
17873 test_->sem_value_ = 1;
17874 test_->sem_->Signal();
17875 }
17876
17877 static void SignalHandler(int signal) {
17878 }
17879
17880 private:
17881 ThreadInterruptTest* test_;
17882 struct sigaction sa_;
17883 };
17884
17885 i::Semaphore* sem_;
17886 volatile int sem_value_;
17887};
17888
17889
17890THREADED_TEST(SemaphoreInterruption) {
17891 ThreadInterruptTest().RunTest();
17892}
17893#endif // WIN32