blob: 9b1371e3292f1a1420b38be7d58e16e2da27b314 [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
ager@chromium.org3811b432009-10-28 14:53:37 +000028#include <limits.h>
29
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000030#ifndef WIN32
31#include <signal.h> // kill
32#include <unistd.h> // getpid
33#endif // WIN32
34
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000035#include "v8.h"
36
37#include "api.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000038#include "isolate.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000039#include "compilation-cache.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000040#include "execution.h"
verwaest@chromium.org753aee42012-07-17 16:15:42 +000041#include "objects.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042#include "snapshot.h"
43#include "platform.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000044#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#include "cctest.h"
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000046#include "parser.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000047#include "unicode-inl.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000048
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000049static const bool kLogThreading = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000050
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000051static bool IsNaN(double x) {
52#ifdef WIN32
53 return _isnan(x);
54#else
55 return isnan(x);
56#endif
57}
58
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000059using ::v8::AccessorInfo;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000060using ::v8::Arguments;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000061using ::v8::Context;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062using ::v8::Extension;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000063using ::v8::Function;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000064using ::v8::FunctionTemplate;
65using ::v8::Handle;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000066using ::v8::HandleScope;
67using ::v8::Local;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000068using ::v8::Message;
69using ::v8::MessageCallback;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000070using ::v8::Object;
71using ::v8::ObjectTemplate;
72using ::v8::Persistent;
73using ::v8::Script;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000074using ::v8::StackTrace;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000075using ::v8::String;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000076using ::v8::TryCatch;
77using ::v8::Undefined;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000078using ::v8::V8;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000079using ::v8::Value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000080
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000081
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000082static void ExpectString(const char* code, const char* expected) {
83 Local<Value> result = CompileRun(code);
84 CHECK(result->IsString());
85 String::AsciiValue ascii(result);
86 CHECK_EQ(expected, *ascii);
87}
88
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000089static void ExpectInt32(const char* code, int expected) {
90 Local<Value> result = CompileRun(code);
91 CHECK(result->IsInt32());
92 CHECK_EQ(expected, result->Int32Value());
93}
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +000094
95static void ExpectBoolean(const char* code, bool expected) {
96 Local<Value> result = CompileRun(code);
97 CHECK(result->IsBoolean());
98 CHECK_EQ(expected, result->BooleanValue());
99}
100
101
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000102static void ExpectTrue(const char* code) {
103 ExpectBoolean(code, true);
104}
105
106
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000107static void ExpectFalse(const char* code) {
108 ExpectBoolean(code, false);
109}
110
111
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000112static void ExpectObject(const char* code, Local<Value> expected) {
113 Local<Value> result = CompileRun(code);
114 CHECK(result->Equals(expected));
115}
116
117
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000118static void ExpectUndefined(const char* code) {
119 Local<Value> result = CompileRun(code);
120 CHECK(result->IsUndefined());
121}
122
123
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000124static int signature_callback_count;
125static v8::Handle<Value> IncrementingSignatureCallback(
126 const v8::Arguments& args) {
127 ApiTestFuzzer::Fuzz();
128 signature_callback_count++;
129 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
130 for (int i = 0; i < args.Length(); i++)
131 result->Set(v8::Integer::New(i), args[i]);
132 return result;
133}
134
135
136static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
137 ApiTestFuzzer::Fuzz();
138 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
139 for (int i = 0; i < args.Length(); i++) {
140 result->Set(v8::Integer::New(i), args[i]);
141 }
142 return result;
143}
144
145
146THREADED_TEST(Handles) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000147 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000148 Local<Context> local_env;
149 {
150 LocalContext env;
151 local_env = env.local();
152 }
153
154 // Local context should still be live.
155 CHECK(!local_env.IsEmpty());
156 local_env->Enter();
157
158 v8::Handle<v8::Primitive> undef = v8::Undefined();
159 CHECK(!undef.IsEmpty());
160 CHECK(undef->IsUndefined());
161
162 const char* c_source = "1 + 2 + 3";
163 Local<String> source = String::New(c_source);
164 Local<Script> script = Script::Compile(source);
165 CHECK_EQ(6, script->Run()->Int32Value());
166
167 local_env->Exit();
168}
169
170
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000171THREADED_TEST(IsolateOfContext) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000172 v8::Persistent<Context> env = Context::New();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000173 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000174
175 CHECK(!env->InContext());
176 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
177 env->Enter();
178 CHECK(env->InContext());
179 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
180 env->Exit();
181 CHECK(!env->InContext());
182 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
183
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000184 env.Dispose(env->GetIsolate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000185}
186
187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188THREADED_TEST(ReceiverSignature) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000189 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000190 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000191 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
192 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
193 fun->PrototypeTemplate()->Set(
194 v8_str("m"),
195 v8::FunctionTemplate::New(IncrementingSignatureCallback,
196 v8::Handle<Value>(),
197 sig));
198 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
199 signature_callback_count = 0;
200 CompileRun(
201 "var o = new Fun();"
202 "o.m();");
203 CHECK_EQ(1, signature_callback_count);
204 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
205 sub_fun->Inherit(fun);
206 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
207 CompileRun(
208 "var o = new SubFun();"
209 "o.m();");
210 CHECK_EQ(2, signature_callback_count);
211
212 v8::TryCatch try_catch;
213 CompileRun(
214 "var o = { };"
215 "o.m = Fun.prototype.m;"
216 "o.m();");
217 CHECK_EQ(2, signature_callback_count);
218 CHECK(try_catch.HasCaught());
219 try_catch.Reset();
220 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
221 sub_fun->Inherit(fun);
222 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
223 CompileRun(
224 "var o = new UnrelFun();"
225 "o.m = Fun.prototype.m;"
226 "o.m();");
227 CHECK_EQ(2, signature_callback_count);
228 CHECK(try_catch.HasCaught());
229}
230
231
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232THREADED_TEST(ArgumentSignature) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000233 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000234 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
236 cons->SetClassName(v8_str("Cons"));
237 v8::Handle<v8::Signature> sig =
238 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
239 v8::Handle<v8::FunctionTemplate> fun =
240 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
241 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
242 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
243
244 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000245 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
247 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000248 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249
250 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000251 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
253 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
254 cons1->SetClassName(v8_str("Cons1"));
255 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
256 cons2->SetClassName(v8_str("Cons2"));
257 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
258 cons3->SetClassName(v8_str("Cons3"));
259
260 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
261 v8::Handle<v8::Signature> wsig =
262 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
263 v8::Handle<v8::FunctionTemplate> fun2 =
264 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
265
266 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
267 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
268 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
269 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
270 v8::Handle<Value> value4 = CompileRun(
271 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
272 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000273 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000274
275 v8::Handle<Value> value5 = CompileRun(
276 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000277 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000278
279 v8::Handle<Value> value6 = CompileRun(
280 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000281 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282
283 v8::Handle<Value> value7 = CompileRun(
284 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
285 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000286 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000287
288 v8::Handle<Value> value8 = CompileRun(
289 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000290 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000291}
292
293
294THREADED_TEST(HulIgennem) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000295 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000296 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000297 v8::Handle<v8::Primitive> undef = v8::Undefined();
298 Local<String> undef_str = undef->ToString();
299 char* value = i::NewArray<char>(undef_str->Length() + 1);
300 undef_str->WriteAscii(value);
301 CHECK_EQ(0, strcmp(value, "undefined"));
302 i::DeleteArray(value);
303}
304
305
306THREADED_TEST(Access) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000307 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000308 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000309 Local<v8::Object> obj = v8::Object::New();
310 Local<Value> foo_before = obj->Get(v8_str("foo"));
311 CHECK(foo_before->IsUndefined());
312 Local<String> bar_str = v8_str("bar");
313 obj->Set(v8_str("foo"), bar_str);
314 Local<Value> foo_after = obj->Get(v8_str("foo"));
315 CHECK(!foo_after->IsUndefined());
316 CHECK(foo_after->IsString());
317 CHECK_EQ(bar_str, foo_after);
318}
319
320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000321THREADED_TEST(AccessElement) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000322 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000323 v8::HandleScope scope(env->GetIsolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000324 Local<v8::Object> obj = v8::Object::New();
325 Local<Value> before = obj->Get(1);
326 CHECK(before->IsUndefined());
327 Local<String> bar_str = v8_str("bar");
328 obj->Set(1, bar_str);
329 Local<Value> after = obj->Get(1);
330 CHECK(!after->IsUndefined());
331 CHECK(after->IsString());
332 CHECK_EQ(bar_str, after);
333
334 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
335 CHECK_EQ(v8_str("a"), value->Get(0));
336 CHECK_EQ(v8_str("b"), value->Get(1));
337}
338
339
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340THREADED_TEST(Script) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000341 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000342 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343 const char* c_source = "1 + 2 + 3";
344 Local<String> source = String::New(c_source);
345 Local<Script> script = Script::Compile(source);
346 CHECK_EQ(6, script->Run()->Int32Value());
347}
348
349
350static uint16_t* AsciiToTwoByteString(const char* source) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000351 int array_length = i::StrLength(source) + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000352 uint16_t* converted = i::NewArray<uint16_t>(array_length);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000353 for (int i = 0; i < array_length; i++) converted[i] = source[i];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354 return converted;
355}
356
357
358class TestResource: public String::ExternalStringResource {
359 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000360 explicit TestResource(uint16_t* data, int* counter = NULL)
361 : data_(data), length_(0), counter_(counter) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362 while (data[length_]) ++length_;
363 }
364
365 ~TestResource() {
366 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000367 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368 }
369
370 const uint16_t* data() const {
371 return data_;
372 }
373
374 size_t length() const {
375 return length_;
376 }
377 private:
378 uint16_t* data_;
379 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000380 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381};
382
383
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384class TestAsciiResource: public String::ExternalAsciiStringResource {
385 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000386 explicit TestAsciiResource(const char* data, int* counter = NULL)
387 : data_(data), length_(strlen(data)), counter_(counter) { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000388
389 ~TestAsciiResource() {
390 i::DeleteArray(data_);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000391 if (counter_ != NULL) ++*counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392 }
393
394 const char* data() const {
395 return data_;
396 }
397
398 size_t length() const {
399 return length_;
400 }
401 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000402 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 size_t length_;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000404 int* counter_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405};
406
407
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408THREADED_TEST(ScriptUsingStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000409 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000410 const char* c_source = "1 + 2 * 3";
411 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
412 {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000413 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000414 v8::HandleScope scope(env->GetIsolate());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000415 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416 Local<String> source = String::NewExternal(resource);
417 Local<Script> script = Script::Compile(source);
418 Local<Value> value = script->Run();
419 CHECK(value->IsNumber());
420 CHECK_EQ(7, value->Int32Value());
421 CHECK(source->IsExternal());
422 CHECK_EQ(resource,
423 static_cast<TestResource*>(source->GetExternalStringResource()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000424 String::Encoding encoding = String::UNKNOWN_ENCODING;
425 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
426 source->GetExternalStringResourceBase(&encoding));
427 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000428 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000429 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 v8::internal::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000432 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000433 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434}
435
436
437THREADED_TEST(ScriptUsingAsciiStringResource) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000438 int dispose_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439 const char* c_source = "1 + 2 * 3";
440 {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000441 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000442 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000443 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
444 &dispose_count);
445 Local<String> source = String::NewExternal(resource);
446 CHECK(source->IsExternalAscii());
447 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
448 source->GetExternalAsciiStringResource());
449 String::Encoding encoding = String::UNKNOWN_ENCODING;
450 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
451 source->GetExternalStringResourceBase(&encoding));
452 CHECK_EQ(String::ASCII_ENCODING, encoding);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453 Local<Script> script = Script::Compile(source);
454 Local<Value> value = script->Run();
455 CHECK(value->IsNumber());
456 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000458 CHECK_EQ(0, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000459 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000461 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000462 CHECK_EQ(1, dispose_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000463}
464
465
ager@chromium.org6f10e412009-02-13 10:11:16 +0000466THREADED_TEST(ScriptMakingExternalString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000467 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000468 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
469 {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000470 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000471 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000472 Local<String> source = String::New(two_byte_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000473 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000474 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
475 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000476 CHECK_EQ(source->IsExternal(), false);
477 CHECK_EQ(source->IsExternalAscii(), false);
478 String::Encoding encoding = String::UNKNOWN_ENCODING;
479 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
480 CHECK_EQ(String::ASCII_ENCODING, encoding);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000481 bool success = source->MakeExternal(new TestResource(two_byte_source,
482 &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000483 CHECK(success);
484 Local<Script> script = Script::Compile(source);
485 Local<Value> value = script->Run();
486 CHECK(value->IsNumber());
487 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000488 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000489 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000490 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000492 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000493 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000494}
495
496
497THREADED_TEST(ScriptMakingExternalAsciiString) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000498 int dispose_count = 0;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000499 const char* c_source = "1 + 2 * 3";
500 {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000501 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000502 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000503 Local<String> source = v8_str(c_source);
ager@chromium.org5c838252010-02-19 08:53:10 +0000504 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
506 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org6f10e412009-02-13 10:11:16 +0000507 bool success = source->MakeExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000508 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000509 CHECK(success);
510 Local<Script> script = Script::Compile(source);
511 Local<Value> value = script->Run();
512 CHECK(value->IsNumber());
513 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000514 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000515 CHECK_EQ(0, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000518 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000519 CHECK_EQ(1, dispose_count);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000520}
521
522
ager@chromium.org5c838252010-02-19 08:53:10 +0000523TEST(MakingExternalStringConditions) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000524 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000525 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000526
527 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 HEAP->CollectGarbage(i::NEW_SPACE);
529 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000530
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000531 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000532 Local<String> small_string = String::New(two_byte_string);
533 i::DeleteArray(two_byte_string);
534
ager@chromium.org5c838252010-02-19 08:53:10 +0000535 // We should refuse to externalize newly created small string.
536 CHECK(!small_string->CanMakeExternal());
537 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
539 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000540 // Old space strings should be accepted.
541 CHECK(small_string->CanMakeExternal());
542
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000543 two_byte_string = AsciiToTwoByteString("small string 2");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000544 small_string = String::New(two_byte_string);
545 i::DeleteArray(two_byte_string);
546
ager@chromium.org5c838252010-02-19 08:53:10 +0000547 // We should refuse externalizing newly created small string.
548 CHECK(!small_string->CanMakeExternal());
549 for (int i = 0; i < 100; i++) {
550 String::Value value(small_string);
551 }
552 // Frequently used strings should be accepted.
553 CHECK(small_string->CanMakeExternal());
554
555 const int buf_size = 10 * 1024;
556 char* buf = i::NewArray<char>(buf_size);
557 memset(buf, 'a', buf_size);
558 buf[buf_size - 1] = '\0';
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000559
560 two_byte_string = AsciiToTwoByteString(buf);
561 Local<String> large_string = String::New(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000562 i::DeleteArray(buf);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000563 i::DeleteArray(two_byte_string);
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 // Large strings should be immediately accepted.
565 CHECK(large_string->CanMakeExternal());
566}
567
568
569TEST(MakingExternalAsciiStringConditions) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000571 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000572
573 // Free some space in the new space so that we can check freshness.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 HEAP->CollectGarbage(i::NEW_SPACE);
575 HEAP->CollectGarbage(i::NEW_SPACE);
ager@chromium.org5c838252010-02-19 08:53:10 +0000576
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000577 Local<String> small_string = String::New("s1");
ager@chromium.org5c838252010-02-19 08:53:10 +0000578 // We should refuse to externalize newly created small string.
579 CHECK(!small_string->CanMakeExternal());
580 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
582 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
ager@chromium.org5c838252010-02-19 08:53:10 +0000583 // Old space strings should be accepted.
584 CHECK(small_string->CanMakeExternal());
585
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000586 small_string = String::New("small string 2");
ager@chromium.org5c838252010-02-19 08:53:10 +0000587 // We should refuse externalizing newly created small string.
588 CHECK(!small_string->CanMakeExternal());
589 for (int i = 0; i < 100; i++) {
590 String::Value value(small_string);
591 }
592 // Frequently used strings should be accepted.
593 CHECK(small_string->CanMakeExternal());
594
595 const int buf_size = 10 * 1024;
596 char* buf = i::NewArray<char>(buf_size);
597 memset(buf, 'a', buf_size);
598 buf[buf_size - 1] = '\0';
599 Local<String> large_string = String::New(buf);
600 i::DeleteArray(buf);
601 // Large strings should be immediately accepted.
602 CHECK(large_string->CanMakeExternal());
603}
604
605
ager@chromium.org6f10e412009-02-13 10:11:16 +0000606THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000607 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000608 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000609 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
610 Local<String> string =
611 String::NewExternal(new TestResource(two_byte_string));
612 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
613 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
615 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000616 i::Handle<i::String> isymbol =
617 FACTORY->InternalizedStringFromString(istring);
618 CHECK(isymbol->IsInternalizedString());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000619 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000620 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
621 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000622}
623
624
625THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000626 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000627 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000628 const char* one_byte_string = "test string";
629 Local<String> string = String::NewExternal(
630 new TestAsciiResource(i::StrDup(one_byte_string)));
631 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
632 // Trigger GCs so that the newly allocated string moves to old gen.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
634 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000635 i::Handle<i::String> isymbol =
636 FACTORY->InternalizedStringFromString(istring);
637 CHECK(isymbol->IsInternalizedString());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000638 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000639 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
640 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000641}
642
643
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644THREADED_TEST(ScavengeExternalString) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000645 i::FLAG_stress_compaction = false;
646 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000647 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000648 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000649 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000650 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
652 Local<String> string =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000653 String::NewExternal(new TestResource(two_byte_string,
654 &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000655 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 HEAP->CollectGarbage(i::NEW_SPACE);
657 in_new_space = HEAP->InNewSpace(*istring);
658 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000659 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000662 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000663}
664
665
666THREADED_TEST(ScavengeExternalAsciiString) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000667 i::FLAG_stress_compaction = false;
668 i::FLAG_gc_global = false;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000669 int dispose_count = 0;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000670 bool in_new_space = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000671 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000672 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000673 const char* one_byte_string = "test string";
674 Local<String> string = String::NewExternal(
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000675 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000676 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 HEAP->CollectGarbage(i::NEW_SPACE);
678 in_new_space = HEAP->InNewSpace(*istring);
679 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000680 CHECK_EQ(0, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000681 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000682 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000683 CHECK_EQ(1, dispose_count);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000684}
685
686
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000687class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
688 public:
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000689 // Only used by non-threaded tests, so it can use static fields.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000690 static int dispose_calls;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000691 static int dispose_count;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000692
693 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000694 : TestAsciiResource(data, &dispose_count),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000695 dispose_(dispose) { }
696
697 void Dispose() {
698 ++dispose_calls;
699 if (dispose_) delete this;
700 }
701 private:
702 bool dispose_;
703};
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000704
705
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000706int TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000707int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000708
709
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000710TEST(ExternalStringWithDisposeHandling) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000711 const char* c_source = "1 + 2 * 3";
712
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000713 // Use a stack 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 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000717 {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000718 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000719 v8::HandleScope scope(env->GetIsolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000720 Local<String> source = String::NewExternal(&res_stack);
721 Local<Script> script = Script::Compile(source);
722 Local<Value> value = script->Run();
723 CHECK(value->IsNumber());
724 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000725 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000726 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000727 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000728 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000729 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000730 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000731 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000732
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000733 // Use a heap allocated external string resource allocated object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000734 TestAsciiResourceWithDisposeControl::dispose_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000735 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
736 TestAsciiResource* res_heap =
737 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000738 {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000739 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000740 v8::HandleScope scope(env->GetIsolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000741 Local<String> source = String::NewExternal(res_heap);
742 Local<Script> script = Script::Compile(source);
743 Local<Value> value = script->Run();
744 CHECK(value->IsNumber());
745 CHECK_EQ(7, value->Int32Value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000746 HEAP->CollectAllAvailableGarbage();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000747 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000748 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 HEAP->CollectAllAvailableGarbage();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000751 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000752 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000753}
754
755
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000756THREADED_TEST(StringConcat) {
757 {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000758 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000759 v8::HandleScope scope(env->GetIsolate());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000760 const char* one_byte_string_1 = "function a_times_t";
761 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
762 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
763 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
764 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
765 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
766 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
767 Local<String> left = v8_str(one_byte_string_1);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000768
769 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
770 Local<String> right = String::New(two_byte_source);
771 i::DeleteArray(two_byte_source);
772
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000773 Local<String> source = String::Concat(left, right);
774 right = String::NewExternal(
775 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
776 source = String::Concat(source, right);
777 right = String::NewExternal(
778 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
779 source = String::Concat(source, right);
780 right = v8_str(one_byte_string_2);
781 source = String::Concat(source, right);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000782
783 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
784 right = String::New(two_byte_source);
785 i::DeleteArray(two_byte_source);
786
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000787 source = String::Concat(source, right);
788 right = String::NewExternal(
789 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
790 source = String::Concat(source, right);
791 Local<Script> script = Script::Compile(source);
792 Local<Value> value = script->Run();
793 CHECK(value->IsNumber());
794 CHECK_EQ(68, value->Int32Value());
795 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 i::Isolate::Current()->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000797 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
798 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000799}
800
801
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000802THREADED_TEST(GlobalProperties) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000803 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000804 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000805 v8::Handle<v8::Object> global = env->Global();
806 global->Set(v8_str("pi"), v8_num(3.1415926));
807 Local<Value> pi = global->Get(v8_str("pi"));
808 CHECK_EQ(3.1415926, pi->NumberValue());
809}
810
811
812static v8::Handle<Value> handle_call(const v8::Arguments& args) {
813 ApiTestFuzzer::Fuzz();
814 return v8_num(102);
815}
816
817
818static v8::Handle<Value> construct_call(const v8::Arguments& args) {
819 ApiTestFuzzer::Fuzz();
820 args.This()->Set(v8_str("x"), v8_num(1));
821 args.This()->Set(v8_str("y"), v8_num(2));
822 return args.This();
823}
824
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000825static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
826 ApiTestFuzzer::Fuzz();
827 return v8_num(239);
828}
829
830
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000831THREADED_TEST(FunctionTemplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000832 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000833 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000834 {
835 Local<v8::FunctionTemplate> fun_templ =
836 v8::FunctionTemplate::New(handle_call);
837 Local<Function> fun = fun_templ->GetFunction();
838 env->Global()->Set(v8_str("obj"), fun);
839 Local<Script> script = v8_compile("obj()");
840 CHECK_EQ(102, script->Run()->Int32Value());
841 }
842 // Use SetCallHandler to initialize a function template, should work like the
843 // previous one.
844 {
845 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
846 fun_templ->SetCallHandler(handle_call);
847 Local<Function> fun = fun_templ->GetFunction();
848 env->Global()->Set(v8_str("obj"), fun);
849 Local<Script> script = v8_compile("obj()");
850 CHECK_EQ(102, script->Run()->Int32Value());
851 }
852 // Test constructor calls.
853 {
854 Local<v8::FunctionTemplate> fun_templ =
855 v8::FunctionTemplate::New(construct_call);
856 fun_templ->SetClassName(v8_str("funky"));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000857 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000858 Local<Function> fun = fun_templ->GetFunction();
859 env->Global()->Set(v8_str("obj"), fun);
860 Local<Script> script = v8_compile("var s = new obj(); s.x");
861 CHECK_EQ(1, script->Run()->Int32Value());
862
863 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
864 CHECK_EQ(v8_str("[object funky]"), result);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000865
866 result = v8_compile("(new obj()).m")->Run();
867 CHECK_EQ(239, result->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000868 }
869}
870
871
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000872THREADED_TEST(FunctionTemplateSetLength) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000873 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000874 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000875 {
876 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
877 handle_call, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
878 Local<Function> fun = fun_templ->GetFunction();
879 env->Global()->Set(v8_str("obj"), fun);
880 Local<Script> script = v8_compile("obj.length");
881 CHECK_EQ(23, script->Run()->Int32Value());
882 }
883 {
884 Local<v8::FunctionTemplate> fun_templ =
885 v8::FunctionTemplate::New(handle_call);
886 fun_templ->SetLength(22);
887 Local<Function> fun = fun_templ->GetFunction();
888 env->Global()->Set(v8_str("obj"), fun);
889 Local<Script> script = v8_compile("obj.length");
890 CHECK_EQ(22, script->Run()->Int32Value());
891 }
892 {
893 // Without setting length it defaults to 0.
894 Local<v8::FunctionTemplate> fun_templ =
895 v8::FunctionTemplate::New(handle_call);
896 Local<Function> fun = fun_templ->GetFunction();
897 env->Global()->Set(v8_str("obj"), fun);
898 Local<Script> script = v8_compile("obj.length");
899 CHECK_EQ(0, script->Run()->Int32Value());
900 }
901}
902
903
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000904static void* expected_ptr;
905static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000906 void* ptr = v8::External::Cast(*args.Data())->Value();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000907 CHECK_EQ(expected_ptr, ptr);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000908 return v8::True();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000909}
910
911
912static void TestExternalPointerWrapping() {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000913 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000914 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000915
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000916 v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000917
918 v8::Handle<v8::Object> obj = v8::Object::New();
919 obj->Set(v8_str("func"),
920 v8::FunctionTemplate::New(callback, data)->GetFunction());
921 env->Global()->Set(v8_str("obj"), obj);
922
923 CHECK(CompileRun(
924 "function foo() {\n"
925 " for (var i = 0; i < 13; i++) obj.func();\n"
926 "}\n"
927 "foo(), true")->BooleanValue());
928}
929
930
931THREADED_TEST(ExternalWrap) {
932 // Check heap allocated object.
933 int* ptr = new int;
934 expected_ptr = ptr;
935 TestExternalPointerWrapping();
936 delete ptr;
937
938 // Check stack allocated object.
939 int foo;
940 expected_ptr = &foo;
941 TestExternalPointerWrapping();
942
943 // Check not aligned addresses.
944 const int n = 100;
945 char* s = new char[n];
946 for (int i = 0; i < n; i++) {
947 expected_ptr = s + i;
948 TestExternalPointerWrapping();
949 }
950
951 delete[] s;
952
953 // Check several invalid addresses.
954 expected_ptr = reinterpret_cast<void*>(1);
955 TestExternalPointerWrapping();
956
957 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
958 TestExternalPointerWrapping();
959
960 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
961 TestExternalPointerWrapping();
962
963#if defined(V8_HOST_ARCH_X64)
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000964 // Check a value with a leading 1 bit in x64 Smi encoding.
965 expected_ptr = reinterpret_cast<void*>(0x400000000);
966 TestExternalPointerWrapping();
967
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000968 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
969 TestExternalPointerWrapping();
970
971 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
972 TestExternalPointerWrapping();
973#endif
974}
975
976
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000977THREADED_TEST(FindInstanceInPrototypeChain) {
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000978 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000979 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000980
981 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
982 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
983 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
984 derived->Inherit(base);
985
986 Local<v8::Function> base_function = base->GetFunction();
987 Local<v8::Function> derived_function = derived->GetFunction();
988 Local<v8::Function> other_function = other->GetFunction();
989
990 Local<v8::Object> base_instance = base_function->NewInstance();
991 Local<v8::Object> derived_instance = derived_function->NewInstance();
992 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
993 Local<v8::Object> other_instance = other_function->NewInstance();
994 derived_instance2->Set(v8_str("__proto__"), derived_instance);
995 other_instance->Set(v8_str("__proto__"), derived_instance2);
996
997 // base_instance is only an instance of base.
998 CHECK_EQ(base_instance,
999 base_instance->FindInstanceInPrototypeChain(base));
1000 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1001 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1002
1003 // derived_instance is an instance of base and derived.
1004 CHECK_EQ(derived_instance,
1005 derived_instance->FindInstanceInPrototypeChain(base));
1006 CHECK_EQ(derived_instance,
1007 derived_instance->FindInstanceInPrototypeChain(derived));
1008 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1009
1010 // other_instance is an instance of other and its immediate
1011 // prototype derived_instance2 is an instance of base and derived.
1012 // Note, derived_instance is an instance of base and derived too,
1013 // but it comes after derived_instance2 in the prototype chain of
1014 // other_instance.
1015 CHECK_EQ(derived_instance2,
1016 other_instance->FindInstanceInPrototypeChain(base));
1017 CHECK_EQ(derived_instance2,
1018 other_instance->FindInstanceInPrototypeChain(derived));
1019 CHECK_EQ(other_instance,
1020 other_instance->FindInstanceInPrototypeChain(other));
1021}
1022
1023
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001024THREADED_TEST(TinyInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001025 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001026 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001027 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1028
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001029 int32_t value = 239;
1030 Local<v8::Integer> value_obj = v8::Integer::New(value);
1031 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001032
1033 value_obj = v8::Integer::New(value, isolate);
1034 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001035}
1036
1037
1038THREADED_TEST(BigSmiInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001039 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001040 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001041 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1042
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001043 int32_t value = i::Smi::kMaxValue;
1044 // We cannot add one to a Smi::kMaxValue without wrapping.
1045 if (i::kSmiValueSize < 32) {
1046 CHECK(i::Smi::IsValid(value));
1047 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001048
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001049 Local<v8::Integer> value_obj = v8::Integer::New(value);
1050 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001051
1052 value_obj = v8::Integer::New(value, isolate);
1053 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001054 }
1055}
1056
1057
1058THREADED_TEST(BigInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001059 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001060 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001061 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1062
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001063 // We cannot add one to a Smi::kMaxValue without wrapping.
1064 if (i::kSmiValueSize < 32) {
1065 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1066 // The code will not be run in that case, due to the "if" guard.
1067 int32_t value =
1068 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1069 CHECK(value > i::Smi::kMaxValue);
1070 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001071
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001072 Local<v8::Integer> value_obj = v8::Integer::New(value);
1073 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001074
1075 value_obj = v8::Integer::New(value, isolate);
1076 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001077 }
1078}
1079
1080
1081THREADED_TEST(TinyUnsignedInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001082 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001083 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001084 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1085
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001086 uint32_t value = 239;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001087
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001088 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1089 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001090
1091 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1092 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093}
1094
1095
1096THREADED_TEST(BigUnsignedSmiInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001097 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001098 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001099 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1100
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001101 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1102 CHECK(i::Smi::IsValid(value));
1103 CHECK(!i::Smi::IsValid(value + 1));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001104
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001105 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1106 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001107
1108 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1109 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001110}
1111
1112
1113THREADED_TEST(BigUnsignedInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001114 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001115 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001116 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1117
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001118 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1119 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1120 CHECK(!i::Smi::IsValid(value));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001121
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001122 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1123 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001124
1125 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1126 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001127}
1128
1129
1130THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001131 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001132 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001133 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1134
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001135 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1136 uint32_t value = INT32_MAX_AS_UINT + 1;
1137 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001138
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001139 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1140 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001141
1142 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1143 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001144}
1145
1146
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001147THREADED_TEST(IsNativeError) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001148 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001149 v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001150 v8::Handle<Value> syntax_error = CompileRun(
1151 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1152 CHECK(syntax_error->IsNativeError());
1153 v8::Handle<Value> not_error = CompileRun("{a:42}");
1154 CHECK(!not_error->IsNativeError());
1155 v8::Handle<Value> not_object = CompileRun("42");
1156 CHECK(!not_object->IsNativeError());
1157}
1158
1159
1160THREADED_TEST(StringObject) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001161 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001162 v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001163 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1164 CHECK(boxed_string->IsStringObject());
1165 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1166 CHECK(!unboxed_string->IsStringObject());
1167 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1168 CHECK(!boxed_not_string->IsStringObject());
1169 v8::Handle<Value> not_object = CompileRun("0");
1170 CHECK(!not_object->IsStringObject());
1171 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1172 CHECK(!as_boxed.IsEmpty());
1173 Local<v8::String> the_string = as_boxed->StringValue();
1174 CHECK(!the_string.IsEmpty());
1175 ExpectObject("\"test\"", the_string);
1176 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1177 CHECK(new_boxed_string->IsStringObject());
1178 as_boxed = new_boxed_string.As<v8::StringObject>();
1179 the_string = as_boxed->StringValue();
1180 CHECK(!the_string.IsEmpty());
1181 ExpectObject("\"test\"", the_string);
1182}
1183
1184
1185THREADED_TEST(NumberObject) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001186 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001187 v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001188 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1189 CHECK(boxed_number->IsNumberObject());
1190 v8::Handle<Value> unboxed_number = CompileRun("42");
1191 CHECK(!unboxed_number->IsNumberObject());
1192 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1193 CHECK(!boxed_not_number->IsNumberObject());
1194 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1195 CHECK(!as_boxed.IsEmpty());
1196 double the_number = as_boxed->NumberValue();
1197 CHECK_EQ(42.0, the_number);
1198 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1199 CHECK(new_boxed_number->IsNumberObject());
1200 as_boxed = new_boxed_number.As<v8::NumberObject>();
1201 the_number = as_boxed->NumberValue();
1202 CHECK_EQ(43.0, the_number);
1203}
1204
1205
1206THREADED_TEST(BooleanObject) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001207 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001208 v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001209 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1210 CHECK(boxed_boolean->IsBooleanObject());
1211 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1212 CHECK(!unboxed_boolean->IsBooleanObject());
1213 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1214 CHECK(!boxed_not_boolean->IsBooleanObject());
1215 v8::Handle<v8::BooleanObject> as_boxed =
1216 boxed_boolean.As<v8::BooleanObject>();
1217 CHECK(!as_boxed.IsEmpty());
1218 bool the_boolean = as_boxed->BooleanValue();
1219 CHECK_EQ(true, the_boolean);
1220 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1221 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1222 CHECK(boxed_true->IsBooleanObject());
1223 CHECK(boxed_false->IsBooleanObject());
1224 as_boxed = boxed_true.As<v8::BooleanObject>();
1225 CHECK_EQ(true, as_boxed->BooleanValue());
1226 as_boxed = boxed_false.As<v8::BooleanObject>();
1227 CHECK_EQ(false, as_boxed->BooleanValue());
1228}
1229
1230
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001231THREADED_TEST(Number) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001232 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001233 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001234 double PI = 3.1415926;
1235 Local<v8::Number> pi_obj = v8::Number::New(PI);
1236 CHECK_EQ(PI, pi_obj->NumberValue());
1237}
1238
1239
1240THREADED_TEST(ToNumber) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001241 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001242 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001243 Local<String> str = v8_str("3.1415926");
1244 CHECK_EQ(3.1415926, str->NumberValue());
1245 v8::Handle<v8::Boolean> t = v8::True();
1246 CHECK_EQ(1.0, t->NumberValue());
1247 v8::Handle<v8::Boolean> f = v8::False();
1248 CHECK_EQ(0.0, f->NumberValue());
1249}
1250
1251
1252THREADED_TEST(Date) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001253 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001254 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001255 double PI = 3.1415926;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001256 Local<Value> date = v8::Date::New(PI);
1257 CHECK_EQ(3.0, date->NumberValue());
1258 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1259 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001260}
1261
1262
1263THREADED_TEST(Boolean) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001264 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001265 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001266 v8::Handle<v8::Boolean> t = v8::True();
1267 CHECK(t->Value());
1268 v8::Handle<v8::Boolean> f = v8::False();
1269 CHECK(!f->Value());
1270 v8::Handle<v8::Primitive> u = v8::Undefined();
1271 CHECK(!u->BooleanValue());
1272 v8::Handle<v8::Primitive> n = v8::Null();
1273 CHECK(!n->BooleanValue());
1274 v8::Handle<String> str1 = v8_str("");
1275 CHECK(!str1->BooleanValue());
1276 v8::Handle<String> str2 = v8_str("x");
1277 CHECK(str2->BooleanValue());
1278 CHECK(!v8::Number::New(0)->BooleanValue());
1279 CHECK(v8::Number::New(-1)->BooleanValue());
1280 CHECK(v8::Number::New(1)->BooleanValue());
1281 CHECK(v8::Number::New(42)->BooleanValue());
1282 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1283}
1284
1285
1286static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1287 ApiTestFuzzer::Fuzz();
1288 return v8_num(13.4);
1289}
1290
1291
1292static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1293 ApiTestFuzzer::Fuzz();
1294 return v8_num(876);
1295}
1296
1297
1298THREADED_TEST(GlobalPrototype) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001299 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001300 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1301 func_templ->PrototypeTemplate()->Set(
1302 "dummy",
1303 v8::FunctionTemplate::New(DummyCallHandler));
1304 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1305 templ->Set("x", v8_num(200));
1306 templ->SetAccessor(v8_str("m"), GetM);
1307 LocalContext env(0, templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001308 v8::Handle<Script> script(v8_compile("dummy()"));
1309 v8::Handle<Value> result(script->Run());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001310 CHECK_EQ(13.4, result->NumberValue());
1311 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1312 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1313}
1314
1315
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001316THREADED_TEST(ObjectTemplate) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001317 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001318 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1319 templ1->Set("x", v8_num(10));
1320 templ1->Set("y", v8_num(13));
1321 LocalContext env;
1322 Local<v8::Object> instance1 = templ1->NewInstance();
1323 env->Global()->Set(v8_str("p"), instance1);
1324 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1325 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1326 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1327 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1328 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1329 templ2->Set("a", v8_num(12));
1330 templ2->Set("b", templ1);
1331 Local<v8::Object> instance2 = templ2->NewInstance();
1332 env->Global()->Set(v8_str("q"), instance2);
1333 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1334 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1335 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1336 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1337}
1338
1339
1340static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1341 ApiTestFuzzer::Fuzz();
1342 return v8_num(17.2);
1343}
1344
1345
1346static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1347 ApiTestFuzzer::Fuzz();
1348 return v8_num(15.2);
1349}
1350
1351
1352THREADED_TEST(DescriptorInheritance) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001353 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001354 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1355 super->PrototypeTemplate()->Set("flabby",
1356 v8::FunctionTemplate::New(GetFlabby));
1357 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1358
1359 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1360
1361 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1362 base1->Inherit(super);
1363 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1364
1365 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1366 base2->Inherit(super);
1367 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1368
1369 LocalContext env;
1370
1371 env->Global()->Set(v8_str("s"), super->GetFunction());
1372 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1373 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1374
1375 // Checks right __proto__ chain.
1376 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1377 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1378
1379 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1380
1381 // Instance accessor should not be visible on function object or its prototype
1382 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1383 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1384 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1385
1386 env->Global()->Set(v8_str("obj"),
1387 base1->GetFunction()->NewInstance());
1388 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1389 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1390 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1391 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1392 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1393
1394 env->Global()->Set(v8_str("obj2"),
1395 base2->GetFunction()->NewInstance());
1396 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1397 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1398 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1399 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1400 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1401
1402 // base1 and base2 cannot cross reference to each's prototype
1403 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1404 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1405}
1406
1407
1408int echo_named_call_count;
1409
1410
1411static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1412 const AccessorInfo& info) {
1413 ApiTestFuzzer::Fuzz();
1414 CHECK_EQ(v8_str("data"), info.Data());
1415 echo_named_call_count++;
1416 return name;
1417}
1418
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419// Helper functions for Interceptor/Accessor interaction tests
1420
1421Handle<Value> SimpleAccessorGetter(Local<String> name,
1422 const AccessorInfo& info) {
1423 Handle<Object> self = info.This();
1424 return self->Get(String::Concat(v8_str("accessor_"), name));
1425}
1426
1427void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1428 const AccessorInfo& info) {
1429 Handle<Object> self = info.This();
1430 self->Set(String::Concat(v8_str("accessor_"), name), value);
1431}
1432
1433Handle<Value> EmptyInterceptorGetter(Local<String> name,
1434 const AccessorInfo& info) {
1435 return Handle<Value>();
1436}
1437
1438Handle<Value> EmptyInterceptorSetter(Local<String> name,
1439 Local<Value> value,
1440 const AccessorInfo& info) {
1441 return Handle<Value>();
1442}
1443
1444Handle<Value> InterceptorGetter(Local<String> name,
1445 const AccessorInfo& info) {
1446 // Intercept names that start with 'interceptor_'.
1447 String::AsciiValue ascii(name);
1448 char* name_str = *ascii;
1449 char prefix[] = "interceptor_";
1450 int i;
1451 for (i = 0; name_str[i] && prefix[i]; ++i) {
1452 if (name_str[i] != prefix[i]) return Handle<Value>();
1453 }
1454 Handle<Object> self = info.This();
1455 return self->GetHiddenValue(v8_str(name_str + i));
1456}
1457
1458Handle<Value> InterceptorSetter(Local<String> name,
1459 Local<Value> value,
1460 const AccessorInfo& info) {
1461 // Intercept accesses that set certain integer values.
1462 if (value->IsInt32() && value->Int32Value() < 10000) {
1463 Handle<Object> self = info.This();
1464 self->SetHiddenValue(name, value);
1465 return value;
1466 }
1467 return Handle<Value>();
1468}
1469
1470void AddAccessor(Handle<FunctionTemplate> templ,
1471 Handle<String> name,
1472 v8::AccessorGetter getter,
1473 v8::AccessorSetter setter) {
1474 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1475}
1476
1477void AddInterceptor(Handle<FunctionTemplate> templ,
1478 v8::NamedPropertyGetter getter,
1479 v8::NamedPropertySetter setter) {
1480 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1481}
1482
1483THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001484 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001485 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1486 Handle<FunctionTemplate> child = FunctionTemplate::New();
1487 child->Inherit(parent);
1488 AddAccessor(parent, v8_str("age"),
1489 SimpleAccessorGetter, SimpleAccessorSetter);
1490 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1491 LocalContext env;
1492 env->Global()->Set(v8_str("Child"), child->GetFunction());
1493 CompileRun("var child = new Child;"
1494 "child.age = 10;");
1495 ExpectBoolean("child.hasOwnProperty('age')", false);
1496 ExpectInt32("child.age", 10);
1497 ExpectInt32("child.accessor_age", 10);
1498}
1499
1500THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001501 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001502 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1503 Handle<FunctionTemplate> child = FunctionTemplate::New();
1504 child->Inherit(parent);
1505 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1506 LocalContext env;
1507 env->Global()->Set(v8_str("Child"), child->GetFunction());
1508 CompileRun("var child = new Child;"
1509 "var parent = child.__proto__;"
1510 "Object.defineProperty(parent, 'age', "
1511 " {get: function(){ return this.accessor_age; }, "
1512 " set: function(v){ this.accessor_age = v; }, "
1513 " enumerable: true, configurable: true});"
1514 "child.age = 10;");
1515 ExpectBoolean("child.hasOwnProperty('age')", false);
1516 ExpectInt32("child.age", 10);
1517 ExpectInt32("child.accessor_age", 10);
1518}
1519
1520THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001521 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1523 Handle<FunctionTemplate> child = FunctionTemplate::New();
1524 child->Inherit(parent);
1525 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1526 LocalContext env;
1527 env->Global()->Set(v8_str("Child"), child->GetFunction());
1528 CompileRun("var child = new Child;"
1529 "var parent = child.__proto__;"
1530 "parent.name = 'Alice';");
1531 ExpectBoolean("child.hasOwnProperty('name')", false);
1532 ExpectString("child.name", "Alice");
1533 CompileRun("child.name = 'Bob';");
1534 ExpectString("child.name", "Bob");
1535 ExpectBoolean("child.hasOwnProperty('name')", true);
1536 ExpectString("parent.name", "Alice");
1537}
1538
1539THREADED_TEST(SwitchFromInterceptorToAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001540 v8::HandleScope scope(v8::Isolate::GetCurrent());
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001541 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1542 AddAccessor(templ, v8_str("age"),
1543 SimpleAccessorGetter, SimpleAccessorSetter);
1544 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1545 LocalContext env;
1546 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1547 CompileRun("var obj = new Obj;"
1548 "function setAge(i){ obj.age = i; };"
1549 "for(var i = 0; i <= 10000; i++) setAge(i);");
1550 // All i < 10000 go to the interceptor.
1551 ExpectInt32("obj.interceptor_age", 9999);
1552 // The last i goes to the accessor.
1553 ExpectInt32("obj.accessor_age", 10000);
1554}
1555
1556THREADED_TEST(SwitchFromAccessorToInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001557 v8::HandleScope scope(v8::Isolate::GetCurrent());
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001558 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1559 AddAccessor(templ, v8_str("age"),
1560 SimpleAccessorGetter, SimpleAccessorSetter);
1561 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1562 LocalContext env;
1563 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1564 CompileRun("var obj = new Obj;"
1565 "function setAge(i){ obj.age = i; };"
1566 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1567 // All i >= 10000 go to the accessor.
1568 ExpectInt32("obj.accessor_age", 10000);
1569 // The last i goes to the interceptor.
1570 ExpectInt32("obj.interceptor_age", 9999);
1571}
1572
1573THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001574 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1576 Handle<FunctionTemplate> child = FunctionTemplate::New();
1577 child->Inherit(parent);
1578 AddAccessor(parent, v8_str("age"),
1579 SimpleAccessorGetter, SimpleAccessorSetter);
1580 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1581 LocalContext env;
1582 env->Global()->Set(v8_str("Child"), child->GetFunction());
1583 CompileRun("var child = new Child;"
1584 "function setAge(i){ child.age = i; };"
1585 "for(var i = 0; i <= 10000; i++) setAge(i);");
1586 // All i < 10000 go to the interceptor.
1587 ExpectInt32("child.interceptor_age", 9999);
1588 // The last i goes to the accessor.
1589 ExpectInt32("child.accessor_age", 10000);
1590}
1591
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001592THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001593 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1595 Handle<FunctionTemplate> child = FunctionTemplate::New();
1596 child->Inherit(parent);
1597 AddAccessor(parent, v8_str("age"),
1598 SimpleAccessorGetter, SimpleAccessorSetter);
1599 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1600 LocalContext env;
1601 env->Global()->Set(v8_str("Child"), child->GetFunction());
1602 CompileRun("var child = new Child;"
1603 "function setAge(i){ child.age = i; };"
1604 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1605 // All i >= 10000 go to the accessor.
1606 ExpectInt32("child.accessor_age", 10000);
1607 // The last i goes to the interceptor.
1608 ExpectInt32("child.interceptor_age", 9999);
1609}
1610
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001611THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001612 v8::HandleScope scope(v8::Isolate::GetCurrent());
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001613 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1614 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1615 LocalContext env;
1616 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1617 CompileRun("var obj = new Obj;"
1618 "function setter(i) { this.accessor_age = i; };"
1619 "function getter() { return this.accessor_age; };"
1620 "function setAge(i) { obj.age = i; };"
1621 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1622 "for(var i = 0; i <= 10000; i++) setAge(i);");
1623 // All i < 10000 go to the interceptor.
1624 ExpectInt32("obj.interceptor_age", 9999);
1625 // The last i goes to the JavaScript accessor.
1626 ExpectInt32("obj.accessor_age", 10000);
1627 // The installed JavaScript getter is still intact.
1628 // This last part is a regression test for issue 1651 and relies on the fact
1629 // that both interceptor and accessor are being installed on the same object.
1630 ExpectInt32("obj.age", 10000);
1631 ExpectBoolean("obj.hasOwnProperty('age')", true);
1632 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1633}
1634
1635THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001636 v8::HandleScope scope(v8::Isolate::GetCurrent());
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001637 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1638 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1639 LocalContext env;
1640 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1641 CompileRun("var obj = new Obj;"
1642 "function setter(i) { this.accessor_age = i; };"
1643 "function getter() { return this.accessor_age; };"
1644 "function setAge(i) { obj.age = i; };"
1645 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
1646 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1647 // All i >= 10000 go to the accessor.
1648 ExpectInt32("obj.accessor_age", 10000);
1649 // The last i goes to the interceptor.
1650 ExpectInt32("obj.interceptor_age", 9999);
1651 // The installed JavaScript getter is still intact.
1652 // This last part is a regression test for issue 1651 and relies on the fact
1653 // that both interceptor and accessor are being installed on the same object.
1654 ExpectInt32("obj.age", 10000);
1655 ExpectBoolean("obj.hasOwnProperty('age')", true);
1656 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
1657}
1658
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001659THREADED_TEST(SwitchFromInterceptorToProperty) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001660 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001661 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1662 Handle<FunctionTemplate> child = FunctionTemplate::New();
1663 child->Inherit(parent);
1664 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1665 LocalContext env;
1666 env->Global()->Set(v8_str("Child"), child->GetFunction());
1667 CompileRun("var child = new Child;"
1668 "function setAge(i){ child.age = i; };"
1669 "for(var i = 0; i <= 10000; i++) setAge(i);");
1670 // All i < 10000 go to the interceptor.
1671 ExpectInt32("child.interceptor_age", 9999);
1672 // The last i goes to child's own property.
1673 ExpectInt32("child.age", 10000);
1674}
1675
1676THREADED_TEST(SwitchFromPropertyToInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001677 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001678 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1679 Handle<FunctionTemplate> child = FunctionTemplate::New();
1680 child->Inherit(parent);
1681 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1682 LocalContext env;
1683 env->Global()->Set(v8_str("Child"), child->GetFunction());
1684 CompileRun("var child = new Child;"
1685 "function setAge(i){ child.age = i; };"
1686 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1687 // All i >= 10000 go to child's own property.
1688 ExpectInt32("child.age", 10000);
1689 // The last i goes to the interceptor.
1690 ExpectInt32("child.interceptor_age", 9999);
1691}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001692
1693THREADED_TEST(NamedPropertyHandlerGetter) {
1694 echo_named_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001695 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001696 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1697 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1698 0, 0, 0, 0,
1699 v8_str("data"));
1700 LocalContext env;
1701 env->Global()->Set(v8_str("obj"),
1702 templ->GetFunction()->NewInstance());
1703 CHECK_EQ(echo_named_call_count, 0);
1704 v8_compile("obj.x")->Run();
1705 CHECK_EQ(echo_named_call_count, 1);
1706 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1707 v8::Handle<Value> str = CompileRun(code);
1708 String::AsciiValue value(str);
1709 CHECK_EQ(*value, "oddlepoddle");
1710 // Check default behavior
1711 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1712 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1713 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1714}
1715
1716
1717int echo_indexed_call_count = 0;
1718
1719
1720static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1721 const AccessorInfo& info) {
1722 ApiTestFuzzer::Fuzz();
1723 CHECK_EQ(v8_num(637), info.Data());
1724 echo_indexed_call_count++;
1725 return v8_num(index);
1726}
1727
1728
1729THREADED_TEST(IndexedPropertyHandlerGetter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001730 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001731 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1732 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1733 0, 0, 0, 0,
1734 v8_num(637));
1735 LocalContext env;
1736 env->Global()->Set(v8_str("obj"),
1737 templ->GetFunction()->NewInstance());
1738 Local<Script> script = v8_compile("obj[900]");
1739 CHECK_EQ(script->Run()->Int32Value(), 900);
1740}
1741
1742
1743v8::Handle<v8::Object> bottom;
1744
1745static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1746 uint32_t index,
1747 const AccessorInfo& info) {
1748 ApiTestFuzzer::Fuzz();
1749 CHECK(info.This()->Equals(bottom));
1750 return v8::Handle<Value>();
1751}
1752
1753static v8::Handle<Value> CheckThisNamedPropertyHandler(
1754 Local<String> name,
1755 const AccessorInfo& info) {
1756 ApiTestFuzzer::Fuzz();
1757 CHECK(info.This()->Equals(bottom));
1758 return v8::Handle<Value>();
1759}
1760
1761
1762v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1763 Local<Value> value,
1764 const AccessorInfo& info) {
1765 ApiTestFuzzer::Fuzz();
1766 CHECK(info.This()->Equals(bottom));
1767 return v8::Handle<Value>();
1768}
1769
1770
1771v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1772 Local<Value> value,
1773 const AccessorInfo& info) {
1774 ApiTestFuzzer::Fuzz();
1775 CHECK(info.This()->Equals(bottom));
1776 return v8::Handle<Value>();
1777}
1778
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001779v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001780 uint32_t index,
1781 const AccessorInfo& info) {
1782 ApiTestFuzzer::Fuzz();
1783 CHECK(info.This()->Equals(bottom));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001784 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001785}
1786
1787
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001788v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001789 const AccessorInfo& info) {
1790 ApiTestFuzzer::Fuzz();
1791 CHECK(info.This()->Equals(bottom));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001792 return v8::Handle<v8::Integer>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001793}
1794
1795
1796v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1797 uint32_t index,
1798 const AccessorInfo& info) {
1799 ApiTestFuzzer::Fuzz();
1800 CHECK(info.This()->Equals(bottom));
1801 return v8::Handle<v8::Boolean>();
1802}
1803
1804
1805v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1806 Local<String> property,
1807 const AccessorInfo& info) {
1808 ApiTestFuzzer::Fuzz();
1809 CHECK(info.This()->Equals(bottom));
1810 return v8::Handle<v8::Boolean>();
1811}
1812
1813
1814v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1815 const AccessorInfo& info) {
1816 ApiTestFuzzer::Fuzz();
1817 CHECK(info.This()->Equals(bottom));
1818 return v8::Handle<v8::Array>();
1819}
1820
1821
1822v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1823 const AccessorInfo& info) {
1824 ApiTestFuzzer::Fuzz();
1825 CHECK(info.This()->Equals(bottom));
1826 return v8::Handle<v8::Array>();
1827}
1828
1829
1830THREADED_TEST(PropertyHandlerInPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001831 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001832 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001833
1834 // Set up a prototype chain with three interceptors.
1835 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1836 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1837 CheckThisIndexedPropertyHandler,
1838 CheckThisIndexedPropertySetter,
1839 CheckThisIndexedPropertyQuery,
1840 CheckThisIndexedPropertyDeleter,
1841 CheckThisIndexedPropertyEnumerator);
1842
1843 templ->InstanceTemplate()->SetNamedPropertyHandler(
1844 CheckThisNamedPropertyHandler,
1845 CheckThisNamedPropertySetter,
1846 CheckThisNamedPropertyQuery,
1847 CheckThisNamedPropertyDeleter,
1848 CheckThisNamedPropertyEnumerator);
1849
1850 bottom = templ->GetFunction()->NewInstance();
1851 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1852 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1853
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001854 bottom->SetPrototype(middle);
1855 middle->SetPrototype(top);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001856 env->Global()->Set(v8_str("obj"), bottom);
1857
1858 // Indexed and named get.
1859 Script::Compile(v8_str("obj[0]"))->Run();
1860 Script::Compile(v8_str("obj.x"))->Run();
1861
1862 // Indexed and named set.
1863 Script::Compile(v8_str("obj[1] = 42"))->Run();
1864 Script::Compile(v8_str("obj.y = 42"))->Run();
1865
1866 // Indexed and named query.
1867 Script::Compile(v8_str("0 in obj"))->Run();
1868 Script::Compile(v8_str("'x' in obj"))->Run();
1869
1870 // Indexed and named deleter.
1871 Script::Compile(v8_str("delete obj[0]"))->Run();
1872 Script::Compile(v8_str("delete obj.x"))->Run();
1873
1874 // Enumerators.
1875 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1876}
1877
1878
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001879static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1880 const AccessorInfo& info) {
1881 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001882 if (v8_str("pre")->Equals(key)) {
1883 return v8_str("PrePropertyHandler: pre");
1884 }
1885 return v8::Handle<String>();
1886}
1887
1888
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001889static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1890 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001891 if (v8_str("pre")->Equals(key)) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001892 return v8::Integer::New(v8::None);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001893 }
1894
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001895 return v8::Handle<v8::Integer>(); // do not intercept the call
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001896}
1897
1898
1899THREADED_TEST(PrePropertyHandler) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001900 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1902 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1903 0,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001904 PrePropertyHandlerQuery);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001905 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001906 Script::Compile(v8_str(
1907 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1908 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1909 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1910 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1911 CHECK_EQ(v8_str("Object: on"), result_on);
1912 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1913 CHECK(result_post.IsEmpty());
1914}
1915
1916
ager@chromium.org870a0b62008-11-04 11:43:05 +00001917THREADED_TEST(UndefinedIsNotEnumerable) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001918 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001919 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +00001920 v8::Handle<Value> result = Script::Compile(v8_str(
1921 "this.propertyIsEnumerable(undefined)"))->Run();
1922 CHECK(result->IsFalse());
1923}
1924
1925
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926v8::Handle<Script> call_recursively_script;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001927static const int kTargetRecursionDepth = 200; // near maximum
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001928
1929
1930static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1931 ApiTestFuzzer::Fuzz();
1932 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1933 if (depth == kTargetRecursionDepth) return v8::Undefined();
1934 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1935 return call_recursively_script->Run();
1936}
1937
1938
1939static v8::Handle<Value> CallFunctionRecursivelyCall(
1940 const v8::Arguments& args) {
1941 ApiTestFuzzer::Fuzz();
1942 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1943 if (depth == kTargetRecursionDepth) {
1944 printf("[depth = %d]\n", depth);
1945 return v8::Undefined();
1946 }
1947 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1948 v8::Handle<Value> function =
1949 args.This()->Get(v8_str("callFunctionRecursively"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001950 return function.As<Function>()->Call(args.This(), 0, NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001951}
1952
1953
1954THREADED_TEST(DeepCrossLanguageRecursion) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001955 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001956 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1957 global->Set(v8_str("callScriptRecursively"),
1958 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1959 global->Set(v8_str("callFunctionRecursively"),
1960 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1961 LocalContext env(NULL, global);
1962
1963 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1964 call_recursively_script = v8_compile("callScriptRecursively()");
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001965 call_recursively_script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001966 call_recursively_script = v8::Handle<Script>();
1967
1968 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1969 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1970}
1971
1972
1973static v8::Handle<Value>
1974 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1975 ApiTestFuzzer::Fuzz();
1976 return v8::ThrowException(key);
1977}
1978
1979
1980static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1981 Local<Value>,
1982 const AccessorInfo&) {
1983 v8::ThrowException(key);
1984 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1985}
1986
1987
1988THREADED_TEST(CallbackExceptionRegression) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001989 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001990 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1991 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1992 ThrowingPropertyHandlerSet);
1993 LocalContext env;
1994 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1995 v8::Handle<Value> otto = Script::Compile(v8_str(
1996 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1997 CHECK_EQ(v8_str("otto"), otto);
1998 v8::Handle<Value> netto = Script::Compile(v8_str(
1999 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2000 CHECK_EQ(v8_str("netto"), netto);
2001}
2002
2003
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002004THREADED_TEST(FunctionPrototype) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002005 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002006 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2007 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2008 LocalContext env;
2009 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2010 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2011 CHECK_EQ(script->Run()->Int32Value(), 321);
2012}
2013
2014
2015THREADED_TEST(InternalFields) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002016 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002017 v8::HandleScope scope(env->GetIsolate());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002019 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2020 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2021 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002022 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2023 CHECK_EQ(1, obj->InternalFieldCount());
2024 CHECK(obj->GetInternalField(0)->IsUndefined());
2025 obj->SetInternalField(0, v8_num(17));
2026 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2027}
2028
2029
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002030THREADED_TEST(GlobalObjectInternalFields) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002031 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002032 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2033 global_template->SetInternalFieldCount(1);
2034 LocalContext env(NULL, global_template);
2035 v8::Handle<v8::Object> global_proxy = env->Global();
2036 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2037 CHECK_EQ(1, global->InternalFieldCount());
2038 CHECK(global->GetInternalField(0)->IsUndefined());
2039 global->SetInternalField(0, v8_num(17));
2040 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2041}
2042
2043
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002044static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2045 void* value) {
2046 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002047 obj->SetAlignedPointerInInternalField(0, value);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002048 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002049 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002050}
2051
2052
2053THREADED_TEST(InternalFieldsAlignedPointers) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002054 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002055 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002056
2057 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2058 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2059 instance_templ->SetInternalFieldCount(1);
2060 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2061 CHECK_EQ(1, obj->InternalFieldCount());
2062
2063 CheckAlignedPointerInInternalField(obj, NULL);
2064
2065 int* heap_allocated = new int[100];
2066 CheckAlignedPointerInInternalField(obj, heap_allocated);
2067 delete[] heap_allocated;
2068
2069 int stack_allocated[100];
2070 CheckAlignedPointerInInternalField(obj, stack_allocated);
2071
2072 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2073 CheckAlignedPointerInInternalField(obj, huge);
2074}
2075
2076
2077static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2078 int index,
2079 void* value) {
2080 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2081 (*env)->SetAlignedPointerInEmbedderData(index, value);
2082 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2083 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2084}
2085
2086
2087static void* AlignedTestPointer(int i) {
2088 return reinterpret_cast<void*>(i * 1234);
2089}
2090
2091
2092THREADED_TEST(EmbedderDataAlignedPointers) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002093 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002094 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002095
2096 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2097
2098 int* heap_allocated = new int[100];
2099 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2100 delete[] heap_allocated;
2101
2102 int stack_allocated[100];
2103 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2104
2105 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2106 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2107
2108 // Test growing of the embedder data's backing store.
2109 for (int i = 0; i < 100; i++) {
2110 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2111 }
2112 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2113 for (int i = 0; i < 100; i++) {
2114 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2115 }
2116}
2117
2118
2119static void CheckEmbedderData(LocalContext* env,
2120 int index,
2121 v8::Handle<Value> data) {
2122 (*env)->SetEmbedderData(index, data);
2123 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2124}
2125
2126THREADED_TEST(EmbedderData) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002127 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002128 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002129
2130 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2131 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2132 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2133 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2134}
2135
2136
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002137THREADED_TEST(IdentityHash) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002138 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002139 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002140
2141 // Ensure that the test starts with an fresh heap to test whether the hash
2142 // code is based on the address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002143 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002144 Local<v8::Object> obj = v8::Object::New();
2145 int hash = obj->GetIdentityHash();
2146 int hash1 = obj->GetIdentityHash();
2147 CHECK_EQ(hash, hash1);
2148 int hash2 = v8::Object::New()->GetIdentityHash();
2149 // Since the identity hash is essentially a random number two consecutive
2150 // objects should not be assigned the same hash code. If the test below fails
2151 // the random number generator should be evaluated.
2152 CHECK_NE(hash, hash2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002153 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002154 int hash3 = v8::Object::New()->GetIdentityHash();
2155 // Make sure that the identity hash is not based on the initial address of
2156 // the object alone. If the test below fails the random number generator
2157 // should be evaluated.
2158 CHECK_NE(hash, hash3);
2159 int hash4 = obj->GetIdentityHash();
2160 CHECK_EQ(hash, hash4);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002161
2162 // Check identity hashes behaviour in the presence of JS accessors.
2163 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2164 {
2165 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2166 Local<v8::Object> o1 = v8::Object::New();
2167 Local<v8::Object> o2 = v8::Object::New();
2168 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2169 }
2170 {
2171 CompileRun(
2172 "function cnst() { return 42; };\n"
2173 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2174 Local<v8::Object> o1 = v8::Object::New();
2175 Local<v8::Object> o2 = v8::Object::New();
2176 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2177 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002178}
2179
2180
2181THREADED_TEST(HiddenProperties) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002182 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002183 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002184
2185 v8::Local<v8::Object> obj = v8::Object::New();
2186 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2187 v8::Local<v8::String> empty = v8_str("");
2188 v8::Local<v8::String> prop_name = v8_str("prop_name");
2189
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002190 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002191
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00002192 // Make sure delete of a non-existent hidden value works
2193 CHECK(obj->DeleteHiddenValue(key));
2194
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002195 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2196 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2197 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2198 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2199
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002200 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002201
2202 // Make sure we do not find the hidden property.
2203 CHECK(!obj->Has(empty));
2204 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2205 CHECK(obj->Get(empty)->IsUndefined());
2206 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2207 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2208 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2209 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2210
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002211 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002212
2213 // Add another property and delete it afterwards to force the object in
2214 // slow case.
2215 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2216 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2217 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2218 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2219 CHECK(obj->Delete(prop_name));
2220 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2221
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002222 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002223
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002224 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2225 CHECK(obj->GetHiddenValue(key).IsEmpty());
2226
2227 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002228 CHECK(obj->DeleteHiddenValue(key));
2229 CHECK(obj->GetHiddenValue(key).IsEmpty());
2230}
2231
2232
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002233THREADED_TEST(Regress97784) {
2234 // Regression test for crbug.com/97784
2235 // Messing with the Object.prototype should not have effect on
2236 // hidden properties.
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002237 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002238 v8::HandleScope scope(env->GetIsolate());
ricow@chromium.org9fe9cdf2011-09-27 08:04:16 +00002239
2240 v8::Local<v8::Object> obj = v8::Object::New();
2241 v8::Local<v8::String> key = v8_str("hidden");
2242
2243 CompileRun(
2244 "set_called = false;"
2245 "Object.defineProperty("
2246 " Object.prototype,"
2247 " 'hidden',"
2248 " {get: function() { return 45; },"
2249 " set: function() { set_called = true; }})");
2250
2251 CHECK(obj->GetHiddenValue(key).IsEmpty());
2252 // Make sure that the getter and setter from Object.prototype is not invoked.
2253 // If it did we would have full access to the hidden properties in
2254 // the accessor.
2255 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2256 ExpectFalse("set_called");
2257 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2258}
2259
2260
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002261static bool interceptor_for_hidden_properties_called;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002262static v8::Handle<Value> InterceptorForHiddenProperties(
2263 Local<String> name, const AccessorInfo& info) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002264 interceptor_for_hidden_properties_called = true;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002265 return v8::Handle<Value>();
2266}
2267
2268
2269THREADED_TEST(HiddenPropertiesWithInterceptors) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002270 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002271 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002272
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002273 interceptor_for_hidden_properties_called = false;
2274
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002275 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2276
2277 // Associate an interceptor with an object and start setting hidden values.
2278 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2279 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2280 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2281 Local<v8::Function> function = fun_templ->GetFunction();
2282 Local<v8::Object> obj = function->NewInstance();
2283 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2284 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002285 CHECK(!interceptor_for_hidden_properties_called);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002286}
2287
2288
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002289THREADED_TEST(External) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002290 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002291 int x = 3;
2292 Local<v8::External> ext = v8::External::New(&x);
2293 LocalContext env;
2294 env->Global()->Set(v8_str("ext"), ext);
2295 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002296 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002297 int* ptr = static_cast<int*>(reext->Value());
2298 CHECK_EQ(x, 3);
2299 *ptr = 10;
2300 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301
2302 // Make sure unaligned pointers are wrapped properly.
2303 char* data = i::StrDup("0123456789");
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002304 Local<v8::Value> zero = v8::External::New(&data[0]);
2305 Local<v8::Value> one = v8::External::New(&data[1]);
2306 Local<v8::Value> two = v8::External::New(&data[2]);
2307 Local<v8::Value> three = v8::External::New(&data[3]);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002309 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002310 CHECK_EQ('0', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002311 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 CHECK_EQ('1', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002313 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 CHECK_EQ('2', *char_ptr);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002315 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 CHECK_EQ('3', *char_ptr);
2317 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318}
2319
2320
2321THREADED_TEST(GlobalHandle) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002322 v8::Isolate* isolate = v8::Isolate::GetCurrent();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002323 v8::Persistent<String> global;
2324 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002325 v8::HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002326 Local<String> str = v8_str("str");
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002327 global = v8::Persistent<String>::New(isolate, str);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002328 }
2329 CHECK_EQ(global->Length(), 3);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002330 global.Dispose(isolate);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002331
2332 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002333 v8::HandleScope scope(isolate);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002334 Local<String> str = v8_str("str");
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002335 global = v8::Persistent<String>::New(isolate, str);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002336 }
2337 CHECK_EQ(global->Length(), 3);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002338 global.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002339}
2340
2341
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002342THREADED_TEST(LocalHandle) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002343 v8::HandleScope scope(v8::Isolate::GetCurrent());
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002344 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
2345 CHECK_EQ(local->Length(), 3);
2346
2347 local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str"));
2348 CHECK_EQ(local->Length(), 3);
2349}
2350
2351
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002352class WeakCallCounter {
2353 public:
2354 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2355 int id() { return id_; }
2356 void increment() { number_of_weak_calls_++; }
2357 int NumberOfWeakCalls() { return number_of_weak_calls_; }
2358 private:
2359 int id_;
2360 int number_of_weak_calls_;
2361};
2362
2363
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002364static void WeakPointerCallback(v8::Isolate* isolate,
2365 Persistent<Value> handle,
2366 void* id) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002367 WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2368 CHECK_EQ(1234, counter->id());
2369 counter->increment();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002370 handle.Dispose(isolate);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002371}
2372
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002373
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002374THREADED_TEST(ApiObjectGroups) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002375 LocalContext env;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002376 v8::Isolate* iso = env->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002377 HandleScope scope(iso);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002378
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002379 Persistent<Object> g1s1;
2380 Persistent<Object> g1s2;
2381 Persistent<Object> g1c1;
2382 Persistent<Object> g2s1;
2383 Persistent<Object> g2s2;
2384 Persistent<Object> g2c1;
2385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002386 WeakCallCounter counter(1234);
2387
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002388 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002389 HandleScope scope(iso);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002390 g1s1 = Persistent<Object>::New(iso, Object::New());
2391 g1s2 = Persistent<Object>::New(iso, Object::New());
2392 g1c1 = Persistent<Object>::New(iso, Object::New());
2393 g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2394 g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2395 g1c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002396
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002397 g2s1 = Persistent<Object>::New(iso, Object::New());
2398 g2s2 = Persistent<Object>::New(iso, Object::New());
2399 g2c1 = Persistent<Object>::New(iso, Object::New());
2400 g2s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2401 g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2402 g2c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002403 }
2404
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002405 Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002406
2407 // Connect group 1 and 2, make a cycle.
2408 CHECK(g1s2->Set(0, g2s2));
2409 CHECK(g2s1->Set(0, g1s1));
2410
2411 {
2412 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2413 Persistent<Value> g1_children[] = { g1c1 };
2414 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2415 Persistent<Value> g2_children[] = { g2c1 };
2416 V8::AddObjectGroup(g1_objects, 2);
2417 V8::AddImplicitReferences(g1s1, g1_children, 1);
2418 V8::AddObjectGroup(g2_objects, 2);
2419 V8::AddImplicitReferences(g2s2, g2_children, 1);
2420 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002421 // Do a single full GC, ensure incremental marking is stopped.
2422 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002423
2424 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002425 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002426
2427 // Weaken the root.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002428 root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002429 // But make children strong roots---all the objects (except for children)
2430 // should be collectable now.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002431 g1c1.ClearWeak(iso);
2432 g2c1.ClearWeak(iso);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002433
2434 // Groups are deleted, rebuild groups.
2435 {
2436 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2437 Persistent<Value> g1_children[] = { g1c1 };
2438 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2439 Persistent<Value> g2_children[] = { g2c1 };
2440 V8::AddObjectGroup(g1_objects, 2);
2441 V8::AddImplicitReferences(g1s1, g1_children, 1);
2442 V8::AddObjectGroup(g2_objects, 2);
2443 V8::AddImplicitReferences(g2s2, g2_children, 1);
2444 }
2445
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002446 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002447
2448 // All objects should be gone. 5 global handles in total.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002449 CHECK_EQ(5, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002450
2451 // And now make children weak again and collect them.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002452 g1c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2453 g2c1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002454
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002455 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002456 CHECK_EQ(7, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002457}
2458
2459
2460THREADED_TEST(ApiObjectGroupsCycle) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002461 LocalContext env;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002462 v8::Isolate* iso = env->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002463 HandleScope scope(iso);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002464
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002465 WeakCallCounter counter(1234);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002466
2467 Persistent<Object> g1s1;
2468 Persistent<Object> g1s2;
2469 Persistent<Object> g2s1;
2470 Persistent<Object> g2s2;
2471 Persistent<Object> g3s1;
2472 Persistent<Object> g3s2;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002473 Persistent<Object> g4s1;
2474 Persistent<Object> g4s2;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002475
2476 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002477 HandleScope scope(iso);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002478 g1s1 = Persistent<Object>::New(iso, Object::New());
2479 g1s2 = Persistent<Object>::New(iso, Object::New());
2480 g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2481 g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2482 CHECK(g1s1.IsWeak(iso));
2483 CHECK(g1s2.IsWeak(iso));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002484
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002485 g2s1 = Persistent<Object>::New(iso, Object::New());
2486 g2s2 = Persistent<Object>::New(iso, Object::New());
2487 g2s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2488 g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2489 CHECK(g2s1.IsWeak(iso));
2490 CHECK(g2s2.IsWeak(iso));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002491
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002492 g3s1 = Persistent<Object>::New(iso, Object::New());
2493 g3s2 = Persistent<Object>::New(iso, Object::New());
2494 g3s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2495 g3s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2496 CHECK(g3s1.IsWeak(iso));
2497 CHECK(g3s2.IsWeak(iso));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002498
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002499 g4s1 = Persistent<Object>::New(iso, Object::New());
2500 g4s2 = Persistent<Object>::New(iso, Object::New());
2501 g4s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2502 g4s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2503 CHECK(g4s1.IsWeak(iso));
2504 CHECK(g4s2.IsWeak(iso));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002505 }
2506
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002507 Persistent<Object> root = Persistent<Object>::New(iso, g1s1); // make a root.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002508
2509 // Connect groups. We're building the following cycle:
2510 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2511 // groups.
2512 {
2513 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2514 Persistent<Value> g1_children[] = { g2s1 };
2515 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2516 Persistent<Value> g2_children[] = { g3s1 };
2517 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002518 Persistent<Value> g3_children[] = { g4s1 };
2519 Persistent<Value> g4_objects[] = { g4s1, g4s2 };
2520 Persistent<Value> g4_children[] = { g1s1 };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002521 V8::AddObjectGroup(g1_objects, 2);
2522 V8::AddImplicitReferences(g1s1, g1_children, 1);
2523 V8::AddObjectGroup(g2_objects, 2);
2524 V8::AddImplicitReferences(g2s1, g2_children, 1);
2525 V8::AddObjectGroup(g3_objects, 2);
2526 V8::AddImplicitReferences(g3s1, g3_children, 1);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002527 V8::AddObjectGroup(iso, g4_objects, 2);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002528 V8::AddImplicitReferences(g4s1, g4_children, 1);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002530 // Do a single full GC
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002531 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002532
2533 // All object should be alive.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002534 CHECK_EQ(0, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002535
2536 // Weaken the root.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002537 root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002538
2539 // Groups are deleted, rebuild groups.
2540 {
2541 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2542 Persistent<Value> g1_children[] = { g2s1 };
2543 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2544 Persistent<Value> g2_children[] = { g3s1 };
2545 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002546 Persistent<Value> g3_children[] = { g4s1 };
2547 Persistent<Value> g4_objects[] = { g4s1, g4s2 };
2548 Persistent<Value> g4_children[] = { g1s1 };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002549 V8::AddObjectGroup(g1_objects, 2);
2550 V8::AddImplicitReferences(g1s1, g1_children, 1);
2551 V8::AddObjectGroup(g2_objects, 2);
2552 V8::AddImplicitReferences(g2s1, g2_children, 1);
2553 V8::AddObjectGroup(g3_objects, 2);
2554 V8::AddImplicitReferences(g3s1, g3_children, 1);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002555 V8::AddObjectGroup(g4_objects, 2);
2556 V8::AddImplicitReferences(g4s1, g4_children, 1);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002557 }
2558
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002559 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002560
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002561 // All objects should be gone. 9 global handles in total.
2562 CHECK_EQ(9, counter.NumberOfWeakCalls());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002563}
2564
2565
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002566// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
2567// on the buildbots, so was made non-threaded for the time being.
2568TEST(ApiObjectGroupsCycleForScavenger) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002569 i::FLAG_stress_compaction = false;
2570 i::FLAG_gc_global = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002571 LocalContext env;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002572 v8::Isolate* iso = env->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002573 HandleScope scope(iso);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002574
2575 WeakCallCounter counter(1234);
2576
2577 Persistent<Object> g1s1;
2578 Persistent<Object> g1s2;
2579 Persistent<Object> g2s1;
2580 Persistent<Object> g2s2;
2581 Persistent<Object> g3s1;
2582 Persistent<Object> g3s2;
2583
2584 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002585 HandleScope scope(iso);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002586 g1s1 = Persistent<Object>::New(iso, Object::New());
2587 g1s2 = Persistent<Object>::New(iso, Object::New());
2588 g1s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2589 g1s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002590
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002591 g2s1 = Persistent<Object>::New(iso, Object::New());
2592 g2s2 = Persistent<Object>::New(iso, Object::New());
2593 g2s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2594 g2s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002595
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002596 g3s1 = Persistent<Object>::New(iso, Object::New());
2597 g3s2 = Persistent<Object>::New(iso, Object::New());
2598 g3s1.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2599 g3s2.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002600 }
2601
2602 // Make a root.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002603 Persistent<Object> root = Persistent<Object>::New(iso, g1s1);
2604 root.MarkPartiallyDependent(iso);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002605
2606 // Connect groups. We're building the following cycle:
2607 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2608 // groups.
2609 {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002610 g1s1.MarkPartiallyDependent(iso);
2611 g1s2.MarkPartiallyDependent(iso);
2612 g2s1.MarkPartiallyDependent(iso);
2613 g2s2.MarkPartiallyDependent(iso);
2614 g3s1.MarkPartiallyDependent(iso);
2615 g3s2.MarkPartiallyDependent(iso);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002616 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2617 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2618 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2619 V8::AddObjectGroup(g1_objects, 2);
2620 g1s1->Set(v8_str("x"), g2s1);
2621 V8::AddObjectGroup(g2_objects, 2);
2622 g2s1->Set(v8_str("x"), g3s1);
2623 V8::AddObjectGroup(g3_objects, 2);
2624 g3s1->Set(v8_str("x"), g1s1);
2625 }
2626
2627 HEAP->CollectGarbage(i::NEW_SPACE);
2628
2629 // All objects should be alive.
2630 CHECK_EQ(0, counter.NumberOfWeakCalls());
2631
2632 // Weaken the root.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002633 root.MakeWeak(iso, reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2634 root.MarkPartiallyDependent(iso);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002635
2636 v8::Isolate* isolate = v8::Isolate::GetCurrent();
2637 // Groups are deleted, rebuild groups.
2638 {
2639 g1s1.MarkPartiallyDependent(isolate);
2640 g1s2.MarkPartiallyDependent(isolate);
2641 g2s1.MarkPartiallyDependent(isolate);
2642 g2s2.MarkPartiallyDependent(isolate);
2643 g3s1.MarkPartiallyDependent(isolate);
2644 g3s2.MarkPartiallyDependent(isolate);
2645 Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2646 Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2647 Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2648 V8::AddObjectGroup(g1_objects, 2);
2649 g1s1->Set(v8_str("x"), g2s1);
2650 V8::AddObjectGroup(g2_objects, 2);
2651 g2s1->Set(v8_str("x"), g3s1);
2652 V8::AddObjectGroup(g3_objects, 2);
2653 g3s1->Set(v8_str("x"), g1s1);
2654 }
2655
2656 HEAP->CollectGarbage(i::NEW_SPACE);
2657
2658 // All objects should be gone. 7 global handles in total.
2659 CHECK_EQ(7, counter.NumberOfWeakCalls());
2660}
2661
2662
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002663THREADED_TEST(ScriptException) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002664 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002665 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002666 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2667 v8::TryCatch try_catch;
2668 Local<Value> result = script->Run();
2669 CHECK(result.IsEmpty());
2670 CHECK(try_catch.HasCaught());
2671 String::AsciiValue exception_value(try_catch.Exception());
2672 CHECK_EQ(*exception_value, "panama!");
2673}
2674
2675
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002676TEST(TryCatchCustomException) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002677 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002678 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002679 v8::TryCatch try_catch;
2680 CompileRun("function CustomError() { this.a = 'b'; }"
2681 "(function f() { throw new CustomError(); })();");
2682 CHECK(try_catch.HasCaught());
2683 CHECK(try_catch.Exception()->ToObject()->
2684 Get(v8_str("a"))->Equals(v8_str("b")));
2685}
2686
2687
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002688bool message_received;
2689
2690
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002691static void check_message_0(v8::Handle<v8::Message> message,
2692 v8::Handle<Value> data) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002693 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002694 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002695 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002696 message_received = true;
2697}
2698
2699
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002700THREADED_TEST(MessageHandler0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002701 message_received = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002702 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002703 CHECK(!message_received);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002704 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002705 LocalContext context;
2706 v8::ScriptOrigin origin =
2707 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002708 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2709 &origin);
2710 script->SetData(v8_str("7.56"));
2711 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002712 CHECK(message_received);
2713 // clear out the message listener
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002714 v8::V8::RemoveMessageListeners(check_message_0);
2715}
2716
2717
2718static void check_message_1(v8::Handle<v8::Message> message,
2719 v8::Handle<Value> data) {
2720 CHECK(data->IsNumber());
2721 CHECK_EQ(1337, data->Int32Value());
2722 message_received = true;
2723}
2724
2725
2726TEST(MessageHandler1) {
2727 message_received = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002728 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002729 CHECK(!message_received);
2730 v8::V8::AddMessageListener(check_message_1);
2731 LocalContext context;
2732 CompileRun("throw 1337;");
2733 CHECK(message_received);
2734 // clear out the message listener
2735 v8::V8::RemoveMessageListeners(check_message_1);
2736}
2737
2738
2739static void check_message_2(v8::Handle<v8::Message> message,
2740 v8::Handle<Value> data) {
2741 LocalContext context;
2742 CHECK(data->IsObject());
2743 v8::Local<v8::Value> hidden_property =
2744 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
2745 CHECK(v8_str("hidden value")->Equals(hidden_property));
2746 message_received = true;
2747}
2748
2749
2750TEST(MessageHandler2) {
2751 message_received = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002752 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002753 CHECK(!message_received);
2754 v8::V8::AddMessageListener(check_message_2);
2755 LocalContext context;
2756 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
2757 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
2758 v8_str("hidden value"));
2759 context->Global()->Set(v8_str("error"), error);
2760 CompileRun("throw error;");
2761 CHECK(message_received);
2762 // clear out the message listener
2763 v8::V8::RemoveMessageListeners(check_message_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002764}
2765
2766
2767THREADED_TEST(GetSetProperty) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002768 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002769 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002770 context->Global()->Set(v8_str("foo"), v8_num(14));
2771 context->Global()->Set(v8_str("12"), v8_num(92));
2772 context->Global()->Set(v8::Integer::New(16), v8_num(32));
2773 context->Global()->Set(v8_num(13), v8_num(56));
2774 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2775 CHECK_EQ(14, foo->Int32Value());
2776 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2777 CHECK_EQ(92, twelve->Int32Value());
2778 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2779 CHECK_EQ(32, sixteen->Int32Value());
2780 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2781 CHECK_EQ(56, thirteen->Int32Value());
2782 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2783 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2784 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2785 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2786 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2787 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2788 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2789 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2790 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2791}
2792
2793
2794THREADED_TEST(PropertyAttributes) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002795 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002796 v8::HandleScope scope(context->GetIsolate());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002797 // none
2798 Local<String> prop = v8_str("none");
2799 context->Global()->Set(prop, v8_num(7));
2800 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002801 // read-only
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002802 prop = v8_str("read_only");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002803 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2804 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002805 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002806 Script::Compile(v8_str("read_only = 9"))->Run();
2807 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2808 context->Global()->Set(prop, v8_num(10));
2809 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2810 // dont-delete
2811 prop = v8_str("dont_delete");
2812 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2813 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2814 Script::Compile(v8_str("delete dont_delete"))->Run();
2815 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002816 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2817 // dont-enum
2818 prop = v8_str("dont_enum");
2819 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2820 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2821 // absent
2822 prop = v8_str("absent");
2823 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2824 Local<Value> fake_prop = v8_num(1);
2825 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2826 // exception
2827 TryCatch try_catch;
2828 Local<Value> exception =
2829 CompileRun("({ toString: function() { throw 'exception';} })");
2830 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2831 CHECK(try_catch.HasCaught());
2832 String::AsciiValue exception_value(try_catch.Exception());
2833 CHECK_EQ("exception", *exception_value);
2834 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002835}
2836
2837
2838THREADED_TEST(Array) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002839 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002840 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002841 Local<v8::Array> array = v8::Array::New();
2842 CHECK_EQ(0, array->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002843 CHECK(array->Get(0)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002844 CHECK(!array->Has(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002845 CHECK(array->Get(100)->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002846 CHECK(!array->Has(100));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002847 array->Set(2, v8_num(7));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002848 CHECK_EQ(3, array->Length());
2849 CHECK(!array->Has(0));
2850 CHECK(!array->Has(1));
2851 CHECK(array->Has(2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002852 CHECK_EQ(7, array->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002853 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002854 Local<v8::Array> arr = obj.As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002855 CHECK_EQ(3, arr->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002856 CHECK_EQ(1, arr->Get(0)->Int32Value());
2857 CHECK_EQ(2, arr->Get(1)->Int32Value());
2858 CHECK_EQ(3, arr->Get(2)->Int32Value());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00002859 array = v8::Array::New(27);
2860 CHECK_EQ(27, array->Length());
2861 array = v8::Array::New(-27);
2862 CHECK_EQ(0, array->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002863}
2864
2865
2866v8::Handle<Value> HandleF(const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002867 v8::HandleScope scope(args.GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002868 ApiTestFuzzer::Fuzz();
2869 Local<v8::Array> result = v8::Array::New(args.Length());
2870 for (int i = 0; i < args.Length(); i++)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002871 result->Set(i, args[i]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002872 return scope.Close(result);
2873}
2874
2875
2876THREADED_TEST(Vector) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002877 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002878 Local<ObjectTemplate> global = ObjectTemplate::New();
2879 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2880 LocalContext context(0, global);
2881
2882 const char* fun = "f()";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002883 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002884 CHECK_EQ(0, a0->Length());
2885
2886 const char* fun2 = "f(11)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002887 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002888 CHECK_EQ(1, a1->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002889 CHECK_EQ(11, a1->Get(0)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002890
2891 const char* fun3 = "f(12, 13)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002892 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002893 CHECK_EQ(2, a2->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002894 CHECK_EQ(12, a2->Get(0)->Int32Value());
2895 CHECK_EQ(13, a2->Get(1)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002896
2897 const char* fun4 = "f(14, 15, 16)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002898 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002899 CHECK_EQ(3, a3->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002900 CHECK_EQ(14, a3->Get(0)->Int32Value());
2901 CHECK_EQ(15, a3->Get(1)->Int32Value());
2902 CHECK_EQ(16, a3->Get(2)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002903
2904 const char* fun5 = "f(17, 18, 19, 20)";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002905 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002906 CHECK_EQ(4, a4->Length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002907 CHECK_EQ(17, a4->Get(0)->Int32Value());
2908 CHECK_EQ(18, a4->Get(1)->Int32Value());
2909 CHECK_EQ(19, a4->Get(2)->Int32Value());
2910 CHECK_EQ(20, a4->Get(3)->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002911}
2912
2913
2914THREADED_TEST(FunctionCall) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002915 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002916 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002917 CompileRun(
2918 "function Foo() {"
2919 " var result = [];"
2920 " for (var i = 0; i < arguments.length; i++) {"
2921 " result.push(arguments[i]);"
2922 " }"
2923 " return result;"
2924 "}");
2925 Local<Function> Foo =
2926 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2927
2928 v8::Handle<Value>* args0 = NULL;
2929 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2930 CHECK_EQ(0, a0->Length());
2931
2932 v8::Handle<Value> args1[] = { v8_num(1.1) };
2933 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2934 CHECK_EQ(1, a1->Length());
2935 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2936
2937 v8::Handle<Value> args2[] = { v8_num(2.2),
2938 v8_num(3.3) };
2939 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2940 CHECK_EQ(2, a2->Length());
2941 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2942 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2943
2944 v8::Handle<Value> args3[] = { v8_num(4.4),
2945 v8_num(5.5),
2946 v8_num(6.6) };
2947 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2948 CHECK_EQ(3, a3->Length());
2949 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2950 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2951 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2952
2953 v8::Handle<Value> args4[] = { v8_num(7.7),
2954 v8_num(8.8),
2955 v8_num(9.9),
2956 v8_num(10.11) };
2957 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2958 CHECK_EQ(4, a4->Length());
2959 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2960 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2961 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2962 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2963}
2964
2965
2966static const char* js_code_causing_out_of_memory =
2967 "var a = new Array(); while(true) a.push(a);";
2968
2969
2970// These tests run for a long time and prevent us from running tests
2971// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002972TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002973 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002974 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002975 // Set heap limits.
2976 static const int K = 1024;
2977 v8::ResourceConstraints constraints;
2978 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002979 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002980 v8::SetResourceConstraints(&constraints);
2981
2982 // Execute a script that causes out of memory.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002983 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002984 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002985 v8::V8::IgnoreOutOfMemoryException();
2986 Local<Script> script =
2987 Script::Compile(String::New(js_code_causing_out_of_memory));
2988 Local<Value> result = script->Run();
2989
2990 // Check for out of memory state.
2991 CHECK(result.IsEmpty());
2992 CHECK(context->HasOutOfMemoryException());
2993}
2994
2995
2996v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2997 ApiTestFuzzer::Fuzz();
2998
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002999 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003000 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003001 Local<Script> script =
3002 Script::Compile(String::New(js_code_causing_out_of_memory));
3003 Local<Value> result = script->Run();
3004
3005 // Check for out of memory state.
3006 CHECK(result.IsEmpty());
3007 CHECK(context->HasOutOfMemoryException());
3008
3009 return result;
3010}
3011
3012
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003013TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003014 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003015 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003016 // Set heap limits.
3017 static const int K = 1024;
3018 v8::ResourceConstraints constraints;
3019 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003020 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003021 v8::SetResourceConstraints(&constraints);
3022
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003023 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003024 Local<ObjectTemplate> templ = ObjectTemplate::New();
3025 templ->Set(v8_str("ProvokeOutOfMemory"),
3026 v8::FunctionTemplate::New(ProvokeOutOfMemory));
3027 LocalContext context(0, templ);
3028 v8::V8::IgnoreOutOfMemoryException();
3029 Local<Value> result = CompileRun(
3030 "var thrown = false;"
3031 "try {"
3032 " ProvokeOutOfMemory();"
3033 "} catch (e) {"
3034 " thrown = true;"
3035 "}");
3036 // Check for out of memory state.
3037 CHECK(result.IsEmpty());
3038 CHECK(context->HasOutOfMemoryException());
3039}
3040
3041
3042TEST(HugeConsStringOutOfMemory) {
3043 // It's not possible to read a snapshot into a heap with different dimensions.
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003044 if (i::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003045 // Set heap limits.
3046 static const int K = 1024;
3047 v8::ResourceConstraints constraints;
3048 constraints.set_max_young_space_size(256 * K);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003049 constraints.set_max_old_space_size(3 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003050 v8::SetResourceConstraints(&constraints);
3051
3052 // Execute a script that causes out of memory.
3053 v8::V8::IgnoreOutOfMemoryException();
3054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003056 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003057
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003058 // Build huge string. This should fail with out of memory exception.
3059 Local<Value> result = CompileRun(
3060 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003061 "for (var i = 0; i < 22; i++) { str = str + str; }");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003062
3063 // Check for out of memory state.
3064 CHECK(result.IsEmpty());
3065 CHECK(context->HasOutOfMemoryException());
3066}
3067
3068
3069THREADED_TEST(ConstructCall) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003070 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003071 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003072 CompileRun(
3073 "function Foo() {"
3074 " var result = [];"
3075 " for (var i = 0; i < arguments.length; i++) {"
3076 " result.push(arguments[i]);"
3077 " }"
3078 " return result;"
3079 "}");
3080 Local<Function> Foo =
3081 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3082
3083 v8::Handle<Value>* args0 = NULL;
3084 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3085 CHECK_EQ(0, a0->Length());
3086
3087 v8::Handle<Value> args1[] = { v8_num(1.1) };
3088 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3089 CHECK_EQ(1, a1->Length());
3090 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3091
3092 v8::Handle<Value> args2[] = { v8_num(2.2),
3093 v8_num(3.3) };
3094 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3095 CHECK_EQ(2, a2->Length());
3096 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3097 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3098
3099 v8::Handle<Value> args3[] = { v8_num(4.4),
3100 v8_num(5.5),
3101 v8_num(6.6) };
3102 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3103 CHECK_EQ(3, a3->Length());
3104 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3105 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3106 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3107
3108 v8::Handle<Value> args4[] = { v8_num(7.7),
3109 v8_num(8.8),
3110 v8_num(9.9),
3111 v8_num(10.11) };
3112 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3113 CHECK_EQ(4, a4->Length());
3114 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3115 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3116 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3117 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3118}
3119
3120
3121static void CheckUncle(v8::TryCatch* try_catch) {
3122 CHECK(try_catch->HasCaught());
3123 String::AsciiValue str_value(try_catch->Exception());
3124 CHECK_EQ(*str_value, "uncle?");
3125 try_catch->Reset();
3126}
3127
3128
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003129THREADED_TEST(ConversionNumber) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003130 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003131 v8::HandleScope scope(env->GetIsolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003132 // Very large number.
3133 CompileRun("var obj = Math.pow(2,32) * 1237;");
3134 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3135 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
3136 CHECK_EQ(0, obj->ToInt32()->Value());
3137 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
3138 // Large number.
3139 CompileRun("var obj = -1234567890123;");
3140 obj = env->Global()->Get(v8_str("obj"));
3141 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
3142 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
3143 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
3144 // Small positive integer.
3145 CompileRun("var obj = 42;");
3146 obj = env->Global()->Get(v8_str("obj"));
3147 CHECK_EQ(42.0, obj->ToNumber()->Value());
3148 CHECK_EQ(42, obj->ToInt32()->Value());
3149 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3150 // Negative integer.
3151 CompileRun("var obj = -37;");
3152 obj = env->Global()->Get(v8_str("obj"));
3153 CHECK_EQ(-37.0, obj->ToNumber()->Value());
3154 CHECK_EQ(-37, obj->ToInt32()->Value());
3155 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
3156 // Positive non-int32 integer.
3157 CompileRun("var obj = 0x81234567;");
3158 obj = env->Global()->Get(v8_str("obj"));
3159 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
3160 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
3161 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
3162 // Fraction.
3163 CompileRun("var obj = 42.3;");
3164 obj = env->Global()->Get(v8_str("obj"));
3165 CHECK_EQ(42.3, obj->ToNumber()->Value());
3166 CHECK_EQ(42, obj->ToInt32()->Value());
3167 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
3168 // Large negative fraction.
3169 CompileRun("var obj = -5726623061.75;");
3170 obj = env->Global()->Get(v8_str("obj"));
3171 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
3172 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
3173 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
3174}
3175
3176
3177THREADED_TEST(isNumberType) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003178 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003179 v8::HandleScope scope(env->GetIsolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003180 // Very large number.
3181 CompileRun("var obj = Math.pow(2,32) * 1237;");
3182 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3183 CHECK(!obj->IsInt32());
3184 CHECK(!obj->IsUint32());
3185 // Large negative number.
3186 CompileRun("var obj = -1234567890123;");
3187 obj = env->Global()->Get(v8_str("obj"));
3188 CHECK(!obj->IsInt32());
3189 CHECK(!obj->IsUint32());
3190 // Small positive integer.
3191 CompileRun("var obj = 42;");
3192 obj = env->Global()->Get(v8_str("obj"));
3193 CHECK(obj->IsInt32());
3194 CHECK(obj->IsUint32());
3195 // Negative integer.
3196 CompileRun("var obj = -37;");
3197 obj = env->Global()->Get(v8_str("obj"));
3198 CHECK(obj->IsInt32());
3199 CHECK(!obj->IsUint32());
3200 // Positive non-int32 integer.
3201 CompileRun("var obj = 0x81234567;");
3202 obj = env->Global()->Get(v8_str("obj"));
3203 CHECK(!obj->IsInt32());
3204 CHECK(obj->IsUint32());
3205 // Fraction.
3206 CompileRun("var obj = 42.3;");
3207 obj = env->Global()->Get(v8_str("obj"));
3208 CHECK(!obj->IsInt32());
3209 CHECK(!obj->IsUint32());
3210 // Large negative fraction.
3211 CompileRun("var obj = -5726623061.75;");
3212 obj = env->Global()->Get(v8_str("obj"));
3213 CHECK(!obj->IsInt32());
3214 CHECK(!obj->IsUint32());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003215 // Positive zero
3216 CompileRun("var obj = 0.0;");
3217 obj = env->Global()->Get(v8_str("obj"));
3218 CHECK(obj->IsInt32());
3219 CHECK(obj->IsUint32());
3220 // Positive zero
3221 CompileRun("var obj = -0.0;");
3222 obj = env->Global()->Get(v8_str("obj"));
3223 CHECK(!obj->IsInt32());
3224 CHECK(!obj->IsUint32());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003225}
3226
3227
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003228THREADED_TEST(ConversionException) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003229 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003230 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003231 CompileRun(
3232 "function TestClass() { };"
3233 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
3234 "var obj = new TestClass();");
3235 Local<Value> obj = env->Global()->Get(v8_str("obj"));
3236
3237 v8::TryCatch try_catch;
3238
3239 Local<Value> to_string_result = obj->ToString();
3240 CHECK(to_string_result.IsEmpty());
3241 CheckUncle(&try_catch);
3242
3243 Local<Value> to_number_result = obj->ToNumber();
3244 CHECK(to_number_result.IsEmpty());
3245 CheckUncle(&try_catch);
3246
3247 Local<Value> to_integer_result = obj->ToInteger();
3248 CHECK(to_integer_result.IsEmpty());
3249 CheckUncle(&try_catch);
3250
3251 Local<Value> to_uint32_result = obj->ToUint32();
3252 CHECK(to_uint32_result.IsEmpty());
3253 CheckUncle(&try_catch);
3254
3255 Local<Value> to_int32_result = obj->ToInt32();
3256 CHECK(to_int32_result.IsEmpty());
3257 CheckUncle(&try_catch);
3258
3259 Local<Value> to_object_result = v8::Undefined()->ToObject();
3260 CHECK(to_object_result.IsEmpty());
3261 CHECK(try_catch.HasCaught());
3262 try_catch.Reset();
3263
3264 int32_t int32_value = obj->Int32Value();
3265 CHECK_EQ(0, int32_value);
3266 CheckUncle(&try_catch);
3267
3268 uint32_t uint32_value = obj->Uint32Value();
3269 CHECK_EQ(0, uint32_value);
3270 CheckUncle(&try_catch);
3271
3272 double number_value = obj->NumberValue();
3273 CHECK_NE(0, IsNaN(number_value));
3274 CheckUncle(&try_catch);
3275
3276 int64_t integer_value = obj->IntegerValue();
3277 CHECK_EQ(0.0, static_cast<double>(integer_value));
3278 CheckUncle(&try_catch);
3279}
3280
3281
3282v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
3283 ApiTestFuzzer::Fuzz();
3284 return v8::ThrowException(v8_str("konto"));
3285}
3286
3287
ager@chromium.org8bb60582008-12-11 12:02:20 +00003288v8::Handle<Value> CCatcher(const v8::Arguments& args) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003289 if (args.Length() < 1) return v8::False();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003290 v8::HandleScope scope(args.GetIsolate());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003291 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003292 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
3293 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003294 return v8::Boolean::New(try_catch.HasCaught());
3295}
3296
3297
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003298THREADED_TEST(APICatch) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003299 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003300 Local<ObjectTemplate> templ = ObjectTemplate::New();
3301 templ->Set(v8_str("ThrowFromC"),
3302 v8::FunctionTemplate::New(ThrowFromC));
3303 LocalContext context(0, templ);
3304 CompileRun(
3305 "var thrown = false;"
3306 "try {"
3307 " ThrowFromC();"
3308 "} catch (e) {"
3309 " thrown = true;"
3310 "}");
3311 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
3312 CHECK(thrown->BooleanValue());
3313}
3314
3315
ager@chromium.org8bb60582008-12-11 12:02:20 +00003316THREADED_TEST(APIThrowTryCatch) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003317 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003318 Local<ObjectTemplate> templ = ObjectTemplate::New();
3319 templ->Set(v8_str("ThrowFromC"),
3320 v8::FunctionTemplate::New(ThrowFromC));
3321 LocalContext context(0, templ);
3322 v8::TryCatch try_catch;
3323 CompileRun("ThrowFromC();");
3324 CHECK(try_catch.HasCaught());
3325}
3326
3327
3328// Test that a try-finally block doesn't shadow a try-catch block
3329// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003330//
3331// BUG(271): Some of the exception propagation does not work on the
3332// ARM simulator because the simulator separates the C++ stack and the
3333// JS stack. This test therefore fails on the simulator. The test is
3334// not threaded to allow the threading tests to run on the simulator.
3335TEST(TryCatchInTryFinally) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003336 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003337 Local<ObjectTemplate> templ = ObjectTemplate::New();
3338 templ->Set(v8_str("CCatcher"),
3339 v8::FunctionTemplate::New(CCatcher));
3340 LocalContext context(0, templ);
3341 Local<Value> result = CompileRun("try {"
3342 " try {"
3343 " CCatcher('throw 7;');"
3344 " } finally {"
3345 " }"
3346 "} catch (e) {"
3347 "}");
3348 CHECK(result->IsTrue());
3349}
3350
3351
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003352static void check_reference_error_message(
3353 v8::Handle<v8::Message> message,
3354 v8::Handle<v8::Value> data) {
3355 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
3356 CHECK(message->Get()->Equals(v8_str(reference_error)));
3357}
3358
3359
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003360static v8::Handle<Value> Fail(const v8::Arguments& args) {
3361 ApiTestFuzzer::Fuzz();
3362 CHECK(false);
3363 return v8::Undefined();
3364}
3365
3366
3367// Test that overwritten methods are not invoked on uncaught exception
3368// formatting. However, they are invoked when performing normal error
3369// string conversions.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003370TEST(APIThrowMessageOverwrittenToString) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003371 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003372 v8::V8::AddMessageListener(check_reference_error_message);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003373 Local<ObjectTemplate> templ = ObjectTemplate::New();
3374 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
3375 LocalContext context(NULL, templ);
3376 CompileRun("asdf;");
3377 CompileRun("var limit = {};"
3378 "limit.valueOf = fail;"
3379 "Error.stackTraceLimit = limit;");
3380 CompileRun("asdf");
3381 CompileRun("Array.prototype.pop = fail;");
3382 CompileRun("Object.prototype.hasOwnProperty = fail;");
3383 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003384 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
3385 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003386 CompileRun("ReferenceError.prototype.toString ="
3387 " function() { return 'Whoops' }");
3388 CompileRun("asdf;");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003389 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
3390 CompileRun("asdf;");
3391 CompileRun("ReferenceError.prototype.constructor = void 0;");
3392 CompileRun("asdf;");
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003393 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
3394 CompileRun("asdf;");
3395 CompileRun("ReferenceError.prototype = new Object();");
3396 CompileRun("asdf;");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003397 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
3398 CHECK(string->Equals(v8_str("Whoops")));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003399 CompileRun("ReferenceError.prototype.constructor = new Object();"
3400 "ReferenceError.prototype.constructor.name = 1;"
3401 "Number.prototype.toString = function() { return 'Whoops'; };"
3402 "ReferenceError.prototype.toString = Object.prototype.toString;");
3403 CompileRun("asdf;");
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003404 v8::V8::RemoveMessageListeners(check_reference_error_message);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003405}
3406
3407
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003408static void check_custom_error_message(
3409 v8::Handle<v8::Message> message,
3410 v8::Handle<v8::Value> data) {
3411 const char* uncaught_error = "Uncaught MyError toString";
3412 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
3413}
3414
3415
3416TEST(CustomErrorToString) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003417 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003418 v8::HandleScope scope(context->GetIsolate());
3419 v8::V8::AddMessageListener(check_custom_error_message);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003420 CompileRun(
3421 "function MyError(name, message) { "
3422 " this.name = name; "
3423 " this.message = message; "
3424 "} "
3425 "MyError.prototype = Object.create(Error.prototype); "
3426 "MyError.prototype.toString = function() { "
3427 " return 'MyError toString'; "
3428 "}; "
3429 "throw new MyError('my name', 'my message'); ");
3430 v8::V8::RemoveMessageListeners(check_custom_error_message);
3431}
3432
3433
ager@chromium.org8bb60582008-12-11 12:02:20 +00003434static void receive_message(v8::Handle<v8::Message> message,
3435 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003436 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00003437 message_received = true;
3438}
3439
3440
3441TEST(APIThrowMessage) {
3442 message_received = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003443 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003444 v8::V8::AddMessageListener(receive_message);
3445 Local<ObjectTemplate> templ = ObjectTemplate::New();
3446 templ->Set(v8_str("ThrowFromC"),
3447 v8::FunctionTemplate::New(ThrowFromC));
3448 LocalContext context(0, templ);
3449 CompileRun("ThrowFromC();");
3450 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003451 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003452}
3453
3454
3455TEST(APIThrowMessageAndVerboseTryCatch) {
3456 message_received = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003457 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003458 v8::V8::AddMessageListener(receive_message);
3459 Local<ObjectTemplate> templ = ObjectTemplate::New();
3460 templ->Set(v8_str("ThrowFromC"),
3461 v8::FunctionTemplate::New(ThrowFromC));
3462 LocalContext context(0, templ);
3463 v8::TryCatch try_catch;
3464 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003465 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00003466 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00003467 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003468 CHECK(message_received);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003469 v8::V8::RemoveMessageListeners(receive_message);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003470}
3471
3472
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003473TEST(APIStackOverflowAndVerboseTryCatch) {
3474 message_received = false;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003475 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003476 v8::HandleScope scope(context->GetIsolate());
3477 v8::V8::AddMessageListener(receive_message);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003478 v8::TryCatch try_catch;
3479 try_catch.SetVerbose(true);
3480 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3481 CHECK(try_catch.HasCaught());
3482 CHECK(result.IsEmpty());
3483 CHECK(message_received);
3484 v8::V8::RemoveMessageListeners(receive_message);
3485}
3486
3487
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003488THREADED_TEST(ExternalScriptException) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003489 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003490 Local<ObjectTemplate> templ = ObjectTemplate::New();
3491 templ->Set(v8_str("ThrowFromC"),
3492 v8::FunctionTemplate::New(ThrowFromC));
3493 LocalContext context(0, templ);
3494
3495 v8::TryCatch try_catch;
3496 Local<Script> script
3497 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3498 Local<Value> result = script->Run();
3499 CHECK(result.IsEmpty());
3500 CHECK(try_catch.HasCaught());
3501 String::AsciiValue exception_value(try_catch.Exception());
3502 CHECK_EQ("konto", *exception_value);
3503}
3504
3505
3506
3507v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3508 ApiTestFuzzer::Fuzz();
3509 CHECK_EQ(4, args.Length());
3510 int count = args[0]->Int32Value();
3511 int cInterval = args[2]->Int32Value();
3512 if (count == 0) {
3513 return v8::ThrowException(v8_str("FromC"));
3514 } else {
3515 Local<v8::Object> global = Context::GetCurrent()->Global();
3516 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3517 v8::Handle<Value> argv[] = { v8_num(count - 1),
3518 args[1],
3519 args[2],
3520 args[3] };
3521 if (count % cInterval == 0) {
3522 v8::TryCatch try_catch;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003523 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003524 int expected = args[3]->Int32Value();
3525 if (try_catch.HasCaught()) {
3526 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003527 CHECK(result.IsEmpty());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 CHECK(!i::Isolate::Current()->has_scheduled_exception());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003529 } else {
3530 CHECK_NE(expected, count);
3531 }
3532 return result;
3533 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003534 return fun.As<Function>()->Call(global, 4, argv);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003535 }
3536 }
3537}
3538
3539
3540v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3541 ApiTestFuzzer::Fuzz();
3542 CHECK_EQ(3, args.Length());
3543 bool equality = args[0]->BooleanValue();
3544 int count = args[1]->Int32Value();
3545 int expected = args[2]->Int32Value();
3546 if (equality) {
3547 CHECK_EQ(count, expected);
3548 } else {
3549 CHECK_NE(count, expected);
3550 }
3551 return v8::Undefined();
3552}
3553
3554
ager@chromium.org8bb60582008-12-11 12:02:20 +00003555THREADED_TEST(EvalInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003556 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003557 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org8bb60582008-12-11 12:02:20 +00003558 v8::TryCatch try_catch;
3559 CompileRun("(function() {"
3560 " try {"
3561 " eval('asldkf (*&^&*^');"
3562 " } finally {"
3563 " return;"
3564 " }"
3565 "})()");
3566 CHECK(!try_catch.HasCaught());
3567}
3568
3569
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003570// This test works by making a stack of alternating JavaScript and C
3571// activations. These activations set up exception handlers with regular
3572// intervals, one interval for C activations and another for JavaScript
3573// activations. When enough activations have been created an exception is
3574// thrown and we check that the right activation catches the exception and that
3575// no other activations do. The right activation is always the topmost one with
3576// a handler, regardless of whether it is in JavaScript or C.
3577//
3578// The notation used to describe a test case looks like this:
3579//
3580// *JS[4] *C[3] @JS[2] C[1] JS[0]
3581//
3582// Each entry is an activation, either JS or C. The index is the count at that
3583// level. Stars identify activations with exception handlers, the @ identifies
3584// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00003585//
3586// BUG(271): Some of the exception propagation does not work on the
3587// ARM simulator because the simulator separates the C++ stack and the
3588// JS stack. This test therefore fails on the simulator. The test is
3589// not threaded to allow the threading tests to run on the simulator.
3590TEST(ExceptionOrder) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003591 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003592 Local<ObjectTemplate> templ = ObjectTemplate::New();
3593 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3594 templ->Set(v8_str("CThrowCountDown"),
3595 v8::FunctionTemplate::New(CThrowCountDown));
3596 LocalContext context(0, templ);
3597 CompileRun(
3598 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3599 " if (count == 0) throw 'FromJS';"
3600 " if (count % jsInterval == 0) {"
3601 " try {"
3602 " var value = CThrowCountDown(count - 1,"
3603 " jsInterval,"
3604 " cInterval,"
3605 " expected);"
3606 " check(false, count, expected);"
3607 " return value;"
3608 " } catch (e) {"
3609 " check(true, count, expected);"
3610 " }"
3611 " } else {"
3612 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3613 " }"
3614 "}");
3615 Local<Function> fun =
3616 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3617
3618 const int argc = 4;
3619 // count jsInterval cInterval expected
3620
3621 // *JS[4] *C[3] @JS[2] C[1] JS[0]
3622 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3623 fun->Call(fun, argc, a0);
3624
3625 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3626 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3627 fun->Call(fun, argc, a1);
3628
3629 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3630 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3631 fun->Call(fun, argc, a2);
3632
3633 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3634 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3635 fun->Call(fun, argc, a3);
3636
3637 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3638 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3639 fun->Call(fun, argc, a4);
3640
3641 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3642 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3643 fun->Call(fun, argc, a5);
3644}
3645
3646
3647v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3648 ApiTestFuzzer::Fuzz();
3649 CHECK_EQ(1, args.Length());
3650 return v8::ThrowException(args[0]);
3651}
3652
3653
3654THREADED_TEST(ThrowValues) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003655 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003656 Local<ObjectTemplate> templ = ObjectTemplate::New();
3657 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3658 LocalContext context(0, templ);
3659 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3660 "function Run(obj) {"
3661 " try {"
3662 " Throw(obj);"
3663 " } catch (e) {"
3664 " return e;"
3665 " }"
3666 " return 'no exception';"
3667 "}"
3668 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3669 CHECK_EQ(5, result->Length());
3670 CHECK(result->Get(v8::Integer::New(0))->IsString());
3671 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3672 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3673 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3674 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3675 CHECK(result->Get(v8::Integer::New(3))->IsNull());
3676 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3677}
3678
3679
3680THREADED_TEST(CatchZero) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003682 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 v8::TryCatch try_catch;
3684 CHECK(!try_catch.HasCaught());
3685 Script::Compile(v8_str("throw 10"))->Run();
3686 CHECK(try_catch.HasCaught());
3687 CHECK_EQ(10, try_catch.Exception()->Int32Value());
3688 try_catch.Reset();
3689 CHECK(!try_catch.HasCaught());
3690 Script::Compile(v8_str("throw 0"))->Run();
3691 CHECK(try_catch.HasCaught());
3692 CHECK_EQ(0, try_catch.Exception()->Int32Value());
3693}
3694
3695
3696THREADED_TEST(CatchExceptionFromWith) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003698 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 v8::TryCatch try_catch;
3700 CHECK(!try_catch.HasCaught());
3701 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3702 CHECK(try_catch.HasCaught());
3703}
3704
3705
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003706THREADED_TEST(TryCatchAndFinallyHidingException) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003707 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003708 v8::HandleScope scope(context->GetIsolate());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003709 v8::TryCatch try_catch;
3710 CHECK(!try_catch.HasCaught());
3711 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3712 CompileRun("f({toString: function() { throw 42; }});");
3713 CHECK(!try_catch.HasCaught());
3714}
3715
3716
3717v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3718 v8::TryCatch try_catch;
3719 return v8::Undefined();
3720}
3721
3722
3723THREADED_TEST(TryCatchAndFinally) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003724 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003725 v8::HandleScope scope(context->GetIsolate());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003726 context->Global()->Set(
3727 v8_str("native_with_try_catch"),
3728 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3729 v8::TryCatch try_catch;
3730 CHECK(!try_catch.HasCaught());
3731 CompileRun(
3732 "try {\n"
3733 " throw new Error('a');\n"
3734 "} finally {\n"
3735 " native_with_try_catch();\n"
3736 "}\n");
3737 CHECK(try_catch.HasCaught());
3738}
3739
3740
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003741static void TryCatchNestedHelper(int depth) {
3742 if (depth > 0) {
3743 v8::TryCatch try_catch;
3744 try_catch.SetVerbose(true);
3745 TryCatchNestedHelper(depth - 1);
3746 CHECK(try_catch.HasCaught());
3747 try_catch.ReThrow();
3748 } else {
3749 v8::ThrowException(v8_str("back"));
3750 }
3751}
3752
3753
3754TEST(TryCatchNested) {
3755 v8::V8::Initialize();
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003756 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003757 v8::HandleScope scope(context->GetIsolate());
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003758 v8::TryCatch try_catch;
3759 TryCatchNestedHelper(5);
3760 CHECK(try_catch.HasCaught());
3761 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
3762}
3763
3764
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003765THREADED_TEST(Equality) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003766 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003767 v8::Isolate* isolate = context->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003768 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003769 // Check that equality works at all before relying on CHECK_EQ
3770 CHECK(v8_str("a")->Equals(v8_str("a")));
3771 CHECK(!v8_str("a")->Equals(v8_str("b")));
3772
3773 CHECK_EQ(v8_str("a"), v8_str("a"));
3774 CHECK_NE(v8_str("a"), v8_str("b"));
3775 CHECK_EQ(v8_num(1), v8_num(1));
3776 CHECK_EQ(v8_num(1.00), v8_num(1));
3777 CHECK_NE(v8_num(1), v8_num(2));
3778
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003779 // Assume String is not internalized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003780 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3781 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3782 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3783 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3784 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3785 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3786 Local<Value> not_a_number = v8_num(i::OS::nan_value());
3787 CHECK(!not_a_number->StrictEquals(not_a_number));
3788 CHECK(v8::False()->StrictEquals(v8::False()));
3789 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3790
3791 v8::Handle<v8::Object> obj = v8::Object::New();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003792 v8::Persistent<v8::Object> alias =
3793 v8::Persistent<v8::Object>::New(isolate, obj);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003794 CHECK(alias->StrictEquals(obj));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00003795 alias.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003796}
3797
3798
3799THREADED_TEST(MultiRun) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003800 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003801 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003802 Local<Script> script = Script::Compile(v8_str("x"));
3803 for (int i = 0; i < 10; i++)
3804 script->Run();
3805}
3806
3807
3808static v8::Handle<Value> GetXValue(Local<String> name,
3809 const AccessorInfo& info) {
3810 ApiTestFuzzer::Fuzz();
3811 CHECK_EQ(info.Data(), v8_str("donut"));
3812 CHECK_EQ(name, v8_str("x"));
3813 return name;
3814}
3815
3816
3817THREADED_TEST(SimplePropertyRead) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003818 LocalContext context;
3819 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003820 Local<ObjectTemplate> templ = ObjectTemplate::New();
3821 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003822 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3823 Local<Script> script = Script::Compile(v8_str("obj.x"));
3824 for (int i = 0; i < 10; i++) {
3825 Local<Value> result = script->Run();
3826 CHECK_EQ(result, v8_str("x"));
3827 }
3828}
3829
ager@chromium.org5c838252010-02-19 08:53:10 +00003830THREADED_TEST(DefinePropertyOnAPIAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003831 LocalContext context;
3832 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00003833 Local<ObjectTemplate> templ = ObjectTemplate::New();
3834 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
ager@chromium.org5c838252010-02-19 08:53:10 +00003835 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3836
3837 // Uses getOwnPropertyDescriptor to check the configurable status
3838 Local<Script> script_desc
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003839 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
ager@chromium.org5c838252010-02-19 08:53:10 +00003840 "obj, 'x');"
3841 "prop.configurable;"));
3842 Local<Value> result = script_desc->Run();
3843 CHECK_EQ(result->BooleanValue(), true);
3844
3845 // Redefine get - but still configurable
3846 Local<Script> script_define
3847 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3848 " configurable: true };"
3849 "Object.defineProperty(obj, 'x', desc);"
3850 "obj.x"));
3851 result = script_define->Run();
3852 CHECK_EQ(result, v8_num(42));
3853
3854 // Check that the accessor is still configurable
3855 result = script_desc->Run();
3856 CHECK_EQ(result->BooleanValue(), true);
3857
3858 // Redefine to a non-configurable
3859 script_define
3860 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3861 " configurable: false };"
3862 "Object.defineProperty(obj, 'x', desc);"
3863 "obj.x"));
3864 result = script_define->Run();
3865 CHECK_EQ(result, v8_num(43));
3866 result = script_desc->Run();
3867 CHECK_EQ(result->BooleanValue(), false);
3868
3869 // Make sure that it is not possible to redefine again
3870 v8::TryCatch try_catch;
3871 result = script_define->Run();
3872 CHECK(try_catch.HasCaught());
3873 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003874 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003875}
3876
3877THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003878 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00003879 Local<ObjectTemplate> templ = ObjectTemplate::New();
3880 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3881 LocalContext context;
3882 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3883
3884 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3885 "Object.getOwnPropertyDescriptor( "
3886 "obj, 'x');"
3887 "prop.configurable;"));
3888 Local<Value> result = script_desc->Run();
3889 CHECK_EQ(result->BooleanValue(), true);
3890
3891 Local<Script> script_define =
3892 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3893 " configurable: true };"
3894 "Object.defineProperty(obj, 'x', desc);"
3895 "obj.x"));
3896 result = script_define->Run();
3897 CHECK_EQ(result, v8_num(42));
3898
3899
3900 result = script_desc->Run();
3901 CHECK_EQ(result->BooleanValue(), true);
3902
3903
3904 script_define =
3905 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3906 " configurable: false };"
3907 "Object.defineProperty(obj, 'x', desc);"
3908 "obj.x"));
3909 result = script_define->Run();
3910 CHECK_EQ(result, v8_num(43));
3911 result = script_desc->Run();
3912
3913 CHECK_EQ(result->BooleanValue(), false);
3914
3915 v8::TryCatch try_catch;
3916 result = script_define->Run();
3917 CHECK(try_catch.HasCaught());
3918 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003919 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
ager@chromium.org5c838252010-02-19 08:53:10 +00003920}
3921
3922
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003923static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3924 char const* name) {
3925 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3926}
ager@chromium.org5c838252010-02-19 08:53:10 +00003927
3928
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003929THREADED_TEST(DefineAPIAccessorOnObject) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003930 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003931 Local<ObjectTemplate> templ = ObjectTemplate::New();
3932 LocalContext context;
3933
3934 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3935 CompileRun("var obj2 = {};");
3936
3937 CHECK(CompileRun("obj1.x")->IsUndefined());
3938 CHECK(CompileRun("obj2.x")->IsUndefined());
3939
3940 CHECK(GetGlobalProperty(&context, "obj1")->
3941 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3942
3943 ExpectString("obj1.x", "x");
3944 CHECK(CompileRun("obj2.x")->IsUndefined());
3945
3946 CHECK(GetGlobalProperty(&context, "obj2")->
3947 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3948
3949 ExpectString("obj1.x", "x");
3950 ExpectString("obj2.x", "x");
3951
3952 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3953 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3954
3955 CompileRun("Object.defineProperty(obj1, 'x',"
3956 "{ get: function() { return 'y'; }, configurable: true })");
3957
3958 ExpectString("obj1.x", "y");
3959 ExpectString("obj2.x", "x");
3960
3961 CompileRun("Object.defineProperty(obj2, 'x',"
3962 "{ get: function() { return 'y'; }, configurable: true })");
3963
3964 ExpectString("obj1.x", "y");
3965 ExpectString("obj2.x", "y");
3966
3967 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3968 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3969
3970 CHECK(GetGlobalProperty(&context, "obj1")->
3971 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3972 CHECK(GetGlobalProperty(&context, "obj2")->
3973 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3974
3975 ExpectString("obj1.x", "x");
3976 ExpectString("obj2.x", "x");
3977
3978 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3979 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3980
3981 // Define getters/setters, but now make them not configurable.
3982 CompileRun("Object.defineProperty(obj1, 'x',"
3983 "{ get: function() { return 'z'; }, configurable: false })");
3984 CompileRun("Object.defineProperty(obj2, 'x',"
3985 "{ get: function() { return 'z'; }, configurable: false })");
3986
3987 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3988 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3989
3990 ExpectString("obj1.x", "z");
3991 ExpectString("obj2.x", "z");
3992
3993 CHECK(!GetGlobalProperty(&context, "obj1")->
3994 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3995 CHECK(!GetGlobalProperty(&context, "obj2")->
3996 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3997
3998 ExpectString("obj1.x", "z");
3999 ExpectString("obj2.x", "z");
4000}
4001
4002
4003THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004004 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004005 Local<ObjectTemplate> templ = ObjectTemplate::New();
4006 LocalContext context;
4007
4008 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4009 CompileRun("var obj2 = {};");
4010
4011 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4012 v8_str("x"),
4013 GetXValue, NULL,
4014 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4015 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4016 v8_str("x"),
4017 GetXValue, NULL,
4018 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4019
4020 ExpectString("obj1.x", "x");
4021 ExpectString("obj2.x", "x");
4022
4023 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4024 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4025
4026 CHECK(!GetGlobalProperty(&context, "obj1")->
4027 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4028 CHECK(!GetGlobalProperty(&context, "obj2")->
4029 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4030
4031 {
4032 v8::TryCatch try_catch;
4033 CompileRun("Object.defineProperty(obj1, 'x',"
4034 "{get: function() { return 'func'; }})");
4035 CHECK(try_catch.HasCaught());
4036 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004037 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004038 }
4039 {
4040 v8::TryCatch try_catch;
4041 CompileRun("Object.defineProperty(obj2, 'x',"
4042 "{get: function() { return 'func'; }})");
4043 CHECK(try_catch.HasCaught());
4044 String::AsciiValue exception_value(try_catch.Exception());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004046 }
4047}
4048
4049
4050static v8::Handle<Value> Get239Value(Local<String> name,
4051 const AccessorInfo& info) {
4052 ApiTestFuzzer::Fuzz();
4053 CHECK_EQ(info.Data(), v8_str("donut"));
4054 CHECK_EQ(name, v8_str("239"));
4055 return name;
4056}
4057
4058
4059THREADED_TEST(ElementAPIAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004060 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004061 Local<ObjectTemplate> templ = ObjectTemplate::New();
4062 LocalContext context;
4063
4064 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4065 CompileRun("var obj2 = {};");
4066
4067 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4068 v8_str("239"),
4069 Get239Value, NULL,
4070 v8_str("donut")));
4071 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4072 v8_str("239"),
4073 Get239Value, NULL,
4074 v8_str("donut")));
4075
4076 ExpectString("obj1[239]", "239");
4077 ExpectString("obj2[239]", "239");
4078 ExpectString("obj1['239']", "239");
4079 ExpectString("obj2['239']", "239");
4080}
4081
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004082
4083v8::Persistent<Value> xValue;
4084
4085
4086static void SetXValue(Local<String> name,
4087 Local<Value> value,
4088 const AccessorInfo& info) {
4089 CHECK_EQ(value, v8_num(4));
4090 CHECK_EQ(info.Data(), v8_str("donut"));
4091 CHECK_EQ(name, v8_str("x"));
4092 CHECK(xValue.IsEmpty());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004093 xValue = v8::Persistent<Value>::New(info.GetIsolate(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004094}
4095
4096
4097THREADED_TEST(SimplePropertyWrite) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004098 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004099 Local<ObjectTemplate> templ = ObjectTemplate::New();
4100 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
4101 LocalContext context;
4102 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4103 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
4104 for (int i = 0; i < 10; i++) {
4105 CHECK(xValue.IsEmpty());
4106 script->Run();
4107 CHECK_EQ(v8_num(4), xValue);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004108 xValue.Dispose(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004109 xValue = v8::Persistent<Value>();
4110 }
4111}
4112
4113
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004114THREADED_TEST(SetterOnly) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004115 v8::HandleScope scope(v8::Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004116 Local<ObjectTemplate> templ = ObjectTemplate::New();
4117 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
4118 LocalContext context;
4119 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4120 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4121 for (int i = 0; i < 10; i++) {
4122 CHECK(xValue.IsEmpty());
4123 script->Run();
4124 CHECK_EQ(v8_num(4), xValue);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004125 xValue.Dispose(context->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004126 xValue = v8::Persistent<Value>();
4127 }
4128}
4129
4130
4131THREADED_TEST(NoAccessors) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004132 v8::HandleScope scope(v8::Isolate::GetCurrent());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004133 Local<ObjectTemplate> templ = ObjectTemplate::New();
4134 templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
4135 LocalContext context;
4136 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4137 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
4138 for (int i = 0; i < 10; i++) {
4139 script->Run();
4140 }
4141}
4142
4143
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144static v8::Handle<Value> XPropertyGetter(Local<String> property,
4145 const AccessorInfo& info) {
4146 ApiTestFuzzer::Fuzz();
4147 CHECK(info.Data()->IsUndefined());
4148 return property;
4149}
4150
4151
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004152THREADED_TEST(NamedInterceptorPropertyRead) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004153 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Local<ObjectTemplate> templ = ObjectTemplate::New();
4155 templ->SetNamedPropertyHandler(XPropertyGetter);
4156 LocalContext context;
4157 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4158 Local<Script> script = Script::Compile(v8_str("obj.x"));
4159 for (int i = 0; i < 10; i++) {
4160 Local<Value> result = script->Run();
4161 CHECK_EQ(result, v8_str("x"));
4162 }
4163}
4164
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004165
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004166THREADED_TEST(NamedInterceptorDictionaryIC) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004167 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004168 Local<ObjectTemplate> templ = ObjectTemplate::New();
4169 templ->SetNamedPropertyHandler(XPropertyGetter);
4170 LocalContext context;
4171 // Create an object with a named interceptor.
4172 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
4173 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
4174 for (int i = 0; i < 10; i++) {
4175 Local<Value> result = script->Run();
4176 CHECK_EQ(result, v8_str("x"));
4177 }
4178 // Create a slow case object and a function accessing a property in
4179 // that slow case object (with dictionary probing in generated
4180 // code). Then force object with a named interceptor into slow-case,
4181 // pass it to the function, and check that the interceptor is called
4182 // instead of accessing the local property.
4183 Local<Value> result =
4184 CompileRun("function get_x(o) { return o.x; };"
4185 "var obj = { x : 42, y : 0 };"
4186 "delete obj.y;"
4187 "for (var i = 0; i < 10; i++) get_x(obj);"
4188 "interceptor_obj.x = 42;"
4189 "interceptor_obj.y = 10;"
4190 "delete interceptor_obj.y;"
4191 "get_x(interceptor_obj)");
4192 CHECK_EQ(result, v8_str("x"));
4193}
4194
4195
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004196THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004197 v8::HandleScope scope(v8::Isolate::GetCurrent());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004198
4199 v8::Persistent<Context> context1 = Context::New();
4200
4201 context1->Enter();
4202 Local<ObjectTemplate> templ = ObjectTemplate::New();
4203 templ->SetNamedPropertyHandler(XPropertyGetter);
4204 // Create an object with a named interceptor.
4205 v8::Local<v8::Object> object = templ->NewInstance();
4206 context1->Global()->Set(v8_str("interceptor_obj"), object);
4207
4208 // Force the object into the slow case.
4209 CompileRun("interceptor_obj.y = 0;"
4210 "delete interceptor_obj.y;");
4211 context1->Exit();
4212
4213 {
4214 // Introduce the object into a different context.
4215 // Repeat named loads to exercise ICs.
4216 LocalContext context2;
4217 context2->Global()->Set(v8_str("interceptor_obj"), object);
4218 Local<Value> result =
4219 CompileRun("function get_x(o) { return o.x; }"
4220 "interceptor_obj.x = 42;"
4221 "for (var i=0; i != 10; i++) {"
4222 " get_x(interceptor_obj);"
4223 "}"
4224 "get_x(interceptor_obj)");
4225 // Check that the interceptor was actually invoked.
4226 CHECK_EQ(result, v8_str("x"));
4227 }
4228
4229 // Return to the original context and force some object to the slow case
4230 // to cause the NormalizedMapCache to verify.
4231 context1->Enter();
4232 CompileRun("var obj = { x : 0 }; delete obj.x;");
4233 context1->Exit();
4234
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004235 context1.Dispose(context1->GetIsolate());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004236}
4237
4238
ager@chromium.org5c838252010-02-19 08:53:10 +00004239static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
4240 const AccessorInfo& info) {
4241 // Set x on the prototype object and do not handle the get request.
4242 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004243 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
ager@chromium.org5c838252010-02-19 08:53:10 +00004244 return v8::Handle<Value>();
4245}
4246
4247
4248// This is a regression test for http://crbug.com/20104. Map
4249// transitions should not interfere with post interceptor lookup.
4250THREADED_TEST(NamedInterceptorMapTransitionRead) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004251 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004252 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
4253 Local<v8::ObjectTemplate> instance_template
4254 = function_template->InstanceTemplate();
4255 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
4256 LocalContext context;
4257 context->Global()->Set(v8_str("F"), function_template->GetFunction());
4258 // Create an instance of F and introduce a map transition for x.
4259 CompileRun("var o = new F(); o.x = 23;");
4260 // Create an instance of F and invoke the getter. The result should be 23.
4261 Local<Value> result = CompileRun("o = new F(); o.x");
4262 CHECK_EQ(result->Int32Value(), 23);
4263}
4264
4265
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004266static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
4267 const AccessorInfo& info) {
4268 ApiTestFuzzer::Fuzz();
4269 if (index == 37) {
4270 return v8::Handle<Value>(v8_num(625));
4271 }
4272 return v8::Handle<Value>();
4273}
4274
4275
4276static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
4277 Local<Value> value,
4278 const AccessorInfo& info) {
4279 ApiTestFuzzer::Fuzz();
4280 if (index == 39) {
4281 return value;
4282 }
4283 return v8::Handle<Value>();
4284}
4285
4286
4287THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004288 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004289 Local<ObjectTemplate> templ = ObjectTemplate::New();
4290 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
4291 IndexedPropertySetter);
4292 LocalContext context;
4293 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4294 Local<Script> getter_script = Script::Compile(v8_str(
4295 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
4296 Local<Script> setter_script = Script::Compile(v8_str(
4297 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
4298 "obj[17] = 23;"
4299 "obj.foo;"));
4300 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
4301 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
4302 "obj[39] = 47;"
4303 "obj.foo;")); // This setter should not run, due to the interceptor.
4304 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
4305 "obj[37];"));
4306 Local<Value> result = getter_script->Run();
4307 CHECK_EQ(v8_num(5), result);
4308 result = setter_script->Run();
4309 CHECK_EQ(v8_num(23), result);
4310 result = interceptor_setter_script->Run();
4311 CHECK_EQ(v8_num(23), result);
4312 result = interceptor_getter_script->Run();
4313 CHECK_EQ(v8_num(625), result);
4314}
4315
4316
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004317static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
4318 uint32_t index,
4319 const AccessorInfo& info) {
4320 ApiTestFuzzer::Fuzz();
4321 if (index < 25) {
4322 return v8::Handle<Value>(v8_num(index));
4323 }
4324 return v8::Handle<Value>();
4325}
4326
4327
4328static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
4329 uint32_t index,
4330 Local<Value> value,
4331 const AccessorInfo& info) {
4332 ApiTestFuzzer::Fuzz();
4333 if (index < 25) {
4334 return v8::Handle<Value>(v8_num(index));
4335 }
4336 return v8::Handle<Value>();
4337}
4338
4339
4340Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
4341 const AccessorInfo& info) {
4342 // Force the list of returned keys to be stored in a FastDoubleArray.
4343 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4344 "keys = new Array(); keys[125000] = 1;"
4345 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
4346 "keys.length = 25; keys;"));
4347 Local<Value> result = indexed_property_names_script->Run();
4348 return Local<v8::Array>(::v8::Array::Cast(*result));
4349}
4350
4351
4352// Make sure that the the interceptor code in the runtime properly handles
4353// merging property name lists for double-array-backed arrays.
4354THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004355 v8::HandleScope scope(v8::Isolate::GetCurrent());
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004356 Local<ObjectTemplate> templ = ObjectTemplate::New();
4357 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
4358 UnboxedDoubleIndexedPropertySetter,
4359 0,
4360 0,
4361 UnboxedDoubleIndexedPropertyEnumerator);
4362 LocalContext context;
4363 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4364 // When obj is created, force it to be Stored in a FastDoubleArray.
4365 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
4366 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
4367 "key_count = 0; "
4368 "for (x in obj) {key_count++;};"
4369 "obj;"));
4370 Local<Value> result = create_unboxed_double_script->Run();
4371 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
4372 Local<Script> key_count_check = Script::Compile(v8_str(
4373 "key_count;"));
4374 result = key_count_check->Run();
4375 CHECK_EQ(v8_num(40013), result);
4376}
4377
4378
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004379Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
4380 const AccessorInfo& info) {
4381 // Force the list of returned keys to be stored in a Arguments object.
4382 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
4383 "function f(w,x) {"
4384 " return arguments;"
4385 "}"
4386 "keys = f(0, 1, 2, 3);"
4387 "keys;"));
4388 Local<Value> result = indexed_property_names_script->Run();
4389 return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
4390}
4391
4392
4393static v8::Handle<Value> NonStrictIndexedPropertyGetter(
4394 uint32_t index,
4395 const AccessorInfo& info) {
4396 ApiTestFuzzer::Fuzz();
4397 if (index < 4) {
4398 return v8::Handle<Value>(v8_num(index));
4399 }
4400 return v8::Handle<Value>();
4401}
4402
4403
4404// Make sure that the the interceptor code in the runtime properly handles
4405// merging property name lists for non-string arguments arrays.
4406THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004407 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.org28a37082011-08-22 11:03:23 +00004408 Local<ObjectTemplate> templ = ObjectTemplate::New();
4409 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
4410 0,
4411 0,
4412 0,
4413 NonStrictArgsIndexedPropertyEnumerator);
4414 LocalContext context;
4415 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4416 Local<Script> create_args_script =
4417 Script::Compile(v8_str(
4418 "var key_count = 0;"
4419 "for (x in obj) {key_count++;} key_count;"));
4420 Local<Value> result = create_args_script->Run();
4421 CHECK_EQ(v8_num(4), result);
4422}
4423
4424
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004425static v8::Handle<Value> IdentityIndexedPropertyGetter(
4426 uint32_t index,
4427 const AccessorInfo& info) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004428 return v8::Integer::NewFromUnsigned(index);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004429}
4430
4431
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004432THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004433 v8::HandleScope scope(v8::Isolate::GetCurrent());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004434 Local<ObjectTemplate> templ = ObjectTemplate::New();
4435 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4436
4437 LocalContext context;
4438 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4439
4440 // Check fast object case.
4441 const char* fast_case_code =
4442 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
4443 ExpectString(fast_case_code, "0");
4444
4445 // Check slow case.
4446 const char* slow_case_code =
4447 "obj.x = 1; delete obj.x;"
4448 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
4449 ExpectString(slow_case_code, "1");
4450}
4451
4452
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004453THREADED_TEST(IndexedInterceptorWithNoSetter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004454 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00004455 Local<ObjectTemplate> templ = ObjectTemplate::New();
4456 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4457
4458 LocalContext context;
4459 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4460
4461 const char* code =
4462 "try {"
4463 " obj[0] = 239;"
4464 " for (var i = 0; i < 100; i++) {"
4465 " var v = obj[0];"
4466 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
4467 " }"
4468 " 'PASSED'"
4469 "} catch(e) {"
4470 " e"
4471 "}";
4472 ExpectString(code, "PASSED");
4473}
4474
4475
ager@chromium.org5c838252010-02-19 08:53:10 +00004476THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004477 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004478 Local<ObjectTemplate> templ = ObjectTemplate::New();
4479 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4480
4481 LocalContext context;
4482 Local<v8::Object> obj = templ->NewInstance();
4483 obj->TurnOnAccessCheck();
4484 context->Global()->Set(v8_str("obj"), obj);
4485
4486 const char* code =
4487 "try {"
4488 " for (var i = 0; i < 100; i++) {"
4489 " var v = obj[0];"
4490 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
4491 " }"
4492 " 'PASSED'"
4493 "} catch(e) {"
4494 " e"
4495 "}";
4496 ExpectString(code, "PASSED");
4497}
4498
4499
4500THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
4501 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004502 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004503 Local<ObjectTemplate> templ = ObjectTemplate::New();
4504 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4505
4506 LocalContext context;
4507 Local<v8::Object> obj = templ->NewInstance();
4508 context->Global()->Set(v8_str("obj"), obj);
4509
4510 const char* code =
4511 "try {"
4512 " for (var i = 0; i < 100; i++) {"
4513 " var expected = i;"
4514 " if (i == 5) {"
4515 " %EnableAccessChecks(obj);"
4516 " expected = undefined;"
4517 " }"
4518 " var v = obj[i];"
4519 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4520 " if (i == 5) %DisableAccessChecks(obj);"
4521 " }"
4522 " 'PASSED'"
4523 "} catch(e) {"
4524 " e"
4525 "}";
4526 ExpectString(code, "PASSED");
4527}
4528
4529
4530THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004531 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004532 Local<ObjectTemplate> templ = ObjectTemplate::New();
4533 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4534
4535 LocalContext context;
4536 Local<v8::Object> obj = templ->NewInstance();
4537 context->Global()->Set(v8_str("obj"), obj);
4538
4539 const char* code =
4540 "try {"
4541 " for (var i = 0; i < 100; i++) {"
4542 " var v = obj[i];"
4543 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4544 " }"
4545 " 'PASSED'"
4546 "} catch(e) {"
4547 " e"
4548 "}";
4549 ExpectString(code, "PASSED");
4550}
4551
4552
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004553THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004554 v8::HandleScope scope(v8::Isolate::GetCurrent());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004555 Local<ObjectTemplate> templ = ObjectTemplate::New();
4556 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4557
4558 LocalContext context;
4559 Local<v8::Object> obj = templ->NewInstance();
4560 context->Global()->Set(v8_str("obj"), obj);
4561
4562 const char* code =
4563 "try {"
4564 " for (var i = 0; i < 100; i++) {"
4565 " var expected = i;"
4566 " var key = i;"
4567 " if (i == 25) {"
4568 " key = -1;"
4569 " expected = undefined;"
4570 " }"
4571 " if (i == 50) {"
4572 " /* probe minimal Smi number on 32-bit platforms */"
4573 " key = -(1 << 30);"
4574 " expected = undefined;"
4575 " }"
4576 " if (i == 75) {"
4577 " /* probe minimal Smi number on 64-bit platforms */"
4578 " key = 1 << 31;"
4579 " expected = undefined;"
4580 " }"
4581 " var v = obj[key];"
4582 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4583 " }"
4584 " 'PASSED'"
4585 "} catch(e) {"
4586 " e"
4587 "}";
4588 ExpectString(code, "PASSED");
4589}
4590
4591
ager@chromium.org5c838252010-02-19 08:53:10 +00004592THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004593 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004594 Local<ObjectTemplate> templ = ObjectTemplate::New();
4595 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4596
4597 LocalContext context;
4598 Local<v8::Object> obj = templ->NewInstance();
4599 context->Global()->Set(v8_str("obj"), obj);
4600
4601 const char* code =
4602 "try {"
4603 " for (var i = 0; i < 100; i++) {"
4604 " var expected = i;"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004605 " var key = i;"
ager@chromium.org5c838252010-02-19 08:53:10 +00004606 " if (i == 50) {"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004607 " key = 'foobar';"
ager@chromium.org5c838252010-02-19 08:53:10 +00004608 " expected = undefined;"
4609 " }"
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004610 " var v = obj[key];"
ager@chromium.org5c838252010-02-19 08:53:10 +00004611 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4612 " }"
4613 " 'PASSED'"
4614 "} catch(e) {"
4615 " e"
4616 "}";
4617 ExpectString(code, "PASSED");
4618}
4619
4620
4621THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004622 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004623 Local<ObjectTemplate> templ = ObjectTemplate::New();
4624 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4625
4626 LocalContext context;
4627 Local<v8::Object> obj = templ->NewInstance();
4628 context->Global()->Set(v8_str("obj"), obj);
4629
4630 const char* code =
4631 "var original = obj;"
4632 "try {"
4633 " for (var i = 0; i < 100; i++) {"
4634 " var expected = i;"
4635 " if (i == 50) {"
4636 " obj = {50: 'foobar'};"
4637 " expected = 'foobar';"
4638 " }"
4639 " var v = obj[i];"
4640 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4641 " if (i == 50) obj = original;"
4642 " }"
4643 " 'PASSED'"
4644 "} catch(e) {"
4645 " e"
4646 "}";
4647 ExpectString(code, "PASSED");
4648}
4649
4650
4651THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004652 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004653 Local<ObjectTemplate> templ = ObjectTemplate::New();
4654 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4655
4656 LocalContext context;
4657 Local<v8::Object> obj = templ->NewInstance();
4658 context->Global()->Set(v8_str("obj"), obj);
4659
4660 const char* code =
4661 "var original = obj;"
4662 "try {"
4663 " for (var i = 0; i < 100; i++) {"
4664 " var expected = i;"
4665 " if (i == 5) {"
4666 " obj = 239;"
4667 " expected = undefined;"
4668 " }"
4669 " var v = obj[i];"
4670 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4671 " if (i == 5) obj = original;"
4672 " }"
4673 " 'PASSED'"
4674 "} catch(e) {"
4675 " e"
4676 "}";
4677 ExpectString(code, "PASSED");
4678}
4679
4680
4681THREADED_TEST(IndexedInterceptorOnProto) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004682 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +00004683 Local<ObjectTemplate> templ = ObjectTemplate::New();
4684 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4685
4686 LocalContext context;
4687 Local<v8::Object> obj = templ->NewInstance();
4688 context->Global()->Set(v8_str("obj"), obj);
4689
4690 const char* code =
4691 "var o = {__proto__: obj};"
4692 "try {"
4693 " for (var i = 0; i < 100; i++) {"
4694 " var v = o[i];"
4695 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4696 " }"
4697 " 'PASSED'"
4698 "} catch(e) {"
4699 " e"
4700 "}";
4701 ExpectString(code, "PASSED");
4702}
4703
4704
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004705THREADED_TEST(MultiContexts) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004706 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004707 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4708 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4709
4710 Local<String> password = v8_str("Password");
4711
4712 // Create an environment
4713 LocalContext context0(0, templ);
4714 context0->SetSecurityToken(password);
4715 v8::Handle<v8::Object> global0 = context0->Global();
4716 global0->Set(v8_str("custom"), v8_num(1234));
4717 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4718
4719 // Create an independent environment
4720 LocalContext context1(0, templ);
4721 context1->SetSecurityToken(password);
4722 v8::Handle<v8::Object> global1 = context1->Global();
4723 global1->Set(v8_str("custom"), v8_num(1234));
4724 CHECK_NE(global0, global1);
4725 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4726 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4727
4728 // Now create a new context with the old global
4729 LocalContext context2(0, templ, global1);
4730 context2->SetSecurityToken(password);
4731 v8::Handle<v8::Object> global2 = context2->Global();
4732 CHECK_EQ(global1, global2);
4733 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4734 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4735}
4736
4737
4738THREADED_TEST(FunctionPrototypeAcrossContexts) {
4739 // Make sure that functions created by cloning boilerplates cannot
4740 // communicate through their __proto__ field.
4741
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004742 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004743
4744 LocalContext env0;
4745 v8::Handle<v8::Object> global0 =
4746 env0->Global();
4747 v8::Handle<v8::Object> object0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004748 global0->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004749 v8::Handle<v8::Object> tostring0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004750 object0->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004751 v8::Handle<v8::Object> proto0 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004752 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004753 proto0->Set(v8_str("custom"), v8_num(1234));
4754
4755 LocalContext env1;
4756 v8::Handle<v8::Object> global1 =
4757 env1->Global();
4758 v8::Handle<v8::Object> object1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004759 global1->Get(v8_str("Object")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004760 v8::Handle<v8::Object> tostring1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004761 object1->Get(v8_str("toString")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004762 v8::Handle<v8::Object> proto1 =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004763 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004764 CHECK(!proto1->Has(v8_str("custom")));
4765}
4766
4767
4768THREADED_TEST(Regress892105) {
4769 // Make sure that object and array literals created by cloning
4770 // boilerplates cannot communicate through their __proto__
4771 // field. This is rather difficult to check, but we try to add stuff
4772 // to Object.prototype and Array.prototype and create a new
4773 // environment. This should succeed.
4774
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004775 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004776
4777 Local<String> source = v8_str("Object.prototype.obj = 1234;"
4778 "Array.prototype.arr = 4567;"
4779 "8901");
4780
4781 LocalContext env0;
4782 Local<Script> script0 = Script::Compile(source);
4783 CHECK_EQ(8901.0, script0->Run()->NumberValue());
4784
4785 LocalContext env1;
4786 Local<Script> script1 = Script::Compile(source);
4787 CHECK_EQ(8901.0, script1->Run()->NumberValue());
4788}
4789
4790
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004791THREADED_TEST(UndetectableObject) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004792 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004793 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004794
4795 Local<v8::FunctionTemplate> desc =
4796 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4797 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4798
4799 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4800 env->Global()->Set(v8_str("undetectable"), obj);
4801
4802 ExpectString("undetectable.toString()", "[object Object]");
4803 ExpectString("typeof undetectable", "undefined");
4804 ExpectString("typeof(undetectable)", "undefined");
4805 ExpectBoolean("typeof undetectable == 'undefined'", true);
4806 ExpectBoolean("typeof undetectable == 'object'", false);
4807 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4808 ExpectBoolean("!undetectable", true);
4809
4810 ExpectObject("true&&undetectable", obj);
4811 ExpectBoolean("false&&undetectable", false);
4812 ExpectBoolean("true||undetectable", true);
4813 ExpectObject("false||undetectable", obj);
4814
4815 ExpectObject("undetectable&&true", obj);
4816 ExpectObject("undetectable&&false", obj);
4817 ExpectBoolean("undetectable||true", true);
4818 ExpectBoolean("undetectable||false", false);
4819
4820 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004821 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004822 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004823 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004824 ExpectBoolean("undetectable==undetectable", true);
4825
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004827 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004828 ExpectBoolean("null===undetectable", false);
4829 ExpectBoolean("undetectable===undefined", false);
4830 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004831 ExpectBoolean("undetectable===undetectable", true);
4832}
4833
4834
ager@chromium.org04921a82011-06-27 13:21:41 +00004835THREADED_TEST(VoidLiteral) {
ager@chromium.org04921a82011-06-27 13:21:41 +00004836 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004837 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org04921a82011-06-27 13:21:41 +00004838
4839 Local<v8::FunctionTemplate> desc =
4840 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4841 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4842
4843 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4844 env->Global()->Set(v8_str("undetectable"), obj);
4845
4846 ExpectBoolean("undefined == void 0", true);
4847 ExpectBoolean("undetectable == void 0", true);
4848 ExpectBoolean("null == void 0", true);
4849 ExpectBoolean("undefined === void 0", true);
4850 ExpectBoolean("undetectable === void 0", false);
4851 ExpectBoolean("null === void 0", false);
4852
4853 ExpectBoolean("void 0 == undefined", true);
4854 ExpectBoolean("void 0 == undetectable", true);
4855 ExpectBoolean("void 0 == null", true);
4856 ExpectBoolean("void 0 === undefined", true);
4857 ExpectBoolean("void 0 === undetectable", false);
4858 ExpectBoolean("void 0 === null", false);
4859
4860 ExpectString("(function() {"
4861 " try {"
4862 " return x === void 0;"
4863 " } catch(e) {"
4864 " return e.toString();"
4865 " }"
4866 "})()",
4867 "ReferenceError: x is not defined");
4868 ExpectString("(function() {"
4869 " try {"
4870 " return void 0 === x;"
4871 " } catch(e) {"
4872 " return e.toString();"
4873 " }"
4874 "})()",
4875 "ReferenceError: x is not defined");
4876}
4877
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004878
4879THREADED_TEST(ExtensibleOnUndetectable) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004880 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004881 v8::HandleScope scope(env->GetIsolate());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004882
4883 Local<v8::FunctionTemplate> desc =
4884 v8::FunctionTemplate::New(0, v8::Handle<Value>());
4885 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
4886
4887 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4888 env->Global()->Set(v8_str("undetectable"), obj);
4889
4890 Local<String> source = v8_str("undetectable.x = 42;"
4891 "undetectable.x");
4892
4893 Local<Script> script = Script::Compile(source);
4894
4895 CHECK_EQ(v8::Integer::New(42), script->Run());
4896
4897 ExpectBoolean("Object.isExtensible(undetectable)", true);
4898
4899 source = v8_str("Object.preventExtensions(undetectable);");
4900 script = Script::Compile(source);
4901 script->Run();
4902 ExpectBoolean("Object.isExtensible(undetectable)", false);
4903
4904 source = v8_str("undetectable.y = 2000;");
4905 script = Script::Compile(source);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004906 script->Run();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004907 ExpectBoolean("undetectable.y == undefined", true);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004908}
4909
4910
4911
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004912THREADED_TEST(UndetectableString) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004913 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004914 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004915
4916 Local<String> obj = String::NewUndetectable("foo");
4917 env->Global()->Set(v8_str("undetectable"), obj);
4918
4919 ExpectString("undetectable", "foo");
4920 ExpectString("typeof undetectable", "undefined");
4921 ExpectString("typeof(undetectable)", "undefined");
4922 ExpectBoolean("typeof undetectable == 'undefined'", true);
4923 ExpectBoolean("typeof undetectable == 'string'", false);
4924 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4925 ExpectBoolean("!undetectable", true);
4926
4927 ExpectObject("true&&undetectable", obj);
4928 ExpectBoolean("false&&undetectable", false);
4929 ExpectBoolean("true||undetectable", true);
4930 ExpectObject("false||undetectable", obj);
4931
4932 ExpectObject("undetectable&&true", obj);
4933 ExpectObject("undetectable&&false", obj);
4934 ExpectBoolean("undetectable||true", true);
4935 ExpectBoolean("undetectable||false", false);
4936
4937 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004938 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004939 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004940 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004941 ExpectBoolean("undetectable==undetectable", true);
4942
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004944 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00004945 ExpectBoolean("null===undetectable", false);
4946 ExpectBoolean("undetectable===undefined", false);
4947 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004948 ExpectBoolean("undetectable===undetectable", true);
4949}
4950
4951
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004952TEST(UndetectableOptimized) {
4953 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004954 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004955 v8::HandleScope scope(env->GetIsolate());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004956
4957 Local<String> obj = String::NewUndetectable("foo");
4958 env->Global()->Set(v8_str("undetectable"), obj);
4959 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4960
4961 ExpectString(
4962 "function testBranch() {"
4963 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
4964 " if (%_IsUndetectableObject(detectable)) throw 2;"
4965 "}\n"
4966 "function testBool() {"
4967 " var b1 = !%_IsUndetectableObject(undetectable);"
4968 " var b2 = %_IsUndetectableObject(detectable);"
4969 " if (b1) throw 3;"
4970 " if (b2) throw 4;"
4971 " return b1 == b2;"
4972 "}\n"
4973 "%OptimizeFunctionOnNextCall(testBranch);"
4974 "%OptimizeFunctionOnNextCall(testBool);"
4975 "for (var i = 0; i < 10; i++) {"
4976 " testBranch();"
4977 " testBool();"
4978 "}\n"
4979 "\"PASS\"",
4980 "PASS");
4981}
4982
4983
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004984template <typename T> static void USE(T) { }
4985
4986
4987// This test is not intended to be run, just type checked.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004988static inline void PersistentHandles(v8::Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004989 USE(PersistentHandles);
4990 Local<String> str = v8_str("foo");
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004991 v8::Persistent<String> p_str = v8::Persistent<String>::New(isolate, str);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004992 USE(p_str);
4993 Local<Script> scr = Script::Compile(v8_str(""));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004994 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(isolate, scr);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004995 USE(p_scr);
4996 Local<ObjectTemplate> templ = ObjectTemplate::New();
4997 v8::Persistent<ObjectTemplate> p_templ =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00004998 v8::Persistent<ObjectTemplate>::New(isolate, templ);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004999 USE(p_templ);
5000}
5001
5002
5003static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
5004 ApiTestFuzzer::Fuzz();
5005 return v8::Undefined();
5006}
5007
5008
5009THREADED_TEST(GlobalObjectTemplate) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005010 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005011 Local<ObjectTemplate> global_template = ObjectTemplate::New();
5012 global_template->Set(v8_str("JSNI_Log"),
5013 v8::FunctionTemplate::New(HandleLogDelegator));
5014 v8::Persistent<Context> context = Context::New(0, global_template);
5015 Context::Scope context_scope(context);
5016 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005017 context.Dispose(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005018}
5019
5020
5021static const char* kSimpleExtensionSource =
5022 "function Foo() {"
5023 " return 4;"
5024 "}";
5025
5026
5027THREADED_TEST(SimpleExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005028 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005029 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
5030 const char* extension_names[] = { "simpletest" };
5031 v8::ExtensionConfiguration extensions(1, extension_names);
5032 v8::Handle<Context> context = Context::New(&extensions);
5033 Context::Scope lock(context);
5034 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5035 CHECK_EQ(result, v8::Integer::New(4));
5036}
5037
5038
danno@chromium.org412fa512012-09-14 13:28:26 +00005039THREADED_TEST(NullExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005040 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
danno@chromium.org412fa512012-09-14 13:28:26 +00005041 v8::RegisterExtension(new Extension("nulltest", NULL));
5042 const char* extension_names[] = { "nulltest" };
5043 v8::ExtensionConfiguration extensions(1, extension_names);
5044 v8::Handle<Context> context = Context::New(&extensions);
5045 Context::Scope lock(context);
5046 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
5047 CHECK_EQ(result, v8::Integer::New(4));
5048}
5049
5050
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005051static const char* kEmbeddedExtensionSource =
5052 "function Ret54321(){return 54321;}~~@@$"
5053 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5054static const int kEmbeddedExtensionSourceValidLen = 34;
5055
5056
5057THREADED_TEST(ExtensionMissingSourceLength) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005058 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005059 v8::RegisterExtension(new Extension("srclentest_fail",
5060 kEmbeddedExtensionSource));
5061 const char* extension_names[] = { "srclentest_fail" };
5062 v8::ExtensionConfiguration extensions(1, extension_names);
5063 v8::Handle<Context> context = Context::New(&extensions);
5064 CHECK_EQ(0, *context);
5065}
5066
5067
5068THREADED_TEST(ExtensionWithSourceLength) {
5069 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5070 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005071 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005072 i::ScopedVector<char> extension_name(32);
5073 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5074 v8::RegisterExtension(new Extension(extension_name.start(),
5075 kEmbeddedExtensionSource, 0, 0,
5076 source_len));
5077 const char* extension_names[1] = { extension_name.start() };
5078 v8::ExtensionConfiguration extensions(1, extension_names);
5079 v8::Handle<Context> context = Context::New(&extensions);
5080 if (source_len == kEmbeddedExtensionSourceValidLen) {
5081 Context::Scope lock(context);
5082 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
5083 CHECK_EQ(v8::Integer::New(54321), result);
5084 } else {
5085 // Anything but exactly the right length should fail to compile.
5086 CHECK_EQ(0, *context);
5087 }
5088 }
5089}
5090
5091
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005092static const char* kEvalExtensionSource1 =
5093 "function UseEval1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005094 " var x = 42;"
5095 " return eval('x');"
5096 "}";
5097
5098
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005099static const char* kEvalExtensionSource2 =
5100 "(function() {"
5101 " var x = 42;"
5102 " function e() {"
5103 " return eval('x');"
5104 " }"
5105 " this.UseEval2 = e;"
5106 "})()";
5107
5108
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005109THREADED_TEST(UseEvalFromExtension) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005110 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005111 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
5112 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
5113 const char* extension_names[] = { "evaltest1", "evaltest2" };
5114 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005115 v8::Handle<Context> context = Context::New(&extensions);
5116 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005117 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
5118 CHECK_EQ(result, v8::Integer::New(42));
5119 result = Script::Compile(v8_str("UseEval2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005120 CHECK_EQ(result, v8::Integer::New(42));
5121}
5122
5123
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005124static const char* kWithExtensionSource1 =
5125 "function UseWith1() {"
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005126 " var x = 42;"
5127 " with({x:87}) { return x; }"
5128 "}";
5129
5130
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005131
5132static const char* kWithExtensionSource2 =
5133 "(function() {"
5134 " var x = 42;"
5135 " function e() {"
5136 " with ({x:87}) { return x; }"
5137 " }"
5138 " this.UseWith2 = e;"
5139 "})()";
5140
5141
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005142THREADED_TEST(UseWithFromExtension) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005143 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005144 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
5145 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
5146 const char* extension_names[] = { "withtest1", "withtest2" };
5147 v8::ExtensionConfiguration extensions(2, extension_names);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005148 v8::Handle<Context> context = Context::New(&extensions);
5149 Context::Scope lock(context);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005150 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
5151 CHECK_EQ(result, v8::Integer::New(87));
5152 result = Script::Compile(v8_str("UseWith2()"))->Run();
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00005153 CHECK_EQ(result, v8::Integer::New(87));
5154}
5155
5156
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005157THREADED_TEST(AutoExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005158 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005159 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5160 extension->set_auto_enable(true);
5161 v8::RegisterExtension(extension);
5162 v8::Handle<Context> context = Context::New();
5163 Context::Scope lock(context);
5164 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5165 CHECK_EQ(result, v8::Integer::New(4));
5166}
5167
5168
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005169static const char* kSyntaxErrorInExtensionSource =
5170 "[";
5171
5172
5173// Test that a syntax error in an extension does not cause a fatal
5174// error but results in an empty context.
5175THREADED_TEST(SyntaxErrorExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005176 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005177 v8::RegisterExtension(new Extension("syntaxerror",
5178 kSyntaxErrorInExtensionSource));
5179 const char* extension_names[] = { "syntaxerror" };
5180 v8::ExtensionConfiguration extensions(1, extension_names);
5181 v8::Handle<Context> context = Context::New(&extensions);
5182 CHECK(context.IsEmpty());
5183}
5184
5185
5186static const char* kExceptionInExtensionSource =
5187 "throw 42";
5188
5189
5190// Test that an exception when installing an extension does not cause
5191// a fatal error but results in an empty context.
5192THREADED_TEST(ExceptionExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005193 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005194 v8::RegisterExtension(new Extension("exception",
5195 kExceptionInExtensionSource));
5196 const char* extension_names[] = { "exception" };
5197 v8::ExtensionConfiguration extensions(1, extension_names);
5198 v8::Handle<Context> context = Context::New(&extensions);
5199 CHECK(context.IsEmpty());
5200}
5201
5202
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005203static const char* kNativeCallInExtensionSource =
5204 "function call_runtime_last_index_of(x) {"
5205 " return %StringLastIndexOf(x, 'bob', 10);"
5206 "}";
5207
5208
5209static const char* kNativeCallTest =
5210 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
5211
5212// Test that a native runtime calls are supported in extensions.
5213THREADED_TEST(NativeCallInExtensions) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005214 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005215 v8::RegisterExtension(new Extension("nativecall",
5216 kNativeCallInExtensionSource));
5217 const char* extension_names[] = { "nativecall" };
5218 v8::ExtensionConfiguration extensions(1, extension_names);
5219 v8::Handle<Context> context = Context::New(&extensions);
5220 Context::Scope lock(context);
5221 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
5222 CHECK_EQ(result, v8::Integer::New(3));
5223}
5224
5225
whesse@chromium.org7b260152011-06-20 15:33:18 +00005226class NativeFunctionExtension : public Extension {
5227 public:
5228 NativeFunctionExtension(const char* name,
5229 const char* source,
5230 v8::InvocationCallback fun = &Echo)
5231 : Extension(name, source),
5232 function_(fun) { }
5233
5234 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5235 v8::Handle<v8::String> name) {
5236 return v8::FunctionTemplate::New(function_);
5237 }
5238
5239 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
5240 if (args.Length() >= 1) return (args[0]);
5241 return v8::Undefined();
5242 }
5243 private:
5244 v8::InvocationCallback function_;
5245};
5246
5247
5248THREADED_TEST(NativeFunctionDeclaration) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005249 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005250 const char* name = "nativedecl";
5251 v8::RegisterExtension(new NativeFunctionExtension(name,
5252 "native function foo();"));
5253 const char* extension_names[] = { name };
5254 v8::ExtensionConfiguration extensions(1, extension_names);
5255 v8::Handle<Context> context = Context::New(&extensions);
5256 Context::Scope lock(context);
5257 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
5258 CHECK_EQ(result, v8::Integer::New(42));
5259}
5260
5261
5262THREADED_TEST(NativeFunctionDeclarationError) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005263 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005264 const char* name = "nativedeclerr";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005265 // Syntax error in extension code.
5266 v8::RegisterExtension(new NativeFunctionExtension(name,
5267 "native\nfunction foo();"));
5268 const char* extension_names[] = { name };
5269 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005270 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005271 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005272}
5273
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005274
whesse@chromium.org7b260152011-06-20 15:33:18 +00005275THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005276 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
lrn@chromium.org67e236d2011-06-23 10:18:16 +00005277 const char* name = "nativedeclerresc";
whesse@chromium.org7b260152011-06-20 15:33:18 +00005278 // Syntax error in extension code - escape code in "native" means that
5279 // it's not treated as a keyword.
5280 v8::RegisterExtension(new NativeFunctionExtension(
5281 name,
5282 "nativ\\u0065 function foo();"));
5283 const char* extension_names[] = { name };
5284 v8::ExtensionConfiguration extensions(1, extension_names);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005285 v8::Handle<Context> context(Context::New(&extensions));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005286 CHECK(context.IsEmpty());
whesse@chromium.org7b260152011-06-20 15:33:18 +00005287}
5288
5289
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005290static void CheckDependencies(const char* name, const char* expected) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005291 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005292 v8::ExtensionConfiguration config(1, &name);
5293 LocalContext context(&config);
5294 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
5295}
5296
5297
5298/*
5299 * Configuration:
5300 *
5301 * /-- B <--\
5302 * A <- -- D <-- E
5303 * \-- C <--/
5304 */
5305THREADED_TEST(ExtensionDependency) {
5306 static const char* kEDeps[] = { "D" };
5307 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
5308 static const char* kDDeps[] = { "B", "C" };
5309 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
5310 static const char* kBCDeps[] = { "A" };
5311 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
5312 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
5313 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
5314 CheckDependencies("A", "undefinedA");
5315 CheckDependencies("B", "undefinedAB");
5316 CheckDependencies("C", "undefinedAC");
5317 CheckDependencies("D", "undefinedABCD");
5318 CheckDependencies("E", "undefinedABCDE");
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005319 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005320 static const char* exts[2] = { "C", "E" };
5321 v8::ExtensionConfiguration config(2, exts);
5322 LocalContext context(&config);
5323 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
5324}
5325
5326
5327static const char* kExtensionTestScript =
5328 "native function A();"
5329 "native function B();"
5330 "native function C();"
5331 "function Foo(i) {"
5332 " if (i == 0) return A();"
5333 " if (i == 1) return B();"
5334 " if (i == 2) return C();"
5335 "}";
5336
5337
5338static v8::Handle<Value> CallFun(const v8::Arguments& args) {
5339 ApiTestFuzzer::Fuzz();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005340 if (args.IsConstructCall()) {
5341 args.This()->Set(v8_str("data"), args.Data());
5342 return v8::Null();
5343 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005344 return args.Data();
5345}
5346
5347
5348class FunctionExtension : public Extension {
5349 public:
5350 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
5351 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
5352 v8::Handle<String> name);
5353};
5354
5355
5356static int lookup_count = 0;
5357v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
5358 v8::Handle<String> name) {
5359 lookup_count++;
5360 if (name->Equals(v8_str("A"))) {
5361 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
5362 } else if (name->Equals(v8_str("B"))) {
5363 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
5364 } else if (name->Equals(v8_str("C"))) {
5365 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
5366 } else {
5367 return v8::Handle<v8::FunctionTemplate>();
5368 }
5369}
5370
5371
5372THREADED_TEST(FunctionLookup) {
5373 v8::RegisterExtension(new FunctionExtension());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005374 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005375 static const char* exts[1] = { "functiontest" };
5376 v8::ExtensionConfiguration config(1, exts);
5377 LocalContext context(&config);
5378 CHECK_EQ(3, lookup_count);
5379 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
5380 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
5381 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
5382}
5383
5384
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005385THREADED_TEST(NativeFunctionConstructCall) {
5386 v8::RegisterExtension(new FunctionExtension());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005387 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005388 static const char* exts[1] = { "functiontest" };
5389 v8::ExtensionConfiguration config(1, exts);
5390 LocalContext context(&config);
5391 for (int i = 0; i < 10; i++) {
5392 // Run a few times to ensure that allocation of objects doesn't
5393 // change behavior of a constructor function.
5394 CHECK_EQ(v8::Integer::New(8),
5395 Script::Compile(v8_str("(new A()).data"))->Run());
5396 CHECK_EQ(v8::Integer::New(7),
5397 Script::Compile(v8_str("(new B()).data"))->Run());
5398 CHECK_EQ(v8::Integer::New(6),
5399 Script::Compile(v8_str("(new C()).data"))->Run());
5400 }
5401}
5402
5403
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005404static const char* last_location;
5405static const char* last_message;
5406void StoringErrorCallback(const char* location, const char* message) {
5407 if (last_location == NULL) {
5408 last_location = location;
5409 last_message = message;
5410 }
5411}
5412
5413
5414// ErrorReporting creates a circular extensions configuration and
5415// tests that the fatal error handler gets called. This renders V8
5416// unusable and therefore this test cannot be run in parallel.
5417TEST(ErrorReporting) {
5418 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
5419 static const char* aDeps[] = { "B" };
5420 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
5421 static const char* bDeps[] = { "A" };
5422 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
5423 last_location = NULL;
5424 v8::ExtensionConfiguration config(1, bDeps);
5425 v8::Handle<Context> context = Context::New(&config);
5426 CHECK(context.IsEmpty());
5427 CHECK_NE(last_location, NULL);
5428}
5429
5430
ager@chromium.org7c537e22008-10-16 08:43:32 +00005431static const char* js_code_causing_huge_string_flattening =
5432 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00005433 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00005434 " str = str + str;"
5435 "}"
5436 "str.match(/X/);";
5437
5438
5439void OOMCallback(const char* location, const char* message) {
5440 exit(0);
5441}
5442
5443
5444TEST(RegexpOutOfMemory) {
5445 // Execute a script that causes out of memory when flattening a string.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005446 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005447 v8::V8::SetFatalErrorHandler(OOMCallback);
5448 LocalContext context;
5449 Local<Script> script =
5450 Script::Compile(String::New(js_code_causing_huge_string_flattening));
5451 last_location = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00005452 script->Run();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005453
5454 CHECK(false); // Should not return.
5455}
5456
5457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005458static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
5459 v8::Handle<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005460 CHECK(message->GetScriptResourceName()->IsUndefined());
5461 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005462 message->GetLineNumber();
5463 message->GetSourceLine();
5464}
5465
5466
5467THREADED_TEST(ErrorWithMissingScriptInfo) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005468 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005469 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005470 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
5471 Script::Compile(v8_str("throw Error()"))->Run();
5472 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
5473}
5474
5475
5476int global_index = 0;
5477
5478class Snorkel {
5479 public:
5480 Snorkel() { index_ = global_index++; }
5481 int index_;
5482};
5483
5484class Whammy {
5485 public:
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005486 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
5487 ~Whammy() { script_.Dispose(isolate_); }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005488 v8::Handle<Script> getScript() {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005489 if (script_.IsEmpty()) {
5490 script_ = v8::Persistent<Script>::New(isolate_,
5491 v8_compile("({}).blammo"));
5492 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005493 return Local<Script>(*script_);
5494 }
5495
5496 public:
5497 static const int kObjectCount = 256;
5498 int cursor_;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005499 v8::Isolate* isolate_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005500 v8::Persistent<v8::Object> objects_[kObjectCount];
5501 v8::Persistent<Script> script_;
5502};
5503
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005504static void HandleWeakReference(v8::Isolate* isolate,
5505 v8::Persistent<v8::Value> obj,
5506 void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005507 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
5508 delete snorkel;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005509 obj.ClearWeak(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005510}
5511
5512v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
5513 const AccessorInfo& info) {
5514 Whammy* whammy =
5515 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
5516
5517 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
5518
5519 v8::Handle<v8::Object> obj = v8::Object::New();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005520 v8::Persistent<v8::Object> global =
5521 v8::Persistent<v8::Object>::New(info.GetIsolate(), obj);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005522 if (!prev.IsEmpty()) {
5523 prev->Set(v8_str("next"), obj);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005524 prev.MakeWeak(info.GetIsolate(), new Snorkel(), &HandleWeakReference);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005525 whammy->objects_[whammy->cursor_].Clear();
5526 }
5527 whammy->objects_[whammy->cursor_] = global;
5528 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
5529 return whammy->getScript()->Run();
5530}
5531
5532THREADED_TEST(WeakReference) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005533 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005534 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005535 Whammy* whammy = new Whammy(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005536 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5537 0, 0, 0, 0,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005538 v8::External::New(whammy));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005539 const char* extension_list[] = { "v8/gc" };
5540 v8::ExtensionConfiguration extensions(1, extension_list);
5541 v8::Persistent<Context> context = Context::New(&extensions);
5542 Context::Scope context_scope(context);
5543
5544 v8::Handle<v8::Object> interceptor = templ->NewInstance();
5545 context->Global()->Set(v8_str("whammy"), interceptor);
5546 const char* code =
5547 "var last;"
5548 "for (var i = 0; i < 10000; i++) {"
5549 " var obj = whammy.length;"
5550 " if (last) last.next = obj;"
5551 " last = obj;"
5552 "}"
5553 "gc();"
5554 "4";
5555 v8::Handle<Value> result = CompileRun(code);
5556 CHECK_EQ(4.0, result->NumberValue());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005557 delete whammy;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005558 context.Dispose(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005559}
5560
5561
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005562static void DisposeAndSetFlag(v8::Isolate* isolate,
5563 v8::Persistent<v8::Value> obj,
5564 void* data) {
5565 obj.Dispose(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005566 obj.Clear();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005567 *(reinterpret_cast<bool*>(data)) = true;
5568}
5569
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005570
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005571THREADED_TEST(IndependentWeakHandle) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005572 v8::Persistent<Context> context = Context::New();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005573 v8::Isolate* iso = context->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005574 Context::Scope context_scope(context);
5575
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005576 v8::Persistent<v8::Object> object_a, object_b;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005577
5578 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005579 v8::HandleScope handle_scope(iso);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005580 object_a = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
5581 object_b = v8::Persistent<v8::Object>::New(iso, v8::Object::New());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005582 }
5583
5584 bool object_a_disposed = false;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005585 bool object_b_disposed = false;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005586 object_a.MakeWeak(iso, &object_a_disposed, &DisposeAndSetFlag);
5587 object_b.MakeWeak(iso, &object_b_disposed, &DisposeAndSetFlag);
5588 CHECK(!object_b.IsIndependent(iso));
5589 object_a.MarkIndependent(iso);
5590 object_b.MarkIndependent(iso);
5591 CHECK(object_b.IsIndependent(iso));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005592 HEAP->PerformScavenge();
5593 CHECK(object_a_disposed);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005594 CHECK(object_b_disposed);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005595}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005596
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005597
5598static void InvokeScavenge() {
5599 HEAP->PerformScavenge();
5600}
5601
5602
5603static void InvokeMarkSweep() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005604 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005605}
5606
5607
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005608static void ForceScavenge(v8::Isolate* isolate,
5609 v8::Persistent<v8::Value> obj,
5610 void* data) {
5611 obj.Dispose(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005612 obj.Clear();
5613 *(reinterpret_cast<bool*>(data)) = true;
5614 InvokeScavenge();
5615}
5616
5617
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005618static void ForceMarkSweep(v8::Isolate* isolate,
5619 v8::Persistent<v8::Value> obj,
5620 void* data) {
5621 obj.Dispose(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005622 obj.Clear();
5623 *(reinterpret_cast<bool*>(data)) = true;
5624 InvokeMarkSweep();
5625}
5626
5627
5628THREADED_TEST(GCFromWeakCallbacks) {
5629 v8::Persistent<Context> context = Context::New();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005630 v8::Isolate* isolate = context->GetIsolate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005631 Context::Scope context_scope(context);
5632
5633 static const int kNumberOfGCTypes = 2;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005634 v8::NearDeathCallback gc_forcing_callback[kNumberOfGCTypes] =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005635 {&ForceScavenge, &ForceMarkSweep};
5636
5637 typedef void (*GCInvoker)();
5638 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5639
5640 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5641 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5642 v8::Persistent<v8::Object> object;
5643 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005644 v8::HandleScope handle_scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005645 object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005646 }
5647 bool disposed = false;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005648 object.MakeWeak(isolate, &disposed, gc_forcing_callback[inner_gc]);
5649 object.MarkIndependent(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005650 invoke_gc[outer_gc]();
5651 CHECK(disposed);
5652 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005653 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005654}
5655
5656
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005657static void RevivingCallback(v8::Isolate* isolate,
5658 v8::Persistent<v8::Value> obj,
5659 void* data) {
5660 obj.ClearWeak(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005661 *(reinterpret_cast<bool*>(data)) = true;
5662}
5663
5664
5665THREADED_TEST(IndependentHandleRevival) {
5666 v8::Persistent<Context> context = Context::New();
5667 Context::Scope context_scope(context);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005668 v8::Isolate* isolate = context->GetIsolate();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005669
5670 v8::Persistent<v8::Object> object;
5671 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005672 v8::HandleScope handle_scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005673 object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005674 object->Set(v8_str("x"), v8::Integer::New(1));
5675 v8::Local<String> y_str = v8_str("y");
5676 object->Set(y_str, y_str);
5677 }
5678 bool revived = false;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00005679 object.MakeWeak(isolate, &revived, &RevivingCallback);
5680 object.MarkIndependent(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005681 HEAP->PerformScavenge();
5682 CHECK(revived);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00005683 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005684 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005685 v8::HandleScope handle_scope(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005686 v8::Local<String> y_str = v8_str("y");
5687 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5688 CHECK(object->Get(y_str)->Equals(y_str));
5689 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005690}
5691
5692
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005693v8::Handle<Function> args_fun;
5694
5695
5696static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5697 ApiTestFuzzer::Fuzz();
5698 CHECK_EQ(args_fun, args.Callee());
5699 CHECK_EQ(3, args.Length());
5700 CHECK_EQ(v8::Integer::New(1), args[0]);
5701 CHECK_EQ(v8::Integer::New(2), args[1]);
5702 CHECK_EQ(v8::Integer::New(3), args[2]);
5703 CHECK_EQ(v8::Undefined(), args[3]);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005704 v8::HandleScope scope(args.GetIsolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005705 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005706 return v8::Undefined();
5707}
5708
5709
5710THREADED_TEST(Arguments) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005711 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005712 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5713 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5714 LocalContext context(NULL, global);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005715 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005716 v8_compile("f(1, 2, 3)")->Run();
5717}
5718
5719
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005720static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5721 const AccessorInfo&) {
5722 return v8::Handle<Value>();
5723}
5724
5725
5726static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5727 const AccessorInfo&) {
5728 return v8::Handle<Value>();
5729}
5730
5731
5732static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5733 const AccessorInfo&) {
5734 if (!name->Equals(v8_str("foo"))) {
5735 return v8::Handle<v8::Boolean>(); // not intercepted
5736 }
5737
5738 return v8::False(); // intercepted, and don't delete the property
5739}
5740
5741
5742static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5743 if (index != 2) {
5744 return v8::Handle<v8::Boolean>(); // not intercepted
5745 }
5746
5747 return v8::False(); // intercepted, and don't delete the property
5748}
5749
5750
5751THREADED_TEST(Deleter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005752 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005753 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5754 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5755 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5756 LocalContext context;
5757 context->Global()->Set(v8_str("k"), obj->NewInstance());
5758 CompileRun(
5759 "k.foo = 'foo';"
5760 "k.bar = 'bar';"
5761 "k[2] = 2;"
5762 "k[4] = 4;");
5763 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5764 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5765
5766 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5767 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5768
5769 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5770 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5771
5772 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5773 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5774}
5775
5776
5777static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5778 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005779 if (name->Equals(v8_str("foo")) ||
5780 name->Equals(v8_str("bar")) ||
5781 name->Equals(v8_str("baz"))) {
5782 return v8::Undefined();
5783 }
5784 return v8::Handle<Value>();
5785}
5786
5787
5788static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5789 ApiTestFuzzer::Fuzz();
5790 if (index == 0 || index == 1) return v8::Undefined();
5791 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005792}
5793
5794
5795static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5796 ApiTestFuzzer::Fuzz();
5797 v8::Handle<v8::Array> result = v8::Array::New(3);
5798 result->Set(v8::Integer::New(0), v8_str("foo"));
5799 result->Set(v8::Integer::New(1), v8_str("bar"));
5800 result->Set(v8::Integer::New(2), v8_str("baz"));
5801 return result;
5802}
5803
5804
5805static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5806 ApiTestFuzzer::Fuzz();
5807 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005808 result->Set(v8::Integer::New(0), v8_str("0"));
5809 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005810 return result;
5811}
5812
5813
5814THREADED_TEST(Enumerators) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005815 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005816 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5817 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005818 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005819 LocalContext context;
5820 context->Global()->Set(v8_str("k"), obj->NewInstance());
5821 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005822 "k[10] = 0;"
5823 "k.a = 0;"
5824 "k[5] = 0;"
5825 "k.b = 0;"
5826 "k[4294967295] = 0;"
5827 "k.c = 0;"
5828 "k[4294967296] = 0;"
5829 "k.d = 0;"
5830 "k[140000] = 0;"
5831 "k.e = 0;"
5832 "k[30000000000] = 0;"
5833 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005834 "var result = [];"
5835 "for (var prop in k) {"
5836 " result.push(prop);"
5837 "}"
5838 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005839 // Check that we get all the property names returned including the
5840 // ones from the enumerators in the right order: indexed properties
5841 // in numerical order, indexed interceptor properties, named
5842 // properties in insertion order, named interceptor properties.
5843 // This order is not mandated by the spec, so this test is just
5844 // documenting our behavior.
5845 CHECK_EQ(17, result->Length());
5846 // Indexed properties in numerical order.
5847 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5848 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5849 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5850 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5851 // Indexed interceptor properties in the order they are returned
5852 // from the enumerator interceptor.
5853 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5854 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5855 // Named properties in insertion order.
5856 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5857 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5858 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5859 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5860 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5861 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5862 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5863 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5864 // Named interceptor properties.
5865 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5866 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5867 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005868}
5869
5870
5871int p_getter_count;
5872int p_getter_count2;
5873
5874
5875static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5876 ApiTestFuzzer::Fuzz();
5877 p_getter_count++;
5878 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5879 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5880 if (name->Equals(v8_str("p1"))) {
5881 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5882 } else if (name->Equals(v8_str("p2"))) {
5883 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5884 } else if (name->Equals(v8_str("p3"))) {
5885 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5886 } else if (name->Equals(v8_str("p4"))) {
5887 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5888 }
5889 return v8::Undefined();
5890}
5891
5892
5893static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5894 ApiTestFuzzer::Fuzz();
5895 LocalContext context;
5896 context->Global()->Set(v8_str("o1"), obj->NewInstance());
5897 CompileRun(
5898 "o1.__proto__ = { };"
5899 "var o2 = { __proto__: o1 };"
5900 "var o3 = { __proto__: o2 };"
5901 "var o4 = { __proto__: o3 };"
5902 "for (var i = 0; i < 10; i++) o4.p4;"
5903 "for (var i = 0; i < 10; i++) o3.p3;"
5904 "for (var i = 0; i < 10; i++) o2.p2;"
5905 "for (var i = 0; i < 10; i++) o1.p1;");
5906}
5907
5908
5909static v8::Handle<Value> PGetter2(Local<String> name,
5910 const AccessorInfo& info) {
5911 ApiTestFuzzer::Fuzz();
5912 p_getter_count2++;
5913 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5914 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5915 if (name->Equals(v8_str("p1"))) {
5916 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5917 } else if (name->Equals(v8_str("p2"))) {
5918 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5919 } else if (name->Equals(v8_str("p3"))) {
5920 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5921 } else if (name->Equals(v8_str("p4"))) {
5922 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5923 }
5924 return v8::Undefined();
5925}
5926
5927
5928THREADED_TEST(GetterHolders) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005929 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005930 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5931 obj->SetAccessor(v8_str("p1"), PGetter);
5932 obj->SetAccessor(v8_str("p2"), PGetter);
5933 obj->SetAccessor(v8_str("p3"), PGetter);
5934 obj->SetAccessor(v8_str("p4"), PGetter);
5935 p_getter_count = 0;
5936 RunHolderTest(obj);
5937 CHECK_EQ(40, p_getter_count);
5938}
5939
5940
5941THREADED_TEST(PreInterceptorHolders) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005942 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005943 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5944 obj->SetNamedPropertyHandler(PGetter2);
5945 p_getter_count2 = 0;
5946 RunHolderTest(obj);
5947 CHECK_EQ(40, p_getter_count2);
5948}
5949
5950
5951THREADED_TEST(ObjectInstantiation) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005952 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005953 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5954 templ->SetAccessor(v8_str("t"), PGetter2);
5955 LocalContext context;
5956 context->Global()->Set(v8_str("o"), templ->NewInstance());
5957 for (int i = 0; i < 100; i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005958 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005959 v8::Handle<v8::Object> obj = templ->NewInstance();
5960 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5961 context->Global()->Set(v8_str("o2"), obj);
5962 v8::Handle<Value> value =
5963 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5964 CHECK_EQ(v8::True(), value);
5965 context->Global()->Set(v8_str("o"), obj);
5966 }
5967}
5968
5969
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005970static int StrCmp16(uint16_t* a, uint16_t* b) {
5971 while (true) {
5972 if (*a == 0 && *b == 0) return 0;
5973 if (*a != *b) return 0 + *a - *b;
5974 a++;
5975 b++;
5976 }
5977}
5978
5979
5980static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5981 while (true) {
5982 if (n-- == 0) return 0;
5983 if (*a == 0 && *b == 0) return 0;
5984 if (*a != *b) return 0 + *a - *b;
5985 a++;
5986 b++;
5987 }
5988}
5989
5990
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005991int GetUtf8Length(Handle<String> str) {
5992 int len = str->Utf8Length();
5993 if (len < 0) {
5994 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
5995 i::FlattenString(istr);
5996 len = str->Utf8Length();
5997 }
5998 return len;
5999}
6000
6001
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006002THREADED_TEST(StringWrite) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006003 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006004 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006005 v8::Handle<String> str = v8_str("abcde");
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006006 // abc<Icelandic eth><Unicode snowman>.
6007 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006008 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006009 const int kStride = 4; // Must match stride in for loops in JS below.
6010 CompileRun(
6011 "var left = '';"
6012 "for (var i = 0; i < 0xd800; i += 4) {"
6013 " left = left + String.fromCharCode(i);"
6014 "}");
6015 CompileRun(
6016 "var right = '';"
6017 "for (var i = 0; i < 0xd800; i += 4) {"
6018 " right = String.fromCharCode(i) + right;"
6019 "}");
6020 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6021 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
6022 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006023
6024 CHECK_EQ(5, str2->Length());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006025 CHECK_EQ(0xd800 / kStride, left_tree->Length());
6026 CHECK_EQ(0xd800 / kStride, right_tree->Length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006027
6028 char buf[100];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006029 char utf8buf[0xd800 * 3];
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006030 uint16_t wbuf[100];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006031 int len;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006032 int charlen;
6033
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006034 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006035 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006036 CHECK_EQ(9, len);
6037 CHECK_EQ(5, charlen);
6038 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006039
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006040 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006041 len = str2->WriteUtf8(utf8buf, 8, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006042 CHECK_EQ(8, len);
6043 CHECK_EQ(5, charlen);
6044 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006045
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006046 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006047 len = str2->WriteUtf8(utf8buf, 7, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006048 CHECK_EQ(5, len);
6049 CHECK_EQ(4, charlen);
6050 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006051
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006052 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006053 len = str2->WriteUtf8(utf8buf, 6, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006054 CHECK_EQ(5, len);
6055 CHECK_EQ(4, charlen);
6056 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006058 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006059 len = str2->WriteUtf8(utf8buf, 5, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006060 CHECK_EQ(5, len);
6061 CHECK_EQ(4, charlen);
6062 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006063
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006064 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006065 len = str2->WriteUtf8(utf8buf, 4, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006066 CHECK_EQ(3, len);
6067 CHECK_EQ(3, charlen);
6068 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006070 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006071 len = str2->WriteUtf8(utf8buf, 3, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006072 CHECK_EQ(3, len);
6073 CHECK_EQ(3, charlen);
6074 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006075
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006076 memset(utf8buf, 0x1, 1000);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006077 len = str2->WriteUtf8(utf8buf, 2, &charlen);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006078 CHECK_EQ(2, len);
6079 CHECK_EQ(2, charlen);
6080 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006081
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006082 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006083 len = GetUtf8Length(left_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006084 int utf8_expected =
6085 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
6086 CHECK_EQ(utf8_expected, len);
6087 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6088 CHECK_EQ(utf8_expected, len);
6089 CHECK_EQ(0xd800 / kStride, charlen);
6090 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
6091 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
6092 CHECK_EQ(0xc0 - kStride,
6093 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
6094 CHECK_EQ(1, utf8buf[utf8_expected]);
6095
6096 memset(utf8buf, 0x1, sizeof(utf8buf));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006097 len = GetUtf8Length(right_tree);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006098 CHECK_EQ(utf8_expected, len);
6099 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6100 CHECK_EQ(utf8_expected, len);
6101 CHECK_EQ(0xd800 / kStride, charlen);
6102 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
6103 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
6104 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
6105 CHECK_EQ(1, utf8buf[utf8_expected]);
6106
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006107 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006108 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006109 len = str->WriteAscii(buf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006110 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006111 len = str->Write(wbuf);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006112 CHECK_EQ(5, len);
6113 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006114 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006115 CHECK_EQ(0, StrCmp16(answer1, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006116
6117 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006118 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006119 len = str->WriteAscii(buf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006120 CHECK_EQ(4, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006121 len = str->Write(wbuf, 0, 4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006122 CHECK_EQ(4, len);
6123 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006124 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006125 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006126
6127 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006128 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006129 len = str->WriteAscii(buf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006130 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006131 len = str->Write(wbuf, 0, 5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006132 CHECK_EQ(5, len);
6133 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006134 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006135 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006136
6137 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006138 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006139 len = str->WriteAscii(buf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006140 CHECK_EQ(5, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006141 len = str->Write(wbuf, 0, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006142 CHECK_EQ(5, len);
6143 CHECK_EQ(0, strcmp("abcde", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006144 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006145 CHECK_EQ(0, StrCmp16(answer4, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006146
6147 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006148 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006149 len = str->WriteAscii(buf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006150 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006151 len = str->Write(wbuf, 4, -1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006152 CHECK_EQ(1, len);
6153 CHECK_EQ(0, strcmp("e", buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006154 uint16_t answer5[] = {'e', '\0'};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006155 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006156
6157 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006158 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006159 len = str->WriteAscii(buf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006160 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006161 len = str->Write(wbuf, 4, 6);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006162 CHECK_EQ(1, len);
6163 CHECK_EQ(0, strcmp("e", buf));
6164 CHECK_EQ(0, StrCmp16(answer5, wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006165
6166 memset(buf, 0x1, sizeof(buf));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006167 memset(wbuf, 0x1, sizeof(wbuf));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006168 len = str->WriteAscii(buf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006169 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006170 len = str->Write(wbuf, 4, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006171 CHECK_EQ(1, len);
6172 CHECK_EQ(0, strncmp("e\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006173 uint16_t answer6[] = {'e', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006174 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006175
6176 memset(buf, 0x1, sizeof(buf));
6177 memset(wbuf, 0x1, sizeof(wbuf));
6178 len = str->WriteAscii(buf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006179 CHECK_EQ(1, len);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006180 len = str->Write(wbuf, 3, 1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006181 CHECK_EQ(1, len);
6182 CHECK_EQ(0, strncmp("d\1", buf, 2));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006183 uint16_t answer7[] = {'d', 0x101};
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006184 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006185
6186 memset(wbuf, 0x1, sizeof(wbuf));
6187 wbuf[5] = 'X';
6188 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
6189 CHECK_EQ(5, len);
6190 CHECK_EQ('X', wbuf[5]);
6191 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
6192 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6193 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
6194 CHECK_NE(0, StrCmp16(answer8b, wbuf));
6195 wbuf[5] = '\0';
6196 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
6197
6198 memset(buf, 0x1, sizeof(buf));
6199 buf[5] = 'X';
6200 len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
6201 CHECK_EQ(5, len);
6202 CHECK_EQ('X', buf[5]);
6203 CHECK_EQ(0, strncmp("abcde", buf, 5));
6204 CHECK_NE(0, strcmp("abcde", buf));
6205 buf[5] = '\0';
6206 CHECK_EQ(0, strcmp("abcde", buf));
6207
6208 memset(utf8buf, 0x1, sizeof(utf8buf));
6209 utf8buf[8] = 'X';
6210 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6211 String::NO_NULL_TERMINATION);
6212 CHECK_EQ(8, len);
6213 CHECK_EQ('X', utf8buf[8]);
6214 CHECK_EQ(5, charlen);
6215 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
6216 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6217 utf8buf[8] = '\0';
6218 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006219
6220 memset(utf8buf, 0x1, sizeof(utf8buf));
6221 utf8buf[5] = 'X';
6222 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
6223 String::NO_NULL_TERMINATION);
6224 CHECK_EQ(5, len);
6225 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
6226 CHECK_EQ(5, charlen);
6227 utf8buf[5] = '\0';
6228 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
6229
6230 memset(buf, 0x1, sizeof(buf));
6231 len = str3->WriteAscii(buf);
6232 CHECK_EQ(7, len);
6233 CHECK_EQ(0, strcmp("abc def", buf));
6234
6235 memset(buf, 0x1, sizeof(buf));
6236 len = str3->WriteAscii(buf, 0, -1, String::PRESERVE_ASCII_NULL);
6237 CHECK_EQ(7, len);
6238 CHECK_EQ(0, strcmp("abc", buf));
6239 CHECK_EQ(0, buf[3]);
6240 CHECK_EQ(0, strcmp("def", buf + 4));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006241
6242 CHECK_EQ(0, str->WriteAscii(NULL, 0, 0, String::NO_NULL_TERMINATION));
6243 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
6244 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006245}
6246
6247
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006248static void Utf16Helper(
6249 LocalContext& context,
6250 const char* name,
6251 const char* lengths_name,
6252 int len) {
6253 Local<v8::Array> a =
6254 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6255 Local<v8::Array> alens =
6256 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6257 for (int i = 0; i < len; i++) {
6258 Local<v8::String> string =
6259 Local<v8::String>::Cast(a->Get(i));
6260 Local<v8::Number> expected_len =
6261 Local<v8::Number>::Cast(alens->Get(i));
6262 int length = GetUtf8Length(string);
6263 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
6264 }
6265}
6266
6267
6268static uint16_t StringGet(Handle<String> str, int index) {
6269 i::Handle<i::String> istring =
6270 v8::Utils::OpenHandle(String::Cast(*str));
6271 return istring->Get(index);
6272}
6273
6274
6275static void WriteUtf8Helper(
6276 LocalContext& context,
6277 const char* name,
6278 const char* lengths_name,
6279 int len) {
6280 Local<v8::Array> b =
6281 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
6282 Local<v8::Array> alens =
6283 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
6284 char buffer[1000];
6285 char buffer2[1000];
6286 for (int i = 0; i < len; i++) {
6287 Local<v8::String> string =
6288 Local<v8::String>::Cast(b->Get(i));
6289 Local<v8::Number> expected_len =
6290 Local<v8::Number>::Cast(alens->Get(i));
6291 int utf8_length = static_cast<int>(expected_len->Value());
6292 for (int j = utf8_length + 1; j >= 0; j--) {
6293 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
6294 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
6295 int nchars;
6296 int utf8_written =
6297 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
6298 int utf8_written2 =
6299 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
6300 CHECK_GE(utf8_length + 1, utf8_written);
6301 CHECK_GE(utf8_length, utf8_written2);
6302 for (int k = 0; k < utf8_written2; k++) {
6303 CHECK_EQ(buffer[k], buffer2[k]);
6304 }
6305 CHECK(nchars * 3 >= utf8_written - 1);
6306 CHECK(nchars <= utf8_written);
6307 if (j == utf8_length + 1) {
6308 CHECK_EQ(utf8_written2, utf8_length);
6309 CHECK_EQ(utf8_written2 + 1, utf8_written);
6310 }
6311 CHECK_EQ(buffer[utf8_written], 42);
6312 if (j > utf8_length) {
6313 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
6314 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
6315 Handle<String> roundtrip = v8_str(buffer);
6316 CHECK(roundtrip->Equals(string));
6317 } else {
6318 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6319 }
6320 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
6321 if (nchars >= 2) {
6322 uint16_t trail = StringGet(string, nchars - 1);
6323 uint16_t lead = StringGet(string, nchars - 2);
6324 if (((lead & 0xfc00) == 0xd800) &&
6325 ((trail & 0xfc00) == 0xdc00)) {
6326 unsigned char u1 = buffer2[utf8_written2 - 4];
6327 unsigned char u2 = buffer2[utf8_written2 - 3];
6328 unsigned char u3 = buffer2[utf8_written2 - 2];
6329 unsigned char u4 = buffer2[utf8_written2 - 1];
6330 CHECK_EQ((u1 & 0xf8), 0xf0);
6331 CHECK_EQ((u2 & 0xc0), 0x80);
6332 CHECK_EQ((u3 & 0xc0), 0x80);
6333 CHECK_EQ((u4 & 0xc0), 0x80);
6334 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
6335 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
6336 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
6337 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
6338 CHECK_EQ((u1 & 0x3), c >> 18);
6339 }
6340 }
6341 }
6342 }
6343}
6344
6345
6346THREADED_TEST(Utf16) {
6347 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006348 v8::HandleScope scope(context->GetIsolate());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006349 CompileRun(
6350 "var pad = '01234567890123456789';"
6351 "var p = [];"
6352 "var plens = [20, 3, 3];"
6353 "p.push('01234567890123456789');"
6354 "var lead = 0xd800;"
6355 "var trail = 0xdc00;"
6356 "p.push(String.fromCharCode(0xd800));"
6357 "p.push(String.fromCharCode(0xdc00));"
6358 "var a = [];"
6359 "var b = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006360 "var c = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006361 "var alens = [];"
6362 "for (var i = 0; i < 3; i++) {"
6363 " p[1] = String.fromCharCode(lead++);"
6364 " for (var j = 0; j < 3; j++) {"
6365 " p[2] = String.fromCharCode(trail++);"
6366 " a.push(p[i] + p[j]);"
6367 " b.push(p[i] + p[j]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006368 " c.push(p[i] + p[j]);"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006369 " alens.push(plens[i] + plens[j]);"
6370 " }"
6371 "}"
6372 "alens[5] -= 2;" // Here the surrogate pairs match up.
6373 "var a2 = [];"
6374 "var b2 = [];"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006375 "var c2 = [];"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006376 "var a2lens = [];"
6377 "for (var m = 0; m < 9; m++) {"
6378 " for (var n = 0; n < 9; n++) {"
6379 " a2.push(a[m] + a[n]);"
6380 " b2.push(b[m] + b[n]);"
danno@chromium.org88aa0582012-03-23 15:11:57 +00006381 " var newc = 'x' + c[m] + c[n] + 'y';"
6382 " c2.push(newc.substring(1, newc.length - 1));"
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006383 " var utf = alens[m] + alens[n];" // And here.
6384 // The 'n's that start with 0xdc.. are 6-8
6385 // The 'm's that end with 0xd8.. are 1, 4 and 7
6386 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
6387 " a2lens.push(utf);"
6388 " }"
6389 "}");
6390 Utf16Helper(context, "a", "alens", 9);
6391 Utf16Helper(context, "a2", "a2lens", 81);
6392 WriteUtf8Helper(context, "b", "alens", 9);
6393 WriteUtf8Helper(context, "b2", "a2lens", 81);
danno@chromium.org88aa0582012-03-23 15:11:57 +00006394 WriteUtf8Helper(context, "c2", "a2lens", 81);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006395}
6396
6397
6398static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
6399 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
6400 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
6401 return *is1 == *is2;
6402}
6403
6404
6405static void SameSymbolHelper(const char* a, const char* b) {
6406 Handle<String> symbol1 = v8::String::NewSymbol(a);
6407 Handle<String> symbol2 = v8::String::NewSymbol(b);
6408 CHECK(SameSymbol(symbol1, symbol2));
6409}
6410
6411
6412THREADED_TEST(Utf16Symbol) {
6413 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006414 v8::HandleScope scope(context->GetIsolate());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006415
6416 Handle<String> symbol1 = v8::String::NewSymbol("abc");
6417 Handle<String> symbol2 = v8::String::NewSymbol("abc");
6418 CHECK(SameSymbol(symbol1, symbol2));
6419
6420 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
6421 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
6422 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
6423 "\360\220\220\206"); // 4 byte encoding.
6424 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
6425 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
6426 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
6427 "x\360\220\220\206"); // 4 byte encoding.
6428 CompileRun(
6429 "var sym0 = 'benedictus';"
6430 "var sym0b = 'S\303\270ren';"
6431 "var sym1 = '\355\240\201\355\260\207';"
6432 "var sym2 = '\360\220\220\210';"
6433 "var sym3 = 'x\355\240\201\355\260\207';"
6434 "var sym4 = 'x\360\220\220\210';"
6435 "if (sym1.length != 2) throw sym1;"
6436 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
6437 "if (sym2.length != 2) throw sym2;"
6438 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
6439 "if (sym3.length != 3) throw sym3;"
6440 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
6441 "if (sym4.length != 3) throw sym4;"
6442 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
6443 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
6444 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
6445 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
6446 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
6447 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
6448 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
6449 v8::Local<v8::Object> global = context->Global();
6450 Local<Value> s0 = global->Get(v8_str("sym0"));
6451 Local<Value> s0b = global->Get(v8_str("sym0b"));
6452 Local<Value> s1 = global->Get(v8_str("sym1"));
6453 Local<Value> s2 = global->Get(v8_str("sym2"));
6454 Local<Value> s3 = global->Get(v8_str("sym3"));
6455 Local<Value> s4 = global->Get(v8_str("sym4"));
6456 CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
6457 CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
6458 CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
6459 CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
6460 CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
6461 CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
6462}
6463
6464
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006465THREADED_TEST(ToArrayIndex) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006466 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006467 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006468
6469 v8::Handle<String> str = v8_str("42");
6470 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
6471 CHECK(!index.IsEmpty());
6472 CHECK_EQ(42.0, index->Uint32Value());
6473 str = v8_str("42asdf");
6474 index = str->ToArrayIndex();
6475 CHECK(index.IsEmpty());
6476 str = v8_str("-42");
6477 index = str->ToArrayIndex();
6478 CHECK(index.IsEmpty());
6479 str = v8_str("4294967295");
6480 index = str->ToArrayIndex();
6481 CHECK(!index.IsEmpty());
6482 CHECK_EQ(4294967295.0, index->Uint32Value());
6483 v8::Handle<v8::Number> num = v8::Number::New(1);
6484 index = num->ToArrayIndex();
6485 CHECK(!index.IsEmpty());
6486 CHECK_EQ(1.0, index->Uint32Value());
6487 num = v8::Number::New(-1);
6488 index = num->ToArrayIndex();
6489 CHECK(index.IsEmpty());
6490 v8::Handle<v8::Object> obj = v8::Object::New();
6491 index = obj->ToArrayIndex();
6492 CHECK(index.IsEmpty());
6493}
6494
6495
6496THREADED_TEST(ErrorConstruction) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006497 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006498 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006499
6500 v8::Handle<String> foo = v8_str("foo");
6501 v8::Handle<String> message = v8_str("message");
6502 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
6503 CHECK(range_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006504 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006505 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
6506 CHECK(reference_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006507 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006508 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
6509 CHECK(syntax_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006510 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006511 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
6512 CHECK(type_error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006513 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006514 v8::Handle<Value> error = v8::Exception::Error(foo);
6515 CHECK(error->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006516 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006517}
6518
6519
6520static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
6521 ApiTestFuzzer::Fuzz();
6522 return v8_num(10);
6523}
6524
6525
6526static void YSetter(Local<String> name,
6527 Local<Value> value,
6528 const AccessorInfo& info) {
6529 if (info.This()->Has(name)) {
6530 info.This()->Delete(name);
6531 }
6532 info.This()->Set(name, value);
6533}
6534
6535
6536THREADED_TEST(DeleteAccessor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006537 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006538 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6539 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
6540 LocalContext context;
6541 v8::Handle<v8::Object> holder = obj->NewInstance();
6542 context->Global()->Set(v8_str("holder"), holder);
6543 v8::Handle<Value> result = CompileRun(
6544 "holder.y = 11; holder.y = 12; holder.y");
6545 CHECK_EQ(12, result->Uint32Value());
6546}
6547
6548
6549THREADED_TEST(TypeSwitch) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006550 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006551 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
6552 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
6553 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
6554 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
6555 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
6556 LocalContext context;
6557 v8::Handle<v8::Object> obj0 = v8::Object::New();
6558 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
6559 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
6560 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
6561 for (int i = 0; i < 10; i++) {
6562 CHECK_EQ(0, type_switch->match(obj0));
6563 CHECK_EQ(1, type_switch->match(obj1));
6564 CHECK_EQ(2, type_switch->match(obj2));
6565 CHECK_EQ(3, type_switch->match(obj3));
6566 CHECK_EQ(3, type_switch->match(obj3));
6567 CHECK_EQ(2, type_switch->match(obj2));
6568 CHECK_EQ(1, type_switch->match(obj1));
6569 CHECK_EQ(0, type_switch->match(obj0));
6570 }
6571}
6572
6573
6574// For use within the TestSecurityHandler() test.
6575static bool g_security_callback_result = false;
6576static bool NamedSecurityTestCallback(Local<v8::Object> global,
6577 Local<Value> name,
6578 v8::AccessType type,
6579 Local<Value> data) {
6580 // Always allow read access.
6581 if (type == v8::ACCESS_GET)
6582 return true;
6583
6584 // Sometimes allow other access.
6585 return g_security_callback_result;
6586}
6587
6588
6589static bool IndexedSecurityTestCallback(Local<v8::Object> global,
6590 uint32_t key,
6591 v8::AccessType type,
6592 Local<Value> data) {
6593 // Always allow read access.
6594 if (type == v8::ACCESS_GET)
6595 return true;
6596
6597 // Sometimes allow other access.
6598 return g_security_callback_result;
6599}
6600
6601
6602static int trouble_nesting = 0;
6603static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
6604 ApiTestFuzzer::Fuzz();
6605 trouble_nesting++;
6606
6607 // Call a JS function that throws an uncaught exception.
6608 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
6609 Local<Value> trouble_callee = (trouble_nesting == 3) ?
6610 arg_this->Get(v8_str("trouble_callee")) :
6611 arg_this->Get(v8_str("trouble_caller"));
6612 CHECK(trouble_callee->IsFunction());
6613 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
6614}
6615
6616
6617static int report_count = 0;
6618static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
6619 v8::Handle<Value>) {
6620 report_count++;
6621}
6622
6623
6624// Counts uncaught exceptions, but other tests running in parallel
6625// also have uncaught exceptions.
6626TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006627 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006628 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006629 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006630 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
6631
6632 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6633 v8::Local<v8::Object> global = env->Global();
6634 global->Set(v8_str("trouble"), fun->GetFunction());
6635
6636 Script::Compile(v8_str("function trouble_callee() {"
6637 " var x = null;"
6638 " return x.foo;"
6639 "};"
6640 "function trouble_caller() {"
6641 " trouble();"
6642 "};"))->Run();
6643 Local<Value> trouble = global->Get(v8_str("trouble"));
6644 CHECK(trouble->IsFunction());
6645 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
6646 CHECK(trouble_callee->IsFunction());
6647 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
6648 CHECK(trouble_caller->IsFunction());
6649 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
6650 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00006651 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
6652}
6653
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006654static const char* script_resource_name = "ExceptionInNativeScript.js";
6655static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
6656 v8::Handle<Value>) {
6657 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
6658 CHECK(!name_val.IsEmpty() && name_val->IsString());
6659 v8::String::AsciiValue name(message->GetScriptResourceName());
6660 CHECK_EQ(script_resource_name, *name);
6661 CHECK_EQ(3, message->GetLineNumber());
6662 v8::String::AsciiValue source_line(message->GetSourceLine());
6663 CHECK_EQ(" new o.foo();", *source_line);
6664}
6665
6666TEST(ExceptionInNativeScript) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006667 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006668 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006669 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
6670
6671 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
6672 v8::Local<v8::Object> global = env->Global();
6673 global->Set(v8_str("trouble"), fun->GetFunction());
6674
6675 Script::Compile(v8_str("function trouble() {\n"
6676 " var o = {};\n"
6677 " new o.foo();\n"
6678 "};"), v8::String::New(script_resource_name))->Run();
6679 Local<Value> trouble = global->Get(v8_str("trouble"));
6680 CHECK(trouble->IsFunction());
6681 Function::Cast(*trouble)->Call(global, 0, NULL);
6682 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
6683}
6684
ager@chromium.org8bb60582008-12-11 12:02:20 +00006685
6686TEST(CompilationErrorUsingTryCatchHandler) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006687 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006688 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org8bb60582008-12-11 12:02:20 +00006689 v8::TryCatch try_catch;
6690 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
6691 CHECK_NE(NULL, *try_catch.Exception());
6692 CHECK(try_catch.HasCaught());
6693}
6694
6695
6696TEST(TryCatchFinallyUsingTryCatchHandler) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00006697 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006698 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org8bb60582008-12-11 12:02:20 +00006699 v8::TryCatch try_catch;
6700 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
6701 CHECK(!try_catch.HasCaught());
6702 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
6703 CHECK(try_catch.HasCaught());
6704 try_catch.Reset();
6705 Script::Compile(v8_str("(function() {"
6706 "try { throw ''; } finally { return; }"
6707 "})()"))->Run();
6708 CHECK(!try_catch.HasCaught());
6709 Script::Compile(v8_str("(function()"
6710 " { try { throw ''; } finally { throw 0; }"
6711 "})()"))->Run();
6712 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006713}
6714
6715
6716// SecurityHandler can't be run twice
6717TEST(SecurityHandler) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006718 v8::HandleScope scope0(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006719 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6720 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
6721 IndexedSecurityTestCallback);
6722 // Create an environment
6723 v8::Persistent<Context> context0 =
6724 Context::New(NULL, global_template);
6725 context0->Enter();
6726
6727 v8::Handle<v8::Object> global0 = context0->Global();
6728 v8::Handle<Script> script0 = v8_compile("foo = 111");
6729 script0->Run();
6730 global0->Set(v8_str("0"), v8_num(999));
6731 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
6732 CHECK_EQ(111, foo0->Int32Value());
6733 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
6734 CHECK_EQ(999, z0->Int32Value());
6735
6736 // Create another environment, should fail security checks.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006737 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006738
6739 v8::Persistent<Context> context1 =
6740 Context::New(NULL, global_template);
6741 context1->Enter();
6742
6743 v8::Handle<v8::Object> global1 = context1->Global();
6744 global1->Set(v8_str("othercontext"), global0);
6745 // This set will fail the security check.
6746 v8::Handle<Script> script1 =
6747 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
6748 script1->Run();
6749 // This read will pass the security check.
6750 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
6751 CHECK_EQ(111, foo1->Int32Value());
6752 // This read will pass the security check.
6753 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
6754 CHECK_EQ(999, z1->Int32Value());
6755
6756 // Create another environment, should pass security checks.
6757 { g_security_callback_result = true; // allow security handler to pass.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006758 v8::HandleScope scope2(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006759 LocalContext context2;
6760 v8::Handle<v8::Object> global2 = context2->Global();
6761 global2->Set(v8_str("othercontext"), global0);
6762 v8::Handle<Script> script2 =
6763 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
6764 script2->Run();
6765 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
6766 CHECK_EQ(333, foo2->Int32Value());
6767 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
6768 CHECK_EQ(888, z2->Int32Value());
6769 }
6770
6771 context1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006772 context1.Dispose(context1->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006773
6774 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006775 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006776}
6777
6778
6779THREADED_TEST(SecurityChecks) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006780 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006781 v8::HandleScope handle_scope(env1->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006782 v8::Persistent<Context> env2 = Context::New();
6783
6784 Local<Value> foo = v8_str("foo");
6785 Local<Value> bar = v8_str("bar");
6786
6787 // Set to the same domain.
6788 env1->SetSecurityToken(foo);
6789
6790 // Create a function in env1.
6791 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
6792 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
6793 CHECK(spy->IsFunction());
6794
6795 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006796 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006797 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
6798 CHECK(spy2->IsFunction());
6799
6800 // Switch to env2 in the same domain and invoke spy on env2.
6801 {
6802 env2->SetSecurityToken(foo);
6803 // Enter env2
6804 Context::Scope scope_env2(env2);
6805 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6806 CHECK(result->IsFunction());
6807 }
6808
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006809 {
6810 env2->SetSecurityToken(bar);
6811 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006812
6813 // Call cross_domain_call, it should throw an exception
6814 v8::TryCatch try_catch;
6815 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6816 CHECK(try_catch.HasCaught());
6817 }
6818
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006819 env2.Dispose(env2->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006820}
6821
6822
6823// Regression test case for issue 1183439.
6824THREADED_TEST(SecurityChecksForPrototypeChain) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006825 LocalContext current;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006826 v8::HandleScope scope(current->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006827 v8::Persistent<Context> other = Context::New();
6828
6829 // Change context to be able to get to the Object function in the
6830 // other context without hitting the security checks.
6831 v8::Local<Value> other_object;
6832 { Context::Scope scope(other);
6833 other_object = other->Global()->Get(v8_str("Object"));
6834 other->Global()->Set(v8_num(42), v8_num(87));
6835 }
6836
6837 current->Global()->Set(v8_str("other"), other->Global());
6838 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6839
6840 // Make sure the security check fails here and we get an undefined
6841 // result instead of getting the Object function. Repeat in a loop
6842 // to make sure to exercise the IC code.
6843 v8::Local<Script> access_other0 = v8_compile("other.Object");
6844 v8::Local<Script> access_other1 = v8_compile("other[42]");
6845 for (int i = 0; i < 5; i++) {
6846 CHECK(!access_other0->Run()->Equals(other_object));
6847 CHECK(access_other0->Run()->IsUndefined());
6848 CHECK(!access_other1->Run()->Equals(v8_num(87)));
6849 CHECK(access_other1->Run()->IsUndefined());
6850 }
6851
6852 // Create an object that has 'other' in its prototype chain and make
6853 // sure we cannot access the Object function indirectly through
6854 // that. Repeat in a loop to make sure to exercise the IC code.
6855 v8_compile("function F() { };"
6856 "F.prototype = other;"
6857 "var f = new F();")->Run();
6858 v8::Local<Script> access_f0 = v8_compile("f.Object");
6859 v8::Local<Script> access_f1 = v8_compile("f[42]");
6860 for (int j = 0; j < 5; j++) {
6861 CHECK(!access_f0->Run()->Equals(other_object));
6862 CHECK(access_f0->Run()->IsUndefined());
6863 CHECK(!access_f1->Run()->Equals(v8_num(87)));
6864 CHECK(access_f1->Run()->IsUndefined());
6865 }
6866
6867 // Now it gets hairy: Set the prototype for the other global object
6868 // to be the current global object. The prototype chain for 'f' now
6869 // goes through 'other' but ends up in the current global object.
6870 { Context::Scope scope(other);
6871 other->Global()->Set(v8_str("__proto__"), current->Global());
6872 }
6873 // Set a named and an index property on the current global
6874 // object. To force the lookup to go through the other global object,
6875 // the properties must not exist in the other global object.
6876 current->Global()->Set(v8_str("foo"), v8_num(100));
6877 current->Global()->Set(v8_num(99), v8_num(101));
6878 // Try to read the properties from f and make sure that the access
6879 // gets stopped by the security checks on the other global object.
6880 Local<Script> access_f2 = v8_compile("f.foo");
6881 Local<Script> access_f3 = v8_compile("f[99]");
6882 for (int k = 0; k < 5; k++) {
6883 CHECK(!access_f2->Run()->Equals(v8_num(100)));
6884 CHECK(access_f2->Run()->IsUndefined());
6885 CHECK(!access_f3->Run()->Equals(v8_num(101)));
6886 CHECK(access_f3->Run()->IsUndefined());
6887 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006888 other.Dispose(other->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006889}
6890
6891
6892THREADED_TEST(CrossDomainDelete) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006893 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006894 v8::HandleScope handle_scope(env1->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006895 v8::Persistent<Context> env2 = Context::New();
6896
6897 Local<Value> foo = v8_str("foo");
6898 Local<Value> bar = v8_str("bar");
6899
6900 // Set to the same domain.
6901 env1->SetSecurityToken(foo);
6902 env2->SetSecurityToken(foo);
6903
6904 env1->Global()->Set(v8_str("prop"), v8_num(3));
6905 env2->Global()->Set(v8_str("env1"), env1->Global());
6906
6907 // Change env2 to a different domain and delete env1.prop.
6908 env2->SetSecurityToken(bar);
6909 {
6910 Context::Scope scope_env2(env2);
6911 Local<Value> result =
6912 Script::Compile(v8_str("delete env1.prop"))->Run();
6913 CHECK(result->IsFalse());
6914 }
6915
6916 // Check that env1.prop still exists.
6917 Local<Value> v = env1->Global()->Get(v8_str("prop"));
6918 CHECK(v->IsNumber());
6919 CHECK_EQ(3, v->Int32Value());
6920
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006921 env2.Dispose(env2->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006922}
6923
6924
ager@chromium.org870a0b62008-11-04 11:43:05 +00006925THREADED_TEST(CrossDomainIsPropertyEnumerable) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006926 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006927 v8::HandleScope handle_scope(env1->GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006928 v8::Persistent<Context> env2 = Context::New();
6929
6930 Local<Value> foo = v8_str("foo");
6931 Local<Value> bar = v8_str("bar");
6932
6933 // Set to the same domain.
6934 env1->SetSecurityToken(foo);
6935 env2->SetSecurityToken(foo);
6936
6937 env1->Global()->Set(v8_str("prop"), v8_num(3));
6938 env2->Global()->Set(v8_str("env1"), env1->Global());
6939
6940 // env1.prop is enumerable in env2.
6941 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6942 {
6943 Context::Scope scope_env2(env2);
6944 Local<Value> result = Script::Compile(test)->Run();
6945 CHECK(result->IsTrue());
6946 }
6947
6948 // Change env2 to a different domain and test again.
6949 env2->SetSecurityToken(bar);
6950 {
6951 Context::Scope scope_env2(env2);
6952 Local<Value> result = Script::Compile(test)->Run();
6953 CHECK(result->IsFalse());
6954 }
6955
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006956 env2.Dispose(env2->GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +00006957}
6958
6959
ager@chromium.org236ad962008-09-25 09:45:57 +00006960THREADED_TEST(CrossDomainForIn) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006961 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006962 v8::HandleScope handle_scope(env1->GetIsolate());
ager@chromium.org236ad962008-09-25 09:45:57 +00006963 v8::Persistent<Context> env2 = Context::New();
6964
6965 Local<Value> foo = v8_str("foo");
6966 Local<Value> bar = v8_str("bar");
6967
6968 // Set to the same domain.
6969 env1->SetSecurityToken(foo);
6970 env2->SetSecurityToken(foo);
6971
6972 env1->Global()->Set(v8_str("prop"), v8_num(3));
6973 env2->Global()->Set(v8_str("env1"), env1->Global());
6974
6975 // Change env2 to a different domain and set env1's global object
6976 // as the __proto__ of an object in env2 and enumerate properties
6977 // in for-in. It shouldn't enumerate properties on env1's global
6978 // object.
6979 env2->SetSecurityToken(bar);
6980 {
6981 Context::Scope scope_env2(env2);
6982 Local<Value> result =
6983 CompileRun("(function(){var obj = {'__proto__':env1};"
6984 "for (var p in obj)"
6985 " if (p == 'prop') return false;"
6986 "return true;})()");
6987 CHECK(result->IsTrue());
6988 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00006989 env2.Dispose(env2->GetIsolate());
ager@chromium.org236ad962008-09-25 09:45:57 +00006990}
6991
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006992
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006993TEST(ContextDetachGlobal) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006994 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006995 v8::HandleScope handle_scope(env1->GetIsolate());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006996 v8::Persistent<Context> env2 = Context::New();
6997
6998 Local<v8::Object> global1 = env1->Global();
6999
7000 Local<Value> foo = v8_str("foo");
7001
7002 // Set to the same domain.
7003 env1->SetSecurityToken(foo);
7004 env2->SetSecurityToken(foo);
7005
7006 // Enter env2
7007 env2->Enter();
7008
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007009 // Create a function in env2 and add a reference to it in env1.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007010 Local<v8::Object> global2 = env2->Global();
7011 global2->Set(v8_str("prop"), v8::Integer::New(1));
7012 CompileRun("function getProp() {return prop;}");
7013
7014 env1->Global()->Set(v8_str("getProp"),
7015 global2->Get(v8_str("getProp")));
7016
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007017 // Detach env2's global, and reuse the global object of env2
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007018 env2->Exit();
7019 env2->DetachGlobal();
7020 // env2 has a new global object.
7021 CHECK(!env2->Global()->Equals(global2));
7022
7023 v8::Persistent<Context> env3 =
7024 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7025 env3->SetSecurityToken(v8_str("bar"));
7026 env3->Enter();
7027
7028 Local<v8::Object> global3 = env3->Global();
7029 CHECK_EQ(global2, global3);
7030 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
7031 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
7032 global3->Set(v8_str("prop"), v8::Integer::New(-1));
7033 global3->Set(v8_str("prop2"), v8::Integer::New(2));
7034 env3->Exit();
7035
7036 // Call getProp in env1, and it should return the value 1
7037 {
7038 Local<Value> get_prop = global1->Get(v8_str("getProp"));
7039 CHECK(get_prop->IsFunction());
7040 v8::TryCatch try_catch;
7041 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
7042 CHECK(!try_catch.HasCaught());
7043 CHECK_EQ(1, r->Int32Value());
7044 }
7045
7046 // Check that env3 is not accessible from env1
7047 {
7048 Local<Value> r = global3->Get(v8_str("prop2"));
7049 CHECK(r->IsUndefined());
7050 }
7051
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007052 env2.Dispose(env2->GetIsolate());
7053 env3.Dispose(env3->GetIsolate());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007054}
7055
7056
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007057TEST(DetachAndReattachGlobal) {
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007058 LocalContext env1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007059 v8::HandleScope scope(env1->GetIsolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007060
7061 // Create second environment.
7062 v8::Persistent<Context> env2 = Context::New();
7063
7064 Local<Value> foo = v8_str("foo");
7065
7066 // Set same security token for env1 and env2.
7067 env1->SetSecurityToken(foo);
7068 env2->SetSecurityToken(foo);
7069
7070 // Create a property on the global object in env2.
7071 {
7072 v8::Context::Scope scope(env2);
7073 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7074 }
7075
7076 // Create a reference to env2 global from env1 global.
7077 env1->Global()->Set(v8_str("other"), env2->Global());
7078
7079 // Check that we have access to other.p in env2 from env1.
7080 Local<Value> result = CompileRun("other.p");
7081 CHECK(result->IsInt32());
7082 CHECK_EQ(42, result->Int32Value());
7083
7084 // Hold on to global from env2 and detach global from env2.
7085 Local<v8::Object> global2 = env2->Global();
7086 env2->DetachGlobal();
7087
7088 // Check that the global has been detached. No other.p property can
7089 // be found.
7090 result = CompileRun("other.p");
7091 CHECK(result->IsUndefined());
7092
7093 // Reuse global2 for env3.
7094 v8::Persistent<Context> env3 =
7095 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
7096 CHECK_EQ(global2, env3->Global());
7097
7098 // Start by using the same security token for env3 as for env1 and env2.
7099 env3->SetSecurityToken(foo);
7100
7101 // Create a property on the global object in env3.
7102 {
7103 v8::Context::Scope scope(env3);
7104 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
7105 }
7106
7107 // Check that other.p is now the property in env3 and that we have access.
7108 result = CompileRun("other.p");
7109 CHECK(result->IsInt32());
7110 CHECK_EQ(24, result->Int32Value());
7111
7112 // Change security token for env3 to something different from env1 and env2.
7113 env3->SetSecurityToken(v8_str("bar"));
7114
7115 // Check that we do not have access to other.p in env1. |other| is now
7116 // the global object for env3 which has a different security token,
7117 // so access should be blocked.
7118 result = CompileRun("other.p");
7119 CHECK(result->IsUndefined());
7120
7121 // Detach the global for env3 and reattach it to env2.
7122 env3->DetachGlobal();
7123 env2->ReattachGlobal(global2);
7124
7125 // Check that we have access to other.p again in env1. |other| is now
7126 // the global object for env2 which has the same security token as env1.
7127 result = CompileRun("other.p");
7128 CHECK(result->IsInt32());
7129 CHECK_EQ(42, result->Int32Value());
7130
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007131 env2.Dispose(env2->GetIsolate());
7132 env3.Dispose(env3->GetIsolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00007133}
7134
7135
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007136static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007137static bool NamedAccessBlocker(Local<v8::Object> global,
7138 Local<Value> name,
7139 v8::AccessType type,
7140 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007141 return Context::GetCurrent()->Global()->Equals(global) ||
7142 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007143}
7144
7145
7146static bool IndexedAccessBlocker(Local<v8::Object> global,
7147 uint32_t key,
7148 v8::AccessType type,
7149 Local<Value> data) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007150 return Context::GetCurrent()->Global()->Equals(global) ||
7151 allowed_access_type[type];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007152}
7153
7154
7155static int g_echo_value = -1;
7156static v8::Handle<Value> EchoGetter(Local<String> name,
7157 const AccessorInfo& info) {
7158 return v8_num(g_echo_value);
7159}
7160
7161
7162static void EchoSetter(Local<String> name,
7163 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007164 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007165 if (value->IsNumber())
7166 g_echo_value = value->Int32Value();
7167}
7168
7169
7170static v8::Handle<Value> UnreachableGetter(Local<String> name,
7171 const AccessorInfo& info) {
7172 CHECK(false); // This function should not be called..
7173 return v8::Undefined();
7174}
7175
7176
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007177static void UnreachableSetter(Local<String>, Local<Value>,
7178 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007179 CHECK(false); // This function should nto be called.
7180}
7181
7182
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007183TEST(AccessControl) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007184 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007185 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7186
7187 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7188 IndexedAccessBlocker);
7189
7190 // Add an accessor accessible by cross-domain JS code.
7191 global_template->SetAccessor(
7192 v8_str("accessible_prop"),
7193 EchoGetter, EchoSetter,
7194 v8::Handle<Value>(),
7195 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7196
7197 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00007198 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007199 UnreachableGetter, UnreachableSetter,
7200 v8::Handle<Value>(),
7201 v8::DEFAULT);
7202
7203 // Create an environment
7204 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7205 context0->Enter();
7206
7207 v8::Handle<v8::Object> global0 = context0->Global();
7208
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007209 // Define a property with JS getter and setter.
7210 CompileRun(
7211 "function getter() { return 'getter'; };\n"
7212 "function setter() { return 'setter'; }\n"
7213 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
7214
7215 Local<Value> getter = global0->Get(v8_str("getter"));
7216 Local<Value> setter = global0->Get(v8_str("setter"));
7217
7218 // And define normal element.
7219 global0->Set(239, v8_str("239"));
7220
7221 // Define an element with JS getter and setter.
7222 CompileRun(
7223 "function el_getter() { return 'el_getter'; };\n"
7224 "function el_setter() { return 'el_setter'; };\n"
7225 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
7226
7227 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
7228 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
7229
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007230 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007231
7232 v8::Persistent<Context> context1 = Context::New();
7233 context1->Enter();
7234
7235 v8::Handle<v8::Object> global1 = context1->Global();
7236 global1->Set(v8_str("other"), global0);
7237
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007238 // Access blocked property.
7239 CompileRun("other.blocked_prop = 1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007240
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007241 ExpectUndefined("other.blocked_prop");
7242 ExpectUndefined(
7243 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7244 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007245
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007246 // Enable ACCESS_HAS
7247 allowed_access_type[v8::ACCESS_HAS] = true;
7248 ExpectUndefined("other.blocked_prop");
7249 // ... and now we can get the descriptor...
7250 ExpectUndefined(
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007251 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007252 // ... and enumerate the property.
7253 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
7254 allowed_access_type[v8::ACCESS_HAS] = false;
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007255
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007256 // Access blocked element.
7257 CompileRun("other[239] = 1");
7258
7259 ExpectUndefined("other[239]");
7260 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
7261 ExpectFalse("propertyIsEnumerable.call(other, '239')");
7262
7263 // Enable ACCESS_HAS
7264 allowed_access_type[v8::ACCESS_HAS] = true;
7265 ExpectUndefined("other[239]");
7266 // ... and now we can get the descriptor...
7267 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
7268 // ... and enumerate the property.
7269 ExpectTrue("propertyIsEnumerable.call(other, '239')");
7270 allowed_access_type[v8::ACCESS_HAS] = false;
7271
7272 // Access a property with JS accessor.
7273 CompileRun("other.js_accessor_p = 2");
7274
7275 ExpectUndefined("other.js_accessor_p");
7276 ExpectUndefined(
7277 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
7278
7279 // Enable ACCESS_HAS.
7280 allowed_access_type[v8::ACCESS_HAS] = true;
7281 ExpectUndefined("other.js_accessor_p");
7282 ExpectUndefined(
7283 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7284 ExpectUndefined(
7285 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7286 ExpectUndefined(
7287 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7288 allowed_access_type[v8::ACCESS_HAS] = false;
7289
7290 // Enable both ACCESS_HAS and ACCESS_GET.
7291 allowed_access_type[v8::ACCESS_HAS] = true;
7292 allowed_access_type[v8::ACCESS_GET] = true;
7293
7294 ExpectString("other.js_accessor_p", "getter");
7295 ExpectObject(
7296 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7297 ExpectUndefined(
7298 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
7299 ExpectUndefined(
7300 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7301
7302 allowed_access_type[v8::ACCESS_GET] = false;
7303 allowed_access_type[v8::ACCESS_HAS] = false;
7304
7305 // Enable both ACCESS_HAS and ACCESS_SET.
7306 allowed_access_type[v8::ACCESS_HAS] = true;
7307 allowed_access_type[v8::ACCESS_SET] = true;
7308
7309 ExpectUndefined("other.js_accessor_p");
7310 ExpectUndefined(
7311 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
7312 ExpectObject(
7313 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7314 ExpectUndefined(
7315 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7316
7317 allowed_access_type[v8::ACCESS_SET] = false;
7318 allowed_access_type[v8::ACCESS_HAS] = false;
7319
7320 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7321 allowed_access_type[v8::ACCESS_HAS] = true;
7322 allowed_access_type[v8::ACCESS_GET] = true;
7323 allowed_access_type[v8::ACCESS_SET] = true;
7324
7325 ExpectString("other.js_accessor_p", "getter");
7326 ExpectObject(
7327 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
7328 ExpectObject(
7329 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
7330 ExpectUndefined(
7331 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
7332
7333 allowed_access_type[v8::ACCESS_SET] = false;
7334 allowed_access_type[v8::ACCESS_GET] = false;
7335 allowed_access_type[v8::ACCESS_HAS] = false;
7336
7337 // Access an element with JS accessor.
7338 CompileRun("other[42] = 2");
7339
7340 ExpectUndefined("other[42]");
7341 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
7342
7343 // Enable ACCESS_HAS.
7344 allowed_access_type[v8::ACCESS_HAS] = true;
7345 ExpectUndefined("other[42]");
7346 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7347 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7348 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7349 allowed_access_type[v8::ACCESS_HAS] = false;
7350
7351 // Enable both ACCESS_HAS and ACCESS_GET.
7352 allowed_access_type[v8::ACCESS_HAS] = true;
7353 allowed_access_type[v8::ACCESS_GET] = true;
7354
7355 ExpectString("other[42]", "el_getter");
7356 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7357 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
7358 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7359
7360 allowed_access_type[v8::ACCESS_GET] = false;
7361 allowed_access_type[v8::ACCESS_HAS] = false;
7362
7363 // Enable both ACCESS_HAS and ACCESS_SET.
7364 allowed_access_type[v8::ACCESS_HAS] = true;
7365 allowed_access_type[v8::ACCESS_SET] = true;
7366
7367 ExpectUndefined("other[42]");
7368 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
7369 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7370 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7371
7372 allowed_access_type[v8::ACCESS_SET] = false;
7373 allowed_access_type[v8::ACCESS_HAS] = false;
7374
7375 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
7376 allowed_access_type[v8::ACCESS_HAS] = true;
7377 allowed_access_type[v8::ACCESS_GET] = true;
7378 allowed_access_type[v8::ACCESS_SET] = true;
7379
7380 ExpectString("other[42]", "el_getter");
7381 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
7382 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
7383 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
7384
7385 allowed_access_type[v8::ACCESS_SET] = false;
7386 allowed_access_type[v8::ACCESS_GET] = false;
7387 allowed_access_type[v8::ACCESS_HAS] = false;
7388
7389 v8::Handle<Value> value;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007390
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007391 // Access accessible property
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007392 value = CompileRun("other.accessible_prop = 3");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007393 CHECK(value->IsNumber());
7394 CHECK_EQ(3, value->Int32Value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007395 CHECK_EQ(3, g_echo_value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007396
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007397 value = CompileRun("other.accessible_prop");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007398 CHECK(value->IsNumber());
7399 CHECK_EQ(3, value->Int32Value());
7400
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007401 value = CompileRun(
7402 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
7403 CHECK(value->IsNumber());
7404 CHECK_EQ(3, value->Int32Value());
7405
7406 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
ager@chromium.org870a0b62008-11-04 11:43:05 +00007407 CHECK(value->IsTrue());
7408
7409 // Enumeration doesn't enumerate accessors from inaccessible objects in
7410 // the prototype chain even if the accessors are in themselves accessible.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007411 value =
ager@chromium.org870a0b62008-11-04 11:43:05 +00007412 CompileRun("(function(){var obj = {'__proto__':other};"
7413 "for (var p in obj)"
7414 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
7415 " return false;"
7416 " }"
7417 "return true;})()");
antonm@chromium.orgdca01352011-01-31 17:15:05 +00007418 CHECK(value->IsTrue());
ager@chromium.org870a0b62008-11-04 11:43:05 +00007419
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007420 context1->Exit();
7421 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007422 context1.Dispose(context1->GetIsolate());
7423 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007424}
7425
7426
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007427TEST(AccessControlES5) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007428 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
ricow@chromium.org65001782011-02-15 13:36:41 +00007429 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7430
7431 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
7432 IndexedAccessBlocker);
7433
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007434 // Add accessible accessor.
7435 global_template->SetAccessor(
7436 v8_str("accessible_prop"),
7437 EchoGetter, EchoSetter,
7438 v8::Handle<Value>(),
7439 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
7440
7441
ricow@chromium.org65001782011-02-15 13:36:41 +00007442 // Add an accessor that is not accessible by cross-domain JS code.
7443 global_template->SetAccessor(v8_str("blocked_prop"),
7444 UnreachableGetter, UnreachableSetter,
7445 v8::Handle<Value>(),
7446 v8::DEFAULT);
7447
7448 // Create an environment
7449 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7450 context0->Enter();
7451
7452 v8::Handle<v8::Object> global0 = context0->Global();
7453
7454 v8::Persistent<Context> context1 = Context::New();
7455 context1->Enter();
7456 v8::Handle<v8::Object> global1 = context1->Global();
7457 global1->Set(v8_str("other"), global0);
7458
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007459 // Regression test for issue 1154.
ricow@chromium.org65001782011-02-15 13:36:41 +00007460 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007461
7462 ExpectUndefined("other.blocked_prop");
7463
7464 // Regression test for issue 1027.
7465 CompileRun("Object.defineProperty(\n"
7466 " other, 'blocked_prop', {configurable: false})");
7467 ExpectUndefined("other.blocked_prop");
7468 ExpectUndefined(
7469 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
7470
7471 // Regression test for issue 1171.
7472 ExpectTrue("Object.isExtensible(other)");
7473 CompileRun("Object.preventExtensions(other)");
7474 ExpectTrue("Object.isExtensible(other)");
7475
7476 // Object.seal and Object.freeze.
7477 CompileRun("Object.freeze(other)");
7478 ExpectTrue("Object.isExtensible(other)");
7479
7480 CompileRun("Object.seal(other)");
7481 ExpectTrue("Object.isExtensible(other)");
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00007482
7483 // Regression test for issue 1250.
7484 // Make sure that we can set the accessible accessors value using normal
7485 // assignment.
7486 CompileRun("other.accessible_prop = 42");
7487 CHECK_EQ(42, g_echo_value);
7488
7489 v8::Handle<Value> value;
7490 // We follow Safari in ignoring assignments to host object accessors.
7491 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
7492 value = CompileRun("other.accessible_prop == 42");
7493 CHECK(value->IsTrue());
ricow@chromium.org65001782011-02-15 13:36:41 +00007494}
7495
7496
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007497static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
7498 Local<Value> name,
7499 v8::AccessType type,
7500 Local<Value> data) {
7501 return false;
7502}
7503
7504
7505static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
7506 uint32_t key,
7507 v8::AccessType type,
7508 Local<Value> data) {
7509 return false;
7510}
7511
7512
7513THREADED_TEST(AccessControlGetOwnPropertyNames) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007514 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007515 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7516
7517 obj_template->Set(v8_str("x"), v8::Integer::New(42));
7518 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
7519 GetOwnPropertyNamesIndexedBlocker);
7520
7521 // Create an environment
7522 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
7523 context0->Enter();
7524
7525 v8::Handle<v8::Object> global0 = context0->Global();
7526
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007527 v8::HandleScope scope1(v8::Isolate::GetCurrent());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007528
7529 v8::Persistent<Context> context1 = Context::New();
7530 context1->Enter();
7531
7532 v8::Handle<v8::Object> global1 = context1->Global();
7533 global1->Set(v8_str("other"), global0);
7534 global1->Set(v8_str("object"), obj_template->NewInstance());
7535
7536 v8::Handle<Value> value;
7537
7538 // Attempt to get the property names of the other global object and
7539 // of an object that requires access checks. Accessing the other
7540 // global object should be blocked by access checks on the global
7541 // proxy object. Accessing the object that requires access checks
7542 // is blocked by the access checks on the object itself.
7543 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
7544 CHECK(value->IsTrue());
7545
7546 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
7547 CHECK(value->IsTrue());
7548
7549 context1->Exit();
7550 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007551 context1.Dispose(context1->GetIsolate());
7552 context0.Dispose(context0->GetIsolate());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007553}
7554
7555
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007556static v8::Handle<v8::Array> IndexedPropertyEnumerator(const AccessorInfo&) {
7557 v8::Handle<v8::Array> result = v8::Array::New(2);
7558 result->Set(0, v8::Integer::New(7));
7559 result->Set(1, v8::Object::New());
7560 return result;
7561}
7562
7563
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007564static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007565 v8::Handle<v8::Array> result = v8::Array::New(2);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007566 result->Set(0, v8_str("x"));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007567 result->Set(1, v8::Object::New());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007568 return result;
7569}
7570
7571
7572THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007573 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007574 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
7575
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007576 obj_template->Set(v8_str("7"), v8::Integer::New(7));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007577 obj_template->Set(v8_str("x"), v8::Integer::New(42));
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007578 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
7579 IndexedPropertyEnumerator);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007580 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
7581 NamedPropertyEnumerator);
7582
7583 LocalContext context;
7584 v8::Handle<v8::Object> global = context->Global();
7585 global->Set(v8_str("object"), obj_template->NewInstance());
7586
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00007587 v8::Handle<v8::Value> result =
7588 CompileRun("Object.getOwnPropertyNames(object)");
7589 CHECK(result->IsArray());
7590 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
7591 CHECK_EQ(3, result_array->Length());
7592 CHECK(result_array->Get(0)->IsString());
7593 CHECK(result_array->Get(1)->IsString());
7594 CHECK(result_array->Get(2)->IsString());
7595 CHECK_EQ(v8_str("7"), result_array->Get(0));
7596 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
7597 CHECK_EQ(v8_str("x"), result_array->Get(2));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007598}
7599
7600
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007601static v8::Handle<Value> ConstTenGetter(Local<String> name,
7602 const AccessorInfo& info) {
7603 return v8_num(10);
7604}
7605
7606
7607THREADED_TEST(CrossDomainAccessors) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007608 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007609
7610 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
7611
7612 v8::Handle<v8::ObjectTemplate> global_template =
7613 func_template->InstanceTemplate();
7614
7615 v8::Handle<v8::ObjectTemplate> proto_template =
7616 func_template->PrototypeTemplate();
7617
7618 // Add an accessor to proto that's accessible by cross-domain JS code.
7619 proto_template->SetAccessor(v8_str("accessible"),
7620 ConstTenGetter, 0,
7621 v8::Handle<Value>(),
7622 v8::ALL_CAN_READ);
7623
7624 // Add an accessor that is not accessible by cross-domain JS code.
7625 global_template->SetAccessor(v8_str("unreachable"),
7626 UnreachableGetter, 0,
7627 v8::Handle<Value>(),
7628 v8::DEFAULT);
7629
7630 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7631 context0->Enter();
7632
7633 Local<v8::Object> global = context0->Global();
7634 // Add a normal property that shadows 'accessible'
7635 global->Set(v8_str("accessible"), v8_num(11));
7636
7637 // Enter a new context.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007638 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007639 v8::Persistent<Context> context1 = Context::New();
7640 context1->Enter();
7641
7642 v8::Handle<v8::Object> global1 = context1->Global();
7643 global1->Set(v8_str("other"), global);
7644
7645 // Should return 10, instead of 11
7646 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
7647 CHECK(value->IsNumber());
7648 CHECK_EQ(10, value->Int32Value());
7649
7650 value = v8_compile("other.unreachable")->Run();
7651 CHECK(value->IsUndefined());
7652
7653 context1->Exit();
7654 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007655 context1.Dispose(context1->GetIsolate());
7656 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007657}
7658
7659
7660static int named_access_count = 0;
7661static int indexed_access_count = 0;
7662
7663static bool NamedAccessCounter(Local<v8::Object> global,
7664 Local<Value> name,
7665 v8::AccessType type,
7666 Local<Value> data) {
7667 named_access_count++;
7668 return true;
7669}
7670
7671
7672static bool IndexedAccessCounter(Local<v8::Object> global,
7673 uint32_t key,
7674 v8::AccessType type,
7675 Local<Value> data) {
7676 indexed_access_count++;
7677 return true;
7678}
7679
7680
7681// This one is too easily disturbed by other tests.
7682TEST(AccessControlIC) {
7683 named_access_count = 0;
7684 indexed_access_count = 0;
7685
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007686 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007687
7688 // Create an environment.
7689 v8::Persistent<Context> context0 = Context::New();
7690 context0->Enter();
7691
7692 // Create an object that requires access-check functions to be
7693 // called for cross-domain access.
7694 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7695 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7696 IndexedAccessCounter);
7697 Local<v8::Object> object = object_template->NewInstance();
7698
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007699 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007700
7701 // Create another environment.
7702 v8::Persistent<Context> context1 = Context::New();
7703 context1->Enter();
7704
7705 // Make easy access to the object from the other environment.
7706 v8::Handle<v8::Object> global1 = context1->Global();
7707 global1->Set(v8_str("obj"), object);
7708
7709 v8::Handle<Value> value;
7710
7711 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007712 CompileRun("function testProp(obj) {"
7713 " for (var i = 0; i < 10; i++) obj.prop = 1;"
7714 " for (var j = 0; j < 10; j++) obj.prop;"
7715 " return obj.prop"
7716 "}");
7717 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007718 CHECK(value->IsNumber());
7719 CHECK_EQ(1, value->Int32Value());
7720 CHECK_EQ(21, named_access_count);
7721
7722 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007723 CompileRun("var p = 'prop';"
7724 "function testKeyed(obj) {"
7725 " for (var i = 0; i < 10; i++) obj[p] = 1;"
7726 " for (var j = 0; j < 10; j++) obj[p];"
7727 " return obj[p];"
7728 "}");
7729 // Use obj which requires access checks. No inline caching is used
7730 // in that case.
7731 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007732 CHECK(value->IsNumber());
7733 CHECK_EQ(1, value->Int32Value());
7734 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007735 // Force the inline caches into generic state and try again.
7736 CompileRun("testKeyed({ a: 0 })");
7737 CompileRun("testKeyed({ b: 0 })");
7738 value = CompileRun("testKeyed(obj)");
7739 CHECK(value->IsNumber());
7740 CHECK_EQ(1, value->Int32Value());
7741 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007742
7743 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00007744 CompileRun("function testIndexed(obj) {"
7745 " for (var i = 0; i < 10; i++) obj[0] = 1;"
7746 " for (var j = 0; j < 10; j++) obj[0];"
7747 " return obj[0]"
7748 "}");
7749 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007750 CHECK(value->IsNumber());
7751 CHECK_EQ(1, value->Int32Value());
7752 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00007753 // Force the inline caches into generic state.
7754 CompileRun("testIndexed(new Array(1))");
7755 // Test that the indexed access check is called.
7756 value = CompileRun("testIndexed(obj)");
7757 CHECK(value->IsNumber());
7758 CHECK_EQ(1, value->Int32Value());
7759 CHECK_EQ(42, indexed_access_count);
7760
7761 // Check that the named access check is called when invoking
7762 // functions on an object that requires access checks.
7763 CompileRun("obj.f = function() {}");
7764 CompileRun("function testCallNormal(obj) {"
7765 " for (var i = 0; i < 10; i++) obj.f();"
7766 "}");
7767 CompileRun("testCallNormal(obj)");
7768 CHECK_EQ(74, named_access_count);
7769
7770 // Force obj into slow case.
7771 value = CompileRun("delete obj.prop");
7772 CHECK(value->BooleanValue());
7773 // Force inline caches into dictionary probing mode.
7774 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
7775 // Test that the named access check is called.
7776 value = CompileRun("testProp(obj);");
7777 CHECK(value->IsNumber());
7778 CHECK_EQ(1, value->Int32Value());
7779 CHECK_EQ(96, named_access_count);
7780
7781 // Force the call inline cache into dictionary probing mode.
7782 CompileRun("o.f = function() {}; testCallNormal(o)");
7783 // Test that the named access check is still called for each
7784 // invocation of the function.
7785 value = CompileRun("testCallNormal(obj)");
7786 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007787
7788 context1->Exit();
7789 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007790 context1.Dispose(context1->GetIsolate());
7791 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007792}
7793
7794
7795static bool NamedAccessFlatten(Local<v8::Object> global,
7796 Local<Value> name,
7797 v8::AccessType type,
7798 Local<Value> data) {
7799 char buf[100];
7800 int len;
7801
7802 CHECK(name->IsString());
7803
7804 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007805 len = name.As<String>()->WriteAscii(buf);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007806 CHECK_EQ(4, len);
7807
7808 uint16_t buf2[100];
7809
7810 memset(buf, 0x1, sizeof(buf));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007811 len = name.As<String>()->Write(buf2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007812 CHECK_EQ(4, len);
7813
7814 return true;
7815}
7816
7817
7818static bool IndexedAccessFlatten(Local<v8::Object> global,
7819 uint32_t key,
7820 v8::AccessType type,
7821 Local<Value> data) {
7822 return true;
7823}
7824
7825
7826// Regression test. In access checks, operations that may cause
7827// garbage collection are not allowed. It used to be the case that
7828// using the Write operation on a string could cause a garbage
7829// collection due to flattening of the string. This is no longer the
7830// case.
7831THREADED_TEST(AccessControlFlatten) {
7832 named_access_count = 0;
7833 indexed_access_count = 0;
7834
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007835 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007836
7837 // Create an environment.
7838 v8::Persistent<Context> context0 = Context::New();
7839 context0->Enter();
7840
7841 // Create an object that requires access-check functions to be
7842 // called for cross-domain access.
7843 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7844 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7845 IndexedAccessFlatten);
7846 Local<v8::Object> object = object_template->NewInstance();
7847
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007848 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007849
7850 // Create another environment.
7851 v8::Persistent<Context> context1 = Context::New();
7852 context1->Enter();
7853
7854 // Make easy access to the object from the other environment.
7855 v8::Handle<v8::Object> global1 = context1->Global();
7856 global1->Set(v8_str("obj"), object);
7857
7858 v8::Handle<Value> value;
7859
7860 value = v8_compile("var p = 'as' + 'df';")->Run();
7861 value = v8_compile("obj[p];")->Run();
7862
7863 context1->Exit();
7864 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007865 context1.Dispose(context1->GetIsolate());
7866 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007867}
7868
7869
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007870static v8::Handle<Value> AccessControlNamedGetter(
7871 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007872 return v8::Integer::New(42);
7873}
7874
7875
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007876static v8::Handle<Value> AccessControlNamedSetter(
7877 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007878 return value;
7879}
7880
7881
7882static v8::Handle<Value> AccessControlIndexedGetter(
7883 uint32_t index,
7884 const AccessorInfo& info) {
7885 return v8_num(42);
7886}
7887
7888
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007889static v8::Handle<Value> AccessControlIndexedSetter(
7890 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007891 return value;
7892}
7893
7894
7895THREADED_TEST(AccessControlInterceptorIC) {
7896 named_access_count = 0;
7897 indexed_access_count = 0;
7898
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007899 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007900
7901 // Create an environment.
7902 v8::Persistent<Context> context0 = Context::New();
7903 context0->Enter();
7904
7905 // Create an object that requires access-check functions to be
7906 // called for cross-domain access. The object also has interceptors
7907 // interceptor.
7908 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7909 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7910 IndexedAccessCounter);
7911 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7912 AccessControlNamedSetter);
7913 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7914 AccessControlIndexedSetter);
7915 Local<v8::Object> object = object_template->NewInstance();
7916
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007917 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007918
7919 // Create another environment.
7920 v8::Persistent<Context> context1 = Context::New();
7921 context1->Enter();
7922
7923 // Make easy access to the object from the other environment.
7924 v8::Handle<v8::Object> global1 = context1->Global();
7925 global1->Set(v8_str("obj"), object);
7926
7927 v8::Handle<Value> value;
7928
7929 // Check that the named access-control function is called every time
7930 // eventhough there is an interceptor on the object.
7931 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7932 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7933 "obj.x")->Run();
7934 CHECK(value->IsNumber());
7935 CHECK_EQ(42, value->Int32Value());
7936 CHECK_EQ(21, named_access_count);
7937
7938 value = v8_compile("var p = 'x';")->Run();
7939 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7940 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7941 "obj[p]")->Run();
7942 CHECK(value->IsNumber());
7943 CHECK_EQ(42, value->Int32Value());
7944 CHECK_EQ(42, named_access_count);
7945
7946 // Check that the indexed access-control function is called every
7947 // time eventhough there is an interceptor on the object.
7948 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7949 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7950 "obj[0]")->Run();
7951 CHECK(value->IsNumber());
7952 CHECK_EQ(42, value->Int32Value());
7953 CHECK_EQ(21, indexed_access_count);
7954
7955 context1->Exit();
7956 context0->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00007957 context1.Dispose(context1->GetIsolate());
7958 context0.Dispose(context0->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007959}
7960
7961
7962THREADED_TEST(Version) {
7963 v8::V8::GetVersion();
7964}
7965
7966
7967static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7968 ApiTestFuzzer::Fuzz();
7969 return v8_num(12);
7970}
7971
7972
7973THREADED_TEST(InstanceProperties) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007974 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00007975 v8::HandleScope handle_scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007976
7977 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7978 Local<ObjectTemplate> instance = t->InstanceTemplate();
7979
7980 instance->Set(v8_str("x"), v8_num(42));
7981 instance->Set(v8_str("f"),
7982 v8::FunctionTemplate::New(InstanceFunctionCallback));
7983
7984 Local<Value> o = t->GetFunction()->NewInstance();
7985
7986 context->Global()->Set(v8_str("i"), o);
7987 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7988 CHECK_EQ(42, value->Int32Value());
7989
7990 value = Script::Compile(v8_str("i.f()"))->Run();
7991 CHECK_EQ(12, value->Int32Value());
7992}
7993
7994
7995static v8::Handle<Value>
7996GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7997 ApiTestFuzzer::Fuzz();
7998 return v8::Handle<Value>();
7999}
8000
8001
8002THREADED_TEST(GlobalObjectInstanceProperties) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008003 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008004
8005 Local<Value> global_object;
8006
8007 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8008 t->InstanceTemplate()->SetNamedPropertyHandler(
8009 GlobalObjectInstancePropertiesGet);
8010 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8011 instance_template->Set(v8_str("x"), v8_num(42));
8012 instance_template->Set(v8_str("f"),
8013 v8::FunctionTemplate::New(InstanceFunctionCallback));
8014
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008015 // The script to check how Crankshaft compiles missing global function
8016 // invocations. function g is not defined and should throw on call.
8017 const char* script =
8018 "function wrapper(call) {"
8019 " var x = 0, y = 1;"
8020 " for (var i = 0; i < 1000; i++) {"
8021 " x += i * 100;"
8022 " y += i * 100;"
8023 " }"
8024 " if (call) g();"
8025 "}"
8026 "for (var i = 0; i < 17; i++) wrapper(false);"
8027 "var thrown = 0;"
8028 "try { wrapper(true); } catch (e) { thrown = 1; };"
8029 "thrown";
8030
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008031 {
8032 LocalContext env(NULL, instance_template);
8033 // Hold on to the global object so it can be used again in another
8034 // environment initialization.
8035 global_object = env->Global();
8036
8037 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8038 CHECK_EQ(42, value->Int32Value());
8039 value = Script::Compile(v8_str("f()"))->Run();
8040 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008041 value = Script::Compile(v8_str(script))->Run();
8042 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008043 }
8044
8045 {
8046 // Create new environment reusing the global object.
8047 LocalContext env(NULL, instance_template, global_object);
8048 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8049 CHECK_EQ(42, value->Int32Value());
8050 value = Script::Compile(v8_str("f()"))->Run();
8051 CHECK_EQ(12, value->Int32Value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008052 value = Script::Compile(v8_str(script))->Run();
8053 CHECK_EQ(1, value->Int32Value());
8054 }
8055}
8056
8057
8058THREADED_TEST(CallKnownGlobalReceiver) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008059 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008060
8061 Local<Value> global_object;
8062
8063 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8064 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8065
8066 // The script to check that we leave global object not
8067 // global object proxy on stack when we deoptimize from inside
8068 // arguments evaluation.
8069 // To provoke error we need to both force deoptimization
8070 // from arguments evaluation and to force CallIC to take
8071 // CallIC_Miss code path that can't cope with global proxy.
8072 const char* script =
8073 "function bar(x, y) { try { } finally { } }"
8074 "function baz(x) { try { } finally { } }"
8075 "function bom(x) { try { } finally { } }"
8076 "function foo(x) { bar([x], bom(2)); }"
8077 "for (var i = 0; i < 10000; i++) foo(1);"
8078 "foo";
8079
8080 Local<Value> foo;
8081 {
8082 LocalContext env(NULL, instance_template);
8083 // Hold on to the global object so it can be used again in another
8084 // environment initialization.
8085 global_object = env->Global();
8086 foo = Script::Compile(v8_str(script))->Run();
8087 }
8088
8089 {
8090 // Create new environment reusing the global object.
8091 LocalContext env(NULL, instance_template, global_object);
8092 env->Global()->Set(v8_str("foo"), foo);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008093 Script::Compile(v8_str("foo()"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008094 }
8095}
8096
8097
8098static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
8099 ApiTestFuzzer::Fuzz();
8100 return v8_num(42);
8101}
8102
8103
8104static int shadow_y;
8105static int shadow_y_setter_call_count;
8106static int shadow_y_getter_call_count;
8107
8108
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008109static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008110 shadow_y_setter_call_count++;
8111 shadow_y = 42;
8112}
8113
8114
8115static v8::Handle<Value> ShadowYGetter(Local<String> name,
8116 const AccessorInfo& info) {
8117 ApiTestFuzzer::Fuzz();
8118 shadow_y_getter_call_count++;
8119 return v8_num(shadow_y);
8120}
8121
8122
8123static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
8124 const AccessorInfo& info) {
8125 return v8::Handle<Value>();
8126}
8127
8128
8129static v8::Handle<Value> ShadowNamedGet(Local<String> key,
8130 const AccessorInfo&) {
8131 return v8::Handle<Value>();
8132}
8133
8134
8135THREADED_TEST(ShadowObject) {
8136 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008137 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008138
8139 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
8140 LocalContext context(NULL, global_template);
8141
8142 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8143 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
8144 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
8145 Local<ObjectTemplate> proto = t->PrototypeTemplate();
8146 Local<ObjectTemplate> instance = t->InstanceTemplate();
8147
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008148 proto->Set(v8_str("f"),
mmassi@chromium.org49a44672012-12-04 13:52:03 +00008149 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008150 proto->Set(v8_str("x"), v8_num(12));
8151
8152 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
8153
8154 Local<Value> o = t->GetFunction()->NewInstance();
8155 context->Global()->Set(v8_str("__proto__"), o);
8156
8157 Local<Value> value =
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008158 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008159 CHECK(value->IsBoolean());
8160 CHECK(!value->BooleanValue());
8161
8162 value = Script::Compile(v8_str("x"))->Run();
8163 CHECK_EQ(12, value->Int32Value());
8164
8165 value = Script::Compile(v8_str("f()"))->Run();
8166 CHECK_EQ(42, value->Int32Value());
8167
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008168 Script::Compile(v8_str("y = 43"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008169 CHECK_EQ(1, shadow_y_setter_call_count);
8170 value = Script::Compile(v8_str("y"))->Run();
8171 CHECK_EQ(1, shadow_y_getter_call_count);
8172 CHECK_EQ(42, value->Int32Value());
8173}
8174
8175
8176THREADED_TEST(HiddenPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008177 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008178 v8::HandleScope handle_scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008179
8180 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8181 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8182 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8183 t1->SetHiddenPrototype(true);
8184 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8185 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8186 t2->SetHiddenPrototype(true);
8187 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8188 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8189 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8190
8191 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8192 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8193 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8194 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8195
8196 // Setting the prototype on an object skips hidden prototypes.
8197 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8198 o0->Set(v8_str("__proto__"), o1);
8199 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8200 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8201 o0->Set(v8_str("__proto__"), o2);
8202 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8203 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8204 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8205 o0->Set(v8_str("__proto__"), o3);
8206 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8207 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8208 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8209 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8210
8211 // Getting the prototype of o0 should get the first visible one
8212 // which is o3. Therefore, z should not be defined on the prototype
8213 // object.
8214 Local<Value> proto = o0->Get(v8_str("__proto__"));
8215 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008216 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008217}
8218
8219
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008220THREADED_TEST(HiddenPrototypeSet) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008221 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008222 v8::HandleScope handle_scope(context->GetIsolate());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008223
8224 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
8225 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
8226 ht->SetHiddenPrototype(true);
8227 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
8228 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8229
8230 Local<v8::Object> o = ot->GetFunction()->NewInstance();
8231 Local<v8::Object> h = ht->GetFunction()->NewInstance();
8232 Local<v8::Object> p = pt->GetFunction()->NewInstance();
8233 o->Set(v8_str("__proto__"), h);
8234 h->Set(v8_str("__proto__"), p);
8235
8236 // Setting a property that exists on the hidden prototype goes there.
8237 o->Set(v8_str("x"), v8_num(7));
8238 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
8239 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
8240 CHECK(p->Get(v8_str("x"))->IsUndefined());
8241
8242 // Setting a new property should not be forwarded to the hidden prototype.
8243 o->Set(v8_str("y"), v8_num(6));
8244 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
8245 CHECK(h->Get(v8_str("y"))->IsUndefined());
8246 CHECK(p->Get(v8_str("y"))->IsUndefined());
8247
8248 // Setting a property that only exists on a prototype of the hidden prototype
8249 // is treated normally again.
8250 p->Set(v8_str("z"), v8_num(8));
8251 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
8252 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
8253 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
8254 o->Set(v8_str("z"), v8_num(9));
8255 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
8256 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
8257 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
8258}
8259
8260
8261// Regression test for issue 2457.
8262THREADED_TEST(HiddenPrototypeIdentityHash) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008263 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008264 v8::HandleScope handle_scope(context->GetIsolate());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008265
8266 Handle<FunctionTemplate> t = FunctionTemplate::New();
8267 t->SetHiddenPrototype(true);
8268 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
8269 Handle<Object> p = t->GetFunction()->NewInstance();
8270 Handle<Object> o = Object::New();
8271 o->SetPrototype(p);
8272
8273 int hash = o->GetIdentityHash();
8274 USE(hash);
8275 o->Set(v8_str("foo"), v8_num(42));
8276 ASSERT_EQ(hash, o->GetIdentityHash());
8277}
8278
8279
ager@chromium.org5c838252010-02-19 08:53:10 +00008280THREADED_TEST(SetPrototype) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008281 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008282 v8::HandleScope handle_scope(context->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00008283
8284 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
8285 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
8286 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8287 t1->SetHiddenPrototype(true);
8288 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
8289 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8290 t2->SetHiddenPrototype(true);
8291 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
8292 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8293 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
8294
8295 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
8296 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8297 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8298 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8299
8300 // Setting the prototype on an object does not skip hidden prototypes.
8301 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8302 CHECK(o0->SetPrototype(o1));
8303 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8304 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8305 CHECK(o1->SetPrototype(o2));
8306 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8307 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8308 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8309 CHECK(o2->SetPrototype(o3));
8310 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
8311 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
8312 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
8313 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
8314
8315 // Getting the prototype of o0 should get the first visible one
8316 // which is o3. Therefore, z should not be defined on the prototype
8317 // object.
8318 Local<Value> proto = o0->Get(v8_str("__proto__"));
8319 CHECK(proto->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008320 CHECK_EQ(proto.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008321
8322 // However, Object::GetPrototype ignores hidden prototype.
8323 Local<Value> proto0 = o0->GetPrototype();
8324 CHECK(proto0->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008325 CHECK_EQ(proto0.As<v8::Object>(), o1);
ager@chromium.org5c838252010-02-19 08:53:10 +00008326
8327 Local<Value> proto1 = o1->GetPrototype();
8328 CHECK(proto1->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008329 CHECK_EQ(proto1.As<v8::Object>(), o2);
ager@chromium.org5c838252010-02-19 08:53:10 +00008330
8331 Local<Value> proto2 = o2->GetPrototype();
8332 CHECK(proto2->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008333 CHECK_EQ(proto2.As<v8::Object>(), o3);
ager@chromium.org5c838252010-02-19 08:53:10 +00008334}
8335
8336
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008337// Getting property names of an object with a prototype chain that
8338// triggers dictionary elements in GetLocalPropertyNames() shouldn't
8339// crash the runtime.
8340THREADED_TEST(Regress91517) {
8341 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008342 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008343 v8::HandleScope handle_scope(context->GetIsolate());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008344
8345 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
8346 t1->SetHiddenPrototype(true);
8347 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
8348 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
8349 t2->SetHiddenPrototype(true);
8350 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
8351 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
8352 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
8353 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
8354 t3->SetHiddenPrototype(true);
8355 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
8356 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
8357 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
8358
8359 // Force dictionary-based properties.
8360 i::ScopedVector<char> name_buf(1024);
8361 for (int i = 1; i <= 1000; i++) {
8362 i::OS::SNPrintF(name_buf, "sdf%d", i);
8363 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
8364 }
8365
8366 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
8367 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
8368 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
8369 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
8370
8371 // Create prototype chain of hidden prototypes.
8372 CHECK(o4->SetPrototype(o3));
8373 CHECK(o3->SetPrototype(o2));
8374 CHECK(o2->SetPrototype(o1));
8375
8376 // Call the runtime version of GetLocalPropertyNames() on the natively
8377 // created object through JavaScript.
8378 context->Global()->Set(v8_str("obj"), o4);
8379 CompileRun("var names = %GetLocalPropertyNames(obj);");
8380
8381 ExpectInt32("names.length", 1006);
8382 ExpectTrue("names.indexOf(\"baz\") >= 0");
8383 ExpectTrue("names.indexOf(\"boo\") >= 0");
8384 ExpectTrue("names.indexOf(\"foo\") >= 0");
8385 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
8386 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
8387 ExpectFalse("names[1005] == undefined");
8388}
8389
8390
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008391THREADED_TEST(FunctionReadOnlyPrototype) {
ager@chromium.org04921a82011-06-27 13:21:41 +00008392 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008393 v8::HandleScope handle_scope(context->GetIsolate());
ager@chromium.org04921a82011-06-27 13:21:41 +00008394
8395 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008396 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
8397 t1->ReadOnlyPrototype();
ager@chromium.org04921a82011-06-27 13:21:41 +00008398 context->Global()->Set(v8_str("func1"), t1->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008399 // Configured value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008400 CHECK(CompileRun(
8401 "(function() {"
8402 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008403 " return (descriptor['writable'] == false);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008404 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008405 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
8406 CHECK_EQ(42,
8407 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008408
8409 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008410 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
ager@chromium.org04921a82011-06-27 13:21:41 +00008411 context->Global()->Set(v8_str("func2"), t2->GetFunction());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008412 // Default value of ReadOnly flag.
ager@chromium.org04921a82011-06-27 13:21:41 +00008413 CHECK(CompileRun(
8414 "(function() {"
8415 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008416 " return (descriptor['writable'] == true);"
ager@chromium.org04921a82011-06-27 13:21:41 +00008417 "})()")->BooleanValue());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008418 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
ager@chromium.org04921a82011-06-27 13:21:41 +00008419}
8420
8421
ager@chromium.org5c838252010-02-19 08:53:10 +00008422THREADED_TEST(SetPrototypeThrows) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008423 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008424 v8::HandleScope handle_scope(context->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00008425
8426 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8427
8428 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
8429 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
8430
8431 CHECK(o0->SetPrototype(o1));
8432 // If setting the prototype leads to the cycle, SetPrototype should
8433 // return false and keep VM in sane state.
8434 v8::TryCatch try_catch;
8435 CHECK(!o1->SetPrototype(o0));
8436 CHECK(!try_catch.HasCaught());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 ASSERT(!i::Isolate::Current()->has_pending_exception());
ager@chromium.org5c838252010-02-19 08:53:10 +00008438
8439 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
8440}
8441
8442
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008443THREADED_TEST(GetterSetterExceptions) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008444 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008445 v8::HandleScope handle_scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008446 CompileRun(
8447 "function Foo() { };"
8448 "function Throw() { throw 5; };"
8449 "var x = { };"
8450 "x.__defineSetter__('set', Throw);"
8451 "x.__defineGetter__('get', Throw);");
8452 Local<v8::Object> x =
8453 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
8454 v8::TryCatch try_catch;
8455 x->Set(v8_str("set"), v8::Integer::New(8));
8456 x->Get(v8_str("get"));
8457 x->Set(v8_str("set"), v8::Integer::New(8));
8458 x->Get(v8_str("get"));
8459 x->Set(v8_str("set"), v8::Integer::New(8));
8460 x->Get(v8_str("get"));
8461 x->Set(v8_str("set"), v8::Integer::New(8));
8462 x->Get(v8_str("get"));
8463}
8464
8465
8466THREADED_TEST(Constructor) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008467 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008468 v8::HandleScope handle_scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008469 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8470 templ->SetClassName(v8_str("Fun"));
8471 Local<Function> cons = templ->GetFunction();
8472 context->Global()->Set(v8_str("Fun"), cons);
8473 Local<v8::Object> inst = cons->NewInstance();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008474 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008475 CHECK(obj->IsJSObject());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008476 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
8477 CHECK(value->BooleanValue());
8478}
8479
lrn@chromium.org1c092762011-05-09 09:42:16 +00008480
8481static Handle<Value> ConstructorCallback(const Arguments& args) {
8482 ApiTestFuzzer::Fuzz();
8483 Local<Object> This;
8484
8485 if (args.IsConstructCall()) {
8486 Local<Object> Holder = args.Holder();
8487 This = Object::New();
8488 Local<Value> proto = Holder->GetPrototype();
8489 if (proto->IsObject()) {
8490 This->SetPrototype(proto);
8491 }
8492 } else {
8493 This = args.This();
8494 }
8495
8496 This->Set(v8_str("a"), args[0]);
8497 return This;
8498}
8499
8500
8501static Handle<Value> FakeConstructorCallback(const Arguments& args) {
8502 ApiTestFuzzer::Fuzz();
8503 return args[0];
8504}
8505
8506
8507THREADED_TEST(ConstructorForObject) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00008508 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008509 v8::HandleScope handle_scope(context->GetIsolate());
lrn@chromium.org1c092762011-05-09 09:42:16 +00008510
8511 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8512 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
8513 Local<Object> instance = instance_template->NewInstance();
8514 context->Global()->Set(v8_str("obj"), instance);
8515 v8::TryCatch try_catch;
8516 Local<Value> value;
8517 CHECK(!try_catch.HasCaught());
8518
8519 // Call the Object's constructor with a 32-bit signed integer.
8520 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
8521 CHECK(!try_catch.HasCaught());
8522 CHECK(value->IsInt32());
8523 CHECK_EQ(28, value->Int32Value());
8524
8525 Local<Value> args1[] = { v8_num(28) };
8526 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
8527 CHECK(value_obj1->IsObject());
8528 Local<Object> object1 = Local<Object>::Cast(value_obj1);
8529 value = object1->Get(v8_str("a"));
8530 CHECK(value->IsInt32());
8531 CHECK(!try_catch.HasCaught());
8532 CHECK_EQ(28, value->Int32Value());
8533
8534 // Call the Object's constructor with a String.
8535 value = CompileRun(
8536 "(function() { var o = new obj('tipli'); return o.a; })()");
8537 CHECK(!try_catch.HasCaught());
8538 CHECK(value->IsString());
8539 String::AsciiValue string_value1(value->ToString());
8540 CHECK_EQ("tipli", *string_value1);
8541
8542 Local<Value> args2[] = { v8_str("tipli") };
8543 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
8544 CHECK(value_obj2->IsObject());
8545 Local<Object> object2 = Local<Object>::Cast(value_obj2);
8546 value = object2->Get(v8_str("a"));
8547 CHECK(!try_catch.HasCaught());
8548 CHECK(value->IsString());
8549 String::AsciiValue string_value2(value->ToString());
8550 CHECK_EQ("tipli", *string_value2);
8551
8552 // Call the Object's constructor with a Boolean.
8553 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
8554 CHECK(!try_catch.HasCaught());
8555 CHECK(value->IsBoolean());
8556 CHECK_EQ(true, value->BooleanValue());
8557
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008558 Handle<Value> args3[] = { v8::True() };
lrn@chromium.org1c092762011-05-09 09:42:16 +00008559 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
8560 CHECK(value_obj3->IsObject());
8561 Local<Object> object3 = Local<Object>::Cast(value_obj3);
8562 value = object3->Get(v8_str("a"));
8563 CHECK(!try_catch.HasCaught());
8564 CHECK(value->IsBoolean());
8565 CHECK_EQ(true, value->BooleanValue());
8566
8567 // Call the Object's constructor with undefined.
8568 Handle<Value> args4[] = { v8::Undefined() };
8569 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
8570 CHECK(value_obj4->IsObject());
8571 Local<Object> object4 = Local<Object>::Cast(value_obj4);
8572 value = object4->Get(v8_str("a"));
8573 CHECK(!try_catch.HasCaught());
8574 CHECK(value->IsUndefined());
8575
8576 // Call the Object's constructor with null.
8577 Handle<Value> args5[] = { v8::Null() };
8578 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
8579 CHECK(value_obj5->IsObject());
8580 Local<Object> object5 = Local<Object>::Cast(value_obj5);
8581 value = object5->Get(v8_str("a"));
8582 CHECK(!try_catch.HasCaught());
8583 CHECK(value->IsNull());
8584 }
8585
8586 // Check exception handling when there is no constructor set for the Object.
8587 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8588 Local<Object> instance = instance_template->NewInstance();
8589 context->Global()->Set(v8_str("obj2"), instance);
8590 v8::TryCatch try_catch;
8591 Local<Value> value;
8592 CHECK(!try_catch.HasCaught());
8593
8594 value = CompileRun("new obj2(28)");
8595 CHECK(try_catch.HasCaught());
8596 String::AsciiValue exception_value1(try_catch.Exception());
8597 CHECK_EQ("TypeError: object is not a function", *exception_value1);
8598 try_catch.Reset();
8599
8600 Local<Value> args[] = { v8_num(29) };
8601 value = instance->CallAsConstructor(1, args);
8602 CHECK(try_catch.HasCaught());
8603 String::AsciiValue exception_value2(try_catch.Exception());
8604 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
8605 try_catch.Reset();
8606 }
8607
8608 // Check the case when constructor throws exception.
8609 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8610 instance_template->SetCallAsFunctionHandler(ThrowValue);
8611 Local<Object> instance = instance_template->NewInstance();
8612 context->Global()->Set(v8_str("obj3"), instance);
8613 v8::TryCatch try_catch;
8614 Local<Value> value;
8615 CHECK(!try_catch.HasCaught());
8616
8617 value = CompileRun("new obj3(22)");
8618 CHECK(try_catch.HasCaught());
8619 String::AsciiValue exception_value1(try_catch.Exception());
8620 CHECK_EQ("22", *exception_value1);
8621 try_catch.Reset();
8622
8623 Local<Value> args[] = { v8_num(23) };
8624 value = instance->CallAsConstructor(1, args);
8625 CHECK(try_catch.HasCaught());
8626 String::AsciiValue exception_value2(try_catch.Exception());
8627 CHECK_EQ("23", *exception_value2);
8628 try_catch.Reset();
8629 }
8630
8631 // Check whether constructor returns with an object or non-object.
8632 { Local<FunctionTemplate> function_template =
8633 FunctionTemplate::New(FakeConstructorCallback);
8634 Local<Function> function = function_template->GetFunction();
8635 Local<Object> instance1 = function;
8636 context->Global()->Set(v8_str("obj4"), instance1);
8637 v8::TryCatch try_catch;
8638 Local<Value> value;
8639 CHECK(!try_catch.HasCaught());
8640
8641 CHECK(instance1->IsObject());
8642 CHECK(instance1->IsFunction());
8643
8644 value = CompileRun("new obj4(28)");
8645 CHECK(!try_catch.HasCaught());
8646 CHECK(value->IsObject());
8647
8648 Local<Value> args1[] = { v8_num(28) };
8649 value = instance1->CallAsConstructor(1, args1);
8650 CHECK(!try_catch.HasCaught());
8651 CHECK(value->IsObject());
8652
8653 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8654 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
8655 Local<Object> instance2 = instance_template->NewInstance();
8656 context->Global()->Set(v8_str("obj5"), instance2);
8657 CHECK(!try_catch.HasCaught());
8658
8659 CHECK(instance2->IsObject());
8660 CHECK(!instance2->IsFunction());
8661
8662 value = CompileRun("new obj5(28)");
8663 CHECK(!try_catch.HasCaught());
8664 CHECK(!value->IsObject());
8665
8666 Local<Value> args2[] = { v8_num(28) };
8667 value = instance2->CallAsConstructor(1, args2);
8668 CHECK(!try_catch.HasCaught());
8669 CHECK(!value->IsObject());
8670 }
8671}
8672
8673
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008674THREADED_TEST(FunctionDescriptorException) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008675 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008676 v8::HandleScope handle_scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008677 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
8678 templ->SetClassName(v8_str("Fun"));
8679 Local<Function> cons = templ->GetFunction();
8680 context->Global()->Set(v8_str("Fun"), cons);
8681 Local<Value> value = CompileRun(
8682 "function test() {"
8683 " try {"
8684 " (new Fun()).blah()"
8685 " } catch (e) {"
8686 " var str = String(e);"
8687 " if (str.indexOf('TypeError') == -1) return 1;"
8688 " if (str.indexOf('[object Fun]') != -1) return 2;"
whesse@chromium.org7a392b32011-01-31 11:30:36 +00008689 " if (str.indexOf('#<Fun>') == -1) return 3;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008690 " return 0;"
8691 " }"
8692 " return 4;"
8693 "}"
8694 "test();");
8695 CHECK_EQ(0, value->Int32Value());
8696}
8697
8698
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008699THREADED_TEST(EvalAliasedDynamic) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008700 LocalContext current;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008701 v8::HandleScope scope(current->GetIsolate());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008702
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008703 // Tests where aliased eval can only be resolved dynamically.
8704 Local<Script> script =
8705 Script::Compile(v8_str("function f(x) { "
8706 " var foo = 2;"
8707 " with (x) { return eval('foo'); }"
8708 "}"
8709 "foo = 0;"
8710 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00008711 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008712 "var x = new Object();"
8713 "x.eval = function(x) { return 1; };"
8714 "result3 = f(x);"));
8715 script->Run();
8716 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
8717 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
8718 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
8719
8720 v8::TryCatch try_catch;
8721 script =
8722 Script::Compile(v8_str("function f(x) { "
8723 " var bar = 2;"
8724 " with (x) { return eval('bar'); }"
8725 "}"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008726 "result4 = f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008727 script->Run();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008728 CHECK(!try_catch.HasCaught());
8729 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
8730
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008731 try_catch.Reset();
8732}
8733
8734
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008735THREADED_TEST(CrossEval) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008736 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008737 LocalContext other;
8738 LocalContext current;
8739
8740 Local<String> token = v8_str("<security token>");
8741 other->SetSecurityToken(token);
8742 current->SetSecurityToken(token);
8743
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008744 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008745 current->Global()->Set(v8_str("other"), other->Global());
8746
8747 // Check that new variables are introduced in other context.
8748 Local<Script> script =
8749 Script::Compile(v8_str("other.eval('var foo = 1234')"));
8750 script->Run();
8751 Local<Value> foo = other->Global()->Get(v8_str("foo"));
8752 CHECK_EQ(1234, foo->Int32Value());
8753 CHECK(!current->Global()->Has(v8_str("foo")));
8754
8755 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008756 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008757 script =
8758 Script::Compile(v8_str("other.eval('na = 1234')"));
8759 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008760 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
8761 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008762
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008763 // Check that global variables in current context are not visible in other
8764 // context.
8765 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008766 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008767 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008768 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008769 CHECK(try_catch.HasCaught());
8770 try_catch.Reset();
8771
8772 // Check that local variables in current context are not visible in other
8773 // context.
8774 script =
8775 Script::Compile(v8_str("(function() { "
8776 " var baz = 87;"
8777 " return other.eval('baz');"
8778 "})();"));
8779 result = script->Run();
8780 CHECK(try_catch.HasCaught());
8781 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008782
8783 // Check that global variables in the other environment are visible
8784 // when evaluting code.
8785 other->Global()->Set(v8_str("bis"), v8_num(1234));
8786 script = Script::Compile(v8_str("other.eval('bis')"));
8787 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008788 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008789
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008790 // Check that the 'this' pointer points to the global object evaluating
8791 // code.
8792 other->Global()->Set(v8_str("t"), other->Global());
8793 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008794 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008795 CHECK(result->IsTrue());
8796 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008797
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008798 // Check that variables introduced in with-statement are not visible in
8799 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008800 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008801 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008802 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008803 CHECK(try_catch.HasCaught());
8804 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008805
8806 // Check that you cannot use 'eval.call' with another object than the
8807 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008808 script =
8809 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
8810 result = script->Run();
8811 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008812}
8813
8814
ager@chromium.orge2902be2009-06-08 12:21:35 +00008815// Test that calling eval in a context which has been detached from
8816// its global throws an exception. This behavior is consistent with
8817// other JavaScript implementations.
8818THREADED_TEST(EvalInDetachedGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008819 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +00008820
8821 v8::Persistent<Context> context0 = Context::New();
8822 v8::Persistent<Context> context1 = Context::New();
8823
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008824 // Set up function in context0 that uses eval from context0.
ager@chromium.orge2902be2009-06-08 12:21:35 +00008825 context0->Enter();
8826 v8::Handle<v8::Value> fun =
8827 CompileRun("var x = 42;"
8828 "(function() {"
8829 " var e = eval;"
8830 " return function(s) { return e(s); }"
8831 "})()");
8832 context0->Exit();
8833
8834 // Put the function into context1 and call it before and after
8835 // detaching the global. Before detaching, the call succeeds and
8836 // after detaching and exception is thrown.
8837 context1->Enter();
8838 context1->Global()->Set(v8_str("fun"), fun);
8839 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
8840 CHECK_EQ(42, x_value->Int32Value());
8841 context0->DetachGlobal();
8842 v8::TryCatch catcher;
8843 x_value = CompileRun("fun('x')");
8844 CHECK(x_value.IsEmpty());
8845 CHECK(catcher.HasCaught());
8846 context1->Exit();
8847
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00008848 context1.Dispose(context1->GetIsolate());
8849 context0.Dispose(context0->GetIsolate());
ager@chromium.orge2902be2009-06-08 12:21:35 +00008850}
8851
8852
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008853THREADED_TEST(CrossLazyLoad) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008854 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008855 LocalContext other;
8856 LocalContext current;
8857
8858 Local<String> token = v8_str("<security token>");
8859 other->SetSecurityToken(token);
8860 current->SetSecurityToken(token);
8861
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008862 // Set up reference from current to other.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008863 current->Global()->Set(v8_str("other"), other->Global());
8864
8865 // Trigger lazy loading in other context.
8866 Local<Script> script =
8867 Script::Compile(v8_str("other.eval('new Date(42)')"));
8868 Local<Value> value = script->Run();
8869 CHECK_EQ(42.0, value->NumberValue());
8870}
8871
8872
8873static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
8874 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008875 if (args.IsConstructCall()) {
8876 if (args[0]->IsInt32()) {
8877 return v8_num(-args[0]->Int32Value());
8878 }
8879 }
8880
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008881 return args[0];
8882}
8883
8884
8885// Test that a call handler can be set for objects which will allow
8886// non-function objects created through the API to be called as
8887// functions.
8888THREADED_TEST(CallAsFunction) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008889 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008890 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008891
lrn@chromium.org1c092762011-05-09 09:42:16 +00008892 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8893 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8894 instance_template->SetCallAsFunctionHandler(call_as_function);
8895 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8896 context->Global()->Set(v8_str("obj"), instance);
8897 v8::TryCatch try_catch;
8898 Local<Value> value;
8899 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008900
lrn@chromium.org1c092762011-05-09 09:42:16 +00008901 value = CompileRun("obj(42)");
8902 CHECK(!try_catch.HasCaught());
8903 CHECK_EQ(42, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008904
lrn@chromium.org1c092762011-05-09 09:42:16 +00008905 value = CompileRun("(function(o){return o(49)})(obj)");
8906 CHECK(!try_catch.HasCaught());
8907 CHECK_EQ(49, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008908
lrn@chromium.org1c092762011-05-09 09:42:16 +00008909 // test special case of call as function
8910 value = CompileRun("[obj]['0'](45)");
8911 CHECK(!try_catch.HasCaught());
8912 CHECK_EQ(45, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008913
lrn@chromium.org1c092762011-05-09 09:42:16 +00008914 value = CompileRun("obj.call = Function.prototype.call;"
8915 "obj.call(null, 87)");
8916 CHECK(!try_catch.HasCaught());
8917 CHECK_EQ(87, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008918
lrn@chromium.org1c092762011-05-09 09:42:16 +00008919 // Regression tests for bug #1116356: Calling call through call/apply
8920 // must work for non-function receivers.
8921 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
8922 value = CompileRun(apply_99);
8923 CHECK(!try_catch.HasCaught());
8924 CHECK_EQ(99, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008925
lrn@chromium.org1c092762011-05-09 09:42:16 +00008926 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
8927 value = CompileRun(call_17);
8928 CHECK(!try_catch.HasCaught());
8929 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00008930
lrn@chromium.org1c092762011-05-09 09:42:16 +00008931 // Check that the call-as-function handler can be called through
8932 // new.
8933 value = CompileRun("new obj(43)");
8934 CHECK(!try_catch.HasCaught());
8935 CHECK_EQ(-43, value->Int32Value());
8936
8937 // Check that the call-as-function handler can be called through
8938 // the API.
8939 v8::Handle<Value> args[] = { v8_num(28) };
8940 value = instance->CallAsFunction(instance, 1, args);
8941 CHECK(!try_catch.HasCaught());
8942 CHECK_EQ(28, value->Int32Value());
8943 }
8944
8945 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008946 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008947 USE(instance_template);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008948 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8949 context->Global()->Set(v8_str("obj2"), instance);
8950 v8::TryCatch try_catch;
8951 Local<Value> value;
8952 CHECK(!try_catch.HasCaught());
8953
8954 // Call an object without call-as-function handler through the JS
8955 value = CompileRun("obj2(28)");
8956 CHECK(value.IsEmpty());
8957 CHECK(try_catch.HasCaught());
8958 String::AsciiValue exception_value1(try_catch.Exception());
8959 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8960 *exception_value1);
8961 try_catch.Reset();
8962
8963 // Call an object without call-as-function handler through the API
8964 value = CompileRun("obj2(28)");
8965 v8::Handle<Value> args[] = { v8_num(28) };
8966 value = instance->CallAsFunction(instance, 1, args);
8967 CHECK(value.IsEmpty());
8968 CHECK(try_catch.HasCaught());
8969 String::AsciiValue exception_value2(try_catch.Exception());
8970 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8971 try_catch.Reset();
8972 }
8973
8974 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8975 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8976 instance_template->SetCallAsFunctionHandler(ThrowValue);
8977 Local<v8::Object> instance = t->GetFunction()->NewInstance();
8978 context->Global()->Set(v8_str("obj3"), instance);
8979 v8::TryCatch try_catch;
8980 Local<Value> value;
8981 CHECK(!try_catch.HasCaught());
8982
8983 // Catch the exception which is thrown by call-as-function handler
8984 value = CompileRun("obj3(22)");
8985 CHECK(try_catch.HasCaught());
8986 String::AsciiValue exception_value1(try_catch.Exception());
8987 CHECK_EQ("22", *exception_value1);
8988 try_catch.Reset();
8989
8990 v8::Handle<Value> args[] = { v8_num(23) };
8991 value = instance->CallAsFunction(instance, 1, args);
8992 CHECK(try_catch.HasCaught());
8993 String::AsciiValue exception_value2(try_catch.Exception());
8994 CHECK_EQ("23", *exception_value2);
8995 try_catch.Reset();
8996 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008997}
8998
8999
karlklose@chromium.org83a47282011-05-11 11:54:09 +00009000// Check whether a non-function object is callable.
9001THREADED_TEST(CallableObject) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00009002 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009003 v8::HandleScope scope(context->GetIsolate());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00009004
9005 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9006 instance_template->SetCallAsFunctionHandler(call_as_function);
9007 Local<Object> instance = instance_template->NewInstance();
9008 v8::TryCatch try_catch;
9009
9010 CHECK(instance->IsCallable());
9011 CHECK(!try_catch.HasCaught());
9012 }
9013
9014 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9015 Local<Object> instance = instance_template->NewInstance();
9016 v8::TryCatch try_catch;
9017
9018 CHECK(!instance->IsCallable());
9019 CHECK(!try_catch.HasCaught());
9020 }
9021
9022 { Local<FunctionTemplate> function_template =
9023 FunctionTemplate::New(call_as_function);
9024 Local<Function> function = function_template->GetFunction();
9025 Local<Object> instance = function;
9026 v8::TryCatch try_catch;
9027
9028 CHECK(instance->IsCallable());
9029 CHECK(!try_catch.HasCaught());
9030 }
9031
9032 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
9033 Local<Function> function = function_template->GetFunction();
9034 Local<Object> instance = function;
9035 v8::TryCatch try_catch;
9036
9037 CHECK(instance->IsCallable());
9038 CHECK(!try_catch.HasCaught());
9039 }
9040}
9041
9042
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009043static int CountHandles() {
9044 return v8::HandleScope::NumberOfHandles();
9045}
9046
9047
9048static int Recurse(int depth, int iterations) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009049 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009050 if (depth == 0) return CountHandles();
9051 for (int i = 0; i < iterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009052 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009053 }
9054 return Recurse(depth - 1, iterations);
9055}
9056
9057
9058THREADED_TEST(HandleIteration) {
9059 static const int kIterations = 500;
9060 static const int kNesting = 200;
9061 CHECK_EQ(0, CountHandles());
9062 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009063 v8::HandleScope scope1(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009064 CHECK_EQ(0, CountHandles());
9065 for (int i = 0; i < kIterations; i++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009066 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009067 CHECK_EQ(i + 1, CountHandles());
9068 }
9069
9070 CHECK_EQ(kIterations, CountHandles());
9071 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009072 v8::HandleScope scope2(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009073 for (int j = 0; j < kIterations; j++) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009074 Local<v8::Number> n(v8::Integer::New(42));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009075 CHECK_EQ(j + 1 + kIterations, CountHandles());
9076 }
9077 }
9078 CHECK_EQ(kIterations, CountHandles());
9079 }
9080 CHECK_EQ(0, CountHandles());
9081 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
9082}
9083
9084
9085static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
9086 Local<String> name,
9087 const AccessorInfo& info) {
9088 ApiTestFuzzer::Fuzz();
9089 return v8::Handle<Value>();
9090}
9091
9092
9093THREADED_TEST(InterceptorHasOwnProperty) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009094 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009095 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009096 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9097 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
9098 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
9099 Local<Function> function = fun_templ->GetFunction();
9100 context->Global()->Set(v8_str("constructor"), function);
9101 v8::Handle<Value> value = CompileRun(
9102 "var o = new constructor();"
9103 "o.hasOwnProperty('ostehaps');");
9104 CHECK_EQ(false, value->BooleanValue());
9105 value = CompileRun(
9106 "o.ostehaps = 42;"
9107 "o.hasOwnProperty('ostehaps');");
9108 CHECK_EQ(true, value->BooleanValue());
9109 value = CompileRun(
9110 "var p = new constructor();"
9111 "p.hasOwnProperty('ostehaps');");
9112 CHECK_EQ(false, value->BooleanValue());
9113}
9114
9115
ager@chromium.org9085a012009-05-11 19:22:57 +00009116static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
9117 Local<String> name,
9118 const AccessorInfo& info) {
9119 ApiTestFuzzer::Fuzz();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009120 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org9085a012009-05-11 19:22:57 +00009121 return v8::Handle<Value>();
9122}
9123
9124
9125THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
ager@chromium.org9085a012009-05-11 19:22:57 +00009126 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009127 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org9085a012009-05-11 19:22:57 +00009128 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9129 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
9130 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
9131 Local<Function> function = fun_templ->GetFunction();
9132 context->Global()->Set(v8_str("constructor"), function);
9133 // Let's first make some stuff so we can be sure to get a good GC.
9134 CompileRun(
9135 "function makestr(size) {"
9136 " switch (size) {"
9137 " case 1: return 'f';"
9138 " case 2: return 'fo';"
9139 " case 3: return 'foo';"
9140 " }"
9141 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
9142 "}"
9143 "var x = makestr(12345);"
9144 "x = makestr(31415);"
9145 "x = makestr(23456);");
9146 v8::Handle<Value> value = CompileRun(
9147 "var o = new constructor();"
9148 "o.__proto__ = new String(x);"
9149 "o.hasOwnProperty('ostehaps');");
9150 CHECK_EQ(false, value->BooleanValue());
9151}
9152
9153
ager@chromium.orge2902be2009-06-08 12:21:35 +00009154typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
9155 const AccessorInfo& info);
9156
9157
9158static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
9159 const char* source,
9160 int expected) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009161 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +00009162 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009163 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
ager@chromium.orge2902be2009-06-08 12:21:35 +00009164 LocalContext context;
9165 context->Global()->Set(v8_str("o"), templ->NewInstance());
9166 v8::Handle<Value> value = CompileRun(source);
9167 CHECK_EQ(expected, value->Int32Value());
9168}
9169
9170
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009171static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
9172 const AccessorInfo& info) {
9173 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009174 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9175 CHECK_EQ(isolate, info.GetIsolate());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009176 CHECK_EQ(v8_str("data"), info.Data());
9177 CHECK_EQ(v8_str("x"), name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009178 return v8::Integer::New(42);
9179}
9180
9181
9182// This test should hit the load IC for the interceptor case.
9183THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00009184 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009185 "var result = 0;"
9186 "for (var i = 0; i < 1000; i++) {"
9187 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00009188 "}",
9189 42);
9190}
9191
9192
9193// Below go several tests which verify that JITing for various
9194// configurations of interceptor and explicit fields works fine
9195// (those cases are special cased to get better performance).
9196
9197static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
9198 const AccessorInfo& info) {
9199 ApiTestFuzzer::Fuzz();
9200 return v8_str("x")->Equals(name)
9201 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
9202}
9203
9204
9205THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
9206 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9207 "var result = 0;"
9208 "o.y = 239;"
9209 "for (var i = 0; i < 1000; i++) {"
9210 " result = o.y;"
9211 "}",
9212 239);
9213}
9214
9215
9216THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
9217 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9218 "var result = 0;"
9219 "o.__proto__ = { 'y': 239 };"
9220 "for (var i = 0; i < 1000; i++) {"
9221 " result = o.y + o.x;"
9222 "}",
9223 239 + 42);
9224}
9225
9226
9227THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
9228 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9229 "var result = 0;"
9230 "o.__proto__.y = 239;"
9231 "for (var i = 0; i < 1000; i++) {"
9232 " result = o.y + o.x;"
9233 "}",
9234 239 + 42);
9235}
9236
9237
9238THREADED_TEST(InterceptorLoadICUndefined) {
9239 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9240 "var result = 0;"
9241 "for (var i = 0; i < 1000; i++) {"
9242 " result = (o.y == undefined) ? 239 : 42;"
9243 "}",
9244 239);
9245}
9246
9247
9248THREADED_TEST(InterceptorLoadICWithOverride) {
9249 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9250 "fst = new Object(); fst.__proto__ = o;"
9251 "snd = new Object(); snd.__proto__ = fst;"
9252 "var result1 = 0;"
9253 "for (var i = 0; i < 1000; i++) {"
9254 " result1 = snd.x;"
9255 "}"
9256 "fst.x = 239;"
9257 "var result = 0;"
9258 "for (var i = 0; i < 1000; i++) {"
9259 " result = snd.x;"
9260 "}"
9261 "result + result1",
9262 239 + 42);
9263}
9264
9265
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009266// Test the case when we stored field into
9267// a stub, but interceptor produced value on its own.
9268THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
9269 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9270 "proto = new Object();"
9271 "o.__proto__ = proto;"
9272 "proto.x = 239;"
9273 "for (var i = 0; i < 1000; i++) {"
9274 " o.x;"
9275 // Now it should be ICed and keep a reference to x defined on proto
9276 "}"
9277 "var result = 0;"
9278 "for (var i = 0; i < 1000; i++) {"
9279 " result += o.x;"
9280 "}"
9281 "result;",
9282 42 * 1000);
9283}
9284
9285
9286// Test the case when we stored field into
9287// a stub, but it got invalidated later on.
9288THREADED_TEST(InterceptorLoadICInvalidatedField) {
9289 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9290 "proto1 = new Object();"
9291 "proto2 = new Object();"
9292 "o.__proto__ = proto1;"
9293 "proto1.__proto__ = proto2;"
9294 "proto2.y = 239;"
9295 "for (var i = 0; i < 1000; i++) {"
9296 " o.y;"
9297 // Now it should be ICed and keep a reference to y defined on proto2
9298 "}"
9299 "proto1.y = 42;"
9300 "var result = 0;"
9301 "for (var i = 0; i < 1000; i++) {"
9302 " result += o.y;"
9303 "}"
9304 "result;",
9305 42 * 1000);
9306}
9307
9308
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00009309static int interceptor_load_not_handled_calls = 0;
9310static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
9311 const AccessorInfo& info) {
9312 ++interceptor_load_not_handled_calls;
9313 return v8::Handle<v8::Value>();
9314}
9315
9316
9317// Test how post-interceptor lookups are done in the non-cacheable
9318// case: the interceptor should not be invoked during this lookup.
9319THREADED_TEST(InterceptorLoadICPostInterceptor) {
9320 interceptor_load_not_handled_calls = 0;
9321 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
9322 "receiver = new Object();"
9323 "receiver.__proto__ = o;"
9324 "proto = new Object();"
9325 "/* Make proto a slow-case object. */"
9326 "for (var i = 0; i < 1000; i++) {"
9327 " proto[\"xxxxxxxx\" + i] = [];"
9328 "}"
9329 "proto.x = 17;"
9330 "o.__proto__ = proto;"
9331 "var result = 0;"
9332 "for (var i = 0; i < 1000; i++) {"
9333 " result += receiver.x;"
9334 "}"
9335 "result;",
9336 17 * 1000);
9337 CHECK_EQ(1000, interceptor_load_not_handled_calls);
9338}
9339
9340
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009341// Test the case when we stored field into
9342// a stub, but it got invalidated later on due to override on
9343// global object which is between interceptor and fields' holders.
9344THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
9345 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
9346 "o.__proto__ = this;" // set a global to be a proto of o.
9347 "this.__proto__.y = 239;"
9348 "for (var i = 0; i < 10; i++) {"
9349 " if (o.y != 239) throw 'oops: ' + o.y;"
9350 // Now it should be ICed and keep a reference to y defined on field_holder.
9351 "}"
9352 "this.y = 42;" // Assign on a global.
9353 "var result = 0;"
9354 "for (var i = 0; i < 10; i++) {"
9355 " result += o.y;"
9356 "}"
9357 "result;",
9358 42 * 10);
9359}
9360
9361
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009362static void SetOnThis(Local<String> name,
9363 Local<Value> value,
9364 const AccessorInfo& info) {
9365 info.This()->ForceSet(name, value);
9366}
9367
9368
9369THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009370 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009371 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9372 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9373 templ->SetAccessor(v8_str("y"), Return239);
9374 LocalContext context;
9375 context->Global()->Set(v8_str("o"), templ->NewInstance());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009376
9377 // Check the case when receiver and interceptor's holder
9378 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009379 v8::Handle<Value> value = CompileRun(
9380 "var result = 0;"
9381 "for (var i = 0; i < 7; i++) {"
9382 " result = o.y;"
9383 "}");
9384 CHECK_EQ(239, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009385
9386 // Check the case when interceptor's holder is in proto chain
9387 // of receiver.
9388 value = CompileRun(
9389 "r = { __proto__: o };"
9390 "var result = 0;"
9391 "for (var i = 0; i < 7; i++) {"
9392 " result = r.y;"
9393 "}");
9394 CHECK_EQ(239, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009395}
9396
9397
9398THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009399 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009400 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9401 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9402 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9403 templ_p->SetAccessor(v8_str("y"), Return239);
9404
9405 LocalContext context;
9406 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9407 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9408
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009409 // Check the case when receiver and interceptor's holder
9410 // are the same objects.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009411 v8::Handle<Value> value = CompileRun(
9412 "o.__proto__ = p;"
9413 "var result = 0;"
9414 "for (var i = 0; i < 7; i++) {"
9415 " result = o.x + o.y;"
9416 "}");
9417 CHECK_EQ(239 + 42, value->Int32Value());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009418
9419 // Check the case when interceptor's holder is in proto chain
9420 // of receiver.
9421 value = CompileRun(
9422 "r = { __proto__: o };"
9423 "var result = 0;"
9424 "for (var i = 0; i < 7; i++) {"
9425 " result = r.x + r.y;"
9426 "}");
9427 CHECK_EQ(239 + 42, value->Int32Value());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009428}
9429
9430
9431THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009432 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009433 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9434 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9435 templ->SetAccessor(v8_str("y"), Return239);
9436
9437 LocalContext context;
9438 context->Global()->Set(v8_str("o"), templ->NewInstance());
9439
9440 v8::Handle<Value> value = CompileRun(
9441 "fst = new Object(); fst.__proto__ = o;"
9442 "snd = new Object(); snd.__proto__ = fst;"
9443 "var result1 = 0;"
9444 "for (var i = 0; i < 7; i++) {"
9445 " result1 = snd.x;"
9446 "}"
9447 "fst.x = 239;"
9448 "var result = 0;"
9449 "for (var i = 0; i < 7; i++) {"
9450 " result = snd.x;"
9451 "}"
9452 "result + result1");
9453 CHECK_EQ(239 + 42, value->Int32Value());
9454}
9455
9456
9457// Test the case when we stored callback into
9458// a stub, but interceptor produced value on its own.
9459THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009460 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009461 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9462 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9463 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9464 templ_p->SetAccessor(v8_str("y"), Return239);
9465
9466 LocalContext context;
9467 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9468 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9469
9470 v8::Handle<Value> value = CompileRun(
9471 "o.__proto__ = p;"
9472 "for (var i = 0; i < 7; i++) {"
9473 " o.x;"
9474 // Now it should be ICed and keep a reference to x defined on p
9475 "}"
9476 "var result = 0;"
9477 "for (var i = 0; i < 7; i++) {"
9478 " result += o.x;"
9479 "}"
9480 "result");
9481 CHECK_EQ(42 * 7, value->Int32Value());
9482}
9483
9484
9485// Test the case when we stored callback into
9486// a stub, but it got invalidated later on.
9487THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009488 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009489 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9490 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9491 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9492 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9493
9494 LocalContext context;
9495 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9496 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9497
9498 v8::Handle<Value> value = CompileRun(
9499 "inbetween = new Object();"
9500 "o.__proto__ = inbetween;"
9501 "inbetween.__proto__ = p;"
9502 "for (var i = 0; i < 10; i++) {"
9503 " o.y;"
9504 // Now it should be ICed and keep a reference to y defined on p
9505 "}"
9506 "inbetween.y = 42;"
9507 "var result = 0;"
9508 "for (var i = 0; i < 10; i++) {"
9509 " result += o.y;"
9510 "}"
9511 "result");
9512 CHECK_EQ(42 * 10, value->Int32Value());
9513}
9514
9515
9516// Test the case when we stored callback into
9517// a stub, but it got invalidated later on due to override on
9518// global object which is between interceptor and callbacks' holders.
9519THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009520 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009521 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9522 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9523 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
9524 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
9525
9526 LocalContext context;
9527 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9528 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
9529
9530 v8::Handle<Value> value = CompileRun(
9531 "o.__proto__ = this;"
9532 "this.__proto__ = p;"
9533 "for (var i = 0; i < 10; i++) {"
9534 " if (o.y != 239) throw 'oops: ' + o.y;"
9535 // Now it should be ICed and keep a reference to y defined on p
9536 "}"
9537 "this.y = 42;"
9538 "var result = 0;"
9539 "for (var i = 0; i < 10; i++) {"
9540 " result += o.y;"
9541 "}"
9542 "result");
9543 CHECK_EQ(42 * 10, value->Int32Value());
9544}
9545
9546
ager@chromium.orge2902be2009-06-08 12:21:35 +00009547static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
9548 const AccessorInfo& info) {
9549 ApiTestFuzzer::Fuzz();
9550 CHECK(v8_str("x")->Equals(name));
9551 return v8::Integer::New(0);
9552}
9553
9554
9555THREADED_TEST(InterceptorReturningZero) {
9556 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
9557 "o.x == undefined ? 1 : 0",
9558 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009559}
9560
9561
9562static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009563 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009564 CHECK(v8_str("x")->Equals(key));
9565 CHECK_EQ(42, value->Int32Value());
9566 return value;
9567}
9568
9569
9570// This test should hit the store IC for the interceptor case.
9571THREADED_TEST(InterceptorStoreIC) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009572 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009573 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9574 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00009575 InterceptorStoreICSetter,
9576 0, 0, 0, v8_str("data"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009577 LocalContext context;
9578 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00009579 CompileRun(
9580 "for (var i = 0; i < 1000; i++) {"
9581 " o.x = 42;"
9582 "}");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009583}
9584
9585
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009586THREADED_TEST(InterceptorStoreICWithNoSetter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009587 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009588 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9589 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9590 LocalContext context;
9591 context->Global()->Set(v8_str("o"), templ->NewInstance());
9592 v8::Handle<Value> value = CompileRun(
9593 "for (var i = 0; i < 1000; i++) {"
9594 " o.y = 239;"
9595 "}"
9596 "42 + o.y");
9597 CHECK_EQ(239 + 42, value->Int32Value());
9598}
9599
9600
9601
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009602
9603v8::Handle<Value> call_ic_function;
9604v8::Handle<Value> call_ic_function2;
9605v8::Handle<Value> call_ic_function3;
9606
9607static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
9608 const AccessorInfo& info) {
9609 ApiTestFuzzer::Fuzz();
9610 CHECK(v8_str("x")->Equals(name));
9611 return call_ic_function;
9612}
9613
9614
9615// This test should hit the call IC for the interceptor case.
9616THREADED_TEST(InterceptorCallIC) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009617 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009618 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9619 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
9620 LocalContext context;
9621 context->Global()->Set(v8_str("o"), templ->NewInstance());
9622 call_ic_function =
9623 v8_compile("function f(x) { return x + 1; }; f")->Run();
9624 v8::Handle<Value> value = CompileRun(
9625 "var result = 0;"
9626 "for (var i = 0; i < 1000; i++) {"
9627 " result = o.x(41);"
9628 "}");
9629 CHECK_EQ(42, value->Int32Value());
9630}
9631
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009632
9633// This test checks that if interceptor doesn't provide
9634// a value, we can fetch regular value.
9635THREADED_TEST(InterceptorCallICSeesOthers) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009636 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009637 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9638 templ->SetNamedPropertyHandler(NoBlockGetterX);
9639 LocalContext context;
9640 context->Global()->Set(v8_str("o"), templ->NewInstance());
9641 v8::Handle<Value> value = CompileRun(
9642 "o.x = function f(x) { return x + 1; };"
9643 "var result = 0;"
9644 "for (var i = 0; i < 7; i++) {"
9645 " result = o.x(41);"
9646 "}");
9647 CHECK_EQ(42, value->Int32Value());
9648}
9649
9650
9651static v8::Handle<Value> call_ic_function4;
9652static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
9653 const AccessorInfo& info) {
9654 ApiTestFuzzer::Fuzz();
9655 CHECK(v8_str("x")->Equals(name));
9656 return call_ic_function4;
9657}
9658
9659
9660// This test checks that if interceptor provides a function,
9661// even if we cached shadowed variant, interceptor's function
9662// is invoked
9663THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009664 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009665 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9666 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
9667 LocalContext context;
9668 context->Global()->Set(v8_str("o"), templ->NewInstance());
9669 call_ic_function4 =
9670 v8_compile("function f(x) { return x - 1; }; f")->Run();
9671 v8::Handle<Value> value = CompileRun(
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00009672 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009673 "var result = 0;"
9674 "for (var i = 0; i < 1000; i++) {"
9675 " result = o.x(42);"
9676 "}");
9677 CHECK_EQ(41, value->Int32Value());
9678}
9679
9680
9681// Test the case when we stored cacheable lookup into
9682// a stub, but it got invalidated later on
9683THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009684 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009685 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9686 templ->SetNamedPropertyHandler(NoBlockGetterX);
9687 LocalContext context;
9688 context->Global()->Set(v8_str("o"), templ->NewInstance());
9689 v8::Handle<Value> value = CompileRun(
9690 "proto1 = new Object();"
9691 "proto2 = new Object();"
9692 "o.__proto__ = proto1;"
9693 "proto1.__proto__ = proto2;"
9694 "proto2.y = function(x) { return x + 1; };"
9695 // Invoke it many times to compile a stub
9696 "for (var i = 0; i < 7; i++) {"
9697 " o.y(42);"
9698 "}"
9699 "proto1.y = function(x) { return x - 1; };"
9700 "var result = 0;"
9701 "for (var i = 0; i < 7; i++) {"
9702 " result += o.y(42);"
9703 "}");
9704 CHECK_EQ(41 * 7, value->Int32Value());
9705}
9706
9707
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009708// This test checks that if interceptor doesn't provide a function,
9709// cached constant function is used
9710THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009711 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009712 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9713 templ->SetNamedPropertyHandler(NoBlockGetterX);
9714 LocalContext context;
9715 context->Global()->Set(v8_str("o"), templ->NewInstance());
9716 v8::Handle<Value> value = CompileRun(
9717 "function inc(x) { return x + 1; };"
9718 "inc(1);"
9719 "o.x = inc;"
9720 "var result = 0;"
9721 "for (var i = 0; i < 1000; i++) {"
9722 " result = o.x(42);"
9723 "}");
9724 CHECK_EQ(43, value->Int32Value());
9725}
9726
9727
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009728static v8::Handle<Value> call_ic_function5;
9729static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
9730 const AccessorInfo& info) {
9731 ApiTestFuzzer::Fuzz();
9732 if (v8_str("x")->Equals(name))
9733 return call_ic_function5;
9734 else
9735 return Local<Value>();
9736}
9737
9738
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009739// This test checks that if interceptor provides a function,
9740// even if we cached constant function, interceptor's function
9741// is invoked
9742THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009743 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009744 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9745 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
9746 LocalContext context;
9747 context->Global()->Set(v8_str("o"), templ->NewInstance());
9748 call_ic_function5 =
9749 v8_compile("function f(x) { return x - 1; }; f")->Run();
9750 v8::Handle<Value> value = CompileRun(
9751 "function inc(x) { return x + 1; };"
9752 "inc(1);"
9753 "o.x = inc;"
9754 "var result = 0;"
9755 "for (var i = 0; i < 1000; i++) {"
9756 " result = o.x(42);"
9757 "}");
9758 CHECK_EQ(41, value->Int32Value());
9759}
9760
9761
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009762static v8::Handle<Value> call_ic_function6;
9763static v8::Handle<Value> InterceptorCallICGetter6(Local<String> name,
9764 const AccessorInfo& info) {
9765 ApiTestFuzzer::Fuzz();
9766 if (v8_str("x")->Equals(name))
9767 return call_ic_function6;
9768 else
9769 return Local<Value>();
9770}
9771
9772
9773// Same test as above, except the code is wrapped in a function
9774// to test the optimized compiler.
9775THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
9776 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009777 v8::HandleScope scope(v8::Isolate::GetCurrent());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009778 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9779 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
9780 LocalContext context;
9781 context->Global()->Set(v8_str("o"), templ->NewInstance());
9782 call_ic_function6 =
9783 v8_compile("function f(x) { return x - 1; }; f")->Run();
9784 v8::Handle<Value> value = CompileRun(
9785 "function inc(x) { return x + 1; };"
9786 "inc(1);"
9787 "o.x = inc;"
9788 "function test() {"
9789 " var result = 0;"
9790 " for (var i = 0; i < 1000; i++) {"
9791 " result = o.x(42);"
9792 " }"
9793 " return result;"
9794 "};"
9795 "test();"
9796 "test();"
9797 "test();"
9798 "%OptimizeFunctionOnNextCall(test);"
9799 "test()");
9800 CHECK_EQ(41, value->Int32Value());
9801}
9802
9803
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009804// Test the case when we stored constant function into
9805// a stub, but it got invalidated later on
9806THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009807 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009808 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9809 templ->SetNamedPropertyHandler(NoBlockGetterX);
9810 LocalContext context;
9811 context->Global()->Set(v8_str("o"), templ->NewInstance());
9812 v8::Handle<Value> value = CompileRun(
9813 "function inc(x) { return x + 1; };"
9814 "inc(1);"
9815 "proto1 = new Object();"
9816 "proto2 = new Object();"
9817 "o.__proto__ = proto1;"
9818 "proto1.__proto__ = proto2;"
9819 "proto2.y = inc;"
9820 // Invoke it many times to compile a stub
9821 "for (var i = 0; i < 7; i++) {"
9822 " o.y(42);"
9823 "}"
9824 "proto1.y = function(x) { return x - 1; };"
9825 "var result = 0;"
9826 "for (var i = 0; i < 7; i++) {"
9827 " result += o.y(42);"
9828 "}");
9829 CHECK_EQ(41 * 7, value->Int32Value());
9830}
9831
9832
9833// Test the case when we stored constant function into
9834// a stub, but it got invalidated later on due to override on
9835// global object which is between interceptor and constant function' holders.
9836THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009837 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00009838 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9839 templ->SetNamedPropertyHandler(NoBlockGetterX);
9840 LocalContext context;
9841 context->Global()->Set(v8_str("o"), templ->NewInstance());
9842 v8::Handle<Value> value = CompileRun(
9843 "function inc(x) { return x + 1; };"
9844 "inc(1);"
9845 "o.__proto__ = this;"
9846 "this.__proto__.y = inc;"
9847 // Invoke it many times to compile a stub
9848 "for (var i = 0; i < 7; i++) {"
9849 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
9850 "}"
9851 "this.y = function(x) { return x - 1; };"
9852 "var result = 0;"
9853 "for (var i = 0; i < 7; i++) {"
9854 " result += o.y(42);"
9855 "}");
9856 CHECK_EQ(41 * 7, value->Int32Value());
9857}
9858
9859
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009860// Test the case when actual function to call sits on global object.
9861THREADED_TEST(InterceptorCallICCachedFromGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009862 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009863 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9864 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9865
9866 LocalContext context;
9867 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9868
9869 v8::Handle<Value> value = CompileRun(
9870 "try {"
9871 " o.__proto__ = this;"
9872 " for (var i = 0; i < 10; i++) {"
9873 " var v = o.parseFloat('239');"
9874 " if (v != 239) throw v;"
9875 // Now it should be ICed and keep a reference to parseFloat.
9876 " }"
9877 " var result = 0;"
9878 " for (var i = 0; i < 10; i++) {"
9879 " result += o.parseFloat('239');"
9880 " }"
9881 " result"
9882 "} catch(e) {"
9883 " e"
9884 "};");
9885 CHECK_EQ(239 * 10, value->Int32Value());
9886}
9887
ager@chromium.org5c838252010-02-19 08:53:10 +00009888static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
9889 const AccessorInfo& info) {
9890 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00009891 int* call_count =
9892 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
ager@chromium.org5c838252010-02-19 08:53:10 +00009893 ++(*call_count);
9894 if ((*call_count) % 20 == 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009895 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org5c838252010-02-19 08:53:10 +00009896 }
9897 return v8::Handle<Value>();
9898}
9899
9900static v8::Handle<Value> FastApiCallback_TrivialSignature(
9901 const v8::Arguments& args) {
9902 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009903 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9904 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009905 CHECK_EQ(args.This(), args.Holder());
9906 CHECK(args.Data()->Equals(v8_str("method_data")));
9907 return v8::Integer::New(args[0]->Int32Value() + 1);
9908}
9909
9910static v8::Handle<Value> FastApiCallback_SimpleSignature(
9911 const v8::Arguments& args) {
9912 ApiTestFuzzer::Fuzz();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00009913 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9914 CHECK_EQ(isolate, args.GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009915 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
9916 CHECK(args.Data()->Equals(v8_str("method_data")));
9917 // Note, we're using HasRealNamedProperty instead of Has to avoid
9918 // invoking the interceptor again.
9919 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
9920 return v8::Integer::New(args[0]->Int32Value() + 1);
9921}
9922
9923// Helper to maximize the odds of object moving.
9924static void GenerateSomeGarbage() {
9925 CompileRun(
9926 "var garbage;"
9927 "for (var i = 0; i < 1000; i++) {"
9928 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
9929 "}"
9930 "garbage = undefined;");
9931}
9932
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009933
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009934v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
9935 static int count = 0;
9936 if (count++ % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009937 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
9938 // This should move the stub
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009939 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
9940 }
9941 return v8::Handle<v8::Value>();
9942}
9943
9944
9945THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009946 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009947 v8::HandleScope scope(context->GetIsolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009948 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9949 nativeobject_templ->Set("callback",
9950 v8::FunctionTemplate::New(DirectApiCallback));
9951 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9952 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9953 // call the api function multiple times to ensure direct call stub creation.
9954 CompileRun(
9955 "function f() {"
9956 " for (var i = 1; i <= 30; i++) {"
9957 " nativeobject.callback();"
9958 " }"
9959 "}"
9960 "f();");
9961}
9962
9963
9964v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
9965 return v8::ThrowException(v8_str("g"));
9966}
9967
9968
9969THREADED_TEST(CallICFastApi_DirectCall_Throw) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009970 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009971 v8::HandleScope scope(context->GetIsolate());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009972 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
9973 nativeobject_templ->Set("callback",
9974 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
9975 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
9976 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
9977 // call the api function multiple times to ensure direct call stub creation.
9978 v8::Handle<Value> result = CompileRun(
9979 "var result = '';"
9980 "function f() {"
9981 " for (var i = 1; i <= 5; i++) {"
9982 " try { nativeobject.callback(); } catch (e) { result += e; }"
9983 " }"
9984 "}"
9985 "f(); result;");
9986 CHECK_EQ(v8_str("ggggg"), result);
9987}
9988
9989
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009990v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9991 const v8::AccessorInfo& info) {
9992 if (++p_getter_count % 3 == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00009993 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 GenerateSomeGarbage();
9995 }
9996 return v8::Handle<v8::Value>();
9997}
9998
9999
10000THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010002 v8::HandleScope scope(context->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10004 obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
10005 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10006 p_getter_count = 0;
10007 CompileRun(
10008 "function f() {"
10009 " for (var i = 0; i < 30; i++) o1.p1;"
10010 "}"
10011 "f();");
10012 CHECK_EQ(30, p_getter_count);
10013}
10014
10015
10016v8::Handle<v8::Value> ThrowingDirectGetterCallback(
10017 Local<String> name, const v8::AccessorInfo& info) {
10018 return v8::ThrowException(v8_str("g"));
10019}
10020
10021
10022THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010023 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010024 v8::HandleScope scope(context->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10026 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10027 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10028 v8::Handle<Value> result = CompileRun(
10029 "var result = '';"
10030 "for (var i = 0; i < 5; i++) {"
10031 " try { o1.p1; } catch (e) { result += e; }"
10032 "}"
10033 "result;");
10034 CHECK_EQ(v8_str("ggggg"), result);
10035}
10036
10037
ager@chromium.org5c838252010-02-19 08:53:10 +000010038THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10039 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010040 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010041 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10042 v8::Handle<v8::FunctionTemplate> method_templ =
10043 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10044 v8_str("method_data"),
10045 v8::Handle<v8::Signature>());
10046 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10047 proto_templ->Set(v8_str("method"), method_templ);
10048 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10049 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10050 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010051 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010052 LocalContext context;
10053 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10054 GenerateSomeGarbage();
10055 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010056 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010057 "var result = 0;"
10058 "for (var i = 0; i < 100; i++) {"
10059 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010060 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010061 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10062 CHECK_EQ(100, interceptor_call_count);
10063}
10064
10065THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10066 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010067 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010068 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10069 v8::Handle<v8::FunctionTemplate> method_templ =
10070 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10071 v8_str("method_data"),
10072 v8::Signature::New(fun_templ));
10073 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10074 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010075 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010076 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10077 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10078 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010079 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010080 LocalContext context;
10081 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10082 GenerateSomeGarbage();
10083 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010084 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010085 "o.foo = 17;"
10086 "var receiver = {};"
10087 "receiver.__proto__ = o;"
10088 "var result = 0;"
10089 "for (var i = 0; i < 100; i++) {"
10090 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010091 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010092 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10093 CHECK_EQ(100, interceptor_call_count);
10094}
10095
10096THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10097 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010098 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010099 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10100 v8::Handle<v8::FunctionTemplate> method_templ =
10101 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10102 v8_str("method_data"),
10103 v8::Signature::New(fun_templ));
10104 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10105 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010106 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010107 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10108 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10109 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010110 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010111 LocalContext context;
10112 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10113 GenerateSomeGarbage();
10114 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010115 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010116 "o.foo = 17;"
10117 "var receiver = {};"
10118 "receiver.__proto__ = o;"
10119 "var result = 0;"
10120 "var saved_result = 0;"
10121 "for (var i = 0; i < 100; i++) {"
10122 " result = receiver.method(41);"
10123 " if (i == 50) {"
10124 " saved_result = result;"
10125 " receiver = {method: function(x) { return x - 1 }};"
10126 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010127 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010128 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10129 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10130 CHECK_GE(interceptor_call_count, 50);
10131}
10132
10133THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10134 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010135 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010136 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10137 v8::Handle<v8::FunctionTemplate> method_templ =
10138 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10139 v8_str("method_data"),
10140 v8::Signature::New(fun_templ));
10141 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10142 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010143 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010144 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10145 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10146 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010147 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010148 LocalContext context;
10149 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10150 GenerateSomeGarbage();
10151 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010152 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010153 "o.foo = 17;"
10154 "var receiver = {};"
10155 "receiver.__proto__ = o;"
10156 "var result = 0;"
10157 "var saved_result = 0;"
10158 "for (var i = 0; i < 100; i++) {"
10159 " result = receiver.method(41);"
10160 " if (i == 50) {"
10161 " saved_result = result;"
10162 " o.method = function(x) { return x - 1 };"
10163 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010164 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010165 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10166 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10167 CHECK_GE(interceptor_call_count, 50);
10168}
10169
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010170THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10171 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010172 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010173 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10174 v8::Handle<v8::FunctionTemplate> method_templ =
10175 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10176 v8_str("method_data"),
10177 v8::Signature::New(fun_templ));
10178 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10179 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010180 fun_templ->SetHiddenPrototype(true);
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010181 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10182 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10183 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010184 v8::External::New(&interceptor_call_count));
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010185 LocalContext context;
10186 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10187 GenerateSomeGarbage();
10188 context->Global()->Set(v8_str("o"), fun->NewInstance());
10189 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010190 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010191 "o.foo = 17;"
10192 "var receiver = {};"
10193 "receiver.__proto__ = o;"
10194 "var result = 0;"
10195 "var saved_result = 0;"
10196 "for (var i = 0; i < 100; i++) {"
10197 " result = receiver.method(41);"
10198 " if (i == 50) {"
10199 " saved_result = result;"
10200 " receiver = 333;"
10201 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010202 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010203 CHECK(try_catch.HasCaught());
10204 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10205 try_catch.Exception()->ToString());
10206 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10207 CHECK_GE(interceptor_call_count, 50);
10208}
10209
ager@chromium.org5c838252010-02-19 08:53:10 +000010210THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10211 int interceptor_call_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010212 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010213 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10214 v8::Handle<v8::FunctionTemplate> method_templ =
10215 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10216 v8_str("method_data"),
10217 v8::Signature::New(fun_templ));
10218 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10219 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010220 fun_templ->SetHiddenPrototype(true);
ager@chromium.org5c838252010-02-19 08:53:10 +000010221 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10222 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10223 NULL, NULL, NULL, NULL,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010224 v8::External::New(&interceptor_call_count));
ager@chromium.org5c838252010-02-19 08:53:10 +000010225 LocalContext context;
10226 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10227 GenerateSomeGarbage();
10228 context->Global()->Set(v8_str("o"), fun->NewInstance());
10229 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010230 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010231 "o.foo = 17;"
10232 "var receiver = {};"
10233 "receiver.__proto__ = o;"
10234 "var result = 0;"
10235 "var saved_result = 0;"
10236 "for (var i = 0; i < 100; i++) {"
10237 " result = receiver.method(41);"
10238 " if (i == 50) {"
10239 " saved_result = result;"
10240 " receiver = {method: receiver.method};"
10241 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010242 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010243 CHECK(try_catch.HasCaught());
10244 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10245 try_catch.Exception()->ToString());
10246 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10247 CHECK_GE(interceptor_call_count, 50);
10248}
10249
10250THREADED_TEST(CallICFastApi_TrivialSignature) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010251 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010252 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10253 v8::Handle<v8::FunctionTemplate> method_templ =
10254 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10255 v8_str("method_data"),
10256 v8::Handle<v8::Signature>());
10257 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10258 proto_templ->Set(v8_str("method"), method_templ);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010259 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010260 USE(templ);
ager@chromium.org5c838252010-02-19 08:53:10 +000010261 LocalContext context;
10262 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10263 GenerateSomeGarbage();
10264 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010265 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010266 "var result = 0;"
10267 "for (var i = 0; i < 100; i++) {"
10268 " result = o.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010269 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010270
10271 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10272}
10273
10274THREADED_TEST(CallICFastApi_SimpleSignature) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010275 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010276 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10277 v8::Handle<v8::FunctionTemplate> method_templ =
10278 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10279 v8_str("method_data"),
10280 v8::Signature::New(fun_templ));
10281 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10282 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010283 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010284 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010285 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010286 LocalContext context;
10287 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10288 GenerateSomeGarbage();
10289 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010290 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010291 "o.foo = 17;"
10292 "var receiver = {};"
10293 "receiver.__proto__ = o;"
10294 "var result = 0;"
10295 "for (var i = 0; i < 100; i++) {"
10296 " result = receiver.method(41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010297 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010298
10299 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10300}
10301
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010302THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010303 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000010304 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10305 v8::Handle<v8::FunctionTemplate> method_templ =
10306 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10307 v8_str("method_data"),
10308 v8::Signature::New(fun_templ));
10309 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10310 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010311 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010312 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010313 CHECK(!templ.IsEmpty());
ager@chromium.org5c838252010-02-19 08:53:10 +000010314 LocalContext context;
10315 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10316 GenerateSomeGarbage();
10317 context->Global()->Set(v8_str("o"), fun->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010318 CompileRun(
ager@chromium.org5c838252010-02-19 08:53:10 +000010319 "o.foo = 17;"
10320 "var receiver = {};"
10321 "receiver.__proto__ = o;"
10322 "var result = 0;"
10323 "var saved_result = 0;"
10324 "for (var i = 0; i < 100; i++) {"
10325 " result = receiver.method(41);"
10326 " if (i == 50) {"
10327 " saved_result = result;"
10328 " receiver = {method: function(x) { return x - 1 }};"
10329 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010330 "}");
ager@chromium.org5c838252010-02-19 08:53:10 +000010331 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10332 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10333}
10334
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010335THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010336 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010337 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10338 v8::Handle<v8::FunctionTemplate> method_templ =
10339 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10340 v8_str("method_data"),
10341 v8::Signature::New(fun_templ));
10342 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10343 proto_templ->Set(v8_str("method"), method_templ);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010344 fun_templ->SetHiddenPrototype(true);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010345 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010346 CHECK(!templ.IsEmpty());
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010347 LocalContext context;
10348 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10349 GenerateSomeGarbage();
10350 context->Global()->Set(v8_str("o"), fun->NewInstance());
10351 v8::TryCatch try_catch;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010352 CompileRun(
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010353 "o.foo = 17;"
10354 "var receiver = {};"
10355 "receiver.__proto__ = o;"
10356 "var result = 0;"
10357 "var saved_result = 0;"
10358 "for (var i = 0; i < 100; i++) {"
10359 " result = receiver.method(41);"
10360 " if (i == 50) {"
10361 " saved_result = result;"
10362 " receiver = 333;"
10363 " }"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010364 "}");
sgjesse@chromium.org534ae572010-02-24 22:09:39 +000010365 CHECK(try_catch.HasCaught());
10366 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
10367 try_catch.Exception()->ToString());
10368 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10369}
10370
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010371THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010372 v8::HandleScope scope(v8::Isolate::GetCurrent());
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010373 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10374 v8::Handle<v8::FunctionTemplate> method_templ =
10375 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
10376 v8_str("method_data"),
10377 v8::Signature::New(fun_templ));
10378 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10379 proto_templ->Set(v8_str("method"), method_templ);
10380 fun_templ->SetHiddenPrototype(true);
10381 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10382 CHECK(!templ.IsEmpty());
10383 LocalContext context;
10384 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10385 GenerateSomeGarbage();
10386 context->Global()->Set(v8_str("o"), fun->NewInstance());
10387 v8::TryCatch try_catch;
10388 CompileRun(
10389 "o.foo = 17;"
10390 "var receiver = {};"
10391 "receiver.__proto__ = o;"
10392 "var result = 0;"
10393 "var saved_result = 0;"
10394 "for (var i = 0; i < 100; i++) {"
10395 " result = receiver.method(41);"
10396 " if (i == 50) {"
10397 " saved_result = result;"
10398 " receiver = Object.create(receiver);"
10399 " }"
10400 "}");
10401 CHECK(try_catch.HasCaught());
10402 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
10403 try_catch.Exception()->ToString());
10404 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10405}
10406
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010407
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010408v8::Handle<Value> keyed_call_ic_function;
10409
10410static v8::Handle<Value> InterceptorKeyedCallICGetter(
10411 Local<String> name, const AccessorInfo& info) {
10412 ApiTestFuzzer::Fuzz();
10413 if (v8_str("x")->Equals(name)) {
10414 return keyed_call_ic_function;
10415 }
10416 return v8::Handle<Value>();
10417}
10418
10419
10420// Test the case when we stored cacheable lookup into
10421// a stub, but the function name changed (to another cacheable function).
10422THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010423 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010424 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10425 templ->SetNamedPropertyHandler(NoBlockGetterX);
10426 LocalContext context;
10427 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010428 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010429 "proto = new Object();"
10430 "proto.y = function(x) { return x + 1; };"
10431 "proto.z = function(x) { return x - 1; };"
10432 "o.__proto__ = proto;"
10433 "var result = 0;"
10434 "var method = 'y';"
10435 "for (var i = 0; i < 10; i++) {"
10436 " if (i == 5) { method = 'z'; };"
10437 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010438 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010439 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10440}
10441
10442
10443// Test the case when we stored cacheable lookup into
10444// a stub, but the function name changed (and the new function is present
10445// both before and after the interceptor in the prototype chain).
10446THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010447 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010448 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10449 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
10450 LocalContext context;
10451 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
10452 keyed_call_ic_function =
10453 v8_compile("function f(x) { return x - 1; }; f")->Run();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010454 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010455 "o = new Object();"
10456 "proto2 = new Object();"
10457 "o.y = function(x) { return x + 1; };"
10458 "proto2.y = function(x) { return x + 2; };"
10459 "o.__proto__ = proto1;"
10460 "proto1.__proto__ = proto2;"
10461 "var result = 0;"
10462 "var method = 'x';"
10463 "for (var i = 0; i < 10; i++) {"
10464 " if (i == 5) { method = 'y'; };"
10465 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010466 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010467 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10468}
10469
10470
10471// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
10472// on the global object.
10473THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010474 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010475 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10476 templ->SetNamedPropertyHandler(NoBlockGetterX);
10477 LocalContext context;
10478 context->Global()->Set(v8_str("o"), templ->NewInstance());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010479 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010480 "function inc(x) { return x + 1; };"
10481 "inc(1);"
10482 "function dec(x) { return x - 1; };"
10483 "dec(1);"
10484 "o.__proto__ = this;"
10485 "this.__proto__.x = inc;"
10486 "this.__proto__.y = dec;"
10487 "var result = 0;"
10488 "var method = 'x';"
10489 "for (var i = 0; i < 10; i++) {"
10490 " if (i == 5) { method = 'y'; };"
10491 " result += o[method](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010492 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010493 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10494}
10495
10496
10497// Test the case when actual function to call sits on global object.
10498THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010499 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010500 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10501 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10502 LocalContext context;
10503 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10504
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010505 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010506 "function len(x) { return x.length; };"
10507 "o.__proto__ = this;"
10508 "var m = 'parseFloat';"
10509 "var result = 0;"
10510 "for (var i = 0; i < 10; i++) {"
10511 " if (i == 5) {"
10512 " m = 'len';"
10513 " saved_result = result;"
10514 " };"
10515 " result = o[m]('239');"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010516 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010517 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
10518 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10519}
10520
10521// Test the map transition before the interceptor.
10522THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010523 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010524 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10525 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10526 LocalContext context;
10527 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
10528
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010529 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010530 "var o = new Object();"
10531 "o.__proto__ = proto;"
10532 "o.method = function(x) { return x + 1; };"
10533 "var m = 'method';"
10534 "var result = 0;"
10535 "for (var i = 0; i < 10; i++) {"
10536 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
10537 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010538 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010539 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10540}
10541
10542
10543// Test the map transition after the interceptor.
10544THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010545 v8::HandleScope scope(v8::Isolate::GetCurrent());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010546 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10547 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10548 LocalContext context;
10549 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10550
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010551 CompileRun(
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010552 "var proto = new Object();"
10553 "o.__proto__ = proto;"
10554 "proto.method = function(x) { return x + 1; };"
10555 "var m = 'method';"
10556 "var result = 0;"
10557 "for (var i = 0; i < 10; i++) {"
10558 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
10559 " result += o[m](41);"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010560 "}");
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000010561 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
10562}
10563
10564
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010565static int interceptor_call_count = 0;
10566
10567static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
10568 const AccessorInfo& info) {
10569 ApiTestFuzzer::Fuzz();
10570 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
10571 return call_ic_function2;
10572 }
10573 return v8::Handle<Value>();
10574}
10575
10576
10577// This test should hit load and call ICs for the interceptor case.
10578// Once in a while, the interceptor will reply that a property was not
10579// found in which case we should get a reference error.
10580THREADED_TEST(InterceptorICReferenceErrors) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010581 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010582 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10583 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
10584 LocalContext context(0, templ, v8::Handle<Value>());
10585 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
10586 v8::Handle<Value> value = CompileRun(
10587 "function f() {"
10588 " for (var i = 0; i < 1000; i++) {"
10589 " try { x; } catch(e) { return true; }"
10590 " }"
10591 " return false;"
10592 "};"
10593 "f();");
10594 CHECK_EQ(true, value->BooleanValue());
10595 interceptor_call_count = 0;
10596 value = CompileRun(
10597 "function g() {"
10598 " for (var i = 0; i < 1000; i++) {"
10599 " try { x(42); } catch(e) { return true; }"
10600 " }"
10601 " return false;"
10602 "};"
10603 "g();");
10604 CHECK_EQ(true, value->BooleanValue());
10605}
10606
10607
10608static int interceptor_ic_exception_get_count = 0;
10609
10610static v8::Handle<Value> InterceptorICExceptionGetter(
10611 Local<String> name,
10612 const AccessorInfo& info) {
10613 ApiTestFuzzer::Fuzz();
10614 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
10615 return call_ic_function3;
10616 }
10617 if (interceptor_ic_exception_get_count == 20) {
10618 return v8::ThrowException(v8_num(42));
10619 }
10620 // Do not handle get for properties other than x.
10621 return v8::Handle<Value>();
10622}
10623
10624// Test interceptor load/call IC where the interceptor throws an
10625// exception once in a while.
10626THREADED_TEST(InterceptorICGetterExceptions) {
10627 interceptor_ic_exception_get_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010628 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010629 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10630 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
10631 LocalContext context(0, templ, v8::Handle<Value>());
10632 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
10633 v8::Handle<Value> value = CompileRun(
10634 "function f() {"
10635 " for (var i = 0; i < 100; i++) {"
10636 " try { x; } catch(e) { return true; }"
10637 " }"
10638 " return false;"
10639 "};"
10640 "f();");
10641 CHECK_EQ(true, value->BooleanValue());
10642 interceptor_ic_exception_get_count = 0;
10643 value = CompileRun(
10644 "function f() {"
10645 " for (var i = 0; i < 100; i++) {"
10646 " try { x(42); } catch(e) { return true; }"
10647 " }"
10648 " return false;"
10649 "};"
10650 "f();");
10651 CHECK_EQ(true, value->BooleanValue());
10652}
10653
10654
10655static int interceptor_ic_exception_set_count = 0;
10656
10657static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010658 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010659 ApiTestFuzzer::Fuzz();
10660 if (++interceptor_ic_exception_set_count > 20) {
10661 return v8::ThrowException(v8_num(42));
10662 }
10663 // Do not actually handle setting.
10664 return v8::Handle<Value>();
10665}
10666
10667// Test interceptor store IC where the interceptor throws an exception
10668// once in a while.
10669THREADED_TEST(InterceptorICSetterExceptions) {
10670 interceptor_ic_exception_set_count = 0;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010671 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010672 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10673 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
10674 LocalContext context(0, templ, v8::Handle<Value>());
10675 v8::Handle<Value> value = CompileRun(
10676 "function f() {"
10677 " for (var i = 0; i < 100; i++) {"
10678 " try { x = 42; } catch(e) { return true; }"
10679 " }"
10680 " return false;"
10681 "};"
10682 "f();");
10683 CHECK_EQ(true, value->BooleanValue());
10684}
10685
10686
10687// Test that we ignore null interceptors.
10688THREADED_TEST(NullNamedInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010689 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010690 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10691 templ->SetNamedPropertyHandler(0);
10692 LocalContext context;
10693 templ->Set("x", v8_num(42));
10694 v8::Handle<v8::Object> obj = templ->NewInstance();
10695 context->Global()->Set(v8_str("obj"), obj);
10696 v8::Handle<Value> value = CompileRun("obj.x");
10697 CHECK(value->IsInt32());
10698 CHECK_EQ(42, value->Int32Value());
10699}
10700
10701
10702// Test that we ignore null interceptors.
10703THREADED_TEST(NullIndexedInterceptor) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010704 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010705 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10706 templ->SetIndexedPropertyHandler(0);
10707 LocalContext context;
10708 templ->Set("42", v8_num(42));
10709 v8::Handle<v8::Object> obj = templ->NewInstance();
10710 context->Global()->Set(v8_str("obj"), obj);
10711 v8::Handle<Value> value = CompileRun("obj[42]");
10712 CHECK(value->IsInt32());
10713 CHECK_EQ(42, value->Int32Value());
10714}
10715
10716
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010717THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010718 v8::HandleScope scope(v8::Isolate::GetCurrent());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010719 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10720 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10721 LocalContext env;
10722 env->Global()->Set(v8_str("obj"),
10723 templ->GetFunction()->NewInstance());
10724 ExpectTrue("obj.x === 42");
10725 ExpectTrue("!obj.propertyIsEnumerable('x')");
10726}
10727
10728
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010729static Handle<Value> ThrowingGetter(Local<String> name,
10730 const AccessorInfo& info) {
10731 ApiTestFuzzer::Fuzz();
10732 ThrowException(Handle<Value>());
10733 return Undefined();
10734}
10735
10736
10737THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010738 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010739 HandleScope scope(context->GetIsolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010740
10741 Local<FunctionTemplate> templ = FunctionTemplate::New();
10742 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10743 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10744
10745 Local<Object> instance = templ->GetFunction()->NewInstance();
10746
10747 Local<Object> another = Object::New();
10748 another->SetPrototype(instance);
10749
10750 Local<Object> with_js_getter = CompileRun(
10751 "o = {};\n"
10752 "o.__defineGetter__('f', function() { throw undefined; });\n"
10753 "o\n").As<Object>();
10754 CHECK(!with_js_getter.IsEmpty());
10755
10756 TryCatch try_catch;
10757
10758 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10759 CHECK(try_catch.HasCaught());
10760 try_catch.Reset();
10761 CHECK(result.IsEmpty());
10762
10763 result = another->GetRealNamedProperty(v8_str("f"));
10764 CHECK(try_catch.HasCaught());
10765 try_catch.Reset();
10766 CHECK(result.IsEmpty());
10767
10768 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10769 CHECK(try_catch.HasCaught());
10770 try_catch.Reset();
10771 CHECK(result.IsEmpty());
10772
10773 result = another->Get(v8_str("f"));
10774 CHECK(try_catch.HasCaught());
10775 try_catch.Reset();
10776 CHECK(result.IsEmpty());
10777
10778 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10779 CHECK(try_catch.HasCaught());
10780 try_catch.Reset();
10781 CHECK(result.IsEmpty());
10782
10783 result = with_js_getter->Get(v8_str("f"));
10784 CHECK(try_catch.HasCaught());
10785 try_catch.Reset();
10786 CHECK(result.IsEmpty());
10787}
10788
10789
10790static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
10791 TryCatch try_catch;
10792 // Verboseness is important: it triggers message delivery which can call into
10793 // external code.
10794 try_catch.SetVerbose(true);
10795 CompileRun("throw 'from JS';");
10796 CHECK(try_catch.HasCaught());
10797 CHECK(!i::Isolate::Current()->has_pending_exception());
10798 CHECK(!i::Isolate::Current()->has_scheduled_exception());
10799 return Undefined();
10800}
10801
10802
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010803static int call_depth;
10804
10805
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010806static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10807 TryCatch try_catch;
10808}
10809
10810
10811static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010812 if (--call_depth) CompileRun("throw 'ThrowInJS';");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010813}
10814
10815
10816static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010817 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010818}
10819
10820
10821static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10822 Handle<String> errorMessageString = message->Get();
10823 CHECK(!errorMessageString.IsEmpty());
10824 message->GetStackTrace();
10825 message->GetScriptResourceName();
10826}
10827
10828THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010829 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010830 HandleScope scope(context->GetIsolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010831
10832 Local<Function> func =
10833 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
10834 context->Global()->Set(v8_str("func"), func);
10835
10836 MessageCallback callbacks[] =
10837 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10838 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10839 MessageCallback callback = callbacks[i];
10840 if (callback != NULL) {
10841 V8::AddMessageListener(callback);
10842 }
ricow@chromium.orgdcebac02011-04-20 09:44:50 +000010843 // Some small number to control number of times message handler should
10844 // throw an exception.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010845 call_depth = 5;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010846 ExpectFalse(
10847 "var thrown = false;\n"
10848 "try { func(); } catch(e) { thrown = true; }\n"
10849 "thrown\n");
10850 if (callback != NULL) {
10851 V8::RemoveMessageListeners(callback);
10852 }
10853 }
10854}
10855
10856
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010857static v8::Handle<Value> ParentGetter(Local<String> name,
10858 const AccessorInfo& info) {
10859 ApiTestFuzzer::Fuzz();
10860 return v8_num(1);
10861}
10862
10863
10864static v8::Handle<Value> ChildGetter(Local<String> name,
10865 const AccessorInfo& info) {
10866 ApiTestFuzzer::Fuzz();
10867 return v8_num(42);
10868}
10869
10870
10871THREADED_TEST(Overriding) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010872 i::FLAG_es5_readonly = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010873 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010874 v8::HandleScope scope(context->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010875
10876 // Parent template.
10877 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
10878 Local<ObjectTemplate> parent_instance_templ =
10879 parent_templ->InstanceTemplate();
10880 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10881
10882 // Template that inherits from the parent template.
10883 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
10884 Local<ObjectTemplate> child_instance_templ =
10885 child_templ->InstanceTemplate();
10886 child_templ->Inherit(parent_templ);
10887 // Override 'f'. The child version of 'f' should get called for child
10888 // instances.
10889 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
10890 // Add 'g' twice. The 'g' added last should get called for instances.
10891 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
10892 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
10893
10894 // Add 'h' as an accessor to the proto template with ReadOnly attributes
10895 // so 'h' can be shadowed on the instance object.
10896 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
10897 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
10898 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10899
10900 // Add 'i' as an accessor to the instance template with ReadOnly attributes
10901 // but the attribute does not have effect because it is duplicated with
10902 // NULL setter.
10903 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
10904 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
10905
10906
10907
10908 // Instantiate the child template.
10909 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
10910
10911 // Check that the child function overrides the parent one.
10912 context->Global()->Set(v8_str("o"), instance);
10913 Local<Value> value = v8_compile("o.f")->Run();
10914 // Check that the 'g' that was added last is hit.
10915 CHECK_EQ(42, value->Int32Value());
10916 value = v8_compile("o.g")->Run();
10917 CHECK_EQ(42, value->Int32Value());
10918
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010919 // Check that 'h' cannot be shadowed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010920 value = v8_compile("o.h = 3; o.h")->Run();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010921 CHECK_EQ(1, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010922
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010923 // Check that 'i' cannot be shadowed or changed.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010924 value = v8_compile("o.i = 3; o.i")->Run();
10925 CHECK_EQ(42, value->Int32Value());
10926}
10927
10928
10929static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
10930 ApiTestFuzzer::Fuzz();
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +000010931 return v8::Boolean::New(args.IsConstructCall());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010932}
10933
10934
10935THREADED_TEST(IsConstructCall) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010936 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010937
10938 // Function template with call handler.
10939 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10940 templ->SetCallHandler(IsConstructHandler);
10941
10942 LocalContext context;
10943
10944 context->Global()->Set(v8_str("f"), templ->GetFunction());
10945 Local<Value> value = v8_compile("f()")->Run();
10946 CHECK(!value->BooleanValue());
10947 value = v8_compile("new f()")->Run();
10948 CHECK(value->BooleanValue());
10949}
10950
10951
10952THREADED_TEST(ObjectProtoToString) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010953 v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010954 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10955 templ->SetClassName(v8_str("MyClass"));
10956
10957 LocalContext context;
10958
10959 Local<String> customized_tostring = v8_str("customized toString");
10960
10961 // Replace Object.prototype.toString
10962 v8_compile("Object.prototype.toString = function() {"
10963 " return 'customized toString';"
10964 "}")->Run();
10965
10966 // Normal ToString call should call replaced Object.prototype.toString
10967 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
10968 Local<String> value = instance->ToString();
10969 CHECK(value->IsString() && value->Equals(customized_tostring));
10970
10971 // ObjectProtoToString should not call replace toString function.
10972 value = instance->ObjectProtoToString();
10973 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
10974
10975 // Check global
10976 value = context->Global()->ObjectProtoToString();
10977 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
10978
10979 // Check ordinary object
10980 Local<Value> object = v8_compile("new Object()")->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010981 value = object.As<v8::Object>()->ObjectProtoToString();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010982 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
10983}
10984
10985
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010986THREADED_TEST(ObjectGetConstructorName) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010987 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010988 v8::HandleScope scope(context->GetIsolate());
ager@chromium.orgbeb25712010-11-29 08:02:25 +000010989 v8_compile("function Parent() {};"
10990 "function Child() {};"
10991 "Child.prototype = new Parent();"
10992 "var outer = { inner: function() { } };"
10993 "var p = new Parent();"
10994 "var c = new Child();"
10995 "var x = new outer.inner();")->Run();
10996
10997 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
10998 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
10999 v8_str("Parent")));
11000
11001 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11002 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
11003 v8_str("Child")));
11004
11005 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11006 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
11007 v8_str("outer.inner")));
11008}
11009
11010
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011011bool ApiTestFuzzer::fuzzing_ = false;
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011012i::Semaphore* ApiTestFuzzer::all_tests_done_=
11013 i::OS::CreateSemaphore(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011014int ApiTestFuzzer::active_tests_;
11015int ApiTestFuzzer::tests_being_run_;
11016int ApiTestFuzzer::current_;
11017
11018
11019// We are in a callback and want to switch to another thread (if we
11020// are currently running the thread fuzzing test).
11021void ApiTestFuzzer::Fuzz() {
11022 if (!fuzzing_) return;
11023 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11024 test->ContextSwitch();
11025}
11026
11027
11028// Let the next thread go. Since it is also waiting on the V8 lock it may
11029// not start immediately.
11030bool ApiTestFuzzer::NextThread() {
11031 int test_position = GetNextTestNumber();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011032 const char* test_name = RegisterThreadedTest::nth(current_)->name();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011033 if (test_position == current_) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011034 if (kLogThreading)
11035 printf("Stay with %s\n", test_name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011036 return false;
11037 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011038 if (kLogThreading) {
11039 printf("Switch from %s to %s\n",
11040 test_name,
11041 RegisterThreadedTest::nth(test_position)->name());
11042 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011043 current_ = test_position;
11044 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
11045 return true;
11046}
11047
11048
11049void ApiTestFuzzer::Run() {
11050 // When it is our turn...
11051 gate_->Wait();
11052 {
11053 // ... get the V8 lock and start running the test.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011054 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011055 CallTest();
11056 }
11057 // This test finished.
11058 active_ = false;
11059 active_tests_--;
11060 // If it was the last then signal that fact.
11061 if (active_tests_ == 0) {
11062 all_tests_done_->Signal();
11063 } else {
11064 // Otherwise select a new test and start that.
11065 NextThread();
11066 }
11067}
11068
11069
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011070static unsigned linear_congruential_generator;
11071
11072
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011073void ApiTestFuzzer::SetUp(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011074 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011075 fuzzing_ = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +000011076 int count = RegisterThreadedTest::count();
11077 int start = count * part / (LAST_PART + 1);
11078 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11079 active_tests_ = tests_being_run_ = end - start + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011080 for (int i = 0; i < tests_being_run_; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011081 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011082 }
11083 for (int i = 0; i < active_tests_; i++) {
11084 RegisterThreadedTest::nth(i)->fuzzer_->Start();
11085 }
11086}
11087
11088
11089static void CallTestNumber(int test_number) {
11090 (RegisterThreadedTest::nth(test_number)->callback())();
11091}
11092
11093
11094void ApiTestFuzzer::RunAllTests() {
11095 // Set off the first test.
11096 current_ = -1;
11097 NextThread();
11098 // Wait till they are all done.
11099 all_tests_done_->Wait();
11100}
11101
11102
11103int ApiTestFuzzer::GetNextTestNumber() {
11104 int next_test;
11105 do {
11106 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11107 linear_congruential_generator *= 1664525u;
11108 linear_congruential_generator += 1013904223u;
11109 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11110 return next_test;
11111}
11112
11113
11114void ApiTestFuzzer::ContextSwitch() {
11115 // If the new thread is the same as the current thread there is nothing to do.
11116 if (NextThread()) {
11117 // Now it can start.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011118 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011119 // Wait till someone starts us again.
11120 gate_->Wait();
11121 // And we're off.
11122 }
11123}
11124
11125
11126void ApiTestFuzzer::TearDown() {
11127 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +000011128 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11129 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11130 if (fuzzer != NULL) fuzzer->Join();
11131 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011132}
11133
11134
11135// Lets not be needlessly self-referential.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011136TEST(Threading1) {
11137 // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the
11138 // correct timeout for this an re-enable this test again
11139 if (i::FLAG_stress_compaction) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011140 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011141 ApiTestFuzzer::RunAllTests();
11142 ApiTestFuzzer::TearDown();
11143}
11144
11145TEST(Threading2) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011146 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011147 ApiTestFuzzer::RunAllTests();
11148 ApiTestFuzzer::TearDown();
11149}
11150
lrn@chromium.org1c092762011-05-09 09:42:16 +000011151TEST(Threading3) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011152 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000011153 ApiTestFuzzer::RunAllTests();
11154 ApiTestFuzzer::TearDown();
11155}
11156
11157TEST(Threading4) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011158 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
lrn@chromium.org1c092762011-05-09 09:42:16 +000011159 ApiTestFuzzer::RunAllTests();
11160 ApiTestFuzzer::TearDown();
11161}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011162
11163void ApiTestFuzzer::CallTest() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011164 if (kLogThreading)
11165 printf("Start test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011166 CallTestNumber(test_number_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011167 if (kLogThreading)
11168 printf("End test %d\n", test_number_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011169}
11170
11171
11172static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011173 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011174 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011175 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011176 const char* code = "throw 7;";
11177 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011178 v8::Locker nested_locker(CcTest::default_isolate());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011179 v8::HandleScope scope(args.GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011180 v8::Handle<Value> exception;
11181 { v8::TryCatch try_catch;
11182 v8::Handle<Value> value = CompileRun(code);
11183 CHECK(value.IsEmpty());
11184 CHECK(try_catch.HasCaught());
11185 // Make sure to wrap the exception in a new handle because
11186 // the handle returned from the TryCatch is destroyed
11187 // when the TryCatch is destroyed.
11188 exception = Local<Value>::New(try_catch.Exception());
11189 }
11190 return v8::ThrowException(exception);
11191 }
11192}
11193
11194
11195static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011196 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011197 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011198 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011199 const char* code = "throw 7;";
11200 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011201 v8::Locker nested_locker(CcTest::default_isolate());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011202 v8::HandleScope scope(args.GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011203 v8::Handle<Value> value = CompileRun(code);
11204 CHECK(value.IsEmpty());
11205 return v8_str("foo");
11206 }
11207}
11208
11209
11210// These are locking tests that don't need to be run again
11211// as part of the locking aggregation tests.
11212TEST(NestedLockers) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011213 v8::Locker locker(CcTest::default_isolate());
11214 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011215 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011216 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011217 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
11218 Local<Function> fun = fun_templ->GetFunction();
11219 env->Global()->Set(v8_str("throw_in_js"), fun);
11220 Local<Script> script = v8_compile("(function () {"
11221 " try {"
11222 " throw_in_js();"
11223 " return 42;"
11224 " } catch (e) {"
11225 " return e * 13;"
11226 " }"
11227 "})();");
11228 CHECK_EQ(91, script->Run()->Int32Value());
11229}
11230
11231
11232// These are locking tests that don't need to be run again
11233// as part of the locking aggregation tests.
11234TEST(NestedLockersNoTryCatch) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011235 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011236 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011237 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011238 Local<v8::FunctionTemplate> fun_templ =
11239 v8::FunctionTemplate::New(ThrowInJSNoCatch);
11240 Local<Function> fun = fun_templ->GetFunction();
11241 env->Global()->Set(v8_str("throw_in_js"), fun);
11242 Local<Script> script = v8_compile("(function () {"
11243 " try {"
11244 " throw_in_js();"
11245 " return 42;"
11246 " } catch (e) {"
11247 " return e * 13;"
11248 " }"
11249 "})();");
11250 CHECK_EQ(91, script->Run()->Int32Value());
11251}
11252
11253
11254THREADED_TEST(RecursiveLocking) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011255 v8::Locker locker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011256 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011257 v8::Locker locker2(CcTest::default_isolate());
11258 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011259 }
11260}
11261
11262
11263static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
11264 ApiTestFuzzer::Fuzz();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011265 v8::Unlocker unlocker(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011266 return v8::Undefined();
11267}
11268
11269
11270THREADED_TEST(LockUnlockLock) {
11271 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011272 v8::Locker locker(CcTest::default_isolate());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011273 v8::HandleScope scope(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011274 LocalContext env;
11275 Local<v8::FunctionTemplate> fun_templ =
11276 v8::FunctionTemplate::New(UnlockForAMoment);
11277 Local<Function> fun = fun_templ->GetFunction();
11278 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11279 Local<Script> script = v8_compile("(function () {"
11280 " unlock_for_a_moment();"
11281 " return 42;"
11282 "})();");
11283 CHECK_EQ(42, script->Run()->Int32Value());
11284 }
11285 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011286 v8::Locker locker(CcTest::default_isolate());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011287 v8::HandleScope scope(CcTest::default_isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011288 LocalContext env;
11289 Local<v8::FunctionTemplate> fun_templ =
11290 v8::FunctionTemplate::New(UnlockForAMoment);
11291 Local<Function> fun = fun_templ->GetFunction();
11292 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11293 Local<Script> script = v8_compile("(function () {"
11294 " unlock_for_a_moment();"
11295 " return 42;"
11296 "})();");
11297 CHECK_EQ(42, script->Run()->Int32Value());
11298 }
11299}
11300
11301
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011302static int GetGlobalObjectsCount() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011303 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011304 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011305 i::HeapIterator it(HEAP);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011306 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11307 if (object->IsJSGlobalObject()) count++;
11308 return count;
11309}
11310
11311
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011312static void CheckSurvivingGlobalObjectsCount(int expected) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011313 // We need to collect all garbage twice to be sure that everything
11314 // has been collected. This is because inline caches are cleared in
11315 // the first garbage collection but some of the maps have already
11316 // been marked at that point. Therefore some of the maps are not
11317 // collected until the second garbage collection.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011318 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11319 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011320 int count = GetGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011321#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 if (count != expected) HEAP->TracePathToGlobal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011323#endif
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011324 CHECK_EQ(expected, count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011325}
11326
11327
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011328TEST(DontLeakGlobalObjects) {
11329 // Regression test for issues 1139850 and 1174891.
11330
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011331 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011332
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011333 for (int i = 0; i < 5; i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011334 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011335 LocalContext context;
11336 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011337 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011338 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011339
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011340 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011341 LocalContext context;
11342 v8_compile("Date")->Run();
11343 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011344 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011345 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011346
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011347 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011348 LocalContext context;
11349 v8_compile("/aaa/")->Run();
11350 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011351 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011352 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011353
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011354 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011355 const char* extension_list[] = { "v8/gc" };
11356 v8::ExtensionConfiguration extensions(1, extension_list);
11357 LocalContext context(&extensions);
11358 v8_compile("gc();")->Run();
11359 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011360 v8::V8::ContextDisposedNotification();
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011361 CheckSurvivingGlobalObjectsCount(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011362 }
11363}
11364
11365
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011366v8::Persistent<v8::Object> some_object;
11367v8::Persistent<v8::Object> bad_handle;
11368
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011369void NewPersistentHandleCallback(v8::Isolate* isolate,
11370 v8::Persistent<v8::Value> handle,
11371 void*) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011372 v8::HandleScope scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011373 bad_handle = v8::Persistent<v8::Object>::New(isolate, some_object);
11374 handle.Dispose(isolate);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011375}
11376
11377
11378THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11379 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011380 v8::Isolate* isolate = context->GetIsolate();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011381
11382 v8::Persistent<v8::Object> handle1, handle2;
11383 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011384 v8::HandleScope scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011385 some_object = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11386 handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11387 handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011388 }
11389 // Note: order is implementation dependent alas: currently
11390 // global handle nodes are processed by PostGarbageCollectionProcessing
11391 // in reverse allocation order, so if second allocated handle is deleted,
11392 // weak callback of the first handle would be able to 'reallocate' it.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011393 handle1.MakeWeak(isolate, NULL, NewPersistentHandleCallback);
11394 handle2.Dispose(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011395 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011396}
11397
11398
11399v8::Persistent<v8::Object> to_be_disposed;
11400
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011401void DisposeAndForceGcCallback(v8::Isolate* isolate,
11402 v8::Persistent<v8::Value> handle,
11403 void*) {
11404 to_be_disposed.Dispose(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011405 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011406 handle.Dispose(isolate);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011407}
11408
11409
11410THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11411 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011412 v8::Isolate* isolate = context->GetIsolate();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011413
11414 v8::Persistent<v8::Object> handle1, handle2;
11415 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011416 v8::HandleScope scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011417 handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11418 handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011419 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011420 handle1.MakeWeak(isolate, NULL, DisposeAndForceGcCallback);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011421 to_be_disposed = handle2;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011422 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011423}
11424
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011425void DisposingCallback(v8::Isolate* isolate,
11426 v8::Persistent<v8::Value> handle,
11427 void*) {
11428 handle.Dispose(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011429}
11430
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011431void HandleCreatingCallback(v8::Isolate* isolate,
11432 v8::Persistent<v8::Value> handle,
11433 void*) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011434 v8::HandleScope scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011435 v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11436 handle.Dispose(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011437}
11438
11439
11440THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11441 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011442 v8::Isolate* isolate = context->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011443
11444 v8::Persistent<v8::Object> handle1, handle2, handle3;
11445 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011446 v8::HandleScope scope(isolate);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011447 handle3 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11448 handle2 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
11449 handle1 = v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011450 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011451 handle2.MakeWeak(isolate, NULL, DisposingCallback);
11452 handle3.MakeWeak(isolate, NULL, HandleCreatingCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011453 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000011454}
11455
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000011456
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011457THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011458 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011459
11460 const int nof = 2;
11461 const char* sources[nof] = {
11462 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11463 "Object()"
11464 };
11465
11466 for (int i = 0; i < nof; i++) {
11467 const char* source = sources[i];
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011468 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011469 LocalContext context;
11470 CompileRun(source);
11471 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011472 { v8::HandleScope scope(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011473 LocalContext context;
11474 CompileRun(source);
11475 }
11476 }
11477}
11478
11479
11480static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011481 v8::HandleScope inner(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011482 env->Enter();
11483 v8::Handle<Value> three = v8_num(3);
11484 v8::Handle<Value> value = inner.Close(three);
11485 env->Exit();
11486 return value;
11487}
11488
11489
11490THREADED_TEST(NestedHandleScopeAndContexts) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011491 v8::HandleScope outer(v8::Isolate::GetCurrent());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011492 v8::Persistent<Context> env = Context::New();
11493 env->Enter();
11494 v8::Handle<Value> value = NestedScope(env);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011495 v8::Handle<String> str(value->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011496 CHECK(!str.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011497 env->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011498 env.Dispose(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011499}
11500
11501
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011502static i::Handle<i::JSFunction>* foo_ptr = NULL;
11503static int foo_count = 0;
11504static i::Handle<i::JSFunction>* bar_ptr = NULL;
11505static int bar_count = 0;
11506
11507
11508static void entry_hook(uintptr_t function,
11509 uintptr_t return_addr_location) {
11510 i::Code* code = i::Code::GetCodeFromTargetAddress(
11511 reinterpret_cast<i::Address>(function));
11512 CHECK(code != NULL);
11513
11514 if (bar_ptr != NULL && code == (*bar_ptr)->code())
11515 ++bar_count;
11516
11517 if (foo_ptr != NULL && code == (*foo_ptr)->code())
11518 ++foo_count;
11519
11520 // TODO(siggi): Verify return_addr_location.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011521 // This can be done by capturing JitCodeEvents, but requires an ordered
11522 // collection.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011523}
11524
11525
11526static void RunLoopInNewEnv() {
11527 bar_ptr = NULL;
11528 foo_ptr = NULL;
11529
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011530 v8::HandleScope outer(v8::Isolate::GetCurrent());
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011531 v8::Persistent<Context> env = Context::New();
11532 env->Enter();
11533
11534 const char* script =
11535 "function bar() {"
11536 " var sum = 0;"
11537 " for (i = 0; i < 100; ++i)"
11538 " sum = foo(i);"
11539 " return sum;"
11540 "}"
11541 "function foo(i) { return i * i; }";
11542 CompileRun(script);
11543 i::Handle<i::JSFunction> bar =
11544 i::Handle<i::JSFunction>::cast(
11545 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
11546 ASSERT(*bar);
11547
11548 i::Handle<i::JSFunction> foo =
11549 i::Handle<i::JSFunction>::cast(
11550 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
11551 ASSERT(*foo);
11552
11553 bar_ptr = &bar;
11554 foo_ptr = &foo;
11555
11556 v8::Handle<v8::Value> value = CompileRun("bar();");
11557 CHECK(value->IsNumber());
11558 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11559
11560 // Test the optimized codegen path.
11561 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
11562 "bar();");
11563 CHECK(value->IsNumber());
11564 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
11565
11566 env->Exit();
11567}
11568
11569
11570TEST(SetFunctionEntryHook) {
11571 i::FLAG_allow_natives_syntax = true;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011572 i::FLAG_use_inlining = false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000011573
11574 // Test setting and resetting the entry hook.
11575 // Nulling it should always succeed.
11576 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11577
11578 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11579 // Setting a hook while one's active should fail.
11580 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
11581
11582 CHECK(v8::V8::SetFunctionEntryHook(NULL));
11583
11584 // Reset the entry count to zero and set the entry hook.
11585 bar_count = 0;
11586 foo_count = 0;
11587 CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
11588 RunLoopInNewEnv();
11589
11590 CHECK_EQ(2, bar_count);
11591 CHECK_EQ(200, foo_count);
11592
11593 // Clear the entry hook and count.
11594 bar_count = 0;
11595 foo_count = 0;
11596 v8::V8::SetFunctionEntryHook(NULL);
11597
11598 // Clear the compilation cache to make sure we don't reuse the
11599 // functions from the previous invocation.
11600 v8::internal::Isolate::Current()->compilation_cache()->Clear();
11601
11602 // Verify that entry hooking is now disabled.
11603 RunLoopInNewEnv();
11604 CHECK_EQ(0u, bar_count);
11605 CHECK_EQ(0u, foo_count);
11606}
11607
11608
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011609static i::HashMap* code_map = NULL;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011610static i::HashMap* jitcode_line_info = NULL;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011611static int saw_bar = 0;
11612static int move_events = 0;
11613
11614
11615static bool FunctionNameIs(const char* expected,
11616 const v8::JitCodeEvent* event) {
11617 // Log lines for functions are of the general form:
11618 // "LazyCompile:<type><function_name>", where the type is one of
11619 // "*", "~" or "".
11620 static const char kPreamble[] = "LazyCompile:";
11621 static size_t kPreambleLen = sizeof(kPreamble) - 1;
11622
11623 if (event->name.len < sizeof(kPreamble) - 1 ||
11624 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
11625 return false;
11626 }
11627
11628 const char* tail = event->name.str + kPreambleLen;
11629 size_t tail_len = event->name.len - kPreambleLen;
11630 size_t expected_len = strlen(expected);
11631 if (tail_len == expected_len + 1) {
11632 if (*tail == '*' || *tail == '~') {
11633 --tail_len;
11634 ++tail;
11635 } else {
11636 return false;
11637 }
11638 }
11639
11640 if (tail_len != expected_len)
11641 return false;
11642
11643 return strncmp(tail, expected, expected_len) == 0;
11644}
11645
11646
11647static void event_handler(const v8::JitCodeEvent* event) {
11648 CHECK(event != NULL);
11649 CHECK(code_map != NULL);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011650 CHECK(jitcode_line_info != NULL);
11651
11652 class DummyJitCodeLineInfo {
11653 };
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011654
11655 switch (event->type) {
11656 case v8::JitCodeEvent::CODE_ADDED: {
11657 CHECK(event->code_start != NULL);
11658 CHECK_NE(0, static_cast<int>(event->code_len));
11659 CHECK(event->name.str != NULL);
11660 i::HashMap::Entry* entry =
11661 code_map->Lookup(event->code_start,
11662 i::ComputePointerHash(event->code_start),
11663 true);
11664 entry->value = reinterpret_cast<void*>(event->code_len);
11665
11666 if (FunctionNameIs("bar", event)) {
11667 ++saw_bar;
11668 }
11669 }
11670 break;
11671
11672 case v8::JitCodeEvent::CODE_MOVED: {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011673 uint32_t hash = i::ComputePointerHash(event->code_start);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011674 // We would like to never see code move that we haven't seen before,
11675 // but the code creation event does not happen until the line endings
11676 // have been calculated (this is so that we can report the line in the
11677 // script at which the function source is found, see
11678 // Compiler::RecordFunctionCompilation) and the line endings
11679 // calculations can cause a GC, which can move the newly created code
11680 // before its existence can be logged.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011681 i::HashMap::Entry* entry =
11682 code_map->Lookup(event->code_start, hash, false);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011683 if (entry != NULL) {
11684 ++move_events;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011685
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000011686 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
11687 code_map->Remove(event->code_start, hash);
11688
11689 entry = code_map->Lookup(event->new_code_start,
11690 i::ComputePointerHash(event->new_code_start),
11691 true);
11692 CHECK(entry != NULL);
11693 entry->value = reinterpret_cast<void*>(event->code_len);
11694 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011695 }
11696 break;
11697
11698 case v8::JitCodeEvent::CODE_REMOVED:
11699 // Object/code removal events are currently not dispatched from the GC.
11700 CHECK(false);
11701 break;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011702
11703 // For CODE_START_LINE_INFO_RECORDING event, we will create one
11704 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
11705 // record it in jitcode_line_info.
11706 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
11707 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
11708 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
11709 temp_event->user_data = line_info;
11710 i::HashMap::Entry* entry =
11711 jitcode_line_info->Lookup(line_info,
11712 i::ComputePointerHash(line_info),
11713 true);
11714 entry->value = reinterpret_cast<void*>(line_info);
11715 }
11716 break;
11717 // For these two events, we will check whether the event->user_data
11718 // data structure is created before during CODE_START_LINE_INFO_RECORDING
11719 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
11720 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
11721 CHECK(event->user_data != NULL);
11722 uint32_t hash = i::ComputePointerHash(event->user_data);
11723 i::HashMap::Entry* entry =
11724 jitcode_line_info->Lookup(event->user_data, hash, false);
11725 CHECK(entry != NULL);
11726 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
11727 }
11728 break;
11729
11730 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
11731 CHECK(event->user_data != NULL);
11732 uint32_t hash = i::ComputePointerHash(event->user_data);
11733 i::HashMap::Entry* entry =
11734 jitcode_line_info->Lookup(event->user_data, hash, false);
11735 CHECK(entry != NULL);
11736 }
11737 break;
11738
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011739 default:
11740 // Impossible event.
11741 CHECK(false);
11742 break;
11743 }
11744}
11745
11746
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011747static bool MatchPointers(void* key1, void* key2) {
11748 return key1 == key2;
11749}
11750
11751
11752TEST(SetJitCodeEventHandler) {
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011753 i::FLAG_stress_compaction = true;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011754 const char* script =
11755 "function bar() {"
11756 " var sum = 0;"
11757 " for (i = 0; i < 100; ++i)"
11758 " sum = foo(i);"
11759 " return sum;"
11760 "}"
11761 "function foo(i) { return i * i; };"
11762 "bar();";
11763
11764 // Run this test in a new isolate to make sure we don't
11765 // have remnants of state from other code.
11766 v8::Isolate* isolate = v8::Isolate::New();
11767 isolate->Enter();
11768
11769 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011770 v8::HandleScope scope(isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011771 i::HashMap code(MatchPointers);
11772 code_map = &code;
11773
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011774 i::HashMap lineinfo(MatchPointers);
11775 jitcode_line_info = &lineinfo;
11776
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011777 saw_bar = 0;
11778 move_events = 0;
11779
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011780 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
11781
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011782 // Generate new code objects sparsely distributed across several
11783 // different fragmented code-space pages.
11784 const int kIterations = 10;
11785 for (int i = 0; i < kIterations; ++i) {
11786 LocalContext env;
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011787 i::AlwaysAllocateScope always_allocate;
11788 SimulateFullSpace(HEAP->code_space());
11789 CompileRun(script);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011790
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011791 // Keep a strong reference to the code object in the handle scope.
11792 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
11793 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
11794 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
11795 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011796
11797 // Clear the compilation cache to get more wastage.
11798 ISOLATE->compilation_cache()->Clear();
11799 }
11800
11801 // Force code movement.
11802 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
11803
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011804 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11805
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011806 CHECK_LE(kIterations, saw_bar);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011807 CHECK_LT(0, move_events);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011808
11809 code_map = NULL;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011810 jitcode_line_info = NULL;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011811 }
11812
11813 isolate->Exit();
11814 isolate->Dispose();
11815
11816 // Do this in a new isolate.
11817 isolate = v8::Isolate::New();
11818 isolate->Enter();
11819
11820 // Verify that we get callbacks for existing code objects when we
11821 // request enumeration of existing code.
11822 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011823 v8::HandleScope scope(isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011824 LocalContext env;
11825 CompileRun(script);
11826
11827 // Now get code through initial iteration.
11828 i::HashMap code(MatchPointers);
11829 code_map = &code;
11830
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011831 i::HashMap lineinfo(MatchPointers);
11832 jitcode_line_info = &lineinfo;
11833
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011834 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
11835 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
11836
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011837 jitcode_line_info = NULL;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011838 // We expect that we got some events. Note that if we could get code removal
11839 // notifications, we could compare two collections, one created by listening
11840 // from the time of creation of an isolate, and the other by subscribing
11841 // with EnumExisting.
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000011842 CHECK_LT(0, code.occupancy());
11843
11844 code_map = NULL;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011845 }
11846
11847 isolate->Exit();
11848 isolate->Dispose();
11849}
11850
11851
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011852static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
11853
11854
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011855THREADED_TEST(ExternalAllocatedMemory) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011856 v8::HandleScope outer(v8::Isolate::GetCurrent());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011857 v8::Persistent<Context> env(Context::New());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011858 CHECK(!env.IsEmpty());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011859 const intptr_t kSize = 1024*1024;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011860 v8::Isolate* isolate = env->GetIsolate();
11861 CHECK_EQ(cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011862 cast(kSize));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011863 CHECK_EQ(cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000011864 cast(0));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011865}
11866
11867
11868THREADED_TEST(DisposeEnteredContext) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011869 LocalContext outer;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011870 v8::HandleScope scope(outer->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011871 { v8::Persistent<v8::Context> inner = v8::Context::New();
11872 inner->Enter();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011873 inner.Dispose(inner->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011874 inner.Clear();
11875 inner->Exit();
11876 }
11877}
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011878
11879
11880// Regression test for issue 54, object templates with internal fields
11881// but no accessors or interceptors did not get their internal field
11882// count set on instances.
11883THREADED_TEST(Regress54) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011884 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011885 v8::Isolate* isolate = context->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011886 v8::HandleScope outer(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011887 static v8::Persistent<v8::ObjectTemplate> templ;
11888 if (templ.IsEmpty()) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011889 v8::HandleScope inner(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011890 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
11891 local->SetInternalFieldCount(1);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000011892 templ =
11893 v8::Persistent<v8::ObjectTemplate>::New(isolate, inner.Close(local));
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011894 }
11895 v8::Handle<v8::Object> result = templ->NewInstance();
11896 CHECK_EQ(1, result->InternalFieldCount());
11897}
11898
11899
11900// If part of the threaded tests, this test makes ThreadingTest fail
11901// on mac.
11902TEST(CatchStackOverflow) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011903 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011904 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011905 v8::TryCatch try_catch;
11906 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
11907 "function f() {"
11908 " return f();"
11909 "}"
11910 ""
11911 "f();"));
11912 v8::Handle<v8::Value> result = script->Run();
11913 CHECK(result.IsEmpty());
11914}
11915
11916
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011917static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
11918 const char* resource_name,
11919 int line_offset) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011920 v8::HandleScope scope(v8::Isolate::GetCurrent());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011921 v8::TryCatch try_catch;
11922 v8::Handle<v8::Value> result = script->Run();
11923 CHECK(result.IsEmpty());
11924 CHECK(try_catch.HasCaught());
11925 v8::Handle<v8::Message> message = try_catch.Message();
11926 CHECK(!message.IsEmpty());
11927 CHECK_EQ(10 + line_offset, message->GetLineNumber());
11928 CHECK_EQ(91, message->GetStartPosition());
11929 CHECK_EQ(92, message->GetEndPosition());
11930 CHECK_EQ(2, message->GetStartColumn());
11931 CHECK_EQ(3, message->GetEndColumn());
11932 v8::String::AsciiValue line(message->GetSourceLine());
11933 CHECK_EQ(" throw 'nirk';", *line);
11934 v8::String::AsciiValue name(message->GetScriptResourceName());
11935 CHECK_EQ(resource_name, *name);
11936}
11937
11938
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011939THREADED_TEST(TryCatchSourceInfo) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011940 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011941 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011942 v8::Handle<v8::String> source = v8::String::New(
11943 "function Foo() {\n"
11944 " return Bar();\n"
11945 "}\n"
11946 "\n"
11947 "function Bar() {\n"
11948 " return Baz();\n"
11949 "}\n"
11950 "\n"
11951 "function Baz() {\n"
11952 " throw 'nirk';\n"
11953 "}\n"
11954 "\n"
11955 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011956
11957 const char* resource_name;
11958 v8::Handle<v8::Script> script;
11959 resource_name = "test.js";
11960 script = v8::Script::Compile(source, v8::String::New(resource_name));
11961 CheckTryCatchSourceInfo(script, resource_name, 0);
11962
11963 resource_name = "test1.js";
11964 v8::ScriptOrigin origin1(v8::String::New(resource_name));
11965 script = v8::Script::Compile(source, &origin1);
11966 CheckTryCatchSourceInfo(script, resource_name, 0);
11967
11968 resource_name = "test2.js";
11969 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
11970 script = v8::Script::Compile(source, &origin2);
11971 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011972}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011973
11974
11975THREADED_TEST(CompilationCache) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011976 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000011977 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011978 v8::Handle<v8::String> source0 = v8::String::New("1234");
11979 v8::Handle<v8::String> source1 = v8::String::New("1234");
11980 v8::Handle<v8::Script> script0 =
11981 v8::Script::Compile(source0, v8::String::New("test.js"));
11982 v8::Handle<v8::Script> script1 =
11983 v8::Script::Compile(source1, v8::String::New("test.js"));
11984 v8::Handle<v8::Script> script2 =
11985 v8::Script::Compile(source0); // different origin
11986 CHECK_EQ(1234, script0->Run()->Int32Value());
11987 CHECK_EQ(1234, script1->Run()->Int32Value());
11988 CHECK_EQ(1234, script2->Run()->Int32Value());
11989}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011990
11991
11992static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
11993 ApiTestFuzzer::Fuzz();
11994 return v8_num(42);
11995}
11996
11997
11998THREADED_TEST(CallbackFunctionName) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000011999 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012000 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000012001 Local<ObjectTemplate> t = ObjectTemplate::New();
12002 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
12003 context->Global()->Set(v8_str("obj"), t->NewInstance());
12004 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12005 CHECK(value->IsString());
12006 v8::String::AsciiValue name(value);
12007 CHECK_EQ("asdf", *name);
12008}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012009
12010
12011THREADED_TEST(DateAccess) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012012 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012013 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012014 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
12015 CHECK(date->IsDate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012016 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012017}
12018
12019
12020void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012021 v8::Handle<v8::Object> obj = val.As<v8::Object>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012022 v8::Handle<v8::Array> props = obj->GetPropertyNames();
12023 CHECK_EQ(elmc, props->Length());
12024 for (int i = 0; i < elmc; i++) {
12025 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
12026 CHECK_EQ(elmv[i], *elm);
12027 }
12028}
12029
12030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012031void CheckOwnProperties(v8::Handle<v8::Value> val,
12032 int elmc,
12033 const char* elmv[]) {
12034 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12035 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12036 CHECK_EQ(elmc, props->Length());
12037 for (int i = 0; i < elmc; i++) {
12038 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
12039 CHECK_EQ(elmv[i], *elm);
12040 }
12041}
12042
12043
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012044THREADED_TEST(PropertyEnumeration) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012045 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012046 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012047 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
12048 "var result = [];"
12049 "result[0] = {};"
12050 "result[1] = {a: 1, b: 2};"
12051 "result[2] = [1, 2, 3];"
12052 "var proto = {x: 1, y: 2, z: 3};"
12053 "var x = { __proto__: proto, w: 0, z: 1 };"
12054 "result[3] = x;"
12055 "result;"))->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012056 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012057 CHECK_EQ(4, elms->Length());
12058 int elmc0 = 0;
12059 const char** elmv0 = NULL;
12060 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012061 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012062 int elmc1 = 2;
12063 const char* elmv1[] = {"a", "b"};
12064 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012065 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012066 int elmc2 = 3;
12067 const char* elmv2[] = {"0", "1", "2"};
12068 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012069 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012070 int elmc3 = 4;
12071 const char* elmv3[] = {"w", "z", "x", "y"};
12072 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012073 int elmc4 = 2;
12074 const char* elmv4[] = {"w", "z"};
12075 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012076}
ager@chromium.org870a0b62008-11-04 11:43:05 +000012077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012078THREADED_TEST(PropertyEnumeration2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012080 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012081 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
12082 "var result = [];"
12083 "result[0] = {};"
12084 "result[1] = {a: 1, b: 2};"
12085 "result[2] = [1, 2, 3];"
12086 "var proto = {x: 1, y: 2, z: 3};"
12087 "var x = { __proto__: proto, w: 0, z: 1 };"
12088 "result[3] = x;"
12089 "result;"))->Run();
12090 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12091 CHECK_EQ(4, elms->Length());
12092 int elmc0 = 0;
12093 const char** elmv0 = NULL;
12094 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
12095
12096 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
12097 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12098 CHECK_EQ(0, props->Length());
12099 for (uint32_t i = 0; i < props->Length(); i++) {
12100 printf("p[%d]\n", i);
12101 }
12102}
ager@chromium.org870a0b62008-11-04 11:43:05 +000012103
ager@chromium.org870a0b62008-11-04 11:43:05 +000012104static bool NamedSetAccessBlocker(Local<v8::Object> obj,
12105 Local<Value> name,
12106 v8::AccessType type,
12107 Local<Value> data) {
12108 return type != v8::ACCESS_SET;
12109}
12110
12111
12112static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
12113 uint32_t key,
12114 v8::AccessType type,
12115 Local<Value> data) {
12116 return type != v8::ACCESS_SET;
12117}
12118
12119
12120THREADED_TEST(DisableAccessChecksWhileConfiguring) {
ager@chromium.org870a0b62008-11-04 11:43:05 +000012121 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012122 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +000012123 Local<ObjectTemplate> templ = ObjectTemplate::New();
12124 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12125 IndexedSetAccessBlocker);
12126 templ->Set(v8_str("x"), v8::True());
12127 Local<v8::Object> instance = templ->NewInstance();
12128 context->Global()->Set(v8_str("obj"), instance);
12129 Local<Value> value = CompileRun("obj.x");
12130 CHECK(value->BooleanValue());
12131}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012132
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012133
ager@chromium.org32912102009-01-16 10:38:43 +000012134static bool NamedGetAccessBlocker(Local<v8::Object> obj,
12135 Local<Value> name,
12136 v8::AccessType type,
12137 Local<Value> data) {
12138 return false;
12139}
12140
12141
12142static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
12143 uint32_t key,
12144 v8::AccessType type,
12145 Local<Value> data) {
12146 return false;
12147}
12148
12149
12150
12151THREADED_TEST(AccessChecksReenabledCorrectly) {
ager@chromium.org32912102009-01-16 10:38:43 +000012152 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012153 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org32912102009-01-16 10:38:43 +000012154 Local<ObjectTemplate> templ = ObjectTemplate::New();
12155 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12156 IndexedGetAccessBlocker);
12157 templ->Set(v8_str("a"), v8_str("a"));
12158 // Add more than 8 (see kMaxFastProperties) properties
12159 // so that the constructor will force copying map.
12160 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012161 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +000012162 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012163 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +000012164 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012165 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +000012166 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012167 buf[2] = k;
12168 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +000012169 templ->Set(v8_str(buf), v8::Number::New(k));
12170 }
12171 }
12172 }
12173
12174 Local<v8::Object> instance_1 = templ->NewInstance();
12175 context->Global()->Set(v8_str("obj_1"), instance_1);
12176
12177 Local<Value> value_1 = CompileRun("obj_1.a");
12178 CHECK(value_1->IsUndefined());
12179
12180 Local<v8::Object> instance_2 = templ->NewInstance();
12181 context->Global()->Set(v8_str("obj_2"), instance_2);
12182
12183 Local<Value> value_2 = CompileRun("obj_2.a");
12184 CHECK(value_2->IsUndefined());
12185}
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012186
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012187
ager@chromium.org8bb60582008-12-11 12:02:20 +000012188// This tests that access check information remains on the global
12189// object template when creating contexts.
12190THREADED_TEST(AccessControlRepeatedContextCreation) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012191 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
ager@chromium.org8bb60582008-12-11 12:02:20 +000012192 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12193 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12194 IndexedSetAccessBlocker);
12195 i::Handle<i::ObjectTemplateInfo> internal_template =
12196 v8::Utils::OpenHandle(*global_template);
12197 CHECK(!internal_template->constructor()->IsUndefined());
12198 i::Handle<i::FunctionTemplateInfo> constructor(
12199 i::FunctionTemplateInfo::cast(internal_template->constructor()));
12200 CHECK(!constructor->access_check_info()->IsUndefined());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012201 v8::Persistent<Context> context0(Context::New(NULL, global_template));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012202 CHECK(!context0.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +000012203 CHECK(!constructor->access_check_info()->IsUndefined());
12204}
12205
12206
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012207THREADED_TEST(TurnOnAccessCheck) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012208 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012209
12210 // Create an environment with access check to the global object disabled by
12211 // default.
12212 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12213 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12214 IndexedGetAccessBlocker,
12215 v8::Handle<v8::Value>(),
12216 false);
12217 v8::Persistent<Context> context = Context::New(NULL, global_template);
12218 Context::Scope context_scope(context);
12219
12220 // Set up a property and a number of functions.
12221 context->Global()->Set(v8_str("a"), v8_num(1));
12222 CompileRun("function f1() {return a;}"
12223 "function f2() {return a;}"
12224 "function g1() {return h();}"
12225 "function g2() {return h();}"
12226 "function h() {return 1;}");
12227 Local<Function> f1 =
12228 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12229 Local<Function> f2 =
12230 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12231 Local<Function> g1 =
12232 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12233 Local<Function> g2 =
12234 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12235 Local<Function> h =
12236 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12237
12238 // Get the global object.
12239 v8::Handle<v8::Object> global = context->Global();
12240
12241 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12242 // uses the runtime system to retreive property a whereas f2 uses global load
12243 // inline cache.
12244 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12245 for (int i = 0; i < 4; i++) {
12246 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12247 }
12248
12249 // Same for g1 and g2.
12250 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12251 for (int i = 0; i < 4; i++) {
12252 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12253 }
12254
12255 // Detach the global and turn on access check.
12256 context->DetachGlobal();
12257 context->Global()->TurnOnAccessCheck();
12258
12259 // Failing access check to property get results in undefined.
12260 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12261 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12262
12263 // Failing access check to function call results in exception.
12264 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12265 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12266
12267 // No failing access check when just returning a constant.
12268 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12269}
12270
12271
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012272static const char* kPropertyA = "a";
12273static const char* kPropertyH = "h";
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012274
12275static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
12276 Local<Value> name,
12277 v8::AccessType type,
12278 Local<Value> data) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012279 if (!name->IsString()) return false;
12280 i::Handle<i::String> name_handle =
12281 v8::Utils::OpenHandle(String::Cast(*name));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012282 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
12283 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012284}
12285
12286
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012287THREADED_TEST(TurnOnAccessCheckAndRecompile) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012288 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012289
12290 // Create an environment with access check to the global object disabled by
12291 // default. When the registered access checker will block access to properties
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012292 // a and h.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012293 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
12294 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
12295 IndexedGetAccessBlocker,
12296 v8::Handle<v8::Value>(),
12297 false);
12298 v8::Persistent<Context> context = Context::New(NULL, global_template);
12299 Context::Scope context_scope(context);
12300
12301 // Set up a property and a number of functions.
12302 context->Global()->Set(v8_str("a"), v8_num(1));
12303 static const char* source = "function f1() {return a;}"
12304 "function f2() {return a;}"
12305 "function g1() {return h();}"
12306 "function g2() {return h();}"
12307 "function h() {return 1;}";
12308
12309 CompileRun(source);
12310 Local<Function> f1;
12311 Local<Function> f2;
12312 Local<Function> g1;
12313 Local<Function> g2;
12314 Local<Function> h;
12315 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12316 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12317 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12318 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12319 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12320
12321 // Get the global object.
12322 v8::Handle<v8::Object> global = context->Global();
12323
12324 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12325 // uses the runtime system to retreive property a whereas f2 uses global load
12326 // inline cache.
12327 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12328 for (int i = 0; i < 4; i++) {
12329 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12330 }
12331
12332 // Same for g1 and g2.
12333 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12334 for (int i = 0; i < 4; i++) {
12335 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12336 }
12337
12338 // Detach the global and turn on access check now blocking access to property
12339 // a and function h.
12340 context->DetachGlobal();
12341 context->Global()->TurnOnAccessCheck();
12342
12343 // Failing access check to property get results in undefined.
12344 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12345 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12346
12347 // Failing access check to function call results in exception.
12348 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12349 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12350
12351 // No failing access check when just returning a constant.
12352 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12353
12354 // Now compile the source again. And get the newly compiled functions, except
12355 // for h for which access is blocked.
12356 CompileRun(source);
12357 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12358 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12359 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12360 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12361 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
12362
12363 // Failing access check to property get results in undefined.
12364 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
12365 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
12366
12367 // Failing access check to function call results in exception.
12368 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12369 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12370}
12371
12372
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012373// This test verifies that pre-compilation (aka preparsing) can be called
12374// without initializing the whole VM. Thus we cannot run this test in a
12375// multi-threaded setup.
12376TEST(PreCompile) {
12377 // TODO(155): This test would break without the initialization of V8. This is
12378 // a workaround for now to make this test not fail.
12379 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012380 const char* script = "function foo(a) { return a+1; }";
12381 v8::ScriptData* sd =
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012382 v8::ScriptData::PreCompile(script, i::StrLength(script));
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012383 CHECK_NE(sd->Length(), 0);
12384 CHECK_NE(sd->Data(), NULL);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012385 CHECK(!sd->HasError());
12386 delete sd;
12387}
12388
12389
12390TEST(PreCompileWithError) {
12391 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012392 const char* script = "function foo(a) { return 1 * * 2; }";
12393 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012394 v8::ScriptData::PreCompile(script, i::StrLength(script));
12395 CHECK(sd->HasError());
12396 delete sd;
12397}
12398
12399
12400TEST(Regress31661) {
12401 v8::V8::Initialize();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012402 const char* script = " The Definintive Guide";
12403 v8::ScriptData* sd =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000012404 v8::ScriptData::PreCompile(script, i::StrLength(script));
12405 CHECK(sd->HasError());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012406 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012407}
12408
12409
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012410// Tests that ScriptData can be serialized and deserialized.
12411TEST(PreCompileSerialization) {
12412 v8::V8::Initialize();
12413 const char* script = "function foo(a) { return a+1; }";
12414 v8::ScriptData* sd =
12415 v8::ScriptData::PreCompile(script, i::StrLength(script));
12416
12417 // Serialize.
12418 int serialized_data_length = sd->Length();
12419 char* serialized_data = i::NewArray<char>(serialized_data_length);
12420 memcpy(serialized_data, sd->Data(), serialized_data_length);
12421
12422 // Deserialize.
12423 v8::ScriptData* deserialized_sd =
12424 v8::ScriptData::New(serialized_data, serialized_data_length);
12425
12426 // Verify that the original is the same as the deserialized.
12427 CHECK_EQ(sd->Length(), deserialized_sd->Length());
12428 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
12429 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
12430
12431 delete sd;
12432 delete deserialized_sd;
12433}
12434
12435
12436// Attempts to deserialize bad data.
12437TEST(PreCompileDeserializationError) {
12438 v8::V8::Initialize();
12439 const char* data = "DONT CARE";
12440 int invalid_size = 3;
12441 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
12442
12443 CHECK_EQ(0, sd->Length());
12444
12445 delete sd;
12446}
12447
12448
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012449// Attempts to deserialize bad data.
12450TEST(PreCompileInvalidPreparseDataError) {
12451 v8::V8::Initialize();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012452 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012453 v8::HandleScope scope(context->GetIsolate());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012454
12455 const char* script = "function foo(){ return 5;}\n"
12456 "function bar(){ return 6 + 7;} foo();";
12457 v8::ScriptData* sd =
12458 v8::ScriptData::PreCompile(script, i::StrLength(script));
12459 CHECK(!sd->HasError());
12460 // ScriptDataImpl private implementation details
ager@chromium.orgbeb25712010-11-29 08:02:25 +000012461 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +000012462 const int kFunctionEntrySize = i::FunctionEntry::kSize;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012463 const int kFunctionEntryStartOffset = 0;
12464 const int kFunctionEntryEndOffset = 1;
12465 unsigned* sd_data =
12466 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012467
12468 // Overwrite function bar's end position with 0.
12469 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
12470 v8::TryCatch try_catch;
12471
12472 Local<String> source = String::New(script);
12473 Local<Script> compiled_script = Script::New(source, NULL, sd);
12474 CHECK(try_catch.HasCaught());
12475 String::AsciiValue exception_value(try_catch.Message()->Get());
12476 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
12477 *exception_value);
12478
12479 try_catch.Reset();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012480
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012481 // Overwrite function bar's start position with 200. The function entry
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012482 // will not be found when searching for it by position and we should fall
12483 // back on eager compilation.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000012484 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
12485 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012486 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
12487 200;
12488 compiled_script = Script::New(source, NULL, sd);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000012489 CHECK(!try_catch.HasCaught());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +000012490
12491 delete sd;
12492}
12493
12494
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012495// Verifies that the Handle<String> and const char* versions of the API produce
12496// the same results (at least for one trivial case).
12497TEST(PreCompileAPIVariationsAreSame) {
12498 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012499 v8::HandleScope scope(v8::Isolate::GetCurrent());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012500
12501 const char* cstring = "function foo(a) { return a+1; }";
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012502
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012503 v8::ScriptData* sd_from_cstring =
12504 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
12505
12506 TestAsciiResource* resource = new TestAsciiResource(cstring);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012507 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012508 v8::String::NewExternal(resource));
12509
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012510 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
12511 v8::String::New(cstring));
12512
12513 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012514 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012515 sd_from_external_string->Data(),
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012516 sd_from_cstring->Length()));
12517
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012518 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
12519 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
12520 sd_from_string->Data(),
12521 sd_from_cstring->Length()));
12522
12523
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012524 delete sd_from_cstring;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012525 delete sd_from_external_string;
12526 delete sd_from_string;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000012527}
12528
12529
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012530// This tests that we do not allow dictionary load/call inline caches
12531// to use functions that have not yet been compiled. The potential
12532// problem of loading a function that has not yet been compiled can
12533// arise because we share code between contexts via the compilation
12534// cache.
12535THREADED_TEST(DictionaryICLoadedFunction) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012536 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012537 // Test LoadIC.
12538 for (int i = 0; i < 2; i++) {
12539 LocalContext context;
12540 context->Global()->Set(v8_str("tmp"), v8::True());
12541 context->Global()->Delete(v8_str("tmp"));
12542 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12543 }
12544 // Test CallIC.
12545 for (int i = 0; i < 2; i++) {
12546 LocalContext context;
12547 context->Global()->Set(v8_str("tmp"), v8::True());
12548 context->Global()->Delete(v8_str("tmp"));
12549 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12550 }
12551}
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012552
12553
12554// Test that cross-context new calls use the context of the callee to
12555// create the new JavaScript object.
12556THREADED_TEST(CrossContextNew) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012557 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012558 v8::Persistent<Context> context0 = Context::New();
12559 v8::Persistent<Context> context1 = Context::New();
12560
12561 // Allow cross-domain access.
12562 Local<String> token = v8_str("<security token>");
12563 context0->SetSecurityToken(token);
12564 context1->SetSecurityToken(token);
12565
12566 // Set an 'x' property on the Object prototype and define a
12567 // constructor function in context0.
12568 context0->Enter();
12569 CompileRun("Object.prototype.x = 42; function C() {};");
12570 context0->Exit();
12571
12572 // Call the constructor function from context0 and check that the
12573 // result has the 'x' property.
12574 context1->Enter();
12575 context1->Global()->Set(v8_str("other"), context0->Global());
12576 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12577 CHECK(value->IsInt32());
12578 CHECK_EQ(42, value->Int32Value());
12579 context1->Exit();
12580
12581 // Dispose the contexts to allow them to be garbage collected.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000012582 context0.Dispose(context0->GetIsolate());
12583 context1.Dispose(context1->GetIsolate());
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012584}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012585
12586
12587class RegExpInterruptTest {
12588 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012589 RegExpInterruptTest() : block_(NULL) {}
12590 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012591 void RunTest() {
12592 block_ = i::OS::CreateSemaphore(0);
12593 gc_count_ = 0;
12594 gc_during_regexp_ = 0;
12595 regexp_success_ = false;
12596 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012597 GCThread gc_thread(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012598 gc_thread.Start();
12599 v8::Locker::StartPreemption(1);
12600
12601 LongRunningRegExp();
12602 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012603 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012604 gc_thread.Join();
12605 }
12606 v8::Locker::StopPreemption();
12607 CHECK(regexp_success_);
12608 CHECK(gc_success_);
12609 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012610
ager@chromium.org381abbb2009-02-25 13:23:22 +000012611 private:
12612 // Number of garbage collections required.
12613 static const int kRequiredGCs = 5;
12614
12615 class GCThread : public i::Thread {
12616 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012617 explicit GCThread(RegExpInterruptTest* test)
12618 : Thread("GCThread"), test_(test) {}
ager@chromium.org381abbb2009-02-25 13:23:22 +000012619 virtual void Run() {
12620 test_->CollectGarbage();
12621 }
12622 private:
12623 RegExpInterruptTest* test_;
12624 };
12625
12626 void CollectGarbage() {
12627 block_->Wait();
12628 while (gc_during_regexp_ < kRequiredGCs) {
12629 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012630 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012631 // TODO(lrn): Perhaps create some garbage before collecting.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012632 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012633 gc_count_++;
12634 }
12635 i::OS::Sleep(1);
12636 }
12637 gc_success_ = true;
12638 }
12639
12640 void LongRunningRegExp() {
12641 block_->Signal(); // Enable garbage collection thread on next preemption.
12642 int rounds = 0;
12643 while (gc_during_regexp_ < kRequiredGCs) {
12644 int gc_before = gc_count_;
12645 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012646 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012647 const char* c_source =
12648 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12649 ".exec('aaaaaaaaaaaaaaab') === null";
12650 Local<String> source = String::New(c_source);
12651 Local<Script> script = Script::Compile(source);
12652 Local<Value> result = script->Run();
12653 if (!result->BooleanValue()) {
12654 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
12655 return;
12656 }
12657 }
12658 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012659 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +000012660 const char* c_source =
12661 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
12662 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
12663 Local<String> source = String::New(c_source);
12664 Local<Script> script = Script::Compile(source);
12665 Local<Value> result = script->Run();
12666 if (!result->BooleanValue()) {
12667 gc_during_regexp_ = kRequiredGCs;
12668 return;
12669 }
12670 }
12671 int gc_after = gc_count_;
12672 gc_during_regexp_ += gc_after - gc_before;
12673 rounds++;
12674 i::OS::Sleep(1);
12675 }
12676 regexp_success_ = true;
12677 }
12678
12679 i::Semaphore* block_;
12680 int gc_count_;
12681 int gc_during_regexp_;
12682 bool regexp_success_;
12683 bool gc_success_;
12684};
12685
12686
12687// Test that a regular expression execution can be interrupted and
12688// survive a garbage collection.
12689TEST(RegExpInterruption) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012690 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012691 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012692 v8::HandleScope scope(CcTest::default_isolate());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012693 Local<Context> local_env;
12694 {
12695 LocalContext env;
12696 local_env = env.local();
12697 }
12698
12699 // Local context should still be live.
12700 CHECK(!local_env.IsEmpty());
12701 local_env->Enter();
12702
12703 // Should complete without problems.
12704 RegExpInterruptTest().RunTest();
12705
12706 local_env->Exit();
12707}
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012708
12709
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012710class ApplyInterruptTest {
12711 public:
12712 ApplyInterruptTest() : block_(NULL) {}
12713 ~ApplyInterruptTest() { delete block_; }
12714 void RunTest() {
12715 block_ = i::OS::CreateSemaphore(0);
12716 gc_count_ = 0;
12717 gc_during_apply_ = 0;
12718 apply_success_ = false;
12719 gc_success_ = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012720 GCThread gc_thread(this);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012721 gc_thread.Start();
12722 v8::Locker::StartPreemption(1);
12723
12724 LongRunningApply();
12725 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012726 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012727 gc_thread.Join();
12728 }
12729 v8::Locker::StopPreemption();
12730 CHECK(apply_success_);
12731 CHECK(gc_success_);
12732 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000012733
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012734 private:
12735 // Number of garbage collections required.
12736 static const int kRequiredGCs = 2;
12737
12738 class GCThread : public i::Thread {
12739 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012740 explicit GCThread(ApplyInterruptTest* test)
12741 : Thread("GCThread"), test_(test) {}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012742 virtual void Run() {
12743 test_->CollectGarbage();
12744 }
12745 private:
12746 ApplyInterruptTest* test_;
12747 };
12748
12749 void CollectGarbage() {
12750 block_->Wait();
12751 while (gc_during_apply_ < kRequiredGCs) {
12752 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012753 v8::Locker lock(CcTest::default_isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012754 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012755 gc_count_++;
12756 }
12757 i::OS::Sleep(1);
12758 }
12759 gc_success_ = true;
12760 }
12761
12762 void LongRunningApply() {
12763 block_->Signal();
12764 int rounds = 0;
12765 while (gc_during_apply_ < kRequiredGCs) {
12766 int gc_before = gc_count_;
12767 {
12768 const char* c_source =
12769 "function do_very_little(bar) {"
12770 " this.foo = bar;"
12771 "}"
12772 "for (var i = 0; i < 100000; i++) {"
12773 " do_very_little.apply(this, ['bar']);"
12774 "}";
12775 Local<String> source = String::New(c_source);
12776 Local<Script> script = Script::Compile(source);
12777 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000012778 // Check that no exception was thrown.
12779 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012780 }
12781 int gc_after = gc_count_;
12782 gc_during_apply_ += gc_after - gc_before;
12783 rounds++;
12784 }
12785 apply_success_ = true;
12786 }
12787
12788 i::Semaphore* block_;
12789 int gc_count_;
12790 int gc_during_apply_;
12791 bool apply_success_;
12792 bool gc_success_;
12793};
12794
12795
12796// Test that nothing bad happens if we get a preemption just when we were
12797// about to do an apply().
12798TEST(ApplyInterruption) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012799 v8::Locker lock(CcTest::default_isolate());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012800 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012801 v8::HandleScope scope(CcTest::default_isolate());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012802 Local<Context> local_env;
12803 {
12804 LocalContext env;
12805 local_env = env.local();
12806 }
12807
12808 // Local context should still be live.
12809 CHECK(!local_env.IsEmpty());
12810 local_env->Enter();
12811
12812 // Should complete without problems.
12813 ApplyInterruptTest().RunTest();
12814
12815 local_env->Exit();
12816}
12817
12818
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012819// Verify that we can clone an object
12820TEST(ObjectClone) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012821 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012822 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012823
12824 const char* sample =
12825 "var rv = {};" \
12826 "rv.alpha = 'hello';" \
12827 "rv.beta = 123;" \
12828 "rv;";
12829
12830 // Create an object, verify basics.
12831 Local<Value> val = CompileRun(sample);
12832 CHECK(val->IsObject());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012833 Local<v8::Object> obj = val.As<v8::Object>();
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012834 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12835
12836 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
12837 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12838 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
12839
12840 // Clone it.
12841 Local<v8::Object> clone = obj->Clone();
12842 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
12843 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
12844 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
12845
12846 // Set a property on the clone, verify each object.
12847 clone->Set(v8_str("beta"), v8::Integer::New(456));
12848 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
12849 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
12850}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012851
12852
ager@chromium.org5ec48922009-05-05 07:25:34 +000012853class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
12854 public:
12855 explicit AsciiVectorResource(i::Vector<const char> vector)
12856 : data_(vector) {}
12857 virtual ~AsciiVectorResource() {}
12858 virtual size_t length() const { return data_.length(); }
12859 virtual const char* data() const { return data_.start(); }
12860 private:
12861 i::Vector<const char> data_;
12862};
12863
12864
12865class UC16VectorResource : public v8::String::ExternalStringResource {
12866 public:
12867 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12868 : data_(vector) {}
12869 virtual ~UC16VectorResource() {}
12870 virtual size_t length() const { return data_.length(); }
12871 virtual const i::uc16* data() const { return data_.start(); }
12872 private:
12873 i::Vector<const i::uc16> data_;
12874};
12875
12876
12877static void MorphAString(i::String* string,
12878 AsciiVectorResource* ascii_resource,
12879 UC16VectorResource* uc16_resource) {
12880 CHECK(i::StringShape(string).IsExternal());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012881 if (string->IsOneByteRepresentation()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012882 // Check old map is not internalized or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012883 CHECK(string->map() == HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012884 // Morph external string to be TwoByte string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 string->set_map(HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012886 i::ExternalTwoByteString* morphed =
12887 i::ExternalTwoByteString::cast(string);
12888 morphed->set_resource(uc16_resource);
12889 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012890 // Check old map is not internalized or long.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 CHECK(string->map() == HEAP->external_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012892 // Morph external string to be ASCII string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893 string->set_map(HEAP->external_ascii_string_map());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012894 i::ExternalAsciiString* morphed =
12895 i::ExternalAsciiString::cast(string);
12896 morphed->set_resource(ascii_resource);
12897 }
12898}
12899
12900
12901// Test that we can still flatten a string if the components it is built up
12902// from have been turned into 16 bit strings in the mean time.
12903THREADED_TEST(MorphCompositeStringTest) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012904 char utf_buffer[129];
ager@chromium.org5ec48922009-05-05 07:25:34 +000012905 const char* c_string = "Now is the time for all good men"
12906 " to come to the aid of the party";
12907 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
12908 {
ager@chromium.org5ec48922009-05-05 07:25:34 +000012909 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012910 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org5ec48922009-05-05 07:25:34 +000012911 AsciiVectorResource ascii_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012912 i::Vector<const char>(c_string, i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012913 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012914 i::Vector<const uint16_t>(two_byte_string,
12915 i::StrLength(c_string)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012916
12917 Local<String> lhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012919 Local<String> rhs(v8::Utils::ToLocal(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012920 FACTORY->NewExternalStringFromAscii(&ascii_resource)));
ager@chromium.org5ec48922009-05-05 07:25:34 +000012921
12922 env->Global()->Set(v8_str("lhs"), lhs);
12923 env->Global()->Set(v8_str("rhs"), rhs);
12924
12925 CompileRun(
12926 "var cons = lhs + rhs;"
12927 "var slice = lhs.substring(1, lhs.length - 1);"
12928 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
12929
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012930 CHECK(lhs->IsOneByte());
12931 CHECK(rhs->IsOneByte());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012932
ager@chromium.org5ec48922009-05-05 07:25:34 +000012933 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
12934 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
12935
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012936 // This should UTF-8 without flattening, since everything is ASCII.
12937 Handle<String> cons = v8_compile("cons")->Run().As<String>();
12938 CHECK_EQ(128, cons->Utf8Length());
12939 int nchars = -1;
12940 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
12941 CHECK_EQ(128, nchars);
12942 CHECK_EQ(0, strcmp(
12943 utf_buffer,
12944 "Now is the time for all good men to come to the aid of the party"
12945 "Now is the time for all good men to come to the aid of the party"));
12946
ager@chromium.org5ec48922009-05-05 07:25:34 +000012947 // Now do some stuff to make sure the strings are flattened, etc.
12948 CompileRun(
12949 "/[^a-z]/.test(cons);"
12950 "/[^a-z]/.test(slice);"
12951 "/[^a-z]/.test(slice_on_cons);");
12952 const char* expected_cons =
12953 "Now is the time for all good men to come to the aid of the party"
12954 "Now is the time for all good men to come to the aid of the party";
12955 const char* expected_slice =
12956 "ow is the time for all good men to come to the aid of the part";
12957 const char* expected_slice_on_cons =
12958 "ow is the time for all good men to come to the aid of the party"
12959 "Now is the time for all good men to come to the aid of the part";
12960 CHECK_EQ(String::New(expected_cons),
12961 env->Global()->Get(v8_str("cons")));
12962 CHECK_EQ(String::New(expected_slice),
12963 env->Global()->Get(v8_str("slice")));
12964 CHECK_EQ(String::New(expected_slice_on_cons),
12965 env->Global()->Get(v8_str("slice_on_cons")));
12966 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012967 i::DeleteArray(two_byte_string);
ager@chromium.org5ec48922009-05-05 07:25:34 +000012968}
12969
12970
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012971TEST(CompileExternalTwoByteSource) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012972 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000012973 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012974
12975 // This is a very short list of sources, which currently is to check for a
12976 // regression caused by r2703.
12977 const char* ascii_sources[] = {
12978 "0.5",
12979 "-0.5", // This mainly testes PushBack in the Scanner.
12980 "--0.5", // This mainly testes PushBack in the Scanner.
12981 NULL
12982 };
12983
12984 // Compile the sources as external two byte strings.
12985 for (int i = 0; ascii_sources[i] != NULL; i++) {
12986 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
12987 UC16VectorResource uc16_resource(
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012988 i::Vector<const uint16_t>(two_byte_string,
12989 i::StrLength(ascii_sources[i])));
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012990 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
12991 v8::Script::Compile(source);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000012992 i::DeleteArray(two_byte_string);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000012993 }
12994}
12995
12996
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012997class RegExpStringModificationTest {
12998 public:
12999 RegExpStringModificationTest()
13000 : block_(i::OS::CreateSemaphore(0)),
13001 morphs_(0),
13002 morphs_during_regexp_(0),
13003 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
13004 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
13005 ~RegExpStringModificationTest() { delete block_; }
13006 void RunTest() {
13007 regexp_success_ = false;
13008 morph_success_ = false;
13009
13010 // Initialize the contents of two_byte_content_ to be a uc16 representation
13011 // of "aaaaaaaaaaaaaab".
13012 for (int i = 0; i < 14; i++) {
13013 two_byte_content_[i] = 'a';
13014 }
13015 two_byte_content_[14] = 'b';
13016
13017 // Create the input string for the regexp - the one we are going to change
13018 // properties of.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013020
13021 // Inject the input as a global variable.
13022 i::Handle<i::String> input_name =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013023 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013024 i::Isolate::Current()->native_context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025 *input_name,
13026 *input_,
13027 NONE,
13028 i::kNonStrictMode)->ToObjectChecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013029
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013030 MorphThread morph_thread(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013031 morph_thread.Start();
13032 v8::Locker::StartPreemption(1);
13033 LongRunningRegExp();
13034 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000013035 v8::Unlocker unlock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013036 morph_thread.Join();
13037 }
13038 v8::Locker::StopPreemption();
13039 CHECK(regexp_success_);
13040 CHECK(morph_success_);
13041 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013042
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000013043 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013044 // Number of string modifications required.
13045 static const int kRequiredModifications = 5;
13046 static const int kMaxModifications = 100;
13047
13048 class MorphThread : public i::Thread {
13049 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013050 explicit MorphThread(RegExpStringModificationTest* test)
13051 : Thread("MorphThread"), test_(test) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013052 virtual void Run() {
13053 test_->MorphString();
13054 }
13055 private:
13056 RegExpStringModificationTest* test_;
13057 };
13058
13059 void MorphString() {
13060 block_->Wait();
13061 while (morphs_during_regexp_ < kRequiredModifications &&
13062 morphs_ < kMaxModifications) {
13063 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000013064 v8::Locker lock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013065 // Swap string between ascii and two-byte representation.
13066 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +000013067 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013068 morphs_++;
13069 }
13070 i::OS::Sleep(1);
13071 }
13072 morph_success_ = true;
13073 }
13074
13075 void LongRunningRegExp() {
13076 block_->Signal(); // Enable morphing thread on next preemption.
13077 while (morphs_during_regexp_ < kRequiredModifications &&
13078 morphs_ < kMaxModifications) {
13079 int morphs_before = morphs_;
13080 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013081 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013082 // Match 15-30 "a"'s against 14 and a "b".
13083 const char* c_source =
13084 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
13085 ".exec(input) === null";
13086 Local<String> source = String::New(c_source);
13087 Local<Script> script = Script::Compile(source);
13088 Local<Value> result = script->Run();
13089 CHECK(result->IsTrue());
13090 }
13091 int morphs_after = morphs_;
13092 morphs_during_regexp_ += morphs_after - morphs_before;
13093 }
13094 regexp_success_ = true;
13095 }
13096
13097 i::uc16 two_byte_content_[15];
13098 i::Semaphore* block_;
13099 int morphs_;
13100 int morphs_during_regexp_;
13101 bool regexp_success_;
13102 bool morph_success_;
13103 i::Handle<i::String> input_;
13104 AsciiVectorResource ascii_resource_;
13105 UC16VectorResource uc16_resource_;
13106};
13107
13108
13109// Test that a regular expression execution can be interrupted and
13110// the string changed without failing.
13111TEST(RegExpStringModification) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000013112 v8::Locker lock(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013113 v8::V8::Initialize();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013114 v8::HandleScope scope(CcTest::default_isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013115 Local<Context> local_env;
13116 {
13117 LocalContext env;
13118 local_env = env.local();
13119 }
13120
13121 // Local context should still be live.
13122 CHECK(!local_env.IsEmpty());
13123 local_env->Enter();
13124
13125 // Should complete without problems.
13126 RegExpStringModificationTest().RunTest();
13127
13128 local_env->Exit();
13129}
13130
13131
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013132// Test that we cannot set a property on the global object if there
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013133// is a read-only property in the prototype chain.
13134TEST(ReadOnlyPropertyInGlobalProto) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013135 i::FLAG_es5_readonly = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013136 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013137 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13138 LocalContext context(0, templ);
13139 v8::Handle<v8::Object> global = context->Global();
13140 v8::Handle<v8::Object> global_proto =
13141 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13142 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
13143 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
13144 // Check without 'eval' or 'with'.
13145 v8::Handle<v8::Value> res =
13146 CompileRun("function f() { x = 42; return x; }; f()");
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013147 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013148 // Check with 'eval'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013149 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13150 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013151 // Check with 'with'.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013152 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13153 CHECK_EQ(v8::Integer::New(0), res);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013154}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013155
13156static int force_set_set_count = 0;
13157static int force_set_get_count = 0;
13158bool pass_on_get = false;
13159
13160static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
13161 const v8::AccessorInfo& info) {
13162 force_set_get_count++;
13163 if (pass_on_get) {
13164 return v8::Handle<v8::Value>();
13165 } else {
13166 return v8::Int32::New(3);
13167 }
13168}
13169
13170static void ForceSetSetter(v8::Local<v8::String> name,
13171 v8::Local<v8::Value> value,
13172 const v8::AccessorInfo& info) {
13173 force_set_set_count++;
13174}
13175
13176static v8::Handle<v8::Value> ForceSetInterceptSetter(
13177 v8::Local<v8::String> name,
13178 v8::Local<v8::Value> value,
13179 const v8::AccessorInfo& info) {
13180 force_set_set_count++;
13181 return v8::Undefined();
13182}
13183
13184TEST(ForceSet) {
13185 force_set_get_count = 0;
13186 force_set_set_count = 0;
13187 pass_on_get = false;
13188
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013189 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013190 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13191 v8::Handle<v8::String> access_property = v8::String::New("a");
13192 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13193 LocalContext context(NULL, templ);
13194 v8::Handle<v8::Object> global = context->Global();
13195
13196 // Ordinary properties
13197 v8::Handle<v8::String> simple_property = v8::String::New("p");
13198 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
13199 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13200 // This should fail because the property is read-only
13201 global->Set(simple_property, v8::Int32::New(5));
13202 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13203 // This should succeed even though the property is read-only
13204 global->ForceSet(simple_property, v8::Int32::New(6));
13205 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13206
13207 // Accessors
13208 CHECK_EQ(0, force_set_set_count);
13209 CHECK_EQ(0, force_set_get_count);
13210 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13211 // CHECK_EQ the property shouldn't override it, just call the setter
13212 // which in this case does nothing.
13213 global->Set(access_property, v8::Int32::New(7));
13214 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13215 CHECK_EQ(1, force_set_set_count);
13216 CHECK_EQ(2, force_set_get_count);
13217 // Forcing the property to be set should override the accessor without
13218 // calling it
13219 global->ForceSet(access_property, v8::Int32::New(8));
13220 CHECK_EQ(8, global->Get(access_property)->Int32Value());
13221 CHECK_EQ(1, force_set_set_count);
13222 CHECK_EQ(2, force_set_get_count);
13223}
13224
13225TEST(ForceSetWithInterceptor) {
13226 force_set_get_count = 0;
13227 force_set_set_count = 0;
13228 pass_on_get = false;
13229
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013230 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013231 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13232 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
13233 LocalContext context(NULL, templ);
13234 v8::Handle<v8::Object> global = context->Global();
13235
13236 v8::Handle<v8::String> some_property = v8::String::New("a");
13237 CHECK_EQ(0, force_set_set_count);
13238 CHECK_EQ(0, force_set_get_count);
13239 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13240 // Setting the property shouldn't override it, just call the setter
13241 // which in this case does nothing.
13242 global->Set(some_property, v8::Int32::New(7));
13243 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13244 CHECK_EQ(1, force_set_set_count);
13245 CHECK_EQ(2, force_set_get_count);
13246 // Getting the property when the interceptor returns an empty handle
13247 // should yield undefined, since the property isn't present on the
13248 // object itself yet.
13249 pass_on_get = true;
13250 CHECK(global->Get(some_property)->IsUndefined());
13251 CHECK_EQ(1, force_set_set_count);
13252 CHECK_EQ(3, force_set_get_count);
13253 // Forcing the property to be set should cause the value to be
13254 // set locally without calling the interceptor.
13255 global->ForceSet(some_property, v8::Int32::New(8));
13256 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13257 CHECK_EQ(1, force_set_set_count);
13258 CHECK_EQ(4, force_set_get_count);
13259 // Reenabling the interceptor should cause it to take precedence over
13260 // the property
13261 pass_on_get = false;
13262 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13263 CHECK_EQ(1, force_set_set_count);
13264 CHECK_EQ(5, force_set_get_count);
13265 // The interceptor should also work for other properties
13266 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
13267 CHECK_EQ(1, force_set_set_count);
13268 CHECK_EQ(6, force_set_get_count);
13269}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013270
13271
ager@chromium.orge2902be2009-06-08 12:21:35 +000013272THREADED_TEST(ForceDelete) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013273 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +000013274 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13275 LocalContext context(NULL, templ);
13276 v8::Handle<v8::Object> global = context->Global();
13277
13278 // Ordinary properties
13279 v8::Handle<v8::String> simple_property = v8::String::New("p");
13280 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
13281 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13282 // This should fail because the property is dont-delete.
13283 CHECK(!global->Delete(simple_property));
13284 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13285 // This should succeed even though the property is dont-delete.
13286 CHECK(global->ForceDelete(simple_property));
13287 CHECK(global->Get(simple_property)->IsUndefined());
13288}
13289
13290
13291static int force_delete_interceptor_count = 0;
13292static bool pass_on_delete = false;
13293
13294
13295static v8::Handle<v8::Boolean> ForceDeleteDeleter(
13296 v8::Local<v8::String> name,
13297 const v8::AccessorInfo& info) {
13298 force_delete_interceptor_count++;
13299 if (pass_on_delete) {
13300 return v8::Handle<v8::Boolean>();
13301 } else {
13302 return v8::True();
13303 }
13304}
13305
13306
13307THREADED_TEST(ForceDeleteWithInterceptor) {
13308 force_delete_interceptor_count = 0;
13309 pass_on_delete = false;
13310
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013311 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orge2902be2009-06-08 12:21:35 +000013312 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13313 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
13314 LocalContext context(NULL, templ);
13315 v8::Handle<v8::Object> global = context->Global();
13316
13317 v8::Handle<v8::String> some_property = v8::String::New("a");
13318 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
13319
13320 // Deleting a property should get intercepted and nothing should
13321 // happen.
13322 CHECK_EQ(0, force_delete_interceptor_count);
13323 CHECK(global->Delete(some_property));
13324 CHECK_EQ(1, force_delete_interceptor_count);
13325 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13326 // Deleting the property when the interceptor returns an empty
13327 // handle should not delete the property since it is DontDelete.
13328 pass_on_delete = true;
13329 CHECK(!global->Delete(some_property));
13330 CHECK_EQ(2, force_delete_interceptor_count);
13331 CHECK_EQ(42, global->Get(some_property)->Int32Value());
13332 // Forcing the property to be deleted should delete the value
13333 // without calling the interceptor.
13334 CHECK(global->ForceDelete(some_property));
13335 CHECK(global->Get(some_property)->IsUndefined());
13336 CHECK_EQ(2, force_delete_interceptor_count);
13337}
13338
13339
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013340// Make sure that forcing a delete invalidates any IC stubs, so we
13341// don't read the hole value.
13342THREADED_TEST(ForceDeleteIC) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013343 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013344 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013345 // Create a DontDelete variable on the global object.
13346 CompileRun("this.__proto__ = { foo: 'horse' };"
13347 "var foo = 'fish';"
13348 "function f() { return foo.length; }");
13349 // Initialize the IC for foo in f.
13350 CompileRun("for (var i = 0; i < 4; i++) f();");
13351 // Make sure the value of foo is correct before the deletion.
13352 CHECK_EQ(4, CompileRun("f()")->Int32Value());
13353 // Force the deletion of foo.
13354 CHECK(context->Global()->ForceDelete(v8_str("foo")));
13355 // Make sure the value for foo is read from the prototype, and that
13356 // we don't get in trouble with reading the deleted cell value
13357 // sentinel.
13358 CHECK_EQ(5, CompileRun("f()")->Int32Value());
13359}
13360
13361
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013362TEST(InlinedFunctionAcrossContexts) {
13363 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013364 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013365 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
13366 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
13367 ctx1->Enter();
13368
13369 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013370 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013371 CompileRun("var G = 42; function foo() { return G; }");
13372 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
13373 ctx2->Enter();
13374 ctx2->Global()->Set(v8_str("o"), foo);
13375 v8::Local<v8::Value> res = CompileRun(
13376 "function f() { return o(); }"
13377 "for (var i = 0; i < 10; ++i) f();"
13378 "%OptimizeFunctionOnNextCall(f);"
13379 "f();");
13380 CHECK_EQ(42, res->Int32Value());
13381 ctx2->Exit();
13382 v8::Handle<v8::String> G_property = v8::String::New("G");
13383 CHECK(ctx1->Global()->ForceDelete(G_property));
13384 ctx2->Enter();
13385 ExpectString(
13386 "(function() {"
13387 " try {"
13388 " return f();"
13389 " } catch(e) {"
13390 " return e.toString();"
13391 " }"
13392 " })()",
13393 "ReferenceError: G is not defined");
13394 ctx2->Exit();
13395 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000013396 ctx1.Dispose(ctx1->GetIsolate());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013397 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000013398 ctx2.Dispose(ctx2->GetIsolate());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013399}
13400
13401
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013402v8::Persistent<Context> calling_context0;
13403v8::Persistent<Context> calling_context1;
13404v8::Persistent<Context> calling_context2;
13405
13406
13407// Check that the call to the callback is initiated in
13408// calling_context2, the directly calling context is calling_context1
13409// and the callback itself is in calling_context0.
13410static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
13411 ApiTestFuzzer::Fuzz();
13412 CHECK(Context::GetCurrent() == calling_context0);
13413 CHECK(Context::GetCalling() == calling_context1);
13414 CHECK(Context::GetEntered() == calling_context2);
13415 return v8::Integer::New(42);
13416}
13417
13418
13419THREADED_TEST(GetCallingContext) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013420 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013421
13422 calling_context0 = Context::New();
13423 calling_context1 = Context::New();
13424 calling_context2 = Context::New();
13425
13426 // Allow cross-domain access.
13427 Local<String> token = v8_str("<security token>");
13428 calling_context0->SetSecurityToken(token);
13429 calling_context1->SetSecurityToken(token);
13430 calling_context2->SetSecurityToken(token);
13431
13432 // Create an object with a C++ callback in context0.
13433 calling_context0->Enter();
13434 Local<v8::FunctionTemplate> callback_templ =
13435 v8::FunctionTemplate::New(GetCallingContextCallback);
13436 calling_context0->Global()->Set(v8_str("callback"),
13437 callback_templ->GetFunction());
13438 calling_context0->Exit();
13439
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013440 // Expose context0 in context1 and set up a function that calls the
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013441 // callback function.
13442 calling_context1->Enter();
13443 calling_context1->Global()->Set(v8_str("context0"),
13444 calling_context0->Global());
13445 CompileRun("function f() { context0.callback() }");
13446 calling_context1->Exit();
13447
13448 // Expose context1 in context2 and call the callback function in
13449 // context0 indirectly through f in context1.
13450 calling_context2->Enter();
13451 calling_context2->Global()->Set(v8_str("context1"),
13452 calling_context1->Global());
13453 CompileRun("context1.f()");
13454 calling_context2->Exit();
13455
13456 // Dispose the contexts to allow them to be garbage collected.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000013457 calling_context0.Dispose(calling_context0->GetIsolate());
13458 calling_context1.Dispose(calling_context1->GetIsolate());
13459 calling_context2.Dispose(calling_context2->GetIsolate());
ager@chromium.org1bf0cd02009-05-20 11:34:19 +000013460 calling_context0.Clear();
13461 calling_context1.Clear();
13462 calling_context2.Clear();
13463}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013464
13465
13466// Check that a variable declaration with no explicit initialization
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013467// value does shadow an existing property in the prototype chain.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013468THREADED_TEST(InitGlobalVarInProtoChain) {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +000013469 i::FLAG_es52_globals = true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013470 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013471 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013472 // Introduce a variable in the prototype chain.
13473 CompileRun("__proto__.x = 42");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013474 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013475 CHECK(!result->IsUndefined());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000013476 CHECK_EQ(43, result->Int32Value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013477}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013478
13479
13480// Regression test for issue 398.
13481// If a function is added to an object, creating a constant function
13482// field, and the result is cloned, replacing the constant function on the
13483// original should not affect the clone.
13484// See http://code.google.com/p/v8/issues/detail?id=398
13485THREADED_TEST(ReplaceConstantFunction) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013486 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013487 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013488 v8::Handle<v8::Object> obj = v8::Object::New();
13489 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
13490 v8::Handle<v8::String> foo_string = v8::String::New("foo");
13491 obj->Set(foo_string, func_templ->GetFunction());
13492 v8::Handle<v8::Object> obj_clone = obj->Clone();
13493 obj_clone->Set(foo_string, v8::String::New("Hello"));
13494 CHECK(!obj->Get(foo_string)->IsUndefined());
13495}
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013496
13497
13498// Regression test for http://crbug.com/16276.
13499THREADED_TEST(Regress16276) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013500 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013501 v8::HandleScope scope(context->GetIsolate());
kasperl@chromium.orge959c182009-07-27 08:59:04 +000013502 // Force the IC in f to be a dictionary load IC.
13503 CompileRun("function f(obj) { return obj.x; }\n"
13504 "var obj = { x: { foo: 42 }, y: 87 };\n"
13505 "var x = obj.x;\n"
13506 "delete obj.y;\n"
13507 "for (var i = 0; i < 5; i++) f(obj);");
13508 // Detach the global object to make 'this' refer directly to the
13509 // global object (not the proxy), and make sure that the dictionary
13510 // load IC doesn't mess up loading directly from the global object.
13511 context->DetachGlobal();
13512 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
13513}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013514
13515
13516THREADED_TEST(PixelArray) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013517 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013518 v8::HandleScope scope(context->GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013519 const int kElementCount = 260;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013520 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013521 i::Handle<i::ExternalPixelArray> pixels =
13522 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013523 FACTORY->NewExternalArray(kElementCount,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013524 v8::kExternalPixelArray,
13525 pixel_data));
13526 // Force GC to trigger verification.
13527 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013528 for (int i = 0; i < kElementCount; i++) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013529 pixels->set(i, i % 256);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013530 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013531 // Force GC to trigger verification.
13532 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013533 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013534 CHECK_EQ(i % 256, pixels->get_scalar(i));
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013535 CHECK_EQ(i % 256, pixel_data[i]);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013536 }
13537
13538 v8::Handle<v8::Object> obj = v8::Object::New();
13539 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13540 // Set the elements to be the pixels.
13541 // jsobj->set_elements(*pixels);
13542 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013543 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013544 obj->Set(v8_str("field"), v8::Int32::New(1503));
13545 context->Global()->Set(v8_str("pixels"), obj);
13546 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13547 CHECK_EQ(1503, result->Int32Value());
13548 result = CompileRun("pixels[1]");
13549 CHECK_EQ(1, result->Int32Value());
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013550
13551 result = CompileRun("var sum = 0;"
13552 "for (var i = 0; i < 8; i++) {"
13553 " sum += pixels[i] = pixels[i] = -i;"
13554 "}"
13555 "sum;");
13556 CHECK_EQ(-28, result->Int32Value());
13557
13558 result = CompileRun("var sum = 0;"
13559 "for (var i = 0; i < 8; i++) {"
13560 " sum += pixels[i] = pixels[i] = 0;"
13561 "}"
13562 "sum;");
13563 CHECK_EQ(0, result->Int32Value());
13564
13565 result = CompileRun("var sum = 0;"
13566 "for (var i = 0; i < 8; i++) {"
13567 " sum += pixels[i] = pixels[i] = 255;"
13568 "}"
13569 "sum;");
13570 CHECK_EQ(8 * 255, result->Int32Value());
13571
13572 result = CompileRun("var sum = 0;"
13573 "for (var i = 0; i < 8; i++) {"
13574 " sum += pixels[i] = pixels[i] = 256 + i;"
13575 "}"
13576 "sum;");
13577 CHECK_EQ(2076, result->Int32Value());
13578
13579 result = CompileRun("var sum = 0;"
13580 "for (var i = 0; i < 8; i++) {"
13581 " sum += pixels[i] = pixels[i] = i;"
13582 "}"
13583 "sum;");
13584 CHECK_EQ(28, result->Int32Value());
13585
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013586 result = CompileRun("var sum = 0;"
13587 "for (var i = 0; i < 8; i++) {"
13588 " sum += pixels[i];"
13589 "}"
13590 "sum;");
13591 CHECK_EQ(28, result->Int32Value());
13592
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000013593 i::Handle<i::Smi> value(i::Smi::FromInt(2),
13594 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013595 i::Handle<i::Object> no_failure;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013596 no_failure =
13597 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013598 ASSERT(!no_failure.is_null());
13599 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013600 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013601 *value.location() = i::Smi::FromInt(256);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013602 no_failure =
13603 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013604 ASSERT(!no_failure.is_null());
13605 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013606 CHECK_EQ(255,
13607 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013608 *value.location() = i::Smi::FromInt(-1);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000013609 no_failure =
13610 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +000013611 ASSERT(!no_failure.is_null());
13612 i::USE(no_failure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013613 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013614
13615 result = CompileRun("for (var i = 0; i < 8; i++) {"
13616 " pixels[i] = (i * 65) - 109;"
13617 "}"
13618 "pixels[1] + pixels[6];");
13619 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013620 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13621 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13622 CHECK_EQ(21,
13623 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13624 CHECK_EQ(86,
13625 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13626 CHECK_EQ(151,
13627 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13628 CHECK_EQ(216,
13629 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13630 CHECK_EQ(255,
13631 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13632 CHECK_EQ(255,
13633 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013634 result = CompileRun("var sum = 0;"
13635 "for (var i = 0; i < 8; i++) {"
13636 " sum += pixels[i];"
13637 "}"
13638 "sum;");
13639 CHECK_EQ(984, result->Int32Value());
13640
13641 result = CompileRun("for (var i = 0; i < 8; i++) {"
13642 " pixels[i] = (i * 1.1);"
13643 "}"
13644 "pixels[1] + pixels[6];");
13645 CHECK_EQ(8, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013646 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
13647 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
13648 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
13649 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
13650 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
13651 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
13652 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
13653 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013654
13655 result = CompileRun("for (var i = 0; i < 8; i++) {"
13656 " pixels[7] = undefined;"
13657 "}"
13658 "pixels[7];");
13659 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013660 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013661
13662 result = CompileRun("for (var i = 0; i < 8; i++) {"
13663 " pixels[6] = '2.3';"
13664 "}"
13665 "pixels[6];");
13666 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013667 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013668
13669 result = CompileRun("for (var i = 0; i < 8; i++) {"
13670 " pixels[5] = NaN;"
13671 "}"
13672 "pixels[5];");
13673 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013674 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013675
13676 result = CompileRun("for (var i = 0; i < 8; i++) {"
13677 " pixels[8] = Infinity;"
13678 "}"
13679 "pixels[8];");
13680 CHECK_EQ(255, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013681 CHECK_EQ(255,
13682 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013683
13684 result = CompileRun("for (var i = 0; i < 8; i++) {"
13685 " pixels[9] = -Infinity;"
13686 "}"
13687 "pixels[9];");
13688 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013689 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013690
13691 result = CompileRun("pixels[3] = 33;"
13692 "delete pixels[3];"
13693 "pixels[3];");
13694 CHECK_EQ(33, result->Int32Value());
13695
13696 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13697 "pixels[2] = 12; pixels[3] = 13;"
13698 "pixels.__defineGetter__('2',"
13699 "function() { return 120; });"
13700 "pixels[2];");
13701 CHECK_EQ(12, result->Int32Value());
13702
13703 result = CompileRun("var js_array = new Array(40);"
13704 "js_array[0] = 77;"
13705 "js_array;");
13706 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13707
13708 result = CompileRun("pixels[1] = 23;"
13709 "pixels.__proto__ = [];"
13710 "js_array.__proto__ = pixels;"
13711 "js_array.concat(pixels);");
13712 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13713 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13714
sgjesse@chromium.org9eceac12009-09-30 07:18:41 +000013715 result = CompileRun("pixels[1] = 23;");
13716 CHECK_EQ(23, result->Int32Value());
13717
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013718 // Test for index greater than 255. Regression test for:
13719 // http://code.google.com/p/chromium/issues/detail?id=26337.
13720 result = CompileRun("pixels[256] = 255;");
13721 CHECK_EQ(255, result->Int32Value());
13722 result = CompileRun("var i = 0;"
13723 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13724 "i");
13725 CHECK_EQ(255, result->Int32Value());
13726
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013727 // Make sure that pixel array ICs recognize when a non-pixel array
13728 // is passed to it.
13729 result = CompileRun("function pa_load(p) {"
13730 " var sum = 0;"
13731 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13732 " return sum;"
13733 "}"
13734 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13735 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13736 "just_ints = new Object();"
13737 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13738 "for (var i = 0; i < 10; ++i) {"
13739 " result = pa_load(just_ints);"
13740 "}"
13741 "result");
13742 CHECK_EQ(32640, result->Int32Value());
13743
13744 // Make sure that pixel array ICs recognize out-of-bound accesses.
13745 result = CompileRun("function pa_load(p, start) {"
13746 " var sum = 0;"
13747 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13748 " return sum;"
13749 "}"
13750 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13751 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13752 "for (var i = 0; i < 10; ++i) {"
13753 " result = pa_load(pixels,-10);"
13754 "}"
13755 "result");
13756 CHECK_EQ(0, result->Int32Value());
13757
13758 // Make sure that generic ICs properly handles a pixel array.
13759 result = CompileRun("function pa_load(p) {"
13760 " var sum = 0;"
13761 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13762 " return sum;"
13763 "}"
13764 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13765 "just_ints = new Object();"
13766 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13767 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13768 "for (var i = 0; i < 10; ++i) {"
13769 " result = pa_load(pixels);"
13770 "}"
13771 "result");
13772 CHECK_EQ(32640, result->Int32Value());
13773
13774 // Make sure that generic load ICs recognize out-of-bound accesses in
13775 // pixel arrays.
13776 result = CompileRun("function pa_load(p, start) {"
13777 " var sum = 0;"
13778 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13779 " return sum;"
13780 "}"
13781 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13782 "just_ints = new Object();"
13783 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13784 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13785 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13786 "for (var i = 0; i < 10; ++i) {"
13787 " result = pa_load(pixels,-10);"
13788 "}"
13789 "result");
13790 CHECK_EQ(0, result->Int32Value());
13791
13792 // Make sure that generic ICs properly handles other types than pixel
13793 // arrays (that the inlined fast pixel array test leaves the right information
13794 // in the right registers).
13795 result = CompileRun("function pa_load(p) {"
13796 " var sum = 0;"
13797 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13798 " return sum;"
13799 "}"
13800 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13801 "just_ints = new Object();"
13802 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13803 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13804 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13805 "sparse_array = new Object();"
13806 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13807 "sparse_array[1000000] = 3;"
13808 "for (var i = 0; i < 10; ++i) {"
13809 " result = pa_load(sparse_array);"
13810 "}"
13811 "result");
13812 CHECK_EQ(32640, result->Int32Value());
13813
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013814 // Make sure that pixel array store ICs clamp values correctly.
13815 result = CompileRun("function pa_store(p) {"
13816 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13817 "}"
13818 "pa_store(pixels);"
13819 "var sum = 0;"
13820 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13821 "sum");
13822 CHECK_EQ(48896, result->Int32Value());
13823
13824 // Make sure that pixel array stores correctly handle accesses outside
13825 // of the pixel array..
13826 result = CompileRun("function pa_store(p,start) {"
13827 " for (var j = 0; j < 256; j++) {"
13828 " p[j+start] = j * 2;"
13829 " }"
13830 "}"
13831 "pa_store(pixels,0);"
13832 "pa_store(pixels,-128);"
13833 "var sum = 0;"
13834 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13835 "sum");
13836 CHECK_EQ(65280, result->Int32Value());
13837
13838 // Make sure that the generic store stub correctly handle accesses outside
13839 // of the pixel array..
13840 result = CompileRun("function pa_store(p,start) {"
13841 " for (var j = 0; j < 256; j++) {"
13842 " p[j+start] = j * 2;"
13843 " }"
13844 "}"
13845 "pa_store(pixels,0);"
13846 "just_ints = new Object();"
13847 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13848 "pa_store(just_ints, 0);"
13849 "pa_store(pixels,-128);"
13850 "var sum = 0;"
13851 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13852 "sum");
13853 CHECK_EQ(65280, result->Int32Value());
13854
13855 // Make sure that the generic keyed store stub clamps pixel array values
13856 // correctly.
13857 result = CompileRun("function pa_store(p) {"
13858 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13859 "}"
13860 "pa_store(pixels);"
13861 "just_ints = new Object();"
13862 "pa_store(just_ints);"
13863 "pa_store(pixels);"
13864 "var sum = 0;"
13865 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13866 "sum");
13867 CHECK_EQ(48896, result->Int32Value());
13868
13869 // Make sure that pixel array loads are optimized by crankshaft.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013870 result = CompileRun("function pa_load(p) {"
13871 " var sum = 0;"
13872 " for (var i=0; i<256; ++i) {"
13873 " sum += p[i];"
13874 " }"
13875 " return sum; "
13876 "}"
13877 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013878 "for (var i = 0; i < 5000; ++i) {"
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013879 " result = pa_load(pixels);"
13880 "}"
13881 "result");
13882 CHECK_EQ(32640, result->Int32Value());
13883
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013884 // Make sure that pixel array stores are optimized by crankshaft.
13885 result = CompileRun("function pa_init(p) {"
13886 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13887 "}"
13888 "function pa_load(p) {"
13889 " var sum = 0;"
13890 " for (var i=0; i<256; ++i) {"
13891 " sum += p[i];"
13892 " }"
13893 " return sum; "
13894 "}"
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013895 "for (var i = 0; i < 5000; ++i) {"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013896 " pa_init(pixels);"
13897 "}"
13898 "result = pa_load(pixels);"
13899 "result");
13900 CHECK_EQ(32640, result->Int32Value());
13901
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013902 free(pixel_data);
13903}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000013904
ager@chromium.org96c75b52009-08-26 09:13:16 +000013905
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013906THREADED_TEST(PixelArrayInfo) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013907 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013908 v8::HandleScope scope(context->GetIsolate());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013909 for (int size = 0; size < 100; size += 10) {
13910 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13911 v8::Handle<v8::Object> obj = v8::Object::New();
13912 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13913 CHECK(obj->HasIndexedPropertiesInPixelData());
13914 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13915 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13916 free(pixel_data);
13917 }
13918}
13919
13920
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013921static v8::Handle<Value> NotHandledIndexedPropertyGetter(
13922 uint32_t index,
13923 const AccessorInfo& info) {
13924 ApiTestFuzzer::Fuzz();
13925 return v8::Handle<Value>();
13926}
13927
13928
13929static v8::Handle<Value> NotHandledIndexedPropertySetter(
13930 uint32_t index,
13931 Local<Value> value,
13932 const AccessorInfo& info) {
13933 ApiTestFuzzer::Fuzz();
13934 return v8::Handle<Value>();
13935}
13936
13937
13938THREADED_TEST(PixelArrayWithInterceptor) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013939 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000013940 v8::HandleScope scope(context->GetIsolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013941 const int kElementCount = 260;
13942 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013943 i::Handle<i::ExternalPixelArray> pixels =
13944 i::Handle<i::ExternalPixelArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013945 FACTORY->NewExternalArray(kElementCount,
13946 v8::kExternalPixelArray,
13947 pixel_data));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000013948 for (int i = 0; i < kElementCount; i++) {
13949 pixels->set(i, i % 256);
13950 }
13951 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
13952 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
13953 NotHandledIndexedPropertySetter);
13954 v8::Handle<v8::Object> obj = templ->NewInstance();
13955 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13956 context->Global()->Set(v8_str("pixels"), obj);
13957 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13958 CHECK_EQ(1, result->Int32Value());
13959 result = CompileRun("var sum = 0;"
13960 "for (var i = 0; i < 8; i++) {"
13961 " sum += pixels[i] = pixels[i] = -i;"
13962 "}"
13963 "sum;");
13964 CHECK_EQ(-28, result->Int32Value());
13965 result = CompileRun("pixels.hasOwnProperty('1')");
13966 CHECK(result->BooleanValue());
13967 free(pixel_data);
13968}
13969
13970
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013971static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13972 switch (array_type) {
13973 case v8::kExternalByteArray:
13974 case v8::kExternalUnsignedByteArray:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013975 case v8::kExternalPixelArray:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013976 return 1;
13977 break;
13978 case v8::kExternalShortArray:
13979 case v8::kExternalUnsignedShortArray:
13980 return 2;
13981 break;
13982 case v8::kExternalIntArray:
13983 case v8::kExternalUnsignedIntArray:
13984 case v8::kExternalFloatArray:
13985 return 4;
13986 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013987 case v8::kExternalDoubleArray:
13988 return 8;
13989 break;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000013990 default:
13991 UNREACHABLE();
13992 return -1;
13993 }
13994 UNREACHABLE();
13995 return -1;
13996}
13997
13998
ager@chromium.org3811b432009-10-28 14:53:37 +000013999template <class ExternalArrayClass, class ElementType>
14000static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
14001 int64_t low,
14002 int64_t high) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014003 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014004 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org3811b432009-10-28 14:53:37 +000014005 const int kElementCount = 40;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014006 int element_size = ExternalArrayElementSize(array_type);
ager@chromium.org3811b432009-10-28 14:53:37 +000014007 ElementType* array_data =
14008 static_cast<ElementType*>(malloc(kElementCount * element_size));
14009 i::Handle<ExternalArrayClass> array =
14010 i::Handle<ExternalArrayClass>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014011 FACTORY->NewExternalArray(kElementCount, array_type, array_data));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014012 // Force GC to trigger verification.
14013 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000014014 for (int i = 0; i < kElementCount; i++) {
14015 array->set(i, static_cast<ElementType>(i));
14016 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014017 // Force GC to trigger verification.
14018 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000014019 for (int i = 0; i < kElementCount; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014020 CHECK_EQ(static_cast<int64_t>(i),
14021 static_cast<int64_t>(array->get_scalar(i)));
ager@chromium.org3811b432009-10-28 14:53:37 +000014022 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
14023 }
14024
14025 v8::Handle<v8::Object> obj = v8::Object::New();
14026 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14027 // Set the elements to be the external array.
14028 obj->SetIndexedPropertiesToExternalArrayData(array_data,
14029 array_type,
14030 kElementCount);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014031 CHECK_EQ(
14032 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000014033 obj->Set(v8_str("field"), v8::Int32::New(1503));
14034 context->Global()->Set(v8_str("ext_array"), obj);
14035 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
14036 CHECK_EQ(1503, result->Int32Value());
14037 result = CompileRun("ext_array[1]");
14038 CHECK_EQ(1, result->Int32Value());
14039
14040 // Check pass through of assigned smis
14041 result = CompileRun("var sum = 0;"
14042 "for (var i = 0; i < 8; i++) {"
14043 " sum += ext_array[i] = ext_array[i] = -i;"
14044 "}"
14045 "sum;");
14046 CHECK_EQ(-28, result->Int32Value());
14047
14048 // Check assigned smis
14049 result = CompileRun("for (var i = 0; i < 8; i++) {"
14050 " ext_array[i] = i;"
14051 "}"
14052 "var sum = 0;"
14053 "for (var i = 0; i < 8; i++) {"
14054 " sum += ext_array[i];"
14055 "}"
14056 "sum;");
14057 CHECK_EQ(28, result->Int32Value());
14058
14059 // Check assigned smis in reverse order
14060 result = CompileRun("for (var i = 8; --i >= 0; ) {"
14061 " ext_array[i] = i;"
14062 "}"
14063 "var sum = 0;"
14064 "for (var i = 0; i < 8; i++) {"
14065 " sum += ext_array[i];"
14066 "}"
14067 "sum;");
14068 CHECK_EQ(28, result->Int32Value());
14069
14070 // Check pass through of assigned HeapNumbers
14071 result = CompileRun("var sum = 0;"
14072 "for (var i = 0; i < 16; i+=2) {"
14073 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
14074 "}"
14075 "sum;");
14076 CHECK_EQ(-28, result->Int32Value());
14077
14078 // Check assigned HeapNumbers
14079 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
14080 " ext_array[i] = (i * 0.5);"
14081 "}"
14082 "var sum = 0;"
14083 "for (var i = 0; i < 16; i+=2) {"
14084 " sum += ext_array[i];"
14085 "}"
14086 "sum;");
14087 CHECK_EQ(28, result->Int32Value());
14088
14089 // Check assigned HeapNumbers in reverse order
14090 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
14091 " ext_array[i] = (i * 0.5);"
14092 "}"
14093 "var sum = 0;"
14094 "for (var i = 0; i < 16; i+=2) {"
14095 " sum += ext_array[i];"
14096 "}"
14097 "sum;");
14098 CHECK_EQ(28, result->Int32Value());
14099
14100 i::ScopedVector<char> test_buf(1024);
14101
14102 // Check legal boundary conditions.
14103 // The repeated loads and stores ensure the ICs are exercised.
14104 const char* boundary_program =
14105 "var res = 0;"
14106 "for (var i = 0; i < 16; i++) {"
14107 " ext_array[i] = %lld;"
14108 " if (i > 8) {"
14109 " res = ext_array[i];"
14110 " }"
14111 "}"
14112 "res;";
14113 i::OS::SNPrintF(test_buf,
14114 boundary_program,
14115 low);
14116 result = CompileRun(test_buf.start());
14117 CHECK_EQ(low, result->IntegerValue());
14118
14119 i::OS::SNPrintF(test_buf,
14120 boundary_program,
14121 high);
14122 result = CompileRun(test_buf.start());
14123 CHECK_EQ(high, result->IntegerValue());
14124
14125 // Check misprediction of type in IC.
14126 result = CompileRun("var tmp_array = ext_array;"
14127 "var sum = 0;"
14128 "for (var i = 0; i < 8; i++) {"
14129 " tmp_array[i] = i;"
14130 " sum += tmp_array[i];"
14131 " if (i == 4) {"
14132 " tmp_array = {};"
14133 " }"
14134 "}"
14135 "sum;");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014136 // Force GC to trigger verification.
14137 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org3811b432009-10-28 14:53:37 +000014138 CHECK_EQ(28, result->Int32Value());
14139
14140 // Make sure out-of-range loads do not throw.
14141 i::OS::SNPrintF(test_buf,
14142 "var caught_exception = false;"
14143 "try {"
14144 " ext_array[%d];"
14145 "} catch (e) {"
14146 " caught_exception = true;"
14147 "}"
14148 "caught_exception;",
14149 kElementCount);
14150 result = CompileRun(test_buf.start());
14151 CHECK_EQ(false, result->BooleanValue());
14152
14153 // Make sure out-of-range stores do not throw.
14154 i::OS::SNPrintF(test_buf,
14155 "var caught_exception = false;"
14156 "try {"
14157 " ext_array[%d] = 1;"
14158 "} catch (e) {"
14159 " caught_exception = true;"
14160 "}"
14161 "caught_exception;",
14162 kElementCount);
14163 result = CompileRun(test_buf.start());
14164 CHECK_EQ(false, result->BooleanValue());
14165
14166 // Check other boundary conditions, values and operations.
14167 result = CompileRun("for (var i = 0; i < 8; i++) {"
14168 " ext_array[7] = undefined;"
14169 "}"
14170 "ext_array[7];");
14171 CHECK_EQ(0, result->Int32Value());
yangguo@chromium.org56454712012-02-16 15:33:53 +000014172 if (array_type == v8::kExternalDoubleArray ||
14173 array_type == v8::kExternalFloatArray) {
14174 CHECK_EQ(
ulan@chromium.org812308e2012-02-29 15:58:45 +000014175 static_cast<int>(i::OS::nan_value()),
yangguo@chromium.org56454712012-02-16 15:33:53 +000014176 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
14177 } else {
14178 CHECK_EQ(0, static_cast<int>(
14179 jsobj->GetElement(7)->ToObjectChecked()->Number()));
14180 }
ager@chromium.org3811b432009-10-28 14:53:37 +000014181
14182 result = CompileRun("for (var i = 0; i < 8; i++) {"
14183 " ext_array[6] = '2.3';"
14184 "}"
14185 "ext_array[6];");
14186 CHECK_EQ(2, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014187 CHECK_EQ(
14188 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
ager@chromium.org3811b432009-10-28 14:53:37 +000014189
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014190 if (array_type != v8::kExternalFloatArray &&
14191 array_type != v8::kExternalDoubleArray) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014192 // Though the specification doesn't state it, be explicit about
14193 // converting NaNs and +/-Infinity to zero.
14194 result = CompileRun("for (var i = 0; i < 8; i++) {"
14195 " ext_array[i] = 5;"
14196 "}"
14197 "for (var i = 0; i < 8; i++) {"
14198 " ext_array[i] = NaN;"
14199 "}"
14200 "ext_array[5];");
14201 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014202 CHECK_EQ(0,
14203 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000014204
14205 result = CompileRun("for (var i = 0; i < 8; i++) {"
14206 " ext_array[i] = 5;"
14207 "}"
14208 "for (var i = 0; i < 8; i++) {"
14209 " ext_array[i] = Infinity;"
14210 "}"
14211 "ext_array[5];");
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014212 int expected_value =
14213 (array_type == v8::kExternalPixelArray) ? 255 : 0;
14214 CHECK_EQ(expected_value, result->Int32Value());
14215 CHECK_EQ(expected_value,
lrn@chromium.org303ada72010-10-27 09:33:13 +000014216 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
ager@chromium.org3811b432009-10-28 14:53:37 +000014217
14218 result = CompileRun("for (var i = 0; i < 8; i++) {"
14219 " ext_array[i] = 5;"
14220 "}"
14221 "for (var i = 0; i < 8; i++) {"
14222 " ext_array[i] = -Infinity;"
14223 "}"
14224 "ext_array[5];");
14225 CHECK_EQ(0, result->Int32Value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014226 CHECK_EQ(0,
14227 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014228
14229 // Check truncation behavior of integral arrays.
14230 const char* unsigned_data =
14231 "var source_data = [0.6, 10.6];"
14232 "var expected_results = [0, 10];";
14233 const char* signed_data =
14234 "var source_data = [0.6, 10.6, -0.6, -10.6];"
14235 "var expected_results = [0, 10, 0, -10];";
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014236 const char* pixel_data =
14237 "var source_data = [0.6, 10.6];"
14238 "var expected_results = [1, 11];";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014239 bool is_unsigned =
14240 (array_type == v8::kExternalUnsignedByteArray ||
14241 array_type == v8::kExternalUnsignedShortArray ||
14242 array_type == v8::kExternalUnsignedIntArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014243 bool is_pixel_data = array_type == v8::kExternalPixelArray;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014244
14245 i::OS::SNPrintF(test_buf,
14246 "%s"
14247 "var all_passed = true;"
14248 "for (var i = 0; i < source_data.length; i++) {"
14249 " for (var j = 0; j < 8; j++) {"
14250 " ext_array[j] = source_data[i];"
14251 " }"
14252 " all_passed = all_passed &&"
14253 " (ext_array[5] == expected_results[i]);"
14254 "}"
14255 "all_passed;",
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014256 (is_unsigned ?
14257 unsigned_data :
14258 (is_pixel_data ? pixel_data : signed_data)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000014259 result = CompileRun(test_buf.start());
14260 CHECK_EQ(true, result->BooleanValue());
ager@chromium.org3811b432009-10-28 14:53:37 +000014261 }
14262
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000014263 for (int i = 0; i < kElementCount; i++) {
14264 array->set(i, static_cast<ElementType>(i));
14265 }
14266 // Test complex assignments
14267 result = CompileRun("function ee_op_test_complex_func(sum) {"
14268 " for (var i = 0; i < 40; ++i) {"
14269 " sum += (ext_array[i] += 1);"
14270 " sum += (ext_array[i] -= 1);"
14271 " } "
14272 " return sum;"
14273 "}"
14274 "sum=0;"
14275 "for (var i=0;i<10000;++i) {"
14276 " sum=ee_op_test_complex_func(sum);"
14277 "}"
14278 "sum;");
14279 CHECK_EQ(16000000, result->Int32Value());
14280
14281 // Test count operations
14282 result = CompileRun("function ee_op_test_count_func(sum) {"
14283 " for (var i = 0; i < 40; ++i) {"
14284 " sum += (++ext_array[i]);"
14285 " sum += (--ext_array[i]);"
14286 " } "
14287 " return sum;"
14288 "}"
14289 "sum=0;"
14290 "for (var i=0;i<10000;++i) {"
14291 " sum=ee_op_test_count_func(sum);"
14292 "}"
14293 "sum;");
14294 CHECK_EQ(16000000, result->Int32Value());
14295
ager@chromium.org3811b432009-10-28 14:53:37 +000014296 result = CompileRun("ext_array[3] = 33;"
14297 "delete ext_array[3];"
14298 "ext_array[3];");
14299 CHECK_EQ(33, result->Int32Value());
14300
14301 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14302 "ext_array[2] = 12; ext_array[3] = 13;"
14303 "ext_array.__defineGetter__('2',"
14304 "function() { return 120; });"
14305 "ext_array[2];");
14306 CHECK_EQ(12, result->Int32Value());
14307
14308 result = CompileRun("var js_array = new Array(40);"
14309 "js_array[0] = 77;"
14310 "js_array;");
14311 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14312
14313 result = CompileRun("ext_array[1] = 23;"
14314 "ext_array.__proto__ = [];"
14315 "js_array.__proto__ = ext_array;"
14316 "js_array.concat(ext_array);");
14317 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14318 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14319
14320 result = CompileRun("ext_array[1] = 23;");
14321 CHECK_EQ(23, result->Int32Value());
14322
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014323 // Test more complex manipulations which cause eax to contain values
14324 // that won't be completely overwritten by loads from the arrays.
14325 // This catches bugs in the instructions used for the KeyedLoadIC
14326 // for byte and word types.
14327 {
14328 const int kXSize = 300;
14329 const int kYSize = 300;
14330 const int kLargeElementCount = kXSize * kYSize * 4;
14331 ElementType* large_array_data =
14332 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000014333 v8::Handle<v8::Object> large_obj = v8::Object::New();
14334 // Set the elements to be the external array.
14335 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14336 array_type,
14337 kLargeElementCount);
14338 context->Global()->Set(v8_str("large_array"), large_obj);
14339 // Initialize contents of a few rows.
14340 for (int x = 0; x < 300; x++) {
14341 int row = 0;
14342 int offset = row * 300 * 4;
14343 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14344 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14345 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14346 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14347 row = 150;
14348 offset = row * 300 * 4;
14349 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14350 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14351 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14352 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14353 row = 298;
14354 offset = row * 300 * 4;
14355 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14356 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14357 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14358 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14359 }
14360 // The goal of the code below is to make "offset" large enough
14361 // that the computation of the index (which goes into eax) has
14362 // high bits set which will not be overwritten by a byte or short
14363 // load.
14364 result = CompileRun("var failed = false;"
14365 "var offset = 0;"
14366 "for (var i = 0; i < 300; i++) {"
14367 " if (large_array[4 * i] != 127 ||"
14368 " large_array[4 * i + 1] != 0 ||"
14369 " large_array[4 * i + 2] != 0 ||"
14370 " large_array[4 * i + 3] != 127) {"
14371 " failed = true;"
14372 " }"
14373 "}"
14374 "offset = 150 * 300 * 4;"
14375 "for (var i = 0; i < 300; i++) {"
14376 " if (large_array[offset + 4 * i] != 127 ||"
14377 " large_array[offset + 4 * i + 1] != 0 ||"
14378 " large_array[offset + 4 * i + 2] != 0 ||"
14379 " large_array[offset + 4 * i + 3] != 127) {"
14380 " failed = true;"
14381 " }"
14382 "}"
14383 "offset = 298 * 300 * 4;"
14384 "for (var i = 0; i < 300; i++) {"
14385 " if (large_array[offset + 4 * i] != 127 ||"
14386 " large_array[offset + 4 * i + 1] != 0 ||"
14387 " large_array[offset + 4 * i + 2] != 0 ||"
14388 " large_array[offset + 4 * i + 3] != 127) {"
14389 " failed = true;"
14390 " }"
14391 "}"
14392 "!failed;");
14393 CHECK_EQ(true, result->BooleanValue());
14394 free(large_array_data);
14395 }
14396
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014397 // The "" property descriptor is overloaded to store information about
14398 // the external array. Ensure that setting and accessing the "" property
14399 // works (it should overwrite the information cached about the external
14400 // array in the DescriptorArray) in various situations.
14401 result = CompileRun("ext_array[''] = 23; ext_array['']");
14402 CHECK_EQ(23, result->Int32Value());
14403
14404 // Property "" set after the external array is associated with the object.
14405 {
14406 v8::Handle<v8::Object> obj2 = v8::Object::New();
14407 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
14408 obj2->Set(v8_str(""), v8::Int32::New(1503));
14409 // Set the elements to be the external array.
14410 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14411 array_type,
14412 kElementCount);
14413 context->Global()->Set(v8_str("ext_array"), obj2);
14414 result = CompileRun("ext_array['']");
14415 CHECK_EQ(1503, result->Int32Value());
14416 }
14417
14418 // Property "" set after the external array is associated with the object.
14419 {
14420 v8::Handle<v8::Object> obj2 = v8::Object::New();
14421 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14422 // Set the elements to be the external array.
14423 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14424 array_type,
14425 kElementCount);
14426 obj2->Set(v8_str(""), v8::Int32::New(1503));
14427 context->Global()->Set(v8_str("ext_array"), obj2);
14428 result = CompileRun("ext_array['']");
14429 CHECK_EQ(1503, result->Int32Value());
14430 }
14431
14432 // Should reuse the map from previous test.
14433 {
14434 v8::Handle<v8::Object> obj2 = v8::Object::New();
14435 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
14436 // Set the elements to be the external array. Should re-use the map
14437 // from previous test.
14438 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14439 array_type,
14440 kElementCount);
14441 context->Global()->Set(v8_str("ext_array"), obj2);
14442 result = CompileRun("ext_array['']");
14443 }
14444
14445 // Property "" is a constant function that shouldn't not be interfered with
14446 // when an external array is set.
14447 {
14448 v8::Handle<v8::Object> obj2 = v8::Object::New();
14449 // Start
14450 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14451
14452 // Add a constant function to an object.
14453 context->Global()->Set(v8_str("ext_array"), obj2);
14454 result = CompileRun("ext_array[''] = function() {return 1503;};"
14455 "ext_array['']();");
14456
14457 // Add an external array transition to the same map that
14458 // has the constant transition.
14459 v8::Handle<v8::Object> obj3 = v8::Object::New();
14460 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
14461 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14462 array_type,
14463 kElementCount);
14464 context->Global()->Set(v8_str("ext_array"), obj3);
14465 }
14466
14467 // If a external array transition is in the map, it should get clobbered
14468 // by a constant function.
14469 {
14470 // Add an external array transition.
14471 v8::Handle<v8::Object> obj3 = v8::Object::New();
14472 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14473 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14474 array_type,
14475 kElementCount);
14476
14477 // Add a constant function to the same map that just got an external array
14478 // transition.
14479 v8::Handle<v8::Object> obj2 = v8::Object::New();
14480 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
14481 context->Global()->Set(v8_str("ext_array"), obj2);
14482 result = CompileRun("ext_array[''] = function() {return 1503;};"
14483 "ext_array['']();");
14484 }
14485
ager@chromium.org3811b432009-10-28 14:53:37 +000014486 free(array_data);
14487}
14488
14489
14490THREADED_TEST(ExternalByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014491 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014492 v8::kExternalByteArray,
14493 -128,
14494 127);
14495}
14496
14497
14498THREADED_TEST(ExternalUnsignedByteArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014499 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014500 v8::kExternalUnsignedByteArray,
14501 0,
14502 255);
14503}
14504
14505
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014506THREADED_TEST(ExternalPixelArray) {
14507 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
14508 v8::kExternalPixelArray,
14509 0,
14510 255);
14511}
14512
14513
ager@chromium.org3811b432009-10-28 14:53:37 +000014514THREADED_TEST(ExternalShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014515 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014516 v8::kExternalShortArray,
14517 -32768,
14518 32767);
14519}
14520
14521
14522THREADED_TEST(ExternalUnsignedShortArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014523 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014524 v8::kExternalUnsignedShortArray,
14525 0,
14526 65535);
14527}
14528
14529
14530THREADED_TEST(ExternalIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014531 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014532 v8::kExternalIntArray,
14533 INT_MIN, // -2147483648
14534 INT_MAX); // 2147483647
14535}
14536
14537
14538THREADED_TEST(ExternalUnsignedIntArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014539 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014540 v8::kExternalUnsignedIntArray,
14541 0,
14542 UINT_MAX); // 4294967295
14543}
14544
14545
14546THREADED_TEST(ExternalFloatArray) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +000014547 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
ager@chromium.org3811b432009-10-28 14:53:37 +000014548 v8::kExternalFloatArray,
14549 -500,
14550 500);
14551}
14552
14553
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014554THREADED_TEST(ExternalDoubleArray) {
14555 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
14556 v8::kExternalDoubleArray,
14557 -500,
14558 500);
14559}
14560
14561
ager@chromium.org3811b432009-10-28 14:53:37 +000014562THREADED_TEST(ExternalArrays) {
14563 TestExternalByteArray();
14564 TestExternalUnsignedByteArray();
14565 TestExternalShortArray();
14566 TestExternalUnsignedShortArray();
14567 TestExternalIntArray();
14568 TestExternalUnsignedIntArray();
14569 TestExternalFloatArray();
14570}
14571
14572
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014573void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014574 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014575 v8::HandleScope scope(context->GetIsolate());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014576 for (int size = 0; size < 100; size += 10) {
14577 int element_size = ExternalArrayElementSize(array_type);
14578 void* external_data = malloc(size * element_size);
14579 v8::Handle<v8::Object> obj = v8::Object::New();
14580 obj->SetIndexedPropertiesToExternalArrayData(
14581 external_data, array_type, size);
14582 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14583 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14584 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14585 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14586 free(external_data);
14587 }
14588}
14589
14590
14591THREADED_TEST(ExternalArrayInfo) {
14592 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
14593 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
14594 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
14595 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
14596 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
14597 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
14598 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014599 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014600 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000014601}
14602
14603
danno@chromium.org412fa512012-09-14 13:28:26 +000014604void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
14605 v8::Handle<v8::Object> obj = v8::Object::New();
14606 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14607 last_location = last_message = NULL;
14608 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14609 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14610 CHECK_NE(NULL, last_location);
14611 CHECK_NE(NULL, last_message);
14612}
14613
14614
14615TEST(ExternalArrayLimits) {
danno@chromium.org412fa512012-09-14 13:28:26 +000014616 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014617 v8::HandleScope scope(context->GetIsolate());
danno@chromium.org412fa512012-09-14 13:28:26 +000014618 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
14619 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
14620 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
14621 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
14622 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
14623 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
14624 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
14625 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
14626 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
14627 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
14628 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
14629 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
14630 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
14631 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
14632 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
14633 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
14634 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
14635 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
14636}
14637
14638
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014639THREADED_TEST(ScriptContextDependence) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014640 LocalContext c1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014641 v8::HandleScope scope(c1->GetIsolate());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014642 const char *source = "foo";
14643 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
14644 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
14645 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
14646 CHECK_EQ(dep->Run()->Int32Value(), 100);
14647 CHECK_EQ(indep->Run()->Int32Value(), 100);
14648 LocalContext c2;
14649 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
14650 CHECK_EQ(dep->Run()->Int32Value(), 100);
14651 CHECK_EQ(indep->Run()->Int32Value(), 101);
14652}
14653
ager@chromium.org96c75b52009-08-26 09:13:16 +000014654
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014655THREADED_TEST(StackTrace) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014656 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014657 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000014658 v8::TryCatch try_catch;
14659 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14660 v8::Handle<v8::String> src = v8::String::New(source);
14661 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
14662 v8::Script::New(src, origin)->Run();
14663 CHECK(try_catch.HasCaught());
14664 v8::String::Utf8Value stack(try_catch.StackTrace());
14665 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14666}
ager@chromium.org96c75b52009-08-26 09:13:16 +000014667
14668
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014669// Checks that a StackFrame has certain expected values.
14670void checkStackFrame(const char* expected_script_name,
14671 const char* expected_func_name, int expected_line_number,
14672 int expected_column, bool is_eval, bool is_constructor,
14673 v8::Handle<v8::StackFrame> frame) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014674 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014675 v8::String::Utf8Value func_name(frame->GetFunctionName());
14676 v8::String::Utf8Value script_name(frame->GetScriptName());
14677 if (*script_name == NULL) {
14678 // The situation where there is no associated script, like for evals.
14679 CHECK(expected_script_name == NULL);
14680 } else {
14681 CHECK(strstr(*script_name, expected_script_name) != NULL);
14682 }
14683 CHECK(strstr(*func_name, expected_func_name) != NULL);
14684 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14685 CHECK_EQ(expected_column, frame->GetColumn());
14686 CHECK_EQ(is_eval, frame->IsEval());
14687 CHECK_EQ(is_constructor, frame->IsConstructor());
14688}
14689
14690
14691v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014692 v8::HandleScope scope(args.GetIsolate());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014693 const char* origin = "capture-stack-trace-test";
14694 const int kOverviewTest = 1;
14695 const int kDetailedTest = 2;
14696
14697 ASSERT(args.Length() == 1);
14698
14699 int testGroup = args[0]->Int32Value();
14700 if (testGroup == kOverviewTest) {
14701 v8::Handle<v8::StackTrace> stackTrace =
14702 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
14703 CHECK_EQ(4, stackTrace->GetFrameCount());
14704 checkStackFrame(origin, "bar", 2, 10, false, false,
14705 stackTrace->GetFrame(0));
14706 checkStackFrame(origin, "foo", 6, 3, false, false,
14707 stackTrace->GetFrame(1));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014708 // This is the source string inside the eval which has the call to foo.
14709 checkStackFrame(NULL, "", 1, 5, false, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014710 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014711 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014712 checkStackFrame(origin, "", 8, 7, false, false,
14713 stackTrace->GetFrame(3));
14714
14715 CHECK(stackTrace->AsArray()->IsArray());
14716 } else if (testGroup == kDetailedTest) {
14717 v8::Handle<v8::StackTrace> stackTrace =
14718 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14719 CHECK_EQ(4, stackTrace->GetFrameCount());
14720 checkStackFrame(origin, "bat", 4, 22, false, false,
14721 stackTrace->GetFrame(0));
14722 checkStackFrame(origin, "baz", 8, 3, false, true,
14723 stackTrace->GetFrame(1));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014724#ifdef ENABLE_DEBUGGER_SUPPORT
14725 bool is_eval = true;
14726#else // ENABLE_DEBUGGER_SUPPORT
14727 bool is_eval = false;
14728#endif // ENABLE_DEBUGGER_SUPPORT
14729
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014730 // This is the source string inside the eval which has the call to baz.
14731 checkStackFrame(NULL, "", 1, 5, is_eval, false,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014732 stackTrace->GetFrame(2));
whesse@chromium.org030d38e2011-07-13 13:23:34 +000014733 // The last frame is an anonymous function which has the initial eval call.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014734 checkStackFrame(origin, "", 10, 1, false, false,
14735 stackTrace->GetFrame(3));
14736
14737 CHECK(stackTrace->AsArray()->IsArray());
14738 }
14739 return v8::Undefined();
14740}
14741
14742
14743// Tests the C++ StackTrace API.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014744// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14745// THREADED_TEST(CaptureStackTrace) {
14746TEST(CaptureStackTrace) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014747 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014748 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
14749 Local<ObjectTemplate> templ = ObjectTemplate::New();
14750 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14751 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
14752 LocalContext context(0, templ);
14753
14754 // Test getting OVERVIEW information. Should ignore information that is not
14755 // script name, function name, line number, and column offset.
14756 const char *overview_source =
14757 "function bar() {\n"
14758 " var y; AnalyzeStackInNativeCode(1);\n"
14759 "}\n"
14760 "function foo() {\n"
14761 "\n"
14762 " bar();\n"
14763 "}\n"
14764 "var x;eval('new foo();');";
14765 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014766 v8::Handle<Value> overview_result(
14767 v8::Script::New(overview_src, origin)->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014768 CHECK(!overview_result.IsEmpty());
14769 CHECK(overview_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014770
14771 // Test getting DETAILED information.
14772 const char *detailed_source =
14773 "function bat() {AnalyzeStackInNativeCode(2);\n"
14774 "}\n"
14775 "\n"
14776 "function baz() {\n"
14777 " bat();\n"
14778 "}\n"
14779 "eval('new baz();');";
14780 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
14781 // Make the script using a non-zero line and column offset.
14782 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
14783 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
14784 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14785 v8::Handle<v8::Script> detailed_script(
14786 v8::Script::New(detailed_src, &detailed_origin));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014787 v8::Handle<Value> detailed_result(detailed_script->Run());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000014788 CHECK(!detailed_result.IsEmpty());
14789 CHECK(detailed_result->IsObject());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000014790}
14791
14792
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014793static void StackTraceForUncaughtExceptionListener(
14794 v8::Handle<v8::Message> message,
14795 v8::Handle<Value>) {
14796 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14797 CHECK_EQ(2, stack_trace->GetFrameCount());
14798 checkStackFrame("origin", "foo", 2, 3, false, false,
14799 stack_trace->GetFrame(0));
14800 checkStackFrame("origin", "bar", 5, 3, false, false,
14801 stack_trace->GetFrame(1));
14802}
14803
14804TEST(CaptureStackTraceForUncaughtException) {
14805 report_count = 0;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014806 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014807 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000014808 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14809 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14810
14811 Script::Compile(v8_str("function foo() {\n"
14812 " throw 1;\n"
14813 "};\n"
14814 "function bar() {\n"
14815 " foo();\n"
14816 "};"),
14817 v8_str("origin"))->Run();
14818 v8::Local<v8::Object> global = env->Global();
14819 Local<Value> trouble = global->Get(v8_str("bar"));
14820 CHECK(trouble->IsFunction());
14821 Function::Cast(*trouble)->Call(global, 0, NULL);
14822 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14823 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14824}
14825
14826
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014827TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014828 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014829 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014830 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14831 1024,
14832 v8::StackTrace::kDetailed);
14833
14834 CompileRun(
14835 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14836 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14837 " 'isConstructor'];\n"
14838 "for (var i = 0; i < setters.length; i++) {\n"
14839 " var prop = setters[i];\n"
14840 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14841 "}\n");
14842 CompileRun("throw 'exception';");
14843 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14844}
14845
14846
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014847static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14848 v8::Handle<v8::Value> data) {
14849 // Use the frame where JavaScript is called from.
14850 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14851 CHECK(!stack_trace.IsEmpty());
14852 int frame_count = stack_trace->GetFrameCount();
14853 CHECK_EQ(3, frame_count);
14854 int line_number[] = {1, 2, 5};
14855 for (int i = 0; i < frame_count; i++) {
14856 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14857 }
14858}
14859
14860
14861// Test that we only return the stack trace at the site where the exception
14862// is first thrown (not where it is rethrown).
14863TEST(RethrowStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014864 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014865 v8::HandleScope scope(env->GetIsolate());
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014866 // We make sure that
14867 // - the stack trace of the ReferenceError in g() is reported.
14868 // - the stack trace is not overwritten when e1 is rethrown by t().
14869 // - the stack trace of e2 does not overwrite that of e1.
14870 const char* source =
14871 "function g() { error; } \n"
14872 "function f() { g(); } \n"
14873 "function t(e) { throw e; } \n"
14874 "try { \n"
14875 " f(); \n"
14876 "} catch (e1) { \n"
14877 " try { \n"
14878 " error; \n"
14879 " } catch (e2) { \n"
14880 " t(e1); \n"
14881 " } \n"
14882 "} \n";
14883 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14884 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14885 CompileRun(source);
14886 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14887 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14888}
14889
14890
14891static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14892 v8::Handle<v8::Value> data) {
14893 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14894 CHECK(!stack_trace.IsEmpty());
14895 int frame_count = stack_trace->GetFrameCount();
14896 CHECK_EQ(2, frame_count);
14897 int line_number[] = {3, 7};
14898 for (int i = 0; i < frame_count; i++) {
14899 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14900 }
14901}
14902
14903
14904// Test that we do not recognize identity for primitive exceptions.
14905TEST(RethrowPrimitiveStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014906 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014907 v8::HandleScope scope(env->GetIsolate());
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014908 // We do not capture stack trace for non Error objects on creation time.
14909 // Instead, we capture the stack trace on last throw.
14910 const char* source =
14911 "function g() { throw 404; } \n"
14912 "function f() { g(); } \n"
14913 "function t(e) { throw e; } \n"
14914 "try { \n"
14915 " f(); \n"
14916 "} catch (e1) { \n"
14917 " t(e1) \n"
14918 "} \n";
14919 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14920 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14921 CompileRun(source);
14922 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14923 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14924}
14925
14926
14927static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14928 v8::Handle<v8::Value> data) {
14929 // Use the frame where JavaScript is called from.
14930 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14931 CHECK(!stack_trace.IsEmpty());
14932 CHECK_EQ(1, stack_trace->GetFrameCount());
14933 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14934}
14935
14936
14937// Test that the stack trace is captured when the error object is created and
14938// not where it is thrown.
14939TEST(RethrowExistingStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014940 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014941 v8::HandleScope scope(env->GetIsolate());
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014942 const char* source =
14943 "var e = new Error(); \n"
14944 "throw e; \n";
14945 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14946 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14947 CompileRun(source);
14948 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14949 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14950}
14951
14952
14953static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14954 v8::Handle<v8::Value> data) {
14955 // Use the frame where JavaScript is called from.
14956 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14957 CHECK(!stack_trace.IsEmpty());
14958 CHECK_EQ(1, stack_trace->GetFrameCount());
14959 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14960}
14961
14962
14963// Test that the stack trace is captured where the bogus Error object is thrown.
14964TEST(RethrowBogusErrorStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014965 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014966 v8::HandleScope scope(env->GetIsolate());
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014967 const char* source =
14968 "var e = {__proto__: new Error()} \n"
14969 "throw e; \n";
14970 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14971 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14972 CompileRun(source);
14973 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14974 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14975}
14976
14977
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014978v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014979 v8::HandleScope scope(args.GetIsolate());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014980 v8::Handle<v8::StackTrace> stackTrace =
14981 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
14982 CHECK_EQ(5, stackTrace->GetFrameCount());
14983 v8::Handle<v8::String> url = v8_str("eval_url");
14984 for (int i = 0; i < 3; i++) {
14985 v8::Handle<v8::String> name =
14986 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
14987 CHECK(!name.IsEmpty());
14988 CHECK_EQ(url, name);
14989 }
14990 return v8::Undefined();
14991}
14992
14993
14994TEST(SourceURLInStackTrace) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000014995 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000014996 Local<ObjectTemplate> templ = ObjectTemplate::New();
14997 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
14998 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
14999 LocalContext context(0, templ);
15000
15001 const char *source =
15002 "function outer() {\n"
15003 "function bar() {\n"
15004 " AnalyzeStackOfEvalWithSourceURL();\n"
15005 "}\n"
15006 "function foo() {\n"
15007 "\n"
15008 " bar();\n"
15009 "}\n"
15010 "foo();\n"
15011 "}\n"
15012 "eval('(' + outer +')()//@ sourceURL=eval_url');";
15013 CHECK(CompileRun(source)->IsUndefined());
15014}
15015
15016
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000015017v8::Handle<Value> AnalyzeStackOfInlineScriptWithSourceURL(
15018 const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015019 v8::HandleScope scope(args.GetIsolate());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000015020 v8::Handle<v8::StackTrace> stackTrace =
15021 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
15022 CHECK_EQ(4, stackTrace->GetFrameCount());
15023 v8::Handle<v8::String> url = v8_str("url");
15024 for (int i = 0; i < 3; i++) {
15025 v8::Handle<v8::String> name =
15026 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15027 CHECK(!name.IsEmpty());
15028 CHECK_EQ(url, name);
15029 }
15030 return v8::Undefined();
15031}
15032
15033
15034TEST(InlineScriptWithSourceURLInStackTrace) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015035 v8::HandleScope scope(v8::Isolate::GetCurrent());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000015036 Local<ObjectTemplate> templ = ObjectTemplate::New();
15037 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15038 v8::FunctionTemplate::New(
15039 AnalyzeStackOfInlineScriptWithSourceURL));
15040 LocalContext context(0, templ);
15041
15042 const char *source =
15043 "function outer() {\n"
15044 "function bar() {\n"
15045 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
15046 "}\n"
15047 "function foo() {\n"
15048 "\n"
15049 " bar();\n"
15050 "}\n"
15051 "foo();\n"
15052 "}\n"
15053 "outer()\n"
15054 "//@ sourceURL=source_url";
15055 CHECK(CompileRunWithOrigin(source, "url", 0, 1)->IsUndefined());
15056}
15057
15058
15059v8::Handle<Value> AnalyzeStackOfDynamicScriptWithSourceURL(
15060 const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015061 v8::HandleScope scope(args.GetIsolate());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000015062 v8::Handle<v8::StackTrace> stackTrace =
15063 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
15064 CHECK_EQ(4, stackTrace->GetFrameCount());
15065 v8::Handle<v8::String> url = v8_str("source_url");
15066 for (int i = 0; i < 3; i++) {
15067 v8::Handle<v8::String> name =
15068 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15069 CHECK(!name.IsEmpty());
15070 CHECK_EQ(url, name);
15071 }
15072 return v8::Undefined();
15073}
15074
15075
15076TEST(DynamicWithSourceURLInStackTrace) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015077 v8::HandleScope scope(v8::Isolate::GetCurrent());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000015078 Local<ObjectTemplate> templ = ObjectTemplate::New();
15079 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15080 v8::FunctionTemplate::New(
15081 AnalyzeStackOfDynamicScriptWithSourceURL));
15082 LocalContext context(0, templ);
15083
15084 const char *source =
15085 "function outer() {\n"
15086 "function bar() {\n"
15087 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15088 "}\n"
15089 "function foo() {\n"
15090 "\n"
15091 " bar();\n"
15092 "}\n"
15093 "foo();\n"
15094 "}\n"
15095 "outer()\n"
15096 "//@ sourceURL=source_url";
15097 CHECK(CompileRunWithOrigin(source, "url", 0, 0)->IsUndefined());
15098}
15099
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015100static void CreateGarbageInOldSpace() {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015101 v8::HandleScope scope(v8::Isolate::GetCurrent());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015102 i::AlwaysAllocateScope always_allocate;
15103 for (int i = 0; i < 1000; i++) {
15104 FACTORY->NewFixedArray(1000, i::TENURED);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015105 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000015106}
15107
15108// Test that idle notification can be handled and eventually returns true.
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015109TEST(IdleNotification) {
15110 const intptr_t MB = 1024 * 1024;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015111 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015112 v8::HandleScope scope(env->GetIsolate());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015113 intptr_t initial_size = HEAP->SizeOfObjects();
15114 CreateGarbageInOldSpace();
15115 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15116 CHECK_GT(size_with_garbage, initial_size + MB);
15117 bool finished = false;
15118 for (int i = 0; i < 200 && !finished; i++) {
15119 finished = v8::V8::IdleNotification();
15120 }
15121 intptr_t final_size = HEAP->SizeOfObjects();
15122 CHECK(finished);
15123 CHECK_LT(final_size, initial_size + 1);
15124}
15125
15126
15127// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000015128TEST(IdleNotificationWithSmallHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015129 const intptr_t MB = 1024 * 1024;
15130 const int IdlePauseInMs = 900;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +000015131 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015132 v8::HandleScope scope(env->GetIsolate());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015133 intptr_t initial_size = HEAP->SizeOfObjects();
15134 CreateGarbageInOldSpace();
15135 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15136 CHECK_GT(size_with_garbage, initial_size + MB);
15137 bool finished = false;
15138 for (int i = 0; i < 200 && !finished; i++) {
15139 finished = v8::V8::IdleNotification(IdlePauseInMs);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015140 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015141 intptr_t final_size = HEAP->SizeOfObjects();
15142 CHECK(finished);
15143 CHECK_LT(final_size, initial_size + 1);
yangguo@chromium.org56454712012-02-16 15:33:53 +000015144}
15145
15146
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015147// Test that idle notification can be handled and eventually collects garbage.
yangguo@chromium.org56454712012-02-16 15:33:53 +000015148TEST(IdleNotificationWithLargeHint) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015149 const intptr_t MB = 1024 * 1024;
15150 const int IdlePauseInMs = 900;
yangguo@chromium.org56454712012-02-16 15:33:53 +000015151 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015152 v8::HandleScope scope(env->GetIsolate());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015153 intptr_t initial_size = HEAP->SizeOfObjects();
15154 CreateGarbageInOldSpace();
15155 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15156 CHECK_GT(size_with_garbage, initial_size + MB);
15157 bool finished = false;
15158 for (int i = 0; i < 200 && !finished; i++) {
15159 finished = v8::V8::IdleNotification(IdlePauseInMs);
yangguo@chromium.org56454712012-02-16 15:33:53 +000015160 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015161 intptr_t final_size = HEAP->SizeOfObjects();
15162 CHECK(finished);
15163 CHECK_LT(final_size, initial_size + 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015164}
15165
15166
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015167TEST(Regress2107) {
15168 const intptr_t MB = 1024 * 1024;
15169 const int kShortIdlePauseInMs = 100;
15170 const int kLongIdlePauseInMs = 1000;
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015171 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015172 v8::HandleScope scope(env->GetIsolate());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015173 intptr_t initial_size = HEAP->SizeOfObjects();
15174 // Send idle notification to start a round of incremental GCs.
15175 v8::V8::IdleNotification(kShortIdlePauseInMs);
15176 // Emulate 7 page reloads.
15177 for (int i = 0; i < 7; i++) {
15178 v8::Persistent<v8::Context> ctx = v8::Context::New();
15179 ctx->Enter();
15180 CreateGarbageInOldSpace();
15181 ctx->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000015182 ctx.Dispose(ctx->GetIsolate());
danno@chromium.org2c26cb12012-05-03 09:06:43 +000015183 v8::V8::ContextDisposedNotification();
15184 v8::V8::IdleNotification(kLongIdlePauseInMs);
15185 }
15186 // Create garbage and check that idle notification still collects it.
15187 CreateGarbageInOldSpace();
15188 intptr_t size_with_garbage = HEAP->SizeOfObjects();
15189 CHECK_GT(size_with_garbage, initial_size + MB);
15190 bool finished = false;
15191 for (int i = 0; i < 200 && !finished; i++) {
15192 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
15193 }
15194 intptr_t final_size = HEAP->SizeOfObjects();
15195 CHECK_LT(final_size, initial_size + 1);
15196}
15197
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015198static uint32_t* stack_limit;
15199
15200static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015201 stack_limit = reinterpret_cast<uint32_t*>(
15202 i::Isolate::Current()->stack_guard()->real_climit());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015203 return v8::Undefined();
15204}
15205
15206
15207// Uses the address of a local variable to determine the stack top now.
15208// Given a size, returns an address that is that far from the current
15209// top of stack.
15210static uint32_t* ComputeStackLimit(uint32_t size) {
15211 uint32_t* answer = &size - (size / sizeof(size));
15212 // If the size is very large and the stack is very near the bottom of
15213 // memory then the calculation above may wrap around and give an address
15214 // that is above the (downwards-growing) stack. In that case we return
15215 // a very low address.
15216 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
15217 return answer;
15218}
15219
15220
15221TEST(SetResourceConstraints) {
15222 static const int K = 1024;
15223 uint32_t* set_limit = ComputeStackLimit(128 * K);
15224
15225 // Set stack limit.
15226 v8::ResourceConstraints constraints;
15227 constraints.set_stack_limit(set_limit);
15228 CHECK(v8::SetResourceConstraints(&constraints));
15229
15230 // Execute a script.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015231 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015232 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015233 Local<v8::FunctionTemplate> fun_templ =
15234 v8::FunctionTemplate::New(GetStackLimitCallback);
15235 Local<Function> fun = fun_templ->GetFunction();
15236 env->Global()->Set(v8_str("get_stack_limit"), fun);
15237 CompileRun("get_stack_limit();");
15238
15239 CHECK(stack_limit == set_limit);
15240}
15241
15242
15243TEST(SetResourceConstraintsInThread) {
15244 uint32_t* set_limit;
15245 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015246 v8::Locker locker(CcTest::default_isolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015247 static const int K = 1024;
15248 set_limit = ComputeStackLimit(128 * K);
15249
15250 // Set stack limit.
15251 v8::ResourceConstraints constraints;
15252 constraints.set_stack_limit(set_limit);
15253 CHECK(v8::SetResourceConstraints(&constraints));
15254
15255 // Execute a script.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015256 v8::HandleScope scope(CcTest::default_isolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015257 LocalContext env;
15258 Local<v8::FunctionTemplate> fun_templ =
15259 v8::FunctionTemplate::New(GetStackLimitCallback);
15260 Local<Function> fun = fun_templ->GetFunction();
15261 env->Global()->Set(v8_str("get_stack_limit"), fun);
15262 CompileRun("get_stack_limit();");
15263
15264 CHECK(stack_limit == set_limit);
15265 }
15266 {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015267 v8::Locker locker(CcTest::default_isolate());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000015268 CHECK(stack_limit == set_limit);
15269 }
ager@chromium.org96c75b52009-08-26 09:13:16 +000015270}
ager@chromium.org3811b432009-10-28 14:53:37 +000015271
15272
15273THREADED_TEST(GetHeapStatistics) {
ager@chromium.org3811b432009-10-28 14:53:37 +000015274 LocalContext c1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015275 v8::HandleScope scope(c1->GetIsolate());
ager@chromium.org3811b432009-10-28 14:53:37 +000015276 v8::HeapStatistics heap_statistics;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015277 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
15278 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000015279 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
ager@chromium.orgc4c92722009-11-18 14:12:51 +000015280 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15281 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000015282}
15283
15284
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015285class VisitorImpl : public v8::ExternalResourceVisitor {
15286 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015287 explicit VisitorImpl(TestResource** resource) {
15288 for (int i = 0; i < 4; i++) {
15289 resource_[i] = resource[i];
15290 found_resource_[i] = false;
15291 }
15292 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015293 virtual ~VisitorImpl() {}
15294 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15295 if (!string->IsExternal()) {
15296 CHECK(string->IsExternalAscii());
15297 return;
15298 }
15299 v8::String::ExternalStringResource* resource =
15300 string->GetExternalStringResource();
15301 CHECK(resource);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015302 for (int i = 0; i < 4; i++) {
15303 if (resource_[i] == resource) {
15304 CHECK(!found_resource_[i]);
15305 found_resource_[i] = true;
15306 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015307 }
15308 }
15309 void CheckVisitedResources() {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015310 for (int i = 0; i < 4; i++) {
15311 CHECK(found_resource_[i]);
15312 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015313 }
15314
15315 private:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015316 v8::String::ExternalStringResource* resource_[4];
15317 bool found_resource_[4];
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015318};
15319
15320TEST(VisitExternalStrings) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015321 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015322 v8::HandleScope scope(env->GetIsolate());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015323 const char* string = "Some string";
15324 uint16_t* two_byte_string = AsciiToTwoByteString(string);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015325 TestResource* resource[4];
15326 resource[0] = new TestResource(two_byte_string);
15327 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
15328 resource[1] = new TestResource(two_byte_string);
15329 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015330
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015331 // Externalized symbol.
15332 resource[2] = new TestResource(two_byte_string);
15333 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
15334 CHECK(string2->MakeExternal(resource[2]));
15335
15336 // Symbolized External.
15337 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15338 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
15339 HEAP->CollectAllAvailableGarbage(); // Tenure string.
15340 // Turn into a symbol.
15341 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015342 CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure());
15343 CHECK(string3_i->IsInternalizedString());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015344
15345 // We need to add usages for string* to avoid warnings in GCC 4.7
15346 CHECK(string0->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015347 CHECK(string1->IsExternal());
15348 CHECK(string2->IsExternal());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015349 CHECK(string3->IsExternal());
ulan@chromium.org2efb9002012-01-19 15:36:35 +000015350
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000015351 VisitorImpl visitor(resource);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015352 v8::V8::VisitExternalResources(&visitor);
15353 visitor.CheckVisitedResources();
15354}
15355
15356
ager@chromium.org3811b432009-10-28 14:53:37 +000015357static double DoubleFromBits(uint64_t value) {
15358 double target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015359 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015360 return target;
15361}
15362
15363
15364static uint64_t DoubleToBits(double value) {
15365 uint64_t target;
ager@chromium.org3811b432009-10-28 14:53:37 +000015366 memcpy(&target, &value, sizeof(target));
ager@chromium.org3811b432009-10-28 14:53:37 +000015367 return target;
15368}
15369
15370
15371static double DoubleToDateTime(double input) {
15372 double date_limit = 864e13;
15373 if (IsNaN(input) || input < -date_limit || input > date_limit) {
15374 return i::OS::nan_value();
15375 }
15376 return (input < 0) ? -(floor(-input)) : floor(input);
15377}
15378
15379// We don't have a consistent way to write 64-bit constants syntactically, so we
15380// split them into two 32-bit constants and combine them programmatically.
15381static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15382 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15383}
15384
15385
15386THREADED_TEST(QuietSignalingNaNs) {
ager@chromium.org3811b432009-10-28 14:53:37 +000015387 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015388 v8::HandleScope scope(context->GetIsolate());
ager@chromium.org3811b432009-10-28 14:53:37 +000015389 v8::TryCatch try_catch;
15390
15391 // Special double values.
15392 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15393 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15394 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15395 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15396 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15397 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15398 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15399
15400 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15401 // on either side of the epoch.
15402 double date_limit = 864e13;
15403
15404 double test_values[] = {
15405 snan,
15406 qnan,
15407 infinity,
15408 max_normal,
15409 date_limit + 1,
15410 date_limit,
15411 min_normal,
15412 max_denormal,
15413 min_denormal,
15414 0,
15415 -0,
15416 -min_denormal,
15417 -max_denormal,
15418 -min_normal,
15419 -date_limit,
15420 -date_limit - 1,
15421 -max_normal,
15422 -infinity,
15423 -qnan,
15424 -snan
15425 };
15426 int num_test_values = 20;
15427
15428 for (int i = 0; i < num_test_values; i++) {
15429 double test_value = test_values[i];
15430
15431 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15432 v8::Handle<v8::Value> number = v8::Number::New(test_value);
15433 double stored_number = number->NumberValue();
15434 if (!IsNaN(test_value)) {
15435 CHECK_EQ(test_value, stored_number);
15436 } else {
15437 uint64_t stored_bits = DoubleToBits(stored_number);
15438 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015439#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15440 // Most significant fraction bit for quiet nan is set to 0
15441 // on MIPS architecture. Allowed by IEEE-754.
15442 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15443#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015444 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015445#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015446 }
15447
15448 // Check that Date::New preserves non-NaNs in the date range and
15449 // quiets SNaNs.
15450 v8::Handle<v8::Value> date = v8::Date::New(test_value);
15451 double expected_stored_date = DoubleToDateTime(test_value);
15452 double stored_date = date->NumberValue();
15453 if (!IsNaN(expected_stored_date)) {
15454 CHECK_EQ(expected_stored_date, stored_date);
15455 } else {
15456 uint64_t stored_bits = DoubleToBits(stored_date);
15457 // Check if quiet nan (bits 51..62 all set).
danno@chromium.orgc612e022011-11-10 11:38:15 +000015458#if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
15459 // Most significant fraction bit for quiet nan is set to 0
15460 // on MIPS architecture. Allowed by IEEE-754.
15461 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15462#else
ager@chromium.org3811b432009-10-28 14:53:37 +000015463 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
danno@chromium.orgc612e022011-11-10 11:38:15 +000015464#endif
ager@chromium.org3811b432009-10-28 14:53:37 +000015465 }
15466 }
15467}
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015468
15469
15470static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015471 v8::HandleScope scope(args.GetIsolate());
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015472 v8::TryCatch tc;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015473 v8::Handle<v8::String> str(args[0]->ToString());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015474 USE(str);
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015475 if (tc.HasCaught())
15476 return tc.ReThrow();
15477 return v8::Undefined();
15478}
15479
15480
15481// Test that an exception can be propagated down through a spaghetti
15482// stack using ReThrow.
15483THREADED_TEST(SpaghettiStackReThrow) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015484 v8::HandleScope scope(v8::Isolate::GetCurrent());
christian.plesner.hansen@gmail.comb9ce6372009-11-03 11:38:18 +000015485 LocalContext context;
15486 context->Global()->Set(
15487 v8::String::New("s"),
15488 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
15489 v8::TryCatch try_catch;
15490 CompileRun(
15491 "var i = 0;"
15492 "var o = {"
15493 " toString: function () {"
15494 " if (i == 10) {"
15495 " throw 'Hey!';"
15496 " } else {"
15497 " i++;"
15498 " return s(o);"
15499 " }"
15500 " }"
15501 "};"
15502 "s(o);");
15503 CHECK(try_catch.HasCaught());
15504 v8::String::Utf8Value value(try_catch.Exception());
15505 CHECK_EQ(0, strcmp(*value, "Hey!"));
15506}
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015507
15508
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015509TEST(Regress528) {
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015510 v8::V8::Initialize();
15511
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015512 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015513 v8::Persistent<Context> context;
ager@chromium.org60121232009-12-03 11:25:37 +000015514 v8::Persistent<Context> other_context;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015515 int gc_count;
15516
ager@chromium.org60121232009-12-03 11:25:37 +000015517 // Create a context used to keep the code from aging in the compilation
15518 // cache.
15519 other_context = Context::New();
15520
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015521 // Context-dependent context data creates reference from the compilation
15522 // cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015523 const char* source_simple = "1";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015524 context = Context::New();
15525 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015526 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015527
15528 context->Enter();
15529 Local<v8::String> obj = v8::String::New("");
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000015530 context->SetEmbedderData(0, obj);
ager@chromium.org60121232009-12-03 11:25:37 +000015531 CompileRun(source_simple);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015532 context->Exit();
15533 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000015534 context.Dispose(context->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015535 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015536 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015537 other_context->Enter();
15538 CompileRun(source_simple);
15539 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015540 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015541 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015542 }
ager@chromium.org60121232009-12-03 11:25:37 +000015543 CHECK_GE(2, gc_count);
15544 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015545
15546 // Eval in a function creates reference from the compilation cache to the
15547 // global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015548 const char* source_eval = "function f(){eval('1')}; f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015549 context = Context::New();
15550 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015551 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015552
15553 context->Enter();
ager@chromium.org60121232009-12-03 11:25:37 +000015554 CompileRun(source_eval);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015555 context->Exit();
15556 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000015557 context.Dispose(context->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015558 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015559 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015560 other_context->Enter();
15561 CompileRun(source_eval);
15562 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015563 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015564 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015565 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000015566 CHECK_GE(2, gc_count);
sgjesse@chromium.org98180592009-12-02 08:17:28 +000015567 CHECK_EQ(1, GetGlobalObjectsCount());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015568
15569 // Looking up the line number for an exception creates reference from the
15570 // compilation cache to the global object.
ager@chromium.org60121232009-12-03 11:25:37 +000015571 const char* source_exception = "function f(){throw 1;} f()";
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015572 context = Context::New();
15573 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015574 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015575
15576 context->Enter();
15577 v8::TryCatch try_catch;
ager@chromium.org60121232009-12-03 11:25:37 +000015578 CompileRun(source_exception);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015579 CHECK(try_catch.HasCaught());
15580 v8::Handle<v8::Message> message = try_catch.Message();
15581 CHECK(!message.IsEmpty());
15582 CHECK_EQ(1, message->GetLineNumber());
15583 context->Exit();
15584 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000015585 context.Dispose(context->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000015586 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015587 for (gc_count = 1; gc_count < 10; gc_count++) {
ager@chromium.org60121232009-12-03 11:25:37 +000015588 other_context->Enter();
15589 CompileRun(source_exception);
15590 other_context->Exit();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015591 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.org60121232009-12-03 11:25:37 +000015592 if (GetGlobalObjectsCount() == 1) break;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015593 }
ager@chromium.org60121232009-12-03 11:25:37 +000015594 CHECK_GE(2, gc_count);
15595 CHECK_EQ(1, GetGlobalObjectsCount());
15596
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000015597 other_context.Dispose(other_context->GetIsolate());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015598 v8::V8::ContextDisposedNotification();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +000015599}
ager@chromium.org5c838252010-02-19 08:53:10 +000015600
15601
15602THREADED_TEST(ScriptOrigin) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015603 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015604 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +000015605 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15606 v8::Handle<v8::String> script = v8::String::New(
15607 "function f() {}\n\nfunction g() {}");
15608 v8::Script::Compile(script, &origin)->Run();
15609 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15610 env->Global()->Get(v8::String::New("f")));
15611 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15612 env->Global()->Get(v8::String::New("g")));
15613
15614 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15615 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
15616 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
15617
15618 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15619 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
15620 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
15621}
15622
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015623THREADED_TEST(FunctionGetInferredName) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015624 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015625 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000015626 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15627 v8::Handle<v8::String> script = v8::String::New(
15628 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15629 v8::Script::Compile(script, &origin)->Run();
15630 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15631 env->Global()->Get(v8::String::New("f")));
15632 CHECK_EQ("foo.bar.baz", *v8::String::AsciiValue(f->GetInferredName()));
15633}
ager@chromium.org5c838252010-02-19 08:53:10 +000015634
15635THREADED_TEST(ScriptLineNumber) {
ager@chromium.org5c838252010-02-19 08:53:10 +000015636 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015637 v8::HandleScope scope(env->GetIsolate());
ager@chromium.org5c838252010-02-19 08:53:10 +000015638 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
15639 v8::Handle<v8::String> script = v8::String::New(
15640 "function f() {}\n\nfunction g() {}");
15641 v8::Script::Compile(script, &origin)->Run();
15642 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15643 env->Global()->Get(v8::String::New("f")));
15644 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15645 env->Global()->Get(v8::String::New("g")));
15646 CHECK_EQ(0, f->GetScriptLineNumber());
15647 CHECK_EQ(2, g->GetScriptLineNumber());
15648}
15649
15650
danno@chromium.orgc612e022011-11-10 11:38:15 +000015651THREADED_TEST(ScriptColumnNumber) {
danno@chromium.orgc612e022011-11-10 11:38:15 +000015652 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015653 v8::HandleScope scope(env->GetIsolate());
danno@chromium.orgc612e022011-11-10 11:38:15 +000015654 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15655 v8::Integer::New(3), v8::Integer::New(2));
15656 v8::Handle<v8::String> script = v8::String::New(
15657 "function foo() {}\n\n function bar() {}");
15658 v8::Script::Compile(script, &origin)->Run();
15659 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15660 env->Global()->Get(v8::String::New("foo")));
15661 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15662 env->Global()->Get(v8::String::New("bar")));
15663 CHECK_EQ(14, foo->GetScriptColumnNumber());
15664 CHECK_EQ(17, bar->GetScriptColumnNumber());
15665}
15666
15667
15668THREADED_TEST(FunctionGetScriptId) {
danno@chromium.orgc612e022011-11-10 11:38:15 +000015669 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015670 v8::HandleScope scope(env->GetIsolate());
danno@chromium.orgc612e022011-11-10 11:38:15 +000015671 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
15672 v8::Integer::New(3), v8::Integer::New(2));
15673 v8::Handle<v8::String> scriptSource = v8::String::New(
15674 "function foo() {}\n\n function bar() {}");
15675 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
15676 script->Run();
15677 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
15678 env->Global()->Get(v8::String::New("foo")));
15679 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
15680 env->Global()->Get(v8::String::New("bar")));
15681 CHECK_EQ(script->Id(), foo->GetScriptId());
15682 CHECK_EQ(script->Id(), bar->GetScriptId());
15683}
15684
15685
ager@chromium.org5c838252010-02-19 08:53:10 +000015686static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
15687 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015688 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15689 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015690 return v8_num(42);
15691}
15692
15693
15694static void SetterWhichSetsYOnThisTo23(Local<String> name,
15695 Local<Value> value,
15696 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015697 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15698 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
ager@chromium.org5c838252010-02-19 08:53:10 +000015699 info.This()->Set(v8_str("y"), v8_num(23));
15700}
15701
15702
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015703Handle<Value> FooGetInterceptor(Local<String> name,
15704 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015705 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15706 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015707 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15708 return v8_num(42);
15709}
15710
15711
15712Handle<Value> FooSetInterceptor(Local<String> name,
15713 Local<Value> value,
15714 const AccessorInfo& info) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000015715 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
15716 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015717 if (!name->Equals(v8_str("foo"))) return Handle<Value>();
15718 info.This()->Set(v8_str("y"), v8_num(23));
15719 return v8_num(23);
15720}
15721
15722
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015723TEST(SetterOnConstructorPrototype) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015724 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000015725 Local<ObjectTemplate> templ = ObjectTemplate::New();
15726 templ->SetAccessor(v8_str("x"),
15727 GetterWhichReturns42,
15728 SetterWhichSetsYOnThisTo23);
15729 LocalContext context;
15730 context->Global()->Set(v8_str("P"), templ->NewInstance());
15731 CompileRun("function C1() {"
15732 " this.x = 23;"
15733 "};"
15734 "C1.prototype = P;"
15735 "function C2() {"
15736 " this.x = 23"
15737 "};"
15738 "C2.prototype = { };"
15739 "C2.prototype.__proto__ = P;");
15740
15741 v8::Local<v8::Script> script;
15742 script = v8::Script::Compile(v8_str("new C1();"));
15743 for (int i = 0; i < 10; i++) {
15744 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15745 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15746 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15747 }
15748
15749 script = v8::Script::Compile(v8_str("new C2();"));
15750 for (int i = 0; i < 10; i++) {
15751 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15752 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
15753 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
15754 }
15755}
15756
15757
15758static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
15759 Local<String> name, const AccessorInfo& info) {
15760 return v8_num(42);
15761}
15762
15763
15764static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
15765 Local<String> name, Local<Value> value, const AccessorInfo& info) {
15766 if (name->Equals(v8_str("x"))) {
15767 info.This()->Set(v8_str("y"), v8_num(23));
15768 }
15769 return v8::Handle<Value>();
15770}
15771
15772
15773THREADED_TEST(InterceptorOnConstructorPrototype) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015774 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.org5c838252010-02-19 08:53:10 +000015775 Local<ObjectTemplate> templ = ObjectTemplate::New();
15776 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
15777 NamedPropertySetterWhichSetsYOnThisTo23);
15778 LocalContext context;
15779 context->Global()->Set(v8_str("P"), templ->NewInstance());
15780 CompileRun("function C1() {"
15781 " this.x = 23;"
15782 "};"
15783 "C1.prototype = P;"
15784 "function C2() {"
15785 " this.x = 23"
15786 "};"
15787 "C2.prototype = { };"
15788 "C2.prototype.__proto__ = P;");
15789
15790 v8::Local<v8::Script> script;
15791 script = v8::Script::Compile(v8_str("new C1();"));
15792 for (int i = 0; i < 10; i++) {
15793 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15794 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15795 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15796 }
15797
15798 script = v8::Script::Compile(v8_str("new C2();"));
15799 for (int i = 0; i < 10; i++) {
15800 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
15801 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
15802 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
15803 }
15804}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015805
15806
15807TEST(Bug618) {
15808 const char* source = "function C1() {"
15809 " this.x = 23;"
15810 "};"
15811 "C1.prototype = P;";
15812
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015813 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015814 v8::HandleScope scope(context->GetIsolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015815 v8::Local<v8::Script> script;
15816
15817 // Use a simple object as prototype.
15818 v8::Local<v8::Object> prototype = v8::Object::New();
15819 prototype->Set(v8_str("y"), v8_num(42));
15820 context->Global()->Set(v8_str("P"), prototype);
15821
15822 // This compile will add the code to the compilation cache.
15823 CompileRun(source);
15824
15825 script = v8::Script::Compile(v8_str("new C1();"));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015826 // Allow enough iterations for the inobject slack tracking logic
15827 // to finalize instance size and install the fast construct stub.
15828 for (int i = 0; i < 256; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000015829 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15830 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
15831 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
15832 }
15833
15834 // Use an API object with accessors as prototype.
15835 Local<ObjectTemplate> templ = ObjectTemplate::New();
15836 templ->SetAccessor(v8_str("x"),
15837 GetterWhichReturns42,
15838 SetterWhichSetsYOnThisTo23);
15839 context->Global()->Set(v8_str("P"), templ->NewInstance());
15840
15841 // This compile will get the code from the compilation cache.
15842 CompileRun(source);
15843
15844 script = v8::Script::Compile(v8_str("new C1();"));
15845 for (int i = 0; i < 10; i++) {
15846 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
15847 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
15848 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
15849 }
15850}
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015851
15852int prologue_call_count = 0;
15853int epilogue_call_count = 0;
15854int prologue_call_count_second = 0;
15855int epilogue_call_count_second = 0;
15856
15857void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
15858 ++prologue_call_count;
15859}
15860
15861void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
15862 ++epilogue_call_count;
15863}
15864
15865void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15866 ++prologue_call_count_second;
15867}
15868
15869void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
15870 ++epilogue_call_count_second;
15871}
15872
15873TEST(GCCallbacks) {
15874 LocalContext context;
15875
15876 v8::V8::AddGCPrologueCallback(PrologueCallback);
15877 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
15878 CHECK_EQ(0, prologue_call_count);
15879 CHECK_EQ(0, epilogue_call_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015880 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015881 CHECK_EQ(1, prologue_call_count);
15882 CHECK_EQ(1, epilogue_call_count);
15883 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
15884 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015885 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015886 CHECK_EQ(2, prologue_call_count);
15887 CHECK_EQ(2, epilogue_call_count);
15888 CHECK_EQ(1, prologue_call_count_second);
15889 CHECK_EQ(1, epilogue_call_count_second);
15890 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
15891 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015892 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015893 CHECK_EQ(2, prologue_call_count);
15894 CHECK_EQ(2, epilogue_call_count);
15895 CHECK_EQ(2, prologue_call_count_second);
15896 CHECK_EQ(2, epilogue_call_count_second);
15897 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
15898 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000015899 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000015900 CHECK_EQ(2, prologue_call_count);
15901 CHECK_EQ(2, epilogue_call_count);
15902 CHECK_EQ(2, prologue_call_count_second);
15903 CHECK_EQ(2, epilogue_call_count_second);
15904}
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015905
15906
15907THREADED_TEST(AddToJSFunctionResultCache) {
15908 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015909 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015910
15911 LocalContext context;
15912
15913 const char* code =
15914 "(function() {"
15915 " var key0 = 'a';"
15916 " var key1 = 'b';"
15917 " var r0 = %_GetFromCache(0, key0);"
15918 " var r1 = %_GetFromCache(0, key1);"
15919 " var r0_ = %_GetFromCache(0, key0);"
15920 " if (r0 !== r0_)"
15921 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
15922 " var r1_ = %_GetFromCache(0, key1);"
15923 " if (r1 !== r1_)"
15924 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
15925 " return 'PASSED';"
15926 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015927 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015928 ExpectString(code, "PASSED");
15929}
15930
15931
15932static const int k0CacheSize = 16;
15933
15934THREADED_TEST(FillJSFunctionResultCache) {
15935 i::FLAG_allow_natives_syntax = true;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015936 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015937 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015938
15939 const char* code =
15940 "(function() {"
15941 " var k = 'a';"
15942 " var r = %_GetFromCache(0, k);"
15943 " for (var i = 0; i < 16; i++) {"
15944 " %_GetFromCache(0, 'a' + i);"
15945 " };"
15946 " if (r === %_GetFromCache(0, k))"
15947 " return 'FAILED: k0CacheSize is too small';"
15948 " return 'PASSED';"
15949 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015950 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015951 ExpectString(code, "PASSED");
15952}
15953
15954
15955THREADED_TEST(RoundRobinGetFromCache) {
15956 i::FLAG_allow_natives_syntax = true;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015957 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015958 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015959
15960 const char* code =
15961 "(function() {"
15962 " var keys = [];"
15963 " for (var i = 0; i < 16; i++) keys.push(i);"
15964 " var values = [];"
15965 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15966 " for (var i = 0; i < 16; i++) {"
15967 " var v = %_GetFromCache(0, keys[i]);"
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000015968 " if (v.toString() !== values[i].toString())"
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015969 " return 'Wrong value for ' + "
15970 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15971 " };"
15972 " return 'PASSED';"
15973 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015974 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015975 ExpectString(code, "PASSED");
15976}
15977
15978
15979THREADED_TEST(ReverseGetFromCache) {
15980 i::FLAG_allow_natives_syntax = true;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015981 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000015982 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015983
15984 const char* code =
15985 "(function() {"
15986 " var keys = [];"
15987 " for (var i = 0; i < 16; i++) keys.push(i);"
15988 " var values = [];"
15989 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
15990 " for (var i = 15; i >= 16; i--) {"
15991 " var v = %_GetFromCache(0, keys[i]);"
15992 " if (v !== values[i])"
15993 " return 'Wrong value for ' + "
15994 " keys[i] + ': ' + v + ' vs. ' + values[i];"
15995 " };"
15996 " return 'PASSED';"
15997 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015998 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000015999 ExpectString(code, "PASSED");
16000}
16001
16002
16003THREADED_TEST(TestEviction) {
16004 i::FLAG_allow_natives_syntax = true;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000016005 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016006 v8::HandleScope scope(context->GetIsolate());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000016007
16008 const char* code =
16009 "(function() {"
16010 " for (var i = 0; i < 2*16; i++) {"
16011 " %_GetFromCache(0, 'a' + i);"
16012 " };"
16013 " return 'PASSED';"
16014 "})()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016015 HEAP->ClearJSFunctionResultCaches();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000016016 ExpectString(code, "PASSED");
16017}
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016018
16019
16020THREADED_TEST(TwoByteStringInAsciiCons) {
16021 // See Chromium issue 47824.
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016022 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016023 v8::HandleScope scope(context->GetIsolate());
16024
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016025 const char* init_code =
16026 "var str1 = 'abelspendabel';"
16027 "var str2 = str1 + str1 + str1;"
16028 "str2;";
16029 Local<Value> result = CompileRun(init_code);
16030
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000016031 Local<Value> indexof = CompileRun("str2.indexOf('els')");
16032 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
16033
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016034 CHECK(result->IsString());
16035 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
16036 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000016037 CHECK(string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016038
16039 FlattenString(string);
16040 i::Handle<i::String> flat_string = FlattenGetString(string);
16041
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000016042 CHECK(string->IsOneByteRepresentation());
16043 CHECK(flat_string->IsOneByteRepresentation());
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016044
16045 // Create external resource.
16046 uint16_t* uc16_buffer = new uint16_t[length + 1];
16047
16048 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
16049 uc16_buffer[length] = 0;
16050
16051 TestResource resource(uc16_buffer);
16052
16053 flat_string->MakeExternal(&resource);
16054
16055 CHECK(flat_string->IsTwoByteRepresentation());
16056
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +000016057 // If the cons string has been short-circuited, skip the following checks.
16058 if (!string.is_identical_to(flat_string)) {
16059 // At this point, we should have a Cons string which is flat and ASCII,
16060 // with a first half that is a two-byte string (although it only contains
16061 // ASCII characters). This is a valid sequence of steps, and it can happen
16062 // in real pages.
16063 CHECK(string->IsOneByteRepresentation());
16064 i::ConsString* cons = i::ConsString::cast(*string);
16065 CHECK_EQ(0, cons->second()->length());
16066 CHECK(cons->first()->IsTwoByteRepresentation());
16067 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016068
16069 // Check that some string operations work.
16070
16071 // Atom RegExp.
16072 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
16073 CHECK_EQ(6, reresult->Int32Value());
16074
16075 // Nonatom RegExp.
16076 reresult = CompileRun("str2.match(/abe./g).length;");
16077 CHECK_EQ(6, reresult->Int32Value());
16078
16079 reresult = CompileRun("str2.search(/bel/g);");
16080 CHECK_EQ(1, reresult->Int32Value());
16081
16082 reresult = CompileRun("str2.search(/be./g);");
16083 CHECK_EQ(1, reresult->Int32Value());
16084
16085 ExpectTrue("/bel/g.test(str2);");
16086
16087 ExpectTrue("/be./g.test(str2);");
16088
16089 reresult = CompileRun("/bel/g.exec(str2);");
16090 CHECK(!reresult->IsNull());
16091
16092 reresult = CompileRun("/be./g.exec(str2);");
16093 CHECK(!reresult->IsNull());
16094
16095 ExpectString("str2.substring(2, 10);", "elspenda");
16096
16097 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
16098
16099 ExpectString("str2.charAt(2);", "e");
16100
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000016101 ExpectObject("str2.indexOf('els');", indexof);
16102
16103 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
16104
lrn@chromium.org32d961d2010-06-30 09:09:34 +000016105 reresult = CompileRun("str2.charCodeAt(2);");
16106 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
16107}
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000016108
16109
16110// Failed access check callback that performs a GC on each invocation.
16111void FailedAccessCheckCallbackGC(Local<v8::Object> target,
16112 v8::AccessType type,
16113 Local<v8::Value> data) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016114 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000016115}
16116
16117
16118TEST(GCInFailedAccessCheckCallback) {
16119 // Install a failed access check callback that performs a GC on each
16120 // invocation. Then force the callback to be called from va
16121
16122 v8::V8::Initialize();
16123 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
16124
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016125 v8::HandleScope scope(v8::Isolate::GetCurrent());
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000016126
16127 // Create an ObjectTemplate for global objects and install access
16128 // check callbacks that will block access.
16129 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
16130 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
16131 IndexedGetAccessBlocker,
16132 v8::Handle<v8::Value>(),
16133 false);
16134
16135 // Create a context and set an x property on it's global object.
16136 LocalContext context0(NULL, global_template);
16137 context0->Global()->Set(v8_str("x"), v8_num(42));
16138 v8::Handle<v8::Object> global0 = context0->Global();
16139
16140 // Create a context with a different security token so that the
16141 // failed access check callback will be called on each access.
16142 LocalContext context1(NULL, global_template);
16143 context1->Global()->Set(v8_str("other"), global0);
16144
16145 // Get property with failed access check.
16146 ExpectUndefined("other.x");
16147
16148 // Get element with failed access check.
16149 ExpectUndefined("other[0]");
16150
16151 // Set property with failed access check.
16152 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
16153 CHECK(result->IsObject());
16154
16155 // Set element with failed access check.
16156 result = CompileRun("other[0] = new Object()");
16157 CHECK(result->IsObject());
16158
16159 // Get property attribute with failed access check.
16160 ExpectFalse("\'x\' in other");
16161
16162 // Get property attribute for element with failed access check.
16163 ExpectFalse("0 in other");
16164
16165 // Delete property.
16166 ExpectFalse("delete other.x");
16167
16168 // Delete element.
16169 CHECK_EQ(false, global0->Delete(0));
16170
16171 // DefineAccessor.
16172 CHECK_EQ(false,
16173 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
16174
16175 // Define JavaScript accessor.
16176 ExpectUndefined("Object.prototype.__defineGetter__.call("
16177 " other, \'x\', function() { return 42; })");
16178
16179 // LookupAccessor.
16180 ExpectUndefined("Object.prototype.__lookupGetter__.call("
16181 " other, \'x\')");
16182
16183 // HasLocalElement.
16184 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
16185
16186 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
16187 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
16188 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
16189
16190 // Reset the failed access check callback so it does not influence
16191 // the other tests.
16192 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
16193}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016194
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016195TEST(DefaultIsolateGetCurrent) {
16196 CHECK(v8::Isolate::GetCurrent() != NULL);
16197 v8::Isolate* isolate = v8::Isolate::GetCurrent();
16198 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16199 printf("*** %s\n", "DefaultIsolateGetCurrent success");
16200}
16201
16202TEST(IsolateNewDispose) {
16203 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
16204 v8::Isolate* isolate = v8::Isolate::New();
16205 CHECK(isolate != NULL);
16206 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16207 CHECK(current_isolate != isolate);
16208 CHECK(current_isolate == v8::Isolate::GetCurrent());
16209
16210 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16211 last_location = last_message = NULL;
16212 isolate->Dispose();
16213 CHECK_EQ(last_location, NULL);
16214 CHECK_EQ(last_message, NULL);
16215}
16216
16217TEST(IsolateEnterExitDefault) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016218 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
16219 CHECK(current_isolate != NULL); // Default isolate.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016220 v8::HandleScope scope(current_isolate);
16221 LocalContext context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016222 ExpectString("'hello'", "hello");
16223 current_isolate->Enter();
16224 ExpectString("'still working'", "still working");
16225 current_isolate->Exit();
16226 ExpectString("'still working 2'", "still working 2");
16227 current_isolate->Exit();
16228 // Default isolate is always, well, 'default current'.
16229 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
16230 // Still working since default isolate is auto-entering any thread
16231 // that has no isolate and attempts to execute V8 APIs.
16232 ExpectString("'still working 3'", "still working 3");
16233}
16234
16235TEST(DisposeDefaultIsolate) {
16236 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16237
16238 // Run some V8 code to trigger default isolate to become 'current'.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016239 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016240 LocalContext context;
16241 ExpectString("'run some V8'", "run some V8");
16242
16243 v8::Isolate* isolate = v8::Isolate::GetCurrent();
16244 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
16245 last_location = last_message = NULL;
16246 isolate->Dispose();
16247 // It is not possible to dispose default isolate via Isolate API.
16248 CHECK_NE(last_location, NULL);
16249 CHECK_NE(last_message, NULL);
16250}
16251
16252TEST(RunDefaultAndAnotherIsolate) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016253 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016254 LocalContext context;
16255
16256 // Enter new isolate.
16257 v8::Isolate* isolate = v8::Isolate::New();
16258 CHECK(isolate);
16259 isolate->Enter();
16260 { // Need this block because subsequent Exit() will deallocate Heap,
16261 // so we need all scope objects to be deconstructed when it happens.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016262 v8::HandleScope scope_new(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016263 LocalContext context_new;
16264
16265 // Run something in new isolate.
16266 CompileRun("var foo = 153;");
16267 ExpectTrue("function f() { return foo == 153; }; f()");
16268 }
16269 isolate->Exit();
16270
16271 // This runs automatically in default isolate.
16272 // Variables in another isolate should be not available.
16273 ExpectTrue("function f() {"
16274 " try {"
16275 " foo;"
16276 " return false;"
16277 " } catch(e) {"
16278 " return true;"
16279 " }"
16280 "};"
16281 "var bar = 371;"
16282 "f()");
16283
16284 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16285 last_location = last_message = NULL;
16286 isolate->Dispose();
16287 CHECK_EQ(last_location, NULL);
16288 CHECK_EQ(last_message, NULL);
16289
16290 // Check that default isolate still runs.
16291 ExpectTrue("function f() { return bar == 371; }; f()");
16292}
16293
16294TEST(DisposeIsolateWhenInUse) {
16295 v8::Isolate* isolate = v8::Isolate::New();
16296 CHECK(isolate);
16297 isolate->Enter();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016298 v8::HandleScope scope(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016299 LocalContext context;
16300 // Run something in this isolate.
16301 ExpectTrue("true");
16302 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16303 last_location = last_message = NULL;
16304 // Still entered, should fail.
16305 isolate->Dispose();
16306 CHECK_NE(last_location, NULL);
16307 CHECK_NE(last_message, NULL);
16308}
16309
16310TEST(RunTwoIsolatesOnSingleThread) {
16311 // Run isolate 1.
16312 v8::Isolate* isolate1 = v8::Isolate::New();
16313 isolate1->Enter();
16314 v8::Persistent<v8::Context> context1 = v8::Context::New();
16315
16316 {
16317 v8::Context::Scope cscope(context1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016318 v8::HandleScope scope(isolate1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016319 // Run something in new isolate.
16320 CompileRun("var foo = 'isolate 1';");
16321 ExpectString("function f() { return foo; }; f()", "isolate 1");
16322 }
16323
16324 // Run isolate 2.
16325 v8::Isolate* isolate2 = v8::Isolate::New();
16326 v8::Persistent<v8::Context> context2;
16327
16328 {
16329 v8::Isolate::Scope iscope(isolate2);
16330 context2 = v8::Context::New();
16331 v8::Context::Scope cscope(context2);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016332 v8::HandleScope scope(isolate2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016333
16334 // Run something in new isolate.
16335 CompileRun("var foo = 'isolate 2';");
16336 ExpectString("function f() { return foo; }; f()", "isolate 2");
16337 }
16338
16339 {
16340 v8::Context::Scope cscope(context1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016341 v8::HandleScope scope(isolate1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016342 // Now again in isolate 1
16343 ExpectString("function f() { return foo; }; f()", "isolate 1");
16344 }
16345
16346 isolate1->Exit();
16347
16348 // Run some stuff in default isolate.
16349 v8::Persistent<v8::Context> context_default = v8::Context::New();
16350
16351 {
16352 v8::Context::Scope cscope(context_default);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016353 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016354 // Variables in other isolates should be not available, verify there
16355 // is an exception.
16356 ExpectTrue("function f() {"
16357 " try {"
16358 " foo;"
16359 " return false;"
16360 " } catch(e) {"
16361 " return true;"
16362 " }"
16363 "};"
16364 "var isDefaultIsolate = true;"
16365 "f()");
16366 }
16367
16368 isolate1->Enter();
16369
16370 {
16371 v8::Isolate::Scope iscope(isolate2);
16372 v8::Context::Scope cscope(context2);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016373 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016374 ExpectString("function f() { return foo; }; f()", "isolate 2");
16375 }
16376
16377 {
16378 v8::Context::Scope cscope(context1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016379 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016380 ExpectString("function f() { return foo; }; f()", "isolate 1");
16381 }
16382
16383 {
16384 v8::Isolate::Scope iscope(isolate2);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016385 context2.Dispose(context2->GetIsolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016386 }
16387
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016388 context1.Dispose(context1->GetIsolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016389 isolate1->Exit();
16390
16391 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16392 last_location = last_message = NULL;
16393
16394 isolate1->Dispose();
16395 CHECK_EQ(last_location, NULL);
16396 CHECK_EQ(last_message, NULL);
16397
16398 isolate2->Dispose();
16399 CHECK_EQ(last_location, NULL);
16400 CHECK_EQ(last_message, NULL);
16401
16402 // Check that default isolate still runs.
16403 {
16404 v8::Context::Scope cscope(context_default);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016405 v8::HandleScope scope(v8::Isolate::GetCurrent());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016406 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
16407 }
16408}
16409
16410static int CalcFibonacci(v8::Isolate* isolate, int limit) {
16411 v8::Isolate::Scope isolate_scope(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016412 v8::HandleScope scope(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016413 LocalContext context;
16414 i::ScopedVector<char> code(1024);
16415 i::OS::SNPrintF(code, "function fib(n) {"
16416 " if (n <= 2) return 1;"
16417 " return fib(n-1) + fib(n-2);"
16418 "}"
16419 "fib(%d)", limit);
16420 Local<Value> value = CompileRun(code.start());
16421 CHECK(value->IsNumber());
16422 return static_cast<int>(value->NumberValue());
16423}
16424
16425class IsolateThread : public v8::internal::Thread {
16426 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016427 IsolateThread(v8::Isolate* isolate, int fib_limit)
16428 : Thread("IsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016429 isolate_(isolate),
16430 fib_limit_(fib_limit),
16431 result_(0) { }
16432
16433 void Run() {
16434 result_ = CalcFibonacci(isolate_, fib_limit_);
16435 }
16436
16437 int result() { return result_; }
16438
16439 private:
16440 v8::Isolate* isolate_;
16441 int fib_limit_;
16442 int result_;
16443};
16444
16445TEST(MultipleIsolatesOnIndividualThreads) {
16446 v8::Isolate* isolate1 = v8::Isolate::New();
16447 v8::Isolate* isolate2 = v8::Isolate::New();
16448
16449 IsolateThread thread1(isolate1, 21);
16450 IsolateThread thread2(isolate2, 12);
16451
16452 // Compute some fibonacci numbers on 3 threads in 3 isolates.
16453 thread1.Start();
16454 thread2.Start();
16455
16456 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
16457 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
16458
16459 thread1.Join();
16460 thread2.Join();
16461
16462 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
16463 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
16464 CHECK_EQ(result1, 10946);
16465 CHECK_EQ(result2, 144);
16466 CHECK_EQ(result1, thread1.result());
16467 CHECK_EQ(result2, thread2.result());
16468
16469 isolate1->Dispose();
16470 isolate2->Dispose();
16471}
16472
lrn@chromium.org1c092762011-05-09 09:42:16 +000016473TEST(IsolateDifferentContexts) {
16474 v8::Isolate* isolate = v8::Isolate::New();
16475 Persistent<v8::Context> context;
16476 {
16477 v8::Isolate::Scope isolate_scope(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016478 v8::HandleScope handle_scope(isolate);
lrn@chromium.org1c092762011-05-09 09:42:16 +000016479 context = v8::Context::New();
16480 v8::Context::Scope context_scope(context);
16481 Local<Value> v = CompileRun("2");
16482 CHECK(v->IsNumber());
16483 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
16484 }
16485 {
16486 v8::Isolate::Scope isolate_scope(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016487 v8::HandleScope handle_scope(isolate);
lrn@chromium.org1c092762011-05-09 09:42:16 +000016488 context = v8::Context::New();
16489 v8::Context::Scope context_scope(context);
16490 Local<Value> v = CompileRun("22");
16491 CHECK(v->IsNumber());
16492 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
16493 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000016494 isolate->Dispose();
lrn@chromium.org1c092762011-05-09 09:42:16 +000016495}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016496
16497class InitDefaultIsolateThread : public v8::internal::Thread {
16498 public:
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016499 enum TestCase {
16500 IgnoreOOM,
16501 SetResourceConstraints,
16502 SetFatalHandler,
16503 SetCounterFunction,
16504 SetCreateHistogramFunction,
16505 SetAddHistogramSampleFunction
16506 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016507
16508 explicit InitDefaultIsolateThread(TestCase testCase)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000016509 : Thread("InitDefaultIsolateThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016510 testCase_(testCase),
16511 result_(false) { }
16512
16513 void Run() {
16514 switch (testCase_) {
16515 case IgnoreOOM:
16516 v8::V8::IgnoreOutOfMemoryException();
16517 break;
16518
16519 case SetResourceConstraints: {
16520 static const int K = 1024;
16521 v8::ResourceConstraints constraints;
16522 constraints.set_max_young_space_size(256 * K);
16523 constraints.set_max_old_space_size(4 * K * K);
16524 v8::SetResourceConstraints(&constraints);
16525 break;
16526 }
16527
16528 case SetFatalHandler:
16529 v8::V8::SetFatalErrorHandler(NULL);
16530 break;
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016531
16532 case SetCounterFunction:
16533 v8::V8::SetCounterFunction(NULL);
16534 break;
16535
16536 case SetCreateHistogramFunction:
16537 v8::V8::SetCreateHistogramFunction(NULL);
16538 break;
16539
16540 case SetAddHistogramSampleFunction:
16541 v8::V8::SetAddHistogramSampleFunction(NULL);
16542 break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016543 }
16544 result_ = true;
16545 }
16546
16547 bool result() { return result_; }
16548
16549 private:
16550 TestCase testCase_;
16551 bool result_;
16552};
16553
16554
16555static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
16556 InitDefaultIsolateThread thread(testCase);
16557 thread.Start();
16558 thread.Join();
16559 CHECK_EQ(thread.result(), true);
16560}
16561
16562TEST(InitializeDefaultIsolateOnSecondaryThread1) {
16563 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
16564}
16565
16566TEST(InitializeDefaultIsolateOnSecondaryThread2) {
16567 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
16568}
16569
16570TEST(InitializeDefaultIsolateOnSecondaryThread3) {
16571 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
16572}
16573
sgjesse@chromium.orge0599052011-03-25 07:34:35 +000016574TEST(InitializeDefaultIsolateOnSecondaryThread4) {
16575 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
16576}
16577
16578TEST(InitializeDefaultIsolateOnSecondaryThread5) {
16579 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
16580}
16581
16582TEST(InitializeDefaultIsolateOnSecondaryThread6) {
16583 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
16584}
16585
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016586
16587TEST(StringCheckMultipleContexts) {
16588 const char* code =
16589 "(function() { return \"a\".charAt(0); })()";
16590
16591 {
16592 // Run the code twice in the first context to initialize the call IC.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016593 LocalContext context1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016594 v8::HandleScope scope(context1->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016595 ExpectString(code, "a");
16596 ExpectString(code, "a");
16597 }
16598
16599 {
16600 // Change the String.prototype in the second context and check
16601 // that the right function gets called.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016602 LocalContext context2;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016603 v8::HandleScope scope(context2->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016604 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
16605 ExpectString(code, "not a");
16606 }
16607}
16608
16609
16610TEST(NumberCheckMultipleContexts) {
16611 const char* code =
16612 "(function() { return (42).toString(); })()";
16613
16614 {
16615 // Run the code twice in the first context to initialize the call IC.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016616 LocalContext context1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016617 v8::HandleScope scope(context1->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016618 ExpectString(code, "42");
16619 ExpectString(code, "42");
16620 }
16621
16622 {
16623 // Change the Number.prototype in the second context and check
16624 // that the right function gets called.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016625 LocalContext context2;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016626 v8::HandleScope scope(context2->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016627 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
16628 ExpectString(code, "not 42");
16629 }
16630}
16631
16632
16633TEST(BooleanCheckMultipleContexts) {
16634 const char* code =
16635 "(function() { return true.toString(); })()";
16636
16637 {
16638 // Run the code twice in the first context to initialize the call IC.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016639 LocalContext context1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016640 v8::HandleScope scope(context1->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016641 ExpectString(code, "true");
16642 ExpectString(code, "true");
16643 }
16644
16645 {
16646 // Change the Boolean.prototype in the second context and check
16647 // that the right function gets called.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016648 LocalContext context2;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016649 v8::HandleScope scope(context2->GetIsolate());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000016650 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
16651 ExpectString(code, "");
16652 }
16653}
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016654
16655
16656TEST(DontDeleteCellLoadIC) {
16657 const char* function_code =
16658 "function readCell() { while (true) { return cell; } }";
16659
16660 {
16661 // Run the code twice in the first context to initialize the load
16662 // IC for a don't delete cell.
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016663 LocalContext context1;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016664 v8::HandleScope scope(context1->GetIsolate());
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016665 CompileRun("var cell = \"first\";");
16666 ExpectBoolean("delete cell", false);
16667 CompileRun(function_code);
16668 ExpectString("readCell()", "first");
16669 ExpectString("readCell()", "first");
16670 }
16671
16672 {
16673 // Use a deletable cell in the second context.
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016674 LocalContext context2;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016675 v8::HandleScope scope(context2->GetIsolate());
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016676 CompileRun("cell = \"second\";");
16677 CompileRun(function_code);
16678 ExpectString("readCell()", "second");
16679 ExpectBoolean("delete cell", true);
16680 ExpectString("(function() {"
16681 " try {"
16682 " return readCell();"
16683 " } catch(e) {"
16684 " return e.toString();"
16685 " }"
16686 "})()",
16687 "ReferenceError: cell is not defined");
16688 CompileRun("cell = \"new_second\";");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000016689 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016690 ExpectString("readCell()", "new_second");
16691 ExpectString("readCell()", "new_second");
16692 }
16693}
16694
16695
16696TEST(DontDeleteCellLoadICForceDelete) {
16697 const char* function_code =
16698 "function readCell() { while (true) { return cell; } }";
16699
16700 // Run the code twice to initialize the load IC for a don't delete
16701 // cell.
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016702 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016703 v8::HandleScope scope(context->GetIsolate());
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016704 CompileRun("var cell = \"value\";");
16705 ExpectBoolean("delete cell", false);
16706 CompileRun(function_code);
16707 ExpectString("readCell()", "value");
16708 ExpectString("readCell()", "value");
16709
16710 // Delete the cell using the API and check the inlined code works
16711 // correctly.
16712 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16713 ExpectString("(function() {"
16714 " try {"
16715 " return readCell();"
16716 " } catch(e) {"
16717 " return e.toString();"
16718 " }"
16719 "})()",
16720 "ReferenceError: cell is not defined");
16721}
16722
16723
16724TEST(DontDeleteCellLoadICAPI) {
16725 const char* function_code =
16726 "function readCell() { while (true) { return cell; } }";
16727
16728 // Run the code twice to initialize the load IC for a don't delete
16729 // cell created using the API.
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016730 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016731 v8::HandleScope scope(context->GetIsolate());
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000016732 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
16733 ExpectBoolean("delete cell", false);
16734 CompileRun(function_code);
16735 ExpectString("readCell()", "value");
16736 ExpectString("readCell()", "value");
16737
16738 // Delete the cell using the API and check the inlined code works
16739 // correctly.
16740 CHECK(context->Global()->ForceDelete(v8_str("cell")));
16741 ExpectString("(function() {"
16742 " try {"
16743 " return readCell();"
16744 " } catch(e) {"
16745 " return e.toString();"
16746 " }"
16747 "})()",
16748 "ReferenceError: cell is not defined");
16749}
16750
16751
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016752class Visitor42 : public v8::PersistentHandleVisitor {
16753 public:
16754 explicit Visitor42(v8::Persistent<v8::Object> object)
16755 : counter_(0), object_(object) { }
16756
16757 virtual void VisitPersistentHandle(Persistent<Value> value,
16758 uint16_t class_id) {
16759 if (class_id == 42) {
16760 CHECK(value->IsObject());
16761 v8::Persistent<v8::Object> visited =
16762 v8::Persistent<v8::Object>::Cast(value);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016763 CHECK_EQ(42, visited.WrapperClassId(v8::Isolate::GetCurrent()));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016764 CHECK_EQ(object_, visited);
16765 ++counter_;
16766 }
16767 }
16768
16769 int counter_;
16770 v8::Persistent<v8::Object> object_;
16771};
16772
16773
16774TEST(PersistentHandleVisitor) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016775 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016776 v8::Isolate* isolate = context->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016777 v8::HandleScope scope(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016778 v8::Persistent<v8::Object> object =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016779 v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
16780 CHECK_EQ(0, object.WrapperClassId(isolate));
16781 object.SetWrapperClassId(isolate, 42);
16782 CHECK_EQ(42, object.WrapperClassId(isolate));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016783
16784 Visitor42 visitor(object);
16785 v8::V8::VisitHandlesWithClassIds(&visitor);
16786 CHECK_EQ(1, visitor.counter_);
16787
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016788 object.Dispose(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000016789}
16790
16791
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000016792TEST(WrapperClassId) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000016793 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016794 v8::Isolate* isolate = context->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016795 v8::HandleScope scope(isolate);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000016796 v8::Persistent<v8::Object> object =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016797 v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
16798 CHECK_EQ(0, object.WrapperClassId(isolate));
16799 object.SetWrapperClassId(isolate, 65535);
16800 CHECK_EQ(65535, object.WrapperClassId(isolate));
16801 object.Dispose(isolate);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000016802}
16803
16804
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016805TEST(PersistentHandleInNewSpaceVisitor) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016806 LocalContext context;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016807 v8::Isolate* isolate = context->GetIsolate();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016808 v8::HandleScope scope(isolate);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016809 v8::Persistent<v8::Object> object1 =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016810 v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
16811 CHECK_EQ(0, object1.WrapperClassId(isolate));
16812 object1.SetWrapperClassId(isolate, 42);
16813 CHECK_EQ(42, object1.WrapperClassId(isolate));
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016814
16815 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16816
16817 v8::Persistent<v8::Object> object2 =
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016818 v8::Persistent<v8::Object>::New(isolate, v8::Object::New());
16819 CHECK_EQ(0, object2.WrapperClassId(isolate));
16820 object2.SetWrapperClassId(isolate, 42);
16821 CHECK_EQ(42, object2.WrapperClassId(isolate));
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016822
16823 Visitor42 visitor(object2);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016824 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016825 CHECK_EQ(1, visitor.counter_);
16826
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000016827 object1.Dispose(isolate);
16828 object2.Dispose(isolate);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000016829}
16830
16831
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016832TEST(RegExp) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016833 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016834 v8::HandleScope scope(context->GetIsolate());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016835
16836 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
16837 CHECK(re->IsRegExp());
16838 CHECK(re->GetSource()->Equals(v8_str("foo")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016839 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016840
16841 re = v8::RegExp::New(v8_str("bar"),
16842 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16843 v8::RegExp::kGlobal));
16844 CHECK(re->IsRegExp());
16845 CHECK(re->GetSource()->Equals(v8_str("bar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016846 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
16847 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016848
16849 re = v8::RegExp::New(v8_str("baz"),
16850 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16851 v8::RegExp::kMultiline));
16852 CHECK(re->IsRegExp());
16853 CHECK(re->GetSource()->Equals(v8_str("baz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016854 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16855 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016856
16857 re = CompileRun("/quux/").As<v8::RegExp>();
16858 CHECK(re->IsRegExp());
16859 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016860 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016861
16862 re = CompileRun("/quux/gm").As<v8::RegExp>();
16863 CHECK(re->IsRegExp());
16864 CHECK(re->GetSource()->Equals(v8_str("quux")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016865 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
16866 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016867
16868 // Override the RegExp constructor and check the API constructor
16869 // still works.
16870 CompileRun("RegExp = function() {}");
16871
16872 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
16873 CHECK(re->IsRegExp());
16874 CHECK(re->GetSource()->Equals(v8_str("foobar")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016875 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016876
16877 re = v8::RegExp::New(v8_str("foobarbaz"),
16878 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
16879 v8::RegExp::kMultiline));
16880 CHECK(re->IsRegExp());
16881 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000016882 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
16883 static_cast<int>(re->GetFlags()));
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016884
16885 context->Global()->Set(v8_str("re"), re);
16886 ExpectTrue("re.test('FoobarbaZ')");
16887
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016888 // RegExps are objects on which you can set properties.
16889 re->Set(v8_str("property"), v8::Integer::New(32));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016890 v8::Handle<v8::Value> value(CompileRun("re.property"));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000016891 CHECK_EQ(32, value->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000016892
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016893 v8::TryCatch try_catch;
16894 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
16895 CHECK(re.IsEmpty());
16896 CHECK(try_catch.HasCaught());
16897 context->Global()->Set(v8_str("ex"), try_catch.Exception());
16898 ExpectTrue("ex instanceof SyntaxError");
16899}
16900
16901
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016902THREADED_TEST(Equals) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016903 LocalContext localContext;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016904 v8::HandleScope handleScope(localContext->GetIsolate());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000016905
16906 v8::Handle<v8::Object> globalProxy = localContext->Global();
16907 v8::Handle<Value> global = globalProxy->GetPrototype();
16908
16909 CHECK(global->StrictEquals(global));
16910 CHECK(!global->StrictEquals(globalProxy));
16911 CHECK(!globalProxy->StrictEquals(global));
16912 CHECK(globalProxy->StrictEquals(globalProxy));
16913
16914 CHECK(global->Equals(global));
16915 CHECK(!global->Equals(globalProxy));
16916 CHECK(!globalProxy->Equals(global));
16917 CHECK(globalProxy->Equals(globalProxy));
16918}
16919
16920
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016921static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
16922 const v8::AccessorInfo& info ) {
16923 return v8_str("42!");
16924}
16925
16926
16927static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
16928 v8::Handle<v8::Array> result = v8::Array::New();
16929 result->Set(0, v8_str("universalAnswer"));
16930 return result;
16931}
16932
16933
16934TEST(NamedEnumeratorAndForIn) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016935 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016936 v8::HandleScope handle_scope(context->GetIsolate());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000016937 v8::Context::Scope context_scope(context.local());
16938
16939 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
16940 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
16941 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
16942 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
16943 "var result = []; for (var k in o) result.push(k); result"));
16944 CHECK_EQ(1, result->Length());
16945 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
16946}
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016947
16948
16949TEST(DefinePropertyPostDetach) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016950 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016951 v8::HandleScope scope(context->GetIsolate());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000016952 v8::Handle<v8::Object> proxy = context->Global();
16953 v8::Handle<v8::Function> define_property =
16954 CompileRun("(function() {"
16955 " Object.defineProperty("
16956 " this,"
16957 " 1,"
16958 " { configurable: true, enumerable: true, value: 3 });"
16959 "})").As<Function>();
16960 context->DetachGlobal();
16961 define_property->Call(proxy, 0, NULL);
16962}
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016963
16964
16965static void InstallContextId(v8::Handle<Context> context, int id) {
16966 Context::Scope scope(context);
16967 CompileRun("Object.prototype").As<Object>()->
16968 Set(v8_str("context_id"), v8::Integer::New(id));
16969}
16970
16971
16972static void CheckContextId(v8::Handle<Object> object, int expected) {
16973 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
16974}
16975
16976
16977THREADED_TEST(CreationContext) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000016978 HandleScope handle_scope(v8::Isolate::GetCurrent());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016979 Persistent<Context> context1 = Context::New();
16980 InstallContextId(context1, 1);
16981 Persistent<Context> context2 = Context::New();
16982 InstallContextId(context2, 2);
16983 Persistent<Context> context3 = Context::New();
16984 InstallContextId(context3, 3);
16985
16986 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
16987
16988 Local<Object> object1;
16989 Local<Function> func1;
16990 {
16991 Context::Scope scope(context1);
16992 object1 = Object::New();
16993 func1 = tmpl->GetFunction();
16994 }
16995
16996 Local<Object> object2;
16997 Local<Function> func2;
16998 {
16999 Context::Scope scope(context2);
17000 object2 = Object::New();
17001 func2 = tmpl->GetFunction();
17002 }
17003
17004 Local<Object> instance1;
17005 Local<Object> instance2;
17006
17007 {
17008 Context::Scope scope(context3);
17009 instance1 = func1->NewInstance();
17010 instance2 = func2->NewInstance();
17011 }
17012
17013 CHECK(object1->CreationContext() == context1);
17014 CheckContextId(object1, 1);
17015 CHECK(func1->CreationContext() == context1);
17016 CheckContextId(func1, 1);
17017 CHECK(instance1->CreationContext() == context1);
17018 CheckContextId(instance1, 1);
17019 CHECK(object2->CreationContext() == context2);
17020 CheckContextId(object2, 2);
17021 CHECK(func2->CreationContext() == context2);
17022 CheckContextId(func2, 2);
17023 CHECK(instance2->CreationContext() == context2);
17024 CheckContextId(instance2, 2);
17025
17026 {
17027 Context::Scope scope(context1);
17028 CHECK(object1->CreationContext() == context1);
17029 CheckContextId(object1, 1);
17030 CHECK(func1->CreationContext() == context1);
17031 CheckContextId(func1, 1);
17032 CHECK(instance1->CreationContext() == context1);
17033 CheckContextId(instance1, 1);
17034 CHECK(object2->CreationContext() == context2);
17035 CheckContextId(object2, 2);
17036 CHECK(func2->CreationContext() == context2);
17037 CheckContextId(func2, 2);
17038 CHECK(instance2->CreationContext() == context2);
17039 CheckContextId(instance2, 2);
17040 }
17041
17042 {
17043 Context::Scope scope(context2);
17044 CHECK(object1->CreationContext() == context1);
17045 CheckContextId(object1, 1);
17046 CHECK(func1->CreationContext() == context1);
17047 CheckContextId(func1, 1);
17048 CHECK(instance1->CreationContext() == context1);
17049 CheckContextId(instance1, 1);
17050 CHECK(object2->CreationContext() == context2);
17051 CheckContextId(object2, 2);
17052 CHECK(func2->CreationContext() == context2);
17053 CheckContextId(func2, 2);
17054 CHECK(instance2->CreationContext() == context2);
17055 CheckContextId(instance2, 2);
17056 }
17057
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000017058 context1.Dispose(context1->GetIsolate());
17059 context2.Dispose(context2->GetIsolate());
17060 context3.Dispose(context3->GetIsolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000017061}
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000017062
17063
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000017064THREADED_TEST(CreationContextOfJsFunction) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017065 HandleScope handle_scope(v8::Isolate::GetCurrent());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000017066 Persistent<Context> context = Context::New();
17067 InstallContextId(context, 1);
17068
17069 Local<Object> function;
17070 {
17071 Context::Scope scope(context);
17072 function = CompileRun("function foo() {}; foo").As<Object>();
17073 }
17074
17075 CHECK(function->CreationContext() == context);
17076 CheckContextId(function, 1);
17077
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000017078 context.Dispose(context->GetIsolate());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000017079}
17080
17081
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000017082Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
17083 const AccessorInfo& info) {
17084 if (index == 42) return v8_str("yes");
17085 return Handle<v8::Integer>();
17086}
17087
17088
17089Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
17090 const AccessorInfo& info) {
17091 if (property->Equals(v8_str("foo"))) return v8_str("yes");
17092 return Handle<Value>();
17093}
17094
17095
17096Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
17097 uint32_t index, const AccessorInfo& info) {
17098 if (index == 42) return v8_num(1).As<v8::Integer>();
17099 return Handle<v8::Integer>();
17100}
17101
17102
17103Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
17104 Local<String> property, const AccessorInfo& info) {
17105 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
17106 return Handle<v8::Integer>();
17107}
17108
17109
17110Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
17111 Local<String> property, const AccessorInfo& info) {
17112 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
17113 return Handle<v8::Integer>();
17114}
17115
17116
17117Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
17118 const AccessorInfo& info) {
17119 return v8_str("yes");
17120}
17121
17122
17123TEST(HasOwnProperty) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000017124 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017125 v8::HandleScope scope(env->GetIsolate());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +000017126 { // Check normal properties and defined getters.
17127 Handle<Value> value = CompileRun(
17128 "function Foo() {"
17129 " this.foo = 11;"
17130 " this.__defineGetter__('baz', function() { return 1; });"
17131 "};"
17132 "function Bar() { "
17133 " this.bar = 13;"
17134 " this.__defineGetter__('bla', function() { return 2; });"
17135 "};"
17136 "Bar.prototype = new Foo();"
17137 "new Bar();");
17138 CHECK(value->IsObject());
17139 Handle<Object> object = value->ToObject();
17140 CHECK(object->Has(v8_str("foo")));
17141 CHECK(!object->HasOwnProperty(v8_str("foo")));
17142 CHECK(object->HasOwnProperty(v8_str("bar")));
17143 CHECK(object->Has(v8_str("baz")));
17144 CHECK(!object->HasOwnProperty(v8_str("baz")));
17145 CHECK(object->HasOwnProperty(v8_str("bla")));
17146 }
17147 { // Check named getter interceptors.
17148 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17149 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
17150 Handle<Object> instance = templ->NewInstance();
17151 CHECK(!instance->HasOwnProperty(v8_str("42")));
17152 CHECK(instance->HasOwnProperty(v8_str("foo")));
17153 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17154 }
17155 { // Check indexed getter interceptors.
17156 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17157 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
17158 Handle<Object> instance = templ->NewInstance();
17159 CHECK(instance->HasOwnProperty(v8_str("42")));
17160 CHECK(!instance->HasOwnProperty(v8_str("43")));
17161 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17162 }
17163 { // Check named query interceptors.
17164 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17165 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
17166 Handle<Object> instance = templ->NewInstance();
17167 CHECK(instance->HasOwnProperty(v8_str("foo")));
17168 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17169 }
17170 { // Check indexed query interceptors.
17171 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17172 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
17173 Handle<Object> instance = templ->NewInstance();
17174 CHECK(instance->HasOwnProperty(v8_str("42")));
17175 CHECK(!instance->HasOwnProperty(v8_str("41")));
17176 }
17177 { // Check callbacks.
17178 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17179 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
17180 Handle<Object> instance = templ->NewInstance();
17181 CHECK(instance->HasOwnProperty(v8_str("foo")));
17182 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17183 }
17184 { // Check that query wins on disagreement.
17185 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17186 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
17187 0,
17188 HasOwnPropertyNamedPropertyQuery2);
17189 Handle<Object> instance = templ->NewInstance();
17190 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17191 CHECK(instance->HasOwnProperty(v8_str("bar")));
17192 }
17193}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017194
17195
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000017196TEST(IndexedInterceptorWithStringProto) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017197 v8::HandleScope scope(v8::Isolate::GetCurrent());
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000017198 Handle<ObjectTemplate> templ = ObjectTemplate::New();
17199 templ->SetIndexedPropertyHandler(NULL,
17200 NULL,
17201 HasOwnPropertyIndexedPropertyQuery);
17202 LocalContext context;
17203 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17204 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
17205 // These should be intercepted.
17206 CHECK(CompileRun("42 in obj")->BooleanValue());
17207 CHECK(CompileRun("'42' in obj")->BooleanValue());
17208 // These should fall through to the String prototype.
17209 CHECK(CompileRun("0 in obj")->BooleanValue());
17210 CHECK(CompileRun("'0' in obj")->BooleanValue());
17211 // And these should both fail.
17212 CHECK(!CompileRun("32 in obj")->BooleanValue());
17213 CHECK(!CompileRun("'32' in obj")->BooleanValue());
17214}
17215
17216
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017217void CheckCodeGenerationAllowed() {
17218 Handle<Value> result = CompileRun("eval('42')");
17219 CHECK_EQ(42, result->Int32Value());
17220 result = CompileRun("(function(e) { return e('42'); })(eval)");
17221 CHECK_EQ(42, result->Int32Value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017222 result = CompileRun("var f = new Function('return 42'); f()");
17223 CHECK_EQ(42, result->Int32Value());
17224}
17225
17226
17227void CheckCodeGenerationDisallowed() {
17228 TryCatch try_catch;
17229
17230 Handle<Value> result = CompileRun("eval('42')");
17231 CHECK(result.IsEmpty());
17232 CHECK(try_catch.HasCaught());
17233 try_catch.Reset();
17234
17235 result = CompileRun("(function(e) { return e('42'); })(eval)");
17236 CHECK(result.IsEmpty());
17237 CHECK(try_catch.HasCaught());
17238 try_catch.Reset();
17239
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017240 result = CompileRun("var f = new Function('return 42'); f()");
17241 CHECK(result.IsEmpty());
17242 CHECK(try_catch.HasCaught());
17243}
17244
17245
17246bool CodeGenerationAllowed(Local<Context> context) {
17247 ApiTestFuzzer::Fuzz();
17248 return true;
17249}
17250
17251
17252bool CodeGenerationDisallowed(Local<Context> context) {
17253 ApiTestFuzzer::Fuzz();
17254 return false;
17255}
17256
17257
17258THREADED_TEST(AllowCodeGenFromStrings) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017259 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017260 v8::HandleScope scope(context->GetIsolate());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017261
ager@chromium.orgea91cc52011-05-23 06:06:11 +000017262 // eval and the Function constructor allowed by default.
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017263 CHECK(context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017264 CheckCodeGenerationAllowed();
17265
ager@chromium.orgea91cc52011-05-23 06:06:11 +000017266 // Disallow eval and the Function constructor.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017267 context->AllowCodeGenerationFromStrings(false);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017268 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017269 CheckCodeGenerationDisallowed();
17270
17271 // Allow again.
17272 context->AllowCodeGenerationFromStrings(true);
17273 CheckCodeGenerationAllowed();
17274
17275 // Disallow but setting a global callback that will allow the calls.
17276 context->AllowCodeGenerationFromStrings(false);
17277 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017278 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017279 CheckCodeGenerationAllowed();
17280
17281 // Set a callback that disallows the code generation.
17282 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +000017283 CHECK(!context->IsCodeGenerationFromStringsAllowed());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000017284 CheckCodeGenerationDisallowed();
17285}
lrn@chromium.org1c092762011-05-09 09:42:16 +000017286
17287
ulan@chromium.org56c14af2012-09-20 12:51:09 +000017288TEST(SetErrorMessageForCodeGenFromStrings) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000017289 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017290 v8::HandleScope scope(context->GetIsolate());
ulan@chromium.org56c14af2012-09-20 12:51:09 +000017291 TryCatch try_catch;
17292
17293 Handle<String> message = v8_str("Message") ;
17294 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
17295 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17296 context->AllowCodeGenerationFromStrings(false);
17297 context->SetErrorMessageForCodeGenerationFromStrings(message);
17298 Handle<Value> result = CompileRun("eval('42')");
17299 CHECK(result.IsEmpty());
17300 CHECK(try_catch.HasCaught());
17301 Handle<String> actual_message = try_catch.Message()->Get();
17302 CHECK(expected_message->Equals(actual_message));
17303}
17304
17305
lrn@chromium.org1c092762011-05-09 09:42:16 +000017306static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
17307 return v8::Undefined();
17308}
17309
17310
17311THREADED_TEST(CallAPIFunctionOnNonObject) {
lrn@chromium.org1c092762011-05-09 09:42:16 +000017312 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017313 v8::HandleScope scope(context->GetIsolate());
lrn@chromium.org1c092762011-05-09 09:42:16 +000017314 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
17315 Handle<Function> function = templ->GetFunction();
17316 context->Global()->Set(v8_str("f"), function);
17317 TryCatch try_catch;
17318 CompileRun("f.call(2)");
lrn@chromium.org1c092762011-05-09 09:42:16 +000017319}
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000017320
17321
17322// Regression test for issue 1470.
17323THREADED_TEST(ReadOnlyIndexedProperties) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017324 v8::HandleScope scope(v8::Isolate::GetCurrent());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000017325 Local<ObjectTemplate> templ = ObjectTemplate::New();
17326
17327 LocalContext context;
17328 Local<v8::Object> obj = templ->NewInstance();
17329 context->Global()->Set(v8_str("obj"), obj);
17330 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17331 obj->Set(v8_str("1"), v8_str("foobar"));
17332 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
17333 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
17334 obj->Set(v8_num(2), v8_str("foobar"));
17335 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
17336
17337 // Test non-smi case.
17338 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
17339 obj->Set(v8_str("2000000000"), v8_str("foobar"));
17340 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
17341}
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017342
17343
17344THREADED_TEST(Regress1516) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017345 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017346 v8::HandleScope scope(context->GetIsolate());
17347
17348 { v8::HandleScope temp_scope(context->GetIsolate());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017349 CompileRun("({'a': 0})");
17350 }
17351
17352 int elements;
17353 { i::MapCache* map_cache =
17354 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
17355 elements = map_cache->NumberOfElements();
17356 CHECK_LE(1, elements);
17357 }
17358
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +000017359 i::Isolate::Current()->heap()->CollectAllGarbage(
17360 i::Heap::kAbortIncrementalMarkingMask);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000017361 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
17362 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
17363 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
17364 CHECK_GT(elements, map_cache->NumberOfElements());
17365 }
17366 }
17367}
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017368
17369
17370static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
17371 Local<Value> name,
17372 v8::AccessType type,
17373 Local<Value> data) {
17374 // Only block read access to __proto__.
17375 if (type == v8::ACCESS_GET &&
17376 name->IsString() &&
17377 name->ToString()->Length() == 9 &&
17378 name->ToString()->Utf8Length() == 9) {
17379 char buffer[10];
17380 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
17381 return strncmp(buffer, "__proto__", 9) != 0;
17382 }
17383
17384 return true;
17385}
17386
17387
17388THREADED_TEST(Regress93759) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017389 HandleScope scope(v8::Isolate::GetCurrent());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017390
17391 // Template for object with security check.
17392 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
17393 // We don't do indexing, so any callback can be used for that.
17394 no_proto_template->SetAccessCheckCallbacks(
17395 BlockProtoNamedSecurityTestCallback,
17396 IndexedSecurityTestCallback);
17397
17398 // Templates for objects with hidden prototypes and possibly security check.
17399 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
17400 hidden_proto_template->SetHiddenPrototype(true);
17401
17402 Local<FunctionTemplate> protected_hidden_proto_template =
17403 v8::FunctionTemplate::New();
17404 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
17405 BlockProtoNamedSecurityTestCallback,
17406 IndexedSecurityTestCallback);
17407 protected_hidden_proto_template->SetHiddenPrototype(true);
17408
17409 // Context for "foreign" objects used in test.
17410 Persistent<Context> context = v8::Context::New();
17411 context->Enter();
17412
17413 // Plain object, no security check.
17414 Local<Object> simple_object = Object::New();
17415
17416 // Object with explicit security check.
17417 Local<Object> protected_object =
17418 no_proto_template->NewInstance();
17419
17420 // JSGlobalProxy object, always have security check.
17421 Local<Object> proxy_object =
17422 context->Global();
17423
17424 // Global object, the prototype of proxy_object. No security checks.
17425 Local<Object> global_object =
17426 proxy_object->GetPrototype()->ToObject();
17427
17428 // Hidden prototype without security check.
17429 Local<Object> hidden_prototype =
17430 hidden_proto_template->GetFunction()->NewInstance();
17431 Local<Object> object_with_hidden =
17432 Object::New();
17433 object_with_hidden->SetPrototype(hidden_prototype);
17434
17435 // Hidden prototype with security check on the hidden prototype.
17436 Local<Object> protected_hidden_prototype =
17437 protected_hidden_proto_template->GetFunction()->NewInstance();
17438 Local<Object> object_with_protected_hidden =
17439 Object::New();
17440 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
17441
17442 context->Exit();
17443
17444 // Template for object for second context. Values to test are put on it as
17445 // properties.
17446 Local<ObjectTemplate> global_template = ObjectTemplate::New();
17447 global_template->Set(v8_str("simple"), simple_object);
17448 global_template->Set(v8_str("protected"), protected_object);
17449 global_template->Set(v8_str("global"), global_object);
17450 global_template->Set(v8_str("proxy"), proxy_object);
17451 global_template->Set(v8_str("hidden"), object_with_hidden);
17452 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
17453
17454 LocalContext context2(NULL, global_template);
17455
17456 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
17457 CHECK(result1->Equals(simple_object->GetPrototype()));
17458
17459 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
17460 CHECK(result2->Equals(Undefined()));
17461
17462 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
17463 CHECK(result3->Equals(global_object->GetPrototype()));
17464
17465 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
17466 CHECK(result4->Equals(Undefined()));
17467
17468 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
17469 CHECK(result5->Equals(
17470 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
17471
17472 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
17473 CHECK(result6->Equals(Undefined()));
17474
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000017475 context.Dispose(context->GetIsolate());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017476}
17477
17478
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017479THREADED_TEST(Regress125988) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017480 v8::HandleScope scope(v8::Isolate::GetCurrent());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000017481 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
17482 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
17483 LocalContext env;
17484 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
17485 CompileRun("var a = new Object();"
17486 "var b = new Intercept();"
17487 "var c = new Object();"
17488 "c.__proto__ = b;"
17489 "b.__proto__ = a;"
17490 "a.x = 23;"
17491 "for (var i = 0; i < 3; i++) c.x;");
17492 ExpectBoolean("c.hasOwnProperty('x')", false);
17493 ExpectInt32("c.x", 23);
17494 CompileRun("a.y = 42;"
17495 "for (var i = 0; i < 3; i++) c.x;");
17496 ExpectBoolean("c.hasOwnProperty('x')", false);
17497 ExpectInt32("c.x", 23);
17498 ExpectBoolean("c.hasOwnProperty('y')", false);
17499 ExpectInt32("c.y", 42);
17500}
17501
17502
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017503static void TestReceiver(Local<Value> expected_result,
17504 Local<Value> expected_receiver,
17505 const char* code) {
17506 Local<Value> result = CompileRun(code);
17507 CHECK(result->IsObject());
17508 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
17509 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
17510}
17511
17512
17513THREADED_TEST(ForeignFunctionReceiver) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017514 HandleScope scope(v8::Isolate::GetCurrent());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017515
17516 // Create two contexts with different "id" properties ('i' and 'o').
17517 // Call a function both from its own context and from a the foreign
17518 // context, and see what "this" is bound to (returning both "this"
17519 // and "this.id" for comparison).
17520
17521 Persistent<Context> foreign_context = v8::Context::New();
17522 foreign_context->Enter();
17523 Local<Value> foreign_function =
17524 CompileRun("function func() { return { 0: this.id, "
17525 " 1: this, "
17526 " toString: function() { "
17527 " return this[0];"
17528 " }"
17529 " };"
17530 "}"
17531 "var id = 'i';"
17532 "func;");
17533 CHECK(foreign_function->IsFunction());
17534 foreign_context->Exit();
17535
17536 LocalContext context;
17537
17538 Local<String> password = v8_str("Password");
17539 // Don't get hit by security checks when accessing foreign_context's
17540 // global receiver (aka. global proxy).
17541 context->SetSecurityToken(password);
17542 foreign_context->SetSecurityToken(password);
17543
17544 Local<String> i = v8_str("i");
17545 Local<String> o = v8_str("o");
17546 Local<String> id = v8_str("id");
17547
17548 CompileRun("function ownfunc() { return { 0: this.id, "
17549 " 1: this, "
17550 " toString: function() { "
17551 " return this[0];"
17552 " }"
17553 " };"
17554 "}"
17555 "var id = 'o';"
17556 "ownfunc");
17557 context->Global()->Set(v8_str("func"), foreign_function);
17558
17559 // Sanity check the contexts.
17560 CHECK(i->Equals(foreign_context->Global()->Get(id)));
17561 CHECK(o->Equals(context->Global()->Get(id)));
17562
17563 // Checking local function's receiver.
17564 // Calling function using its call/apply methods.
17565 TestReceiver(o, context->Global(), "ownfunc.call()");
17566 TestReceiver(o, context->Global(), "ownfunc.apply()");
17567 // Making calls through built-in functions.
17568 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
17569 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
17570 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
17571 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
17572 // Calling with environment record as base.
17573 TestReceiver(o, context->Global(), "ownfunc()");
17574 // Calling with no base.
17575 TestReceiver(o, context->Global(), "(1,ownfunc)()");
17576
17577 // Checking foreign function return value.
17578 // Calling function using its call/apply methods.
17579 TestReceiver(i, foreign_context->Global(), "func.call()");
17580 TestReceiver(i, foreign_context->Global(), "func.apply()");
17581 // Calling function using another context's call/apply methods.
17582 TestReceiver(i, foreign_context->Global(),
17583 "Function.prototype.call.call(func)");
17584 TestReceiver(i, foreign_context->Global(),
17585 "Function.prototype.call.apply(func)");
17586 TestReceiver(i, foreign_context->Global(),
17587 "Function.prototype.apply.call(func)");
17588 TestReceiver(i, foreign_context->Global(),
17589 "Function.prototype.apply.apply(func)");
17590 // Making calls through built-in functions.
17591 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
17592 // ToString(func()) is func()[0], i.e., the returned this.id.
17593 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
17594 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
17595 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
17596
17597 // TODO(1547): Make the following also return "i".
17598 // Calling with environment record as base.
17599 TestReceiver(o, context->Global(), "func()");
17600 // Calling with no base.
17601 TestReceiver(o, context->Global(), "(1,func)()");
17602
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000017603 foreign_context.Dispose(foreign_context->GetIsolate());
ricow@chromium.org4668a2c2011-08-29 10:41:00 +000017604}
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017605
17606
17607uint8_t callback_fired = 0;
17608
17609
17610void CallCompletedCallback1() {
17611 i::OS::Print("Firing callback 1.\n");
17612 callback_fired ^= 1; // Toggle first bit.
17613}
17614
17615
17616void CallCompletedCallback2() {
17617 i::OS::Print("Firing callback 2.\n");
17618 callback_fired ^= 2; // Toggle second bit.
17619}
17620
17621
17622Handle<Value> RecursiveCall(const Arguments& args) {
17623 int32_t level = args[0]->Int32Value();
17624 if (level < 3) {
17625 level++;
17626 i::OS::Print("Entering recursion level %d.\n", level);
17627 char script[64];
17628 i::Vector<char> script_vector(script, sizeof(script));
17629 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
17630 CompileRun(script_vector.start());
17631 i::OS::Print("Leaving recursion level %d.\n", level);
17632 CHECK_EQ(0, callback_fired);
17633 } else {
17634 i::OS::Print("Recursion ends.\n");
17635 CHECK_EQ(0, callback_fired);
17636 }
17637 return Undefined();
17638}
17639
17640
17641TEST(CallCompletedCallback) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017642 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017643 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017644 v8::Handle<v8::FunctionTemplate> recursive_runtime =
17645 v8::FunctionTemplate::New(RecursiveCall);
17646 env->Global()->Set(v8_str("recursion"),
17647 recursive_runtime->GetFunction());
17648 // Adding the same callback a second time has no effect.
17649 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17650 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
17651 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
17652 i::OS::Print("--- Script (1) ---\n");
17653 Local<Script> script =
17654 v8::Script::Compile(v8::String::New("recursion(0)"));
17655 script->Run();
17656 CHECK_EQ(3, callback_fired);
17657
17658 i::OS::Print("\n--- Script (2) ---\n");
17659 callback_fired = 0;
17660 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
17661 script->Run();
17662 CHECK_EQ(2, callback_fired);
17663
17664 i::OS::Print("\n--- Function ---\n");
17665 callback_fired = 0;
17666 Local<Function> recursive_function =
17667 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
17668 v8::Handle<Value> args[] = { v8_num(0) };
17669 recursive_function->Call(env->Global(), 1, args);
17670 CHECK_EQ(2, callback_fired);
17671}
17672
17673
17674void CallCompletedCallbackNoException() {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017675 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017676 CompileRun("1+1;");
17677}
17678
17679
17680void CallCompletedCallbackException() {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017681 v8::HandleScope scope(v8::Isolate::GetCurrent());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017682 CompileRun("throw 'second exception';");
17683}
17684
17685
17686TEST(CallCompletedCallbackOneException) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017687 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017688 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017689 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
17690 CompileRun("throw 'exception';");
17691}
17692
17693
17694TEST(CallCompletedCallbackTwoExceptions) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017695 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017696 v8::HandleScope scope(env->GetIsolate());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000017697 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
17698 CompileRun("throw 'first exception';");
17699}
ulan@chromium.org812308e2012-02-29 15:58:45 +000017700
17701
17702static int probes_counter = 0;
17703static int misses_counter = 0;
17704static int updates_counter = 0;
17705
17706
17707static int* LookupCounter(const char* name) {
17708 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
17709 return &probes_counter;
17710 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
17711 return &misses_counter;
17712 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
17713 return &updates_counter;
17714 }
17715 return NULL;
17716}
17717
17718
17719static const char* kMegamorphicTestProgram =
17720 "function ClassA() { };"
17721 "function ClassB() { };"
17722 "ClassA.prototype.foo = function() { };"
17723 "ClassB.prototype.foo = function() { };"
17724 "function fooify(obj) { obj.foo(); };"
17725 "var a = new ClassA();"
17726 "var b = new ClassB();"
17727 "for (var i = 0; i < 10000; i++) {"
17728 " fooify(a);"
17729 " fooify(b);"
17730 "}";
17731
17732
17733static void StubCacheHelper(bool primary) {
17734 V8::SetCounterFunction(LookupCounter);
17735 USE(kMegamorphicTestProgram);
17736#ifdef DEBUG
17737 i::FLAG_native_code_counters = true;
17738 if (primary) {
17739 i::FLAG_test_primary_stub_cache = true;
17740 } else {
17741 i::FLAG_test_secondary_stub_cache = true;
17742 }
17743 i::FLAG_crankshaft = false;
ulan@chromium.org812308e2012-02-29 15:58:45 +000017744 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017745 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.org812308e2012-02-29 15:58:45 +000017746 int initial_probes = probes_counter;
17747 int initial_misses = misses_counter;
17748 int initial_updates = updates_counter;
17749 CompileRun(kMegamorphicTestProgram);
17750 int probes = probes_counter - initial_probes;
17751 int misses = misses_counter - initial_misses;
17752 int updates = updates_counter - initial_updates;
17753 CHECK_LT(updates, 10);
17754 CHECK_LT(misses, 10);
17755 CHECK_GE(probes, 10000);
17756#endif
17757}
17758
17759
17760TEST(SecondaryStubCache) {
17761 StubCacheHelper(true);
17762}
17763
17764
17765TEST(PrimaryStubCache) {
17766 StubCacheHelper(false);
17767}
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017768
17769
17770static int fatal_error_callback_counter = 0;
17771static void CountingErrorCallback(const char* location, const char* message) {
17772 printf("CountingErrorCallback(\"%s\", \"%s\")\n", location, message);
17773 fatal_error_callback_counter++;
17774}
17775
17776
17777TEST(StaticGetters) {
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017778 LocalContext context;
17779 v8::Isolate* isolate = v8::Isolate::GetCurrent();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017780 v8::HandleScope scope(isolate);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017781 i::Handle<i::Object> undefined_value = FACTORY->undefined_value();
17782 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
17783 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
17784 i::Handle<i::Object> null_value = FACTORY->null_value();
17785 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
17786 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
17787 i::Handle<i::Object> true_value = FACTORY->true_value();
17788 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
17789 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
17790 i::Handle<i::Object> false_value = FACTORY->false_value();
17791 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
17792 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
17793
17794 // Test after-death behavior.
17795 CHECK(i::Internals::IsInitialized(isolate));
17796 CHECK_EQ(0, fatal_error_callback_counter);
17797 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17798 v8::Utils::ReportApiFailure("StaticGetters()", "Kill V8");
17799 i::Isolate::Current()->TearDown();
17800 CHECK(!i::Internals::IsInitialized(isolate));
17801 CHECK_EQ(1, fatal_error_callback_counter);
17802 CHECK(v8::Undefined().IsEmpty());
17803 CHECK_EQ(2, fatal_error_callback_counter);
17804 CHECK(v8::Undefined(isolate).IsEmpty());
17805 CHECK_EQ(3, fatal_error_callback_counter);
17806 CHECK(v8::Null().IsEmpty());
17807 CHECK_EQ(4, fatal_error_callback_counter);
17808 CHECK(v8::Null(isolate).IsEmpty());
17809 CHECK_EQ(5, fatal_error_callback_counter);
17810 CHECK(v8::True().IsEmpty());
17811 CHECK_EQ(6, fatal_error_callback_counter);
17812 CHECK(v8::True(isolate).IsEmpty());
17813 CHECK_EQ(7, fatal_error_callback_counter);
17814 CHECK(v8::False().IsEmpty());
17815 CHECK_EQ(8, fatal_error_callback_counter);
17816 CHECK(v8::False(isolate).IsEmpty());
17817 CHECK_EQ(9, fatal_error_callback_counter);
17818}
17819
17820
17821TEST(IsolateEmbedderData) {
17822 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17823 CHECK_EQ(NULL, isolate->GetData());
17824 CHECK_EQ(NULL, ISOLATE->GetData());
17825 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
17826 isolate->SetData(data1);
17827 CHECK_EQ(data1, isolate->GetData());
17828 CHECK_EQ(data1, ISOLATE->GetData());
17829 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
17830 ISOLATE->SetData(data2);
17831 CHECK_EQ(data2, isolate->GetData());
17832 CHECK_EQ(data2, ISOLATE->GetData());
17833 ISOLATE->TearDown();
17834 CHECK_EQ(data2, isolate->GetData());
17835 CHECK_EQ(data2, ISOLATE->GetData());
17836}
17837
17838
17839TEST(StringEmpty) {
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017840 LocalContext context;
17841 v8::Isolate* isolate = v8::Isolate::GetCurrent();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017842 v8::HandleScope scope(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000017843 i::Handle<i::Object> empty_string = FACTORY->empty_string();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +000017844 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
17845 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
17846
17847 // Test after-death behavior.
17848 CHECK(i::Internals::IsInitialized(isolate));
17849 CHECK_EQ(0, fatal_error_callback_counter);
17850 v8::V8::SetFatalErrorHandler(CountingErrorCallback);
17851 v8::Utils::ReportApiFailure("StringEmpty()", "Kill V8");
17852 i::Isolate::Current()->TearDown();
17853 CHECK(!i::Internals::IsInitialized(isolate));
17854 CHECK_EQ(1, fatal_error_callback_counter);
17855 CHECK(v8::String::Empty().IsEmpty());
17856 CHECK_EQ(2, fatal_error_callback_counter);
17857 CHECK(v8::String::Empty(isolate).IsEmpty());
17858 CHECK_EQ(3, fatal_error_callback_counter);
17859}
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017860
17861
17862static int instance_checked_getter_count = 0;
17863static Handle<Value> InstanceCheckedGetter(Local<String> name,
17864 const AccessorInfo& info) {
17865 CHECK_EQ(name, v8_str("foo"));
17866 instance_checked_getter_count++;
17867 return v8_num(11);
17868}
17869
17870
17871static int instance_checked_setter_count = 0;
17872static void InstanceCheckedSetter(Local<String> name,
17873 Local<Value> value,
17874 const AccessorInfo& info) {
17875 CHECK_EQ(name, v8_str("foo"));
17876 CHECK_EQ(value, v8_num(23));
17877 instance_checked_setter_count++;
17878}
17879
17880
17881static void CheckInstanceCheckedResult(int getters,
17882 int setters,
17883 bool expects_callbacks,
17884 TryCatch* try_catch) {
17885 if (expects_callbacks) {
17886 CHECK(!try_catch->HasCaught());
17887 CHECK_EQ(getters, instance_checked_getter_count);
17888 CHECK_EQ(setters, instance_checked_setter_count);
17889 } else {
17890 CHECK(try_catch->HasCaught());
17891 CHECK_EQ(0, instance_checked_getter_count);
17892 CHECK_EQ(0, instance_checked_setter_count);
17893 }
17894 try_catch->Reset();
17895}
17896
17897
17898static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
17899 instance_checked_getter_count = 0;
17900 instance_checked_setter_count = 0;
17901 TryCatch try_catch;
17902
17903 // Test path through generic runtime code.
17904 CompileRun("obj.foo");
17905 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
17906 CompileRun("obj.foo = 23");
17907 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
17908
17909 // Test path through generated LoadIC and StoredIC.
17910 CompileRun("function test_get(o) { o.foo; }"
17911 "test_get(obj);");
17912 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
17913 CompileRun("test_get(obj);");
17914 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
17915 CompileRun("test_get(obj);");
17916 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
17917 CompileRun("function test_set(o) { o.foo = 23; }"
17918 "test_set(obj);");
17919 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
17920 CompileRun("test_set(obj);");
17921 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
17922 CompileRun("test_set(obj);");
17923 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
17924
17925 // Test path through optimized code.
17926 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
17927 "test_get(obj);");
17928 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
17929 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
17930 "test_set(obj);");
17931 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
17932
17933 // Cleanup so that closures start out fresh in next check.
17934 CompileRun("%DeoptimizeFunction(test_get);"
17935 "%ClearFunctionTypeFeedback(test_get);"
17936 "%DeoptimizeFunction(test_set);"
17937 "%ClearFunctionTypeFeedback(test_set);");
17938}
17939
17940
17941THREADED_TEST(InstanceCheckOnInstanceAccessor) {
17942 v8::internal::FLAG_allow_natives_syntax = true;
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017943 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017944 v8::HandleScope scope(context->GetIsolate());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017945
17946 Local<FunctionTemplate> templ = FunctionTemplate::New();
17947 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17948 inst->SetAccessor(v8_str("foo"),
17949 InstanceCheckedGetter, InstanceCheckedSetter,
17950 Handle<Value>(),
17951 v8::DEFAULT,
17952 v8::None,
17953 v8::AccessorSignature::New(templ));
17954 context->Global()->Set(v8_str("f"), templ->GetFunction());
17955
17956 printf("Testing positive ...\n");
17957 CompileRun("var obj = new f();");
17958 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17959 CheckInstanceCheckedAccessors(true);
17960
17961 printf("Testing negative ...\n");
17962 CompileRun("var obj = {};"
17963 "obj.__proto__ = new f();");
17964 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17965 CheckInstanceCheckedAccessors(false);
17966}
17967
17968
17969THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
17970 v8::internal::FLAG_allow_natives_syntax = true;
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017971 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000017972 v8::HandleScope scope(context->GetIsolate());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000017973
17974 Local<FunctionTemplate> templ = FunctionTemplate::New();
17975 Local<ObjectTemplate> inst = templ->InstanceTemplate();
17976 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
17977 inst->SetAccessor(v8_str("foo"),
17978 InstanceCheckedGetter, InstanceCheckedSetter,
17979 Handle<Value>(),
17980 v8::DEFAULT,
17981 v8::None,
17982 v8::AccessorSignature::New(templ));
17983 context->Global()->Set(v8_str("f"), templ->GetFunction());
17984
17985 printf("Testing positive ...\n");
17986 CompileRun("var obj = new f();");
17987 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17988 CheckInstanceCheckedAccessors(true);
17989
17990 printf("Testing negative ...\n");
17991 CompileRun("var obj = {};"
17992 "obj.__proto__ = new f();");
17993 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
17994 CheckInstanceCheckedAccessors(false);
17995}
17996
17997
17998THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
17999 v8::internal::FLAG_allow_natives_syntax = true;
mmassi@chromium.org7028c052012-06-13 11:51:58 +000018000 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018001 v8::HandleScope scope(context->GetIsolate());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000018002
18003 Local<FunctionTemplate> templ = FunctionTemplate::New();
18004 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
18005 proto->SetAccessor(v8_str("foo"),
18006 InstanceCheckedGetter, InstanceCheckedSetter,
18007 Handle<Value>(),
18008 v8::DEFAULT,
18009 v8::None,
18010 v8::AccessorSignature::New(templ));
18011 context->Global()->Set(v8_str("f"), templ->GetFunction());
18012
18013 printf("Testing positive ...\n");
18014 CompileRun("var obj = new f();");
18015 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18016 CheckInstanceCheckedAccessors(true);
18017
18018 printf("Testing negative ...\n");
18019 CompileRun("var obj = {};"
18020 "obj.__proto__ = new f();");
18021 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18022 CheckInstanceCheckedAccessors(false);
18023
18024 printf("Testing positive with modified prototype chain ...\n");
18025 CompileRun("var obj = new f();"
18026 "var pro = {};"
18027 "pro.__proto__ = obj.__proto__;"
18028 "obj.__proto__ = pro;");
18029 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18030 CheckInstanceCheckedAccessors(true);
18031}
18032
18033
18034TEST(TryFinallyMessage) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000018035 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018036 v8::HandleScope scope(context->GetIsolate());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000018037 {
18038 // Test that the original error message is not lost if there is a
18039 // recursive call into Javascript is done in the finally block, e.g. to
18040 // initialize an IC. (crbug.com/129171)
18041 TryCatch try_catch;
18042 const char* trigger_ic =
18043 "try { \n"
18044 " throw new Error('test'); \n"
18045 "} finally { \n"
18046 " var x = 0; \n"
18047 " x++; \n" // Trigger an IC initialization here.
18048 "} \n";
18049 CompileRun(trigger_ic);
18050 CHECK(try_catch.HasCaught());
18051 Local<Message> message = try_catch.Message();
18052 CHECK(!message.IsEmpty());
18053 CHECK_EQ(2, message->GetLineNumber());
18054 }
18055
18056 {
18057 // Test that the original exception message is indeed overwritten if
18058 // a new error is thrown in the finally block.
18059 TryCatch try_catch;
18060 const char* throw_again =
18061 "try { \n"
18062 " throw new Error('test'); \n"
18063 "} finally { \n"
18064 " var x = 0; \n"
18065 " x++; \n"
18066 " throw new Error('again'); \n" // This is the new uncaught error.
18067 "} \n";
18068 CompileRun(throw_again);
18069 CHECK(try_catch.HasCaught());
18070 Local<Message> message = try_catch.Message();
18071 CHECK(!message.IsEmpty());
18072 CHECK_EQ(6, message->GetLineNumber());
18073 }
18074}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018075
18076
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018077static void Helper137002(bool do_store,
18078 bool polymorphic,
18079 bool remove_accessor,
18080 bool interceptor) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018081 LocalContext context;
18082 Local<ObjectTemplate> templ = ObjectTemplate::New();
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018083 if (interceptor) {
18084 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
18085 } else {
18086 templ->SetAccessor(v8_str("foo"),
18087 GetterWhichReturns42,
18088 SetterWhichSetsYOnThisTo23);
18089 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018090 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18091
18092 // Turn monomorphic on slow object with native accessor, then turn
18093 // polymorphic, finally optimize to create negative lookup and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018094 CompileRun(do_store ?
18095 "function f(x) { x.foo = void 0; }" :
18096 "function f(x) { return x.foo; }");
18097 CompileRun("obj.y = void 0;");
18098 if (!interceptor) {
18099 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
18100 }
18101 CompileRun("obj.__proto__ = null;"
18102 "f(obj); f(obj); f(obj);");
18103 if (polymorphic) {
18104 CompileRun("f({});");
18105 }
18106 CompileRun("obj.y = void 0;"
18107 "%OptimizeFunctionOnNextCall(f);");
18108 if (remove_accessor) {
18109 CompileRun("delete obj.foo;");
18110 }
18111 CompileRun("var result = f(obj);");
18112 if (do_store) {
18113 CompileRun("result = obj.y;");
18114 }
18115 if (remove_accessor && !interceptor) {
18116 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
18117 } else {
18118 CHECK_EQ(do_store ? 23 : 42,
18119 context->Global()->Get(v8_str("result"))->Int32Value());
18120 }
18121}
18122
18123
18124THREADED_TEST(Regress137002a) {
18125 i::FLAG_allow_natives_syntax = true;
18126 i::FLAG_compilation_cache = false;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018127 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018128 for (int i = 0; i < 16; i++) {
18129 Helper137002(i & 8, i & 4, i & 2, i & 1);
18130 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018131}
18132
18133
18134THREADED_TEST(Regress137002b) {
18135 i::FLAG_allow_natives_syntax = true;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018136 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018137 v8::HandleScope scope(context->GetIsolate());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018138 Local<ObjectTemplate> templ = ObjectTemplate::New();
18139 templ->SetAccessor(v8_str("foo"),
18140 GetterWhichReturns42,
18141 SetterWhichSetsYOnThisTo23);
18142 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18143
18144 // Turn monomorphic on slow object with native accessor, then just
18145 // delete the property and fail.
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018146 CompileRun("function load(x) { return x.foo; }"
18147 "function store(x) { x.foo = void 0; }"
18148 "function keyed_load(x, key) { return x[key]; }"
18149 // Second version of function has a different source (add void 0)
18150 // so that it does not share code with the first version. This
18151 // ensures that the ICs are monomorphic.
18152 "function load2(x) { void 0; return x.foo; }"
18153 "function store2(x) { void 0; x.foo = void 0; }"
18154 "function keyed_load2(x, key) { void 0; return x[key]; }"
18155
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018156 "obj.y = void 0;"
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018157 "obj.__proto__ = null;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018158 "var subobj = {};"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018159 "subobj.y = void 0;"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018160 "subobj.__proto__ = obj;"
18161 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
18162
18163 // Make the ICs monomorphic.
18164 "load(obj); load(obj);"
18165 "load2(subobj); load2(subobj);"
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018166 "store(obj); store(obj);"
18167 "store2(subobj); store2(subobj);"
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018168 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
18169 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
18170
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018171 // Actually test the shiny new ICs and better not crash. This
18172 // serves as a regression test for issue 142088 as well.
18173 "load(obj);"
18174 "load2(subobj);"
18175 "store(obj);"
18176 "store2(subobj);"
18177 "keyed_load(obj, 'foo');"
18178 "keyed_load2(subobj, 'foo');"
18179
erik.corry@gmail.com88767242012-08-08 14:43:45 +000018180 // Delete the accessor. It better not be called any more now.
18181 "delete obj.foo;"
18182 "obj.y = void 0;"
18183 "subobj.y = void 0;"
18184
18185 "var load_result = load(obj);"
18186 "var load_result2 = load2(subobj);"
18187 "var keyed_load_result = keyed_load(obj, 'foo');"
18188 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
18189 "store(obj);"
18190 "store2(subobj);"
18191 "var y_from_obj = obj.y;"
18192 "var y_from_subobj = subobj.y;");
18193 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
18194 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
18195 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
18196 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
18197 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
18198 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +000018199}
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018200
18201
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018202THREADED_TEST(Regress142088) {
18203 i::FLAG_allow_natives_syntax = true;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018204 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018205 v8::HandleScope scope(context->GetIsolate());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000018206 Local<ObjectTemplate> templ = ObjectTemplate::New();
18207 templ->SetAccessor(v8_str("foo"),
18208 GetterWhichReturns42,
18209 SetterWhichSetsYOnThisTo23);
18210 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18211
18212 CompileRun("function load(x) { return x.foo; }"
18213 "var o = Object.create(obj);"
18214 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
18215 "load(o); load(o); load(o); load(o);");
18216}
18217
18218
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018219THREADED_TEST(Regress137496) {
18220 i::FLAG_expose_gc = true;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018221 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018222 v8::HandleScope scope(context->GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +000018223
18224 // Compile a try-finally clause where the finally block causes a GC
18225 // while there still is a message pending for external reporting.
18226 TryCatch try_catch;
18227 try_catch.SetVerbose(true);
18228 CompileRun("try { throw new Error(); } finally { gc(); }");
18229 CHECK(try_catch.HasCaught());
18230}
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018231
18232
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000018233THREADED_TEST(Regress149912) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000018234 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018235 v8::HandleScope scope(context->GetIsolate());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000018236 Handle<FunctionTemplate> templ = FunctionTemplate::New();
18237 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
18238 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
18239 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
18240}
18241
18242
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000018243THREADED_TEST(Regress157124) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000018244 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018245 v8::HandleScope scope(context->GetIsolate());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000018246 Local<ObjectTemplate> templ = ObjectTemplate::New();
18247 Local<Object> obj = templ->NewInstance();
18248 obj->GetIdentityHash();
18249 obj->DeleteHiddenValue(v8_str("Bug"));
18250}
18251
18252
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000018253THREADED_TEST(Regress2535) {
18254 i::FLAG_harmony_collections = true;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000018255 LocalContext context;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000018256 v8::HandleScope scope(context->GetIsolate());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000018257 Local<Value> set_value = CompileRun("new Set();");
18258 Local<Object> set_object(Object::Cast(*set_value));
18259 CHECK_EQ(0, set_object->InternalFieldCount());
18260 Local<Value> map_value = CompileRun("new Map();");
18261 Local<Object> map_object(Object::Cast(*map_value));
18262 CHECK_EQ(0, map_object->InternalFieldCount());
18263}
18264
18265
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018266#ifndef WIN32
18267class ThreadInterruptTest {
18268 public:
18269 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
18270 ~ThreadInterruptTest() { delete sem_; }
18271
18272 void RunTest() {
18273 sem_ = i::OS::CreateSemaphore(0);
18274
18275 InterruptThread i_thread(this);
18276 i_thread.Start();
18277
18278 sem_->Wait();
18279 CHECK_EQ(kExpectedValue, sem_value_);
18280 }
18281
18282 private:
18283 static const int kExpectedValue = 1;
18284
18285 class InterruptThread : public i::Thread {
18286 public:
18287 explicit InterruptThread(ThreadInterruptTest* test)
18288 : Thread("InterruptThread"), test_(test) {}
18289
18290 virtual void Run() {
18291 struct sigaction action;
18292
18293 // Ensure that we'll enter waiting condition
18294 i::OS::Sleep(100);
18295
18296 // Setup signal handler
18297 memset(&action, 0, sizeof(action));
18298 action.sa_handler = SignalHandler;
18299 sigaction(SIGCHLD, &action, NULL);
18300
18301 // Send signal
18302 kill(getpid(), SIGCHLD);
18303
18304 // Ensure that if wait has returned because of error
18305 i::OS::Sleep(100);
18306
18307 // Set value and signal semaphore
18308 test_->sem_value_ = 1;
18309 test_->sem_->Signal();
18310 }
18311
18312 static void SignalHandler(int signal) {
18313 }
18314
18315 private:
18316 ThreadInterruptTest* test_;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018317 };
18318
18319 i::Semaphore* sem_;
18320 volatile int sem_value_;
18321};
18322
18323
18324THREADED_TEST(SemaphoreInterruption) {
18325 ThreadInterruptTest().RunTest();
18326}
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000018327
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000018328#endif // WIN32