blob: 06cf5532e244e30a2eb17b8d77ac8f1e52522730 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028#include <climits>
29#include <csignal>
30#include <map>
31#include <string>
Steve Blocka7e24c12009-10-30 11:49:00 +000032
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035#if V8_OS_POSIX
36#include <unistd.h> // NOLINT
37#endif
38
39#include "include/v8-util.h"
40#include "src/api.h"
41#include "src/arguments.h"
42#include "src/base/platform/platform.h"
43#include "src/compilation-cache.h"
44#include "src/cpu-profiler.h"
45#include "src/execution.h"
46#include "src/isolate.h"
47#include "src/objects.h"
48#include "src/parser.h"
49#include "src/snapshot.h"
50#include "src/unicode-inl.h"
51#include "src/utils.h"
52#include "src/vm-state.h"
53#include "test/cctest/cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000054
Ben Murdoch257744e2011-11-30 15:57:28 +000055static const bool kLogThreading = false;
Steve Blockd0582a62009-12-15 09:54:21 +000056
Ben Murdochb8a8cc12014-11-26 15:28:44 +000057using ::v8::Boolean;
58using ::v8::BooleanObject;
Steve Block44f0eee2011-05-26 01:26:41 +010059using ::v8::Context;
Steve Blocka7e24c12009-10-30 11:49:00 +000060using ::v8::Extension;
Steve Block44f0eee2011-05-26 01:26:41 +010061using ::v8::Function;
Ben Murdoch8b112d22011-06-08 16:22:53 +010062using ::v8::FunctionTemplate;
63using ::v8::Handle;
Steve Block44f0eee2011-05-26 01:26:41 +010064using ::v8::HandleScope;
65using ::v8::Local;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066using ::v8::Name;
Ben Murdoch8b112d22011-06-08 16:22:53 +010067using ::v8::Message;
68using ::v8::MessageCallback;
Steve Block44f0eee2011-05-26 01:26:41 +010069using ::v8::Object;
70using ::v8::ObjectTemplate;
71using ::v8::Persistent;
72using ::v8::Script;
Ben Murdoch8b112d22011-06-08 16:22:53 +010073using ::v8::StackTrace;
Steve Block44f0eee2011-05-26 01:26:41 +010074using ::v8::String;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075using ::v8::Symbol;
Ben Murdoch8b112d22011-06-08 16:22:53 +010076using ::v8::TryCatch;
77using ::v8::Undefined;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000078using ::v8::UniqueId;
Steve Block44f0eee2011-05-26 01:26:41 +010079using ::v8::V8;
Ben Murdoch8b112d22011-06-08 16:22:53 +010080using ::v8::Value;
Steve Blocka7e24c12009-10-30 11:49:00 +000081
Steve Blocka7e24c12009-10-30 11:49:00 +000082
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083#define THREADED_PROFILED_TEST(Name) \
84 static void Test##Name(); \
85 TEST(Name##WithProfiler) { \
86 RunWithProfiler(&Test##Name); \
87 } \
88 THREADED_TEST(Name)
Leon Clarked91b9f72010-01-27 17:25:45 +000089
90
Ben Murdochb8a8cc12014-11-26 15:28:44 +000091void RunWithProfiler(void (*test)()) {
92 LocalContext env;
93 v8::HandleScope scope(env->GetIsolate());
94 v8::Local<v8::String> profile_name =
95 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
Leon Clarkef7060e22010-06-03 12:02:55 +010097
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 cpu_profiler->StartProfiling(profile_name);
99 (*test)();
100 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
Iain Merrick75681382010-08-19 15:07:18 +0100101}
102
103
Steve Blocka7e24c12009-10-30 11:49:00 +0000104static int signature_callback_count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105static Local<Value> signature_expected_receiver;
106static void IncrementingSignatureCallback(
107 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 ApiTestFuzzer::Fuzz();
109 signature_callback_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 CHECK_EQ(signature_expected_receiver, args.Holder());
111 CHECK_EQ(signature_expected_receiver, args.This());
112 v8::Handle<v8::Array> result =
113 v8::Array::New(args.GetIsolate(), args.Length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 for (int i = 0; i < args.Length(); i++)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000115 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116 args.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000117}
118
119
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120static void SignatureCallback(
121 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 v8::Handle<v8::Array> result =
124 v8::Array::New(args.GetIsolate(), args.Length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000126 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 args.GetReturnValue().Set(result);
129}
130
131
132// Tests that call v8::V8::Dispose() cannot be threaded.
133UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134 CHECK(v8::V8::Initialize());
135 CHECK(v8::V8::Dispose());
136}
137
138
139// Tests that call v8::V8::Dispose() cannot be threaded.
140UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
Steve Blocka7e24c12009-10-30 11:49:00 +0000146}
147
148
149THREADED_TEST(Handles) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 Local<Context> local_env;
152 {
153 LocalContext env;
154 local_env = env.local();
155 }
156
157 // Local context should still be live.
158 CHECK(!local_env.IsEmpty());
159 local_env->Enter();
160
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 CHECK(!undef.IsEmpty());
163 CHECK(undef->IsUndefined());
164
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 const char* source = "1 + 2 + 3";
166 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000167 CHECK_EQ(6, script->Run()->Int32Value());
168
169 local_env->Exit();
170}
171
172
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173THREADED_TEST(IsolateOfContext) {
174 v8::HandleScope scope(CcTest::isolate());
175 v8::Handle<Context> env = Context::New(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000176
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 CHECK(!env->GetIsolate()->InContext());
178 CHECK(env->GetIsolate() == CcTest::isolate());
179 env->Enter();
180 CHECK(env->GetIsolate()->InContext());
181 CHECK(env->GetIsolate() == CcTest::isolate());
182 env->Exit();
183 CHECK(!env->GetIsolate()->InContext());
184 CHECK(env->GetIsolate() == CcTest::isolate());
185}
186
187
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400188static void TestSignature(const char* loop_js, Local<Value> receiver,
189 v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 i::ScopedVector<char> source(200);
191 i::SNPrintF(source,
192 "for (var i = 0; i < 10; i++) {"
193 " %s"
194 "}",
195 loop_js);
196 signature_callback_count = 0;
197 signature_expected_receiver = receiver;
198 bool expected_to_throw = receiver.IsEmpty();
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 CompileRun(source.start());
201 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
202 if (!expected_to_throw) {
203 CHECK_EQ(10, signature_callback_count);
204 } else {
205 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206 try_catch.Exception()->ToString(isolate));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 }
208}
209
210
211THREADED_TEST(ReceiverSignature) {
212 LocalContext env;
213 v8::Isolate* isolate = env->GetIsolate();
214 v8::HandleScope scope(isolate);
215 // Setup templates.
216 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
217 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
218 v8::Handle<v8::FunctionTemplate> callback_sig =
219 v8::FunctionTemplate::New(
220 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
221 v8::Handle<v8::FunctionTemplate> callback =
222 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
223 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 sub_fun->Inherit(fun);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225 v8::Handle<v8::FunctionTemplate> unrel_fun =
226 v8::FunctionTemplate::New(isolate);
227 // Install properties.
228 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
229 fun_proto->Set(v8_str("prop_sig"), callback_sig);
230 fun_proto->Set(v8_str("prop"), callback);
231 fun_proto->SetAccessorProperty(
232 v8_str("accessor_sig"), callback_sig, callback_sig);
233 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
234 // Instantiate templates.
235 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
236 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
237 // Setup global variables.
238 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 env->Global()->Set(v8_str("fun_instance"), fun_instance);
241 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 "var accessor_sig_key = 'accessor_sig';"
244 "var accessor_key = 'accessor';"
245 "var prop_sig_key = 'prop_sig';"
246 "var prop_key = 'prop';"
247 ""
248 "function copy_props(obj) {"
249 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
250 " var source = Fun.prototype;"
251 " for (var i in keys) {"
252 " var key = keys[i];"
253 " var desc = Object.getOwnPropertyDescriptor(source, key);"
254 " Object.defineProperty(obj, key, desc);"
255 " }"
256 "}"
257 ""
258 "var obj = {};"
259 "copy_props(obj);"
260 "var unrel = new UnrelFun();"
261 "copy_props(unrel);");
262 // Test with and without ICs
263 const char* test_objects[] = {
264 "fun_instance", "sub_fun_instance", "obj", "unrel" };
265 unsigned bad_signature_start_offset = 2;
266 for (unsigned i = 0; i < arraysize(test_objects); i++) {
267 i::ScopedVector<char> source(200);
268 i::SNPrintF(
269 source, "var test_object = %s; test_object", test_objects[i]);
270 Local<Value> test_object = CompileRun(source.start());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271 TestSignature("test_object.prop();", test_object, isolate);
272 TestSignature("test_object.accessor;", test_object, isolate);
273 TestSignature("test_object[accessor_key];", test_object, isolate);
274 TestSignature("test_object.accessor = 1;", test_object, isolate);
275 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 if (i >= bad_signature_start_offset) test_object = Local<Value>();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400277 TestSignature("test_object.prop_sig();", test_object, isolate);
278 TestSignature("test_object.accessor_sig;", test_object, isolate);
279 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
280 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
281 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000283}
284
285
Steve Blocka7e24c12009-10-30 11:49:00 +0000286THREADED_TEST(ArgumentSignature) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 v8::Isolate* isolate = env->GetIsolate();
289 v8::HandleScope scope(isolate);
290 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 cons->SetClassName(v8_str("Cons"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 v8::Handle<v8::Signature> sig = v8::Signature::New(
293 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
Steve Blocka7e24c12009-10-30 11:49:00 +0000294 v8::Handle<v8::FunctionTemplate> fun =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 v8::FunctionTemplate::New(isolate,
296 SignatureCallback,
297 v8::Handle<Value>(),
298 sig);
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
300 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
301
302 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
303 CHECK(value1->IsTrue());
304
305 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
306 CHECK(value2->IsTrue());
307
308 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
309 CHECK(value3->IsTrue());
310
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 cons1->SetClassName(v8_str("Cons1"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000313 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 cons2->SetClassName(v8_str("Cons2"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 cons3->SetClassName(v8_str("Cons3"));
317
318 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319 v8::Handle<v8::Signature> wsig = v8::Signature::New(
320 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 v8::Handle<v8::FunctionTemplate> fun2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 v8::FunctionTemplate::New(isolate,
323 SignatureCallback,
324 v8::Handle<Value>(),
325 wsig);
Steve Blocka7e24c12009-10-30 11:49:00 +0000326
327 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
328 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
329 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
330 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
331 v8::Handle<Value> value4 = CompileRun(
332 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
333 "'[object Cons1],[object Cons2],[object Cons3]'");
334 CHECK(value4->IsTrue());
335
336 v8::Handle<Value> value5 = CompileRun(
337 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
338 CHECK(value5->IsTrue());
339
340 v8::Handle<Value> value6 = CompileRun(
341 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
342 CHECK(value6->IsTrue());
343
344 v8::Handle<Value> value7 = CompileRun(
345 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
346 "'[object Cons1],[object Cons2],[object Cons3],d';");
347 CHECK(value7->IsTrue());
348
349 v8::Handle<Value> value8 = CompileRun(
350 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
351 CHECK(value8->IsTrue());
352}
353
354
355THREADED_TEST(HulIgennem) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 v8::Isolate* isolate = env->GetIsolate();
358 v8::HandleScope scope(isolate);
359 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360 Local<String> undef_str = undef->ToString(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
362 undef_str->WriteUtf8(value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 CHECK_EQ(0, strcmp(value, "undefined"));
364 i::DeleteArray(value);
365}
366
367
368THREADED_TEST(Access) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370 v8::Isolate* isolate = env->GetIsolate();
371 v8::HandleScope scope(isolate);
372 Local<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000373 Local<Value> foo_before = obj->Get(v8_str("foo"));
374 CHECK(foo_before->IsUndefined());
375 Local<String> bar_str = v8_str("bar");
376 obj->Set(v8_str("foo"), bar_str);
377 Local<Value> foo_after = obj->Get(v8_str("foo"));
378 CHECK(!foo_after->IsUndefined());
379 CHECK(foo_after->IsString());
380 CHECK_EQ(bar_str, foo_after);
381}
382
383
Steve Block6ded16b2010-05-10 14:33:55 +0100384THREADED_TEST(AccessElement) {
Steve Block6ded16b2010-05-10 14:33:55 +0100385 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386 v8::HandleScope scope(env->GetIsolate());
387 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +0100388 Local<Value> before = obj->Get(1);
389 CHECK(before->IsUndefined());
390 Local<String> bar_str = v8_str("bar");
391 obj->Set(1, bar_str);
392 Local<Value> after = obj->Get(1);
393 CHECK(!after->IsUndefined());
394 CHECK(after->IsString());
395 CHECK_EQ(bar_str, after);
396
397 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
398 CHECK_EQ(v8_str("a"), value->Get(0));
399 CHECK_EQ(v8_str("b"), value->Get(1));
400}
401
402
Steve Blocka7e24c12009-10-30 11:49:00 +0000403THREADED_TEST(Script) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405 v8::HandleScope scope(env->GetIsolate());
406 const char* source = "1 + 2 + 3";
407 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000408 CHECK_EQ(6, script->Run()->Int32Value());
409}
410
411
Steve Blocka7e24c12009-10-30 11:49:00 +0000412class TestResource: public String::ExternalStringResource {
413 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 explicit TestResource(uint16_t* data, int* counter = NULL,
415 bool owning_data = true)
416 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 while (data[length_]) ++length_;
418 }
419
420 ~TestResource() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 if (owning_data_) i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000422 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 }
424
425 const uint16_t* data() const {
426 return data_;
427 }
428
429 size_t length() const {
430 return length_;
431 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 private:
434 uint16_t* data_;
435 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000436 int* counter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 bool owning_data_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000438};
439
440
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441class TestOneByteResource : public String::ExternalOneByteStringResource {
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443 explicit TestOneByteResource(const char* data, int* counter = NULL,
444 size_t offset = 0)
445 : orig_data_(data),
446 data_(data + offset),
447 length_(strlen(data) - offset),
448 counter_(counter) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000449
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450 ~TestOneByteResource() {
451 i::DeleteArray(orig_data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000452 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000453 }
454
455 const char* data() const {
456 return data_;
457 }
458
459 size_t length() const {
460 return length_;
461 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 const char* orig_data_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 const char* data_;
466 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000467 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000468};
469
470
Steve Blocka7e24c12009-10-30 11:49:00 +0000471THREADED_TEST(ScriptUsingStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000472 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 const char* c_source = "1 + 2 * 3";
474 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
475 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000478 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
480 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 Local<Value> value = script->Run();
482 CHECK(value->IsNumber());
483 CHECK_EQ(7, value->Int32Value());
484 CHECK(source->IsExternal());
485 CHECK_EQ(resource,
486 static_cast<TestResource*>(source->GetExternalStringResource()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 String::Encoding encoding = String::UNKNOWN_ENCODING;
488 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
489 source->GetExternalStringResourceBase(&encoding));
490 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
491 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000492 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494 CcTest::i_isolate()->compilation_cache()->Clear();
495 CcTest::heap()->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000496 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497}
498
499
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500THREADED_TEST(ScriptUsingOneByteStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000501 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 const char* c_source = "1 + 2 * 3";
503 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000504 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505 v8::HandleScope scope(env->GetIsolate());
506 TestOneByteResource* resource =
507 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
508 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
509 CHECK(source->IsExternalOneByte());
510 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
511 source->GetExternalOneByteStringResource());
512 String::Encoding encoding = String::UNKNOWN_ENCODING;
513 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
514 source->GetExternalStringResourceBase(&encoding));
515 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
516 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 Local<Value> value = script->Run();
518 CHECK(value->IsNumber());
519 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000520 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000521 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000522 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523 CcTest::i_isolate()->compilation_cache()->Clear();
524 CcTest::heap()->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000525 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000526}
527
528
529THREADED_TEST(ScriptMakingExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000530 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000531 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
532 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 v8::HandleScope scope(env->GetIsolate());
535 Local<String> source =
536 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000537 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
539 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
540 CHECK_EQ(source->IsExternal(), false);
541 CHECK_EQ(source->IsExternalOneByte(), false);
542 String::Encoding encoding = String::UNKNOWN_ENCODING;
543 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
544 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000545 bool success = source->MakeExternal(new TestResource(two_byte_source,
546 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 CHECK(success);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 Local<Value> value = script->Run();
550 CHECK(value->IsNumber());
551 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000553 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 CcTest::i_isolate()->compilation_cache()->Clear();
556 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000557 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000558}
559
560
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561THREADED_TEST(ScriptMakingExternalOneByteString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000562 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 const char* c_source = "1 + 2 * 3";
564 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000567 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000568 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
570 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 bool success = source->MakeExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 CHECK(success);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 Local<Value> value = script->Run();
576 CHECK(value->IsNumber());
577 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000579 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 CcTest::i_isolate()->compilation_cache()->Clear();
582 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000583 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000584}
585
586
Andrei Popescu402d9372010-02-26 13:31:12 +0000587TEST(MakingExternalStringConditions) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000588 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 v8::HandleScope scope(env->GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +0000590
591 // Free some space in the new space so that we can check freshness.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000592 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000594
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100595 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 Local<String> small_string =
597 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100598 i::DeleteArray(two_byte_string);
599
Andrei Popescu402d9372010-02-26 13:31:12 +0000600 // We should refuse to externalize newly created small string.
601 CHECK(!small_string->CanMakeExternal());
602 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
604 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000605 // Old space strings should be accepted.
606 CHECK(small_string->CanMakeExternal());
607
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100608 two_byte_string = AsciiToTwoByteString("small string 2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100610 i::DeleteArray(two_byte_string);
611
Andrei Popescu402d9372010-02-26 13:31:12 +0000612 // We should refuse externalizing newly created small string.
613 CHECK(!small_string->CanMakeExternal());
614 for (int i = 0; i < 100; i++) {
615 String::Value value(small_string);
616 }
617 // Frequently used strings should be accepted.
618 CHECK(small_string->CanMakeExternal());
619
620 const int buf_size = 10 * 1024;
621 char* buf = i::NewArray<char>(buf_size);
622 memset(buf, 'a', buf_size);
623 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100624
625 two_byte_string = AsciiToTwoByteString(buf);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626 Local<String> large_string =
627 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000628 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100629 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000630 // Large strings should be immediately accepted.
631 CHECK(large_string->CanMakeExternal());
632}
633
634
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635TEST(MakingExternalOneByteStringConditions) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000636 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637 v8::HandleScope scope(env->GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +0000638
639 // Free some space in the new space so that we can check freshness.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000642
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000643 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
Andrei Popescu402d9372010-02-26 13:31:12 +0000644 // We should refuse to externalize newly created small string.
645 CHECK(!small_string->CanMakeExternal());
646 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
648 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000649 // Old space strings should be accepted.
650 CHECK(small_string->CanMakeExternal());
651
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
Andrei Popescu402d9372010-02-26 13:31:12 +0000653 // We should refuse externalizing newly created small string.
654 CHECK(!small_string->CanMakeExternal());
655 for (int i = 0; i < 100; i++) {
656 String::Value value(small_string);
657 }
658 // Frequently used strings should be accepted.
659 CHECK(small_string->CanMakeExternal());
660
661 const int buf_size = 10 * 1024;
662 char* buf = i::NewArray<char>(buf_size);
663 memset(buf, 'a', buf_size);
664 buf[buf_size - 1] = '\0';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
Andrei Popescu402d9372010-02-26 13:31:12 +0000666 i::DeleteArray(buf);
667 // Large strings should be immediately accepted.
668 CHECK(large_string->CanMakeExternal());
669}
670
671
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672TEST(MakingExternalUnalignedOneByteString) {
673 LocalContext env;
674 v8::HandleScope scope(env->GetIsolate());
675
676 CompileRun("function cons(a, b) { return a + b; }"
677 "function slice(a) { return a.substring(1); }");
678 // Create a cons string that will land in old pointer space.
679 Local<String> cons = Local<String>::Cast(CompileRun(
680 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
681 // Create a sliced string that will land in old pointer space.
682 Local<String> slice = Local<String>::Cast(CompileRun(
683 "slice('abcdefghijklmnopqrstuvwxyz');"));
684
685 // Trigger GCs so that the newly allocated string moves to old gen.
686 SimulateFullSpace(CcTest::heap()->old_pointer_space());
687 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
688 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
689
690 // Turn into external string with unaligned resource data.
691 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
692 bool success =
693 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
694 CHECK(success);
695 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
696 success =
697 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
698 CHECK(success);
699
700 // Trigger GCs and force evacuation.
701 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
702 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
Steve Blocka7e24c12009-10-30 11:49:00 +0000703}
704
705
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706THREADED_TEST(UsingExternalString) {
707 i::Factory* factory = CcTest::i_isolate()->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +0000708 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709 v8::HandleScope scope(CcTest::isolate());
710 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
Steve Blocka7e24c12009-10-30 11:49:00 +0000711 Local<String> string = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 CcTest::isolate(), new TestResource(two_byte_string));
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
714 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
716 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
717 i::Handle<i::String> isymbol =
718 factory->InternalizeString(istring);
719 CHECK(isymbol->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
723}
724
725
726THREADED_TEST(UsingExternalOneByteString) {
727 i::Factory* factory = CcTest::i_isolate()->factory();
728 {
729 v8::HandleScope scope(CcTest::isolate());
730 const char* one_byte_string = "test string";
731 Local<String> string = String::NewExternal(
732 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
733 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
734 // Trigger GCs so that the newly allocated string moves to old gen.
735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
736 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
737 i::Handle<i::String> isymbol =
738 factory->InternalizeString(istring);
739 CHECK(isymbol->IsInternalizedString());
740 }
741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000743}
744
745
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400746class RandomLengthResource : public v8::String::ExternalStringResource {
747 public:
748 explicit RandomLengthResource(int length) : length_(length) {}
749 virtual const uint16_t* data() const { return string_; }
750 virtual size_t length() const { return length_; }
751
752 private:
753 uint16_t string_[10];
754 int length_;
755};
756
757
758class RandomLengthOneByteResource
759 : public v8::String::ExternalOneByteStringResource {
760 public:
761 explicit RandomLengthOneByteResource(int length) : length_(length) {}
762 virtual const char* data() const { return string_; }
763 virtual size_t length() const { return length_; }
764
765 private:
766 char string_[10];
767 int length_;
768};
769
770
771THREADED_TEST(NewExternalForVeryLongString) {
772 {
773 LocalContext env;
774 v8::HandleScope scope(env->GetIsolate());
775 v8::TryCatch try_catch;
776 RandomLengthOneByteResource r(1 << 30);
777 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
778 CHECK(str.IsEmpty());
779 CHECK(try_catch.HasCaught());
780 String::Utf8Value exception_value(try_catch.Exception());
781 CHECK_EQ("RangeError: Invalid string length", *exception_value);
782 }
783
784 {
785 LocalContext env;
786 v8::HandleScope scope(env->GetIsolate());
787 v8::TryCatch try_catch;
788 RandomLengthResource r(1 << 30);
789 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
790 CHECK(str.IsEmpty());
791 CHECK(try_catch.HasCaught());
792 String::Utf8Value exception_value(try_catch.Exception());
793 CHECK_EQ("RangeError: Invalid string length", *exception_value);
794 }
795}
796
797
Leon Clarkee46be812010-01-19 14:06:41 +0000798THREADED_TEST(ScavengeExternalString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 i::FLAG_stress_compaction = false;
800 i::FLAG_gc_global = false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000801 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100802 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000803 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000804 v8::HandleScope scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000805 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 Local<String> string = String::NewExternal(
807 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000808 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000809 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
810 in_new_space = CcTest::heap()->InNewSpace(*istring);
811 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000812 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000813 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000814 CcTest::heap()->CollectGarbage(
815 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000816 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000817}
818
819
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820THREADED_TEST(ScavengeExternalOneByteString) {
821 i::FLAG_stress_compaction = false;
822 i::FLAG_gc_global = false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000823 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100824 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000825 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826 v8::HandleScope scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000827 const char* one_byte_string = "test string";
828 Local<String> string = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 CcTest::isolate(),
830 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000831 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
833 in_new_space = CcTest::heap()->InNewSpace(*istring);
834 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000835 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000836 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 CcTest::heap()->CollectGarbage(
838 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000839 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000840}
841
842
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000843class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100844 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000845 // Only used by non-threaded tests, so it can use static fields.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100846 static int dispose_calls;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000847 static int dispose_count;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100848
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
850 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100851
852 void Dispose() {
853 ++dispose_calls;
854 if (dispose_) delete this;
855 }
856 private:
857 bool dispose_;
858};
859
860
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861int TestOneByteResourceWithDisposeControl::dispose_count = 0;
862int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100863
864
865TEST(ExternalStringWithDisposeHandling) {
866 const char* c_source = "1 + 2 * 3";
867
868 // Use a stack allocated external string resource allocated object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000869 TestOneByteResourceWithDisposeControl::dispose_count = 0;
870 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
871 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100872 {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100873 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000874 v8::HandleScope scope(env->GetIsolate());
875 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
876 Local<Script> script = v8_compile(source);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100877 Local<Value> value = script->Run();
878 CHECK(value->IsNumber());
879 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000880 CcTest::heap()->CollectAllAvailableGarbage();
881 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100882 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000883 CcTest::i_isolate()->compilation_cache()->Clear();
884 CcTest::heap()->CollectAllAvailableGarbage();
885 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
886 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100887
888 // Use a heap allocated external string resource allocated object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 TestOneByteResourceWithDisposeControl::dispose_count = 0;
890 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
891 TestOneByteResource* res_heap =
892 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100893 {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100894 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895 v8::HandleScope scope(env->GetIsolate());
896 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
897 Local<Script> script = v8_compile(source);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100898 Local<Value> value = script->Run();
899 CHECK(value->IsNumber());
900 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000901 CcTest::heap()->CollectAllAvailableGarbage();
902 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100903 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000904 CcTest::i_isolate()->compilation_cache()->Clear();
905 CcTest::heap()->CollectAllAvailableGarbage();
906 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
907 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100908}
909
910
Steve Block3ce2e202009-11-05 08:53:23 +0000911THREADED_TEST(StringConcat) {
912 {
Steve Block3ce2e202009-11-05 08:53:23 +0000913 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000914 v8::HandleScope scope(env->GetIsolate());
Steve Block3ce2e202009-11-05 08:53:23 +0000915 const char* one_byte_string_1 = "function a_times_t";
916 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
917 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
918 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
919 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
920 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
921 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
922 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100923
924 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 Local<String> right =
926 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100927 i::DeleteArray(two_byte_source);
928
Steve Block3ce2e202009-11-05 08:53:23 +0000929 Local<String> source = String::Concat(left, right);
930 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 env->GetIsolate(),
932 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
Steve Block3ce2e202009-11-05 08:53:23 +0000933 source = String::Concat(source, right);
934 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000935 env->GetIsolate(),
Steve Block3ce2e202009-11-05 08:53:23 +0000936 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
937 source = String::Concat(source, right);
938 right = v8_str(one_byte_string_2);
939 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100940
941 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000942 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100943 i::DeleteArray(two_byte_source);
944
Steve Block3ce2e202009-11-05 08:53:23 +0000945 source = String::Concat(source, right);
946 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947 env->GetIsolate(),
Steve Block3ce2e202009-11-05 08:53:23 +0000948 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
949 source = String::Concat(source, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000950 Local<Script> script = v8_compile(source);
Steve Block3ce2e202009-11-05 08:53:23 +0000951 Local<Value> value = script->Run();
952 CHECK(value->IsNumber());
953 CHECK_EQ(68, value->Int32Value());
954 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000955 CcTest::i_isolate()->compilation_cache()->Clear();
956 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
957 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +0000958}
959
960
Steve Blocka7e24c12009-10-30 11:49:00 +0000961THREADED_TEST(GlobalProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 v8::Handle<v8::Object> global = env->Global();
965 global->Set(v8_str("pi"), v8_num(3.1415926));
966 Local<Value> pi = global->Get(v8_str("pi"));
967 CHECK_EQ(3.1415926, pi->NumberValue());
968}
969
970
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000971template<typename T>
972static void CheckReturnValue(const T& t, i::Address callback) {
973 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
974 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
975 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
976 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
977 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
978 // Verify reset
979 bool is_runtime = (*o)->IsTheHole();
980 rv.Set(true);
981 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
982 rv.Set(v8::Handle<v8::Object>());
983 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
984 CHECK_EQ(is_runtime, (*o)->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +0000985
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
987 // If CPU profiler is active check that when API callback is invoked
988 // VMState is set to EXTERNAL.
989 if (isolate->cpu_profiler()->is_profiling()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400990 CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000991 CHECK(isolate->external_callback_scope());
992 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000994}
995
996
997static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
998 i::Address callback) {
999 ApiTestFuzzer::Fuzz();
1000 CheckReturnValue(info, callback);
1001 info.GetReturnValue().Set(v8_str("bad value"));
1002 info.GetReturnValue().Set(v8_num(102));
1003}
1004
1005
1006static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1007 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1008}
1009
1010
1011static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1012 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1013}
1014
1015static void construct_callback(
1016 const v8::FunctionCallbackInfo<Value>& info) {
1017 ApiTestFuzzer::Fuzz();
1018 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1019 info.This()->Set(v8_str("x"), v8_num(1));
1020 info.This()->Set(v8_str("y"), v8_num(2));
1021 info.GetReturnValue().Set(v8_str("bad value"));
1022 info.GetReturnValue().Set(info.This());
1023}
1024
1025
1026static void Return239Callback(
1027 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1028 ApiTestFuzzer::Fuzz();
1029 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1030 info.GetReturnValue().Set(v8_str("bad value"));
1031 info.GetReturnValue().Set(v8_num(239));
1032}
1033
1034
1035template<typename Handler>
1036static void TestFunctionTemplateInitializer(Handler handler,
1037 Handler handler_2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001038 // Test constructor calls.
1039 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040 LocalContext env;
1041 v8::Isolate* isolate = env->GetIsolate();
1042 v8::HandleScope scope(isolate);
1043
Steve Blocka7e24c12009-10-30 11:49:00 +00001044 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001045 v8::FunctionTemplate::New(isolate, handler);
Steve Blocka7e24c12009-10-30 11:49:00 +00001046 Local<Function> fun = fun_templ->GetFunction();
1047 env->Global()->Set(v8_str("obj"), fun);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001048 Local<Script> script = v8_compile("obj()");
1049 for (int i = 0; i < 30; i++) {
1050 CHECK_EQ(102, script->Run()->Int32Value());
1051 }
1052 }
1053 // Use SetCallHandler to initialize a function template, should work like
1054 // the previous one.
1055 {
1056 LocalContext env;
1057 v8::Isolate* isolate = env->GetIsolate();
1058 v8::HandleScope scope(isolate);
1059
1060 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1061 fun_templ->SetCallHandler(handler_2);
1062 Local<Function> fun = fun_templ->GetFunction();
1063 env->Global()->Set(v8_str("obj"), fun);
1064 Local<Script> script = v8_compile("obj()");
1065 for (int i = 0; i < 30; i++) {
1066 CHECK_EQ(102, script->Run()->Int32Value());
1067 }
1068 }
1069}
1070
1071
1072template<typename Constructor, typename Accessor>
1073static void TestFunctionTemplateAccessor(Constructor constructor,
1074 Accessor accessor) {
1075 LocalContext env;
1076 v8::HandleScope scope(env->GetIsolate());
1077
1078 Local<v8::FunctionTemplate> fun_templ =
1079 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1080 fun_templ->SetClassName(v8_str("funky"));
1081 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1082 Local<Function> fun = fun_templ->GetFunction();
1083 env->Global()->Set(v8_str("obj"), fun);
1084 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1085 CHECK_EQ(v8_str("[object funky]"), result);
1086 CompileRun("var obj_instance = new obj();");
1087 Local<Script> script;
1088 script = v8_compile("obj_instance.x");
1089 for (int i = 0; i < 30; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 CHECK_EQ(1, script->Run()->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091 }
1092 script = v8_compile("obj_instance.m");
1093 for (int i = 0; i < 30; i++) {
1094 CHECK_EQ(239, script->Run()->Int32Value());
1095 }
1096}
Steve Blocka7e24c12009-10-30 11:49:00 +00001097
Ben Murdochf87a2032010-10-22 12:50:53 +01001098
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001099THREADED_PROFILED_TEST(FunctionTemplate) {
1100 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1101 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1102}
1103
1104
1105static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1106 ApiTestFuzzer::Fuzz();
1107 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1108 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1109}
1110
1111
1112template<typename Callback>
1113static void TestSimpleCallback(Callback callback) {
1114 LocalContext env;
1115 v8::Isolate* isolate = env->GetIsolate();
1116 v8::HandleScope scope(isolate);
1117
1118 v8::Handle<v8::ObjectTemplate> object_template =
1119 v8::ObjectTemplate::New(isolate);
1120 object_template->Set(isolate, "callback",
1121 v8::FunctionTemplate::New(isolate, callback));
1122 v8::Local<v8::Object> object = object_template->NewInstance();
1123 (*env)->Global()->Set(v8_str("callback_object"), object);
1124 v8::Handle<v8::Script> script;
1125 script = v8_compile("callback_object.callback(17)");
1126 for (int i = 0; i < 30; i++) {
1127 CHECK_EQ(51424, script->Run()->Int32Value());
1128 }
1129 script = v8_compile("callback_object.callback(17, 24)");
1130 for (int i = 0; i < 30; i++) {
1131 CHECK_EQ(51425, script->Run()->Int32Value());
1132 }
1133}
1134
1135
1136THREADED_PROFILED_TEST(SimpleCallback) {
1137 TestSimpleCallback(SimpleCallback);
1138}
1139
1140
1141template<typename T>
1142void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1143
1144// constant return values
1145static int32_t fast_return_value_int32 = 471;
1146static uint32_t fast_return_value_uint32 = 571;
1147static const double kFastReturnValueDouble = 2.7;
1148// variable return values
1149static bool fast_return_value_bool = false;
1150enum ReturnValueOddball {
1151 kNullReturnValue,
1152 kUndefinedReturnValue,
1153 kEmptyStringReturnValue
1154};
1155static ReturnValueOddball fast_return_value_void;
1156static bool fast_return_value_object_is_empty = false;
1157
1158// Helper function to avoid compiler error: insufficient contextual information
1159// to determine type when applying FUNCTION_ADDR to a template function.
1160static i::Address address_of(v8::FunctionCallback callback) {
1161 return FUNCTION_ADDR(callback);
1162}
1163
1164template<>
1165void FastReturnValueCallback<int32_t>(
1166 const v8::FunctionCallbackInfo<v8::Value>& info) {
1167 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1168 info.GetReturnValue().Set(fast_return_value_int32);
1169}
1170
1171template<>
1172void FastReturnValueCallback<uint32_t>(
1173 const v8::FunctionCallbackInfo<v8::Value>& info) {
1174 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1175 info.GetReturnValue().Set(fast_return_value_uint32);
1176}
1177
1178template<>
1179void FastReturnValueCallback<double>(
1180 const v8::FunctionCallbackInfo<v8::Value>& info) {
1181 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1182 info.GetReturnValue().Set(kFastReturnValueDouble);
1183}
1184
1185template<>
1186void FastReturnValueCallback<bool>(
1187 const v8::FunctionCallbackInfo<v8::Value>& info) {
1188 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1189 info.GetReturnValue().Set(fast_return_value_bool);
1190}
1191
1192template<>
1193void FastReturnValueCallback<void>(
1194 const v8::FunctionCallbackInfo<v8::Value>& info) {
1195 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1196 switch (fast_return_value_void) {
1197 case kNullReturnValue:
1198 info.GetReturnValue().SetNull();
1199 break;
1200 case kUndefinedReturnValue:
1201 info.GetReturnValue().SetUndefined();
1202 break;
1203 case kEmptyStringReturnValue:
1204 info.GetReturnValue().SetEmptyString();
1205 break;
1206 }
1207}
1208
1209template<>
1210void FastReturnValueCallback<Object>(
1211 const v8::FunctionCallbackInfo<v8::Value>& info) {
1212 v8::Handle<v8::Object> object;
1213 if (!fast_return_value_object_is_empty) {
1214 object = Object::New(info.GetIsolate());
1215 }
1216 info.GetReturnValue().Set(object);
1217}
1218
1219template<typename T>
1220Handle<Value> TestFastReturnValues() {
1221 LocalContext env;
1222 v8::Isolate* isolate = env->GetIsolate();
1223 v8::EscapableHandleScope scope(isolate);
1224 v8::Handle<v8::ObjectTemplate> object_template =
1225 v8::ObjectTemplate::New(isolate);
1226 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1227 object_template->Set(isolate, "callback",
1228 v8::FunctionTemplate::New(isolate, callback));
1229 v8::Local<v8::Object> object = object_template->NewInstance();
1230 (*env)->Global()->Set(v8_str("callback_object"), object);
1231 return scope.Escape(CompileRun("callback_object.callback()"));
1232}
1233
1234
1235THREADED_PROFILED_TEST(FastReturnValues) {
1236 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001237 v8::Isolate* isolate = env->GetIsolate();
1238 v8::HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 v8::Handle<v8::Value> value;
1240 // check int32_t and uint32_t
1241 int32_t int_values[] = {
1242 0, 234, -723,
1243 i::Smi::kMinValue, i::Smi::kMaxValue
1244 };
1245 for (size_t i = 0; i < arraysize(int_values); i++) {
1246 for (int modifier = -1; modifier <= 1; modifier++) {
1247 int int_value = int_values[i] + modifier;
1248 // check int32_t
1249 fast_return_value_int32 = int_value;
1250 value = TestFastReturnValues<int32_t>();
1251 CHECK(value->IsInt32());
1252 CHECK(fast_return_value_int32 == value->Int32Value());
1253 // check uint32_t
1254 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1255 value = TestFastReturnValues<uint32_t>();
1256 CHECK(value->IsUint32());
1257 CHECK(fast_return_value_uint32 == value->Uint32Value());
1258 }
1259 }
1260 // check double
1261 value = TestFastReturnValues<double>();
1262 CHECK(value->IsNumber());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001263 CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001264 // check bool values
1265 for (int i = 0; i < 2; i++) {
1266 fast_return_value_bool = i == 0;
1267 value = TestFastReturnValues<bool>();
1268 CHECK(value->IsBoolean());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001270 }
1271 // check oddballs
1272 ReturnValueOddball oddballs[] = {
1273 kNullReturnValue,
1274 kUndefinedReturnValue,
1275 kEmptyStringReturnValue
1276 };
1277 for (size_t i = 0; i < arraysize(oddballs); i++) {
1278 fast_return_value_void = oddballs[i];
1279 value = TestFastReturnValues<void>();
1280 switch (fast_return_value_void) {
1281 case kNullReturnValue:
1282 CHECK(value->IsNull());
1283 break;
1284 case kUndefinedReturnValue:
1285 CHECK(value->IsUndefined());
1286 break;
1287 case kEmptyStringReturnValue:
1288 CHECK(value->IsString());
1289 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1290 break;
1291 }
1292 }
1293 // check handles
1294 fast_return_value_object_is_empty = false;
1295 value = TestFastReturnValues<Object>();
1296 CHECK(value->IsObject());
1297 fast_return_value_object_is_empty = true;
1298 value = TestFastReturnValues<Object>();
1299 CHECK(value->IsUndefined());
1300}
1301
1302
1303THREADED_TEST(FunctionTemplateSetLength) {
1304 LocalContext env;
1305 v8::Isolate* isolate = env->GetIsolate();
1306 v8::HandleScope scope(isolate);
1307 {
1308 Local<v8::FunctionTemplate> fun_templ =
1309 v8::FunctionTemplate::New(isolate,
1310 handle_callback,
1311 Handle<v8::Value>(),
1312 Handle<v8::Signature>(),
1313 23);
1314 Local<Function> fun = fun_templ->GetFunction();
1315 env->Global()->Set(v8_str("obj"), fun);
1316 Local<Script> script = v8_compile("obj.length");
1317 CHECK_EQ(23, script->Run()->Int32Value());
1318 }
1319 {
1320 Local<v8::FunctionTemplate> fun_templ =
1321 v8::FunctionTemplate::New(isolate, handle_callback);
1322 fun_templ->SetLength(22);
1323 Local<Function> fun = fun_templ->GetFunction();
1324 env->Global()->Set(v8_str("obj"), fun);
1325 Local<Script> script = v8_compile("obj.length");
1326 CHECK_EQ(22, script->Run()->Int32Value());
1327 }
1328 {
1329 // Without setting length it defaults to 0.
1330 Local<v8::FunctionTemplate> fun_templ =
1331 v8::FunctionTemplate::New(isolate, handle_callback);
1332 Local<Function> fun = fun_templ->GetFunction();
1333 env->Global()->Set(v8_str("obj"), fun);
1334 Local<Script> script = v8_compile("obj.length");
1335 CHECK_EQ(0, script->Run()->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 }
1337}
1338
1339
Ben Murdochb8e0da22011-05-16 14:20:40 +01001340static void* expected_ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1342 void* ptr = v8::External::Cast(*args.Data())->Value();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001343 CHECK_EQ(expected_ptr, ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001344 args.GetReturnValue().Set(true);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001345}
1346
1347
1348static void TestExternalPointerWrapping() {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001349 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 v8::Isolate* isolate = env->GetIsolate();
1351 v8::HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353 v8::Handle<v8::Value> data =
1354 v8::External::New(isolate, expected_ptr);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001355
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001357 obj->Set(v8_str("func"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001359 env->Global()->Set(v8_str("obj"), obj);
1360
1361 CHECK(CompileRun(
1362 "function foo() {\n"
1363 " for (var i = 0; i < 13; i++) obj.func();\n"
1364 "}\n"
1365 "foo(), true")->BooleanValue());
1366}
1367
1368
1369THREADED_TEST(ExternalWrap) {
1370 // Check heap allocated object.
1371 int* ptr = new int;
1372 expected_ptr = ptr;
1373 TestExternalPointerWrapping();
1374 delete ptr;
1375
1376 // Check stack allocated object.
1377 int foo;
1378 expected_ptr = &foo;
1379 TestExternalPointerWrapping();
1380
1381 // Check not aligned addresses.
1382 const int n = 100;
1383 char* s = new char[n];
1384 for (int i = 0; i < n; i++) {
1385 expected_ptr = s + i;
1386 TestExternalPointerWrapping();
1387 }
1388
1389 delete[] s;
1390
1391 // Check several invalid addresses.
1392 expected_ptr = reinterpret_cast<void*>(1);
1393 TestExternalPointerWrapping();
1394
1395 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1396 TestExternalPointerWrapping();
1397
1398 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1399 TestExternalPointerWrapping();
1400
1401#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +01001402 // Check a value with a leading 1 bit in x64 Smi encoding.
1403 expected_ptr = reinterpret_cast<void*>(0x400000000);
1404 TestExternalPointerWrapping();
1405
Ben Murdochb8e0da22011-05-16 14:20:40 +01001406 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1407 TestExternalPointerWrapping();
1408
1409 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1410 TestExternalPointerWrapping();
1411#endif
1412}
1413
1414
Steve Blocka7e24c12009-10-30 11:49:00 +00001415THREADED_TEST(FindInstanceInPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001417 v8::Isolate* isolate = env->GetIsolate();
1418 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001419
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1421 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1422 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001423 derived->Inherit(base);
1424
1425 Local<v8::Function> base_function = base->GetFunction();
1426 Local<v8::Function> derived_function = derived->GetFunction();
1427 Local<v8::Function> other_function = other->GetFunction();
1428
1429 Local<v8::Object> base_instance = base_function->NewInstance();
1430 Local<v8::Object> derived_instance = derived_function->NewInstance();
1431 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1432 Local<v8::Object> other_instance = other_function->NewInstance();
1433 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1434 other_instance->Set(v8_str("__proto__"), derived_instance2);
1435
1436 // base_instance is only an instance of base.
1437 CHECK_EQ(base_instance,
1438 base_instance->FindInstanceInPrototypeChain(base));
1439 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1440 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1441
1442 // derived_instance is an instance of base and derived.
1443 CHECK_EQ(derived_instance,
1444 derived_instance->FindInstanceInPrototypeChain(base));
1445 CHECK_EQ(derived_instance,
1446 derived_instance->FindInstanceInPrototypeChain(derived));
1447 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1448
1449 // other_instance is an instance of other and its immediate
1450 // prototype derived_instance2 is an instance of base and derived.
1451 // Note, derived_instance is an instance of base and derived too,
1452 // but it comes after derived_instance2 in the prototype chain of
1453 // other_instance.
1454 CHECK_EQ(derived_instance2,
1455 other_instance->FindInstanceInPrototypeChain(base));
1456 CHECK_EQ(derived_instance2,
1457 other_instance->FindInstanceInPrototypeChain(derived));
1458 CHECK_EQ(other_instance,
1459 other_instance->FindInstanceInPrototypeChain(other));
1460}
1461
1462
Steve Block3ce2e202009-11-05 08:53:23 +00001463THREADED_TEST(TinyInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001464 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001465 v8::Isolate* isolate = env->GetIsolate();
1466 v8::HandleScope scope(isolate);
1467
Steve Block3ce2e202009-11-05 08:53:23 +00001468 int32_t value = 239;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1470 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1471
1472 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001473 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1474}
1475
1476
1477THREADED_TEST(BigSmiInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001478 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001479 v8::HandleScope scope(env->GetIsolate());
1480 v8::Isolate* isolate = CcTest::isolate();
1481
Steve Block3ce2e202009-11-05 08:53:23 +00001482 int32_t value = i::Smi::kMaxValue;
1483 // We cannot add one to a Smi::kMaxValue without wrapping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001484 if (i::SmiValuesAre31Bits()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001485 CHECK(i::Smi::IsValid(value));
1486 CHECK(!i::Smi::IsValid(value + 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001487
1488 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1489 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1490
1491 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001492 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1493 }
1494}
1495
1496
1497THREADED_TEST(BigInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001498 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001499 v8::HandleScope scope(env->GetIsolate());
1500 v8::Isolate* isolate = CcTest::isolate();
1501
Steve Block3ce2e202009-11-05 08:53:23 +00001502 // We cannot add one to a Smi::kMaxValue without wrapping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 if (i::SmiValuesAre31Bits()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001504 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1505 // The code will not be run in that case, due to the "if" guard.
1506 int32_t value =
1507 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1508 CHECK(value > i::Smi::kMaxValue);
1509 CHECK(!i::Smi::IsValid(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510
1511 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1512 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1513
1514 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001515 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1516 }
1517}
1518
1519
1520THREADED_TEST(TinyUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001521 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522 v8::HandleScope scope(env->GetIsolate());
1523 v8::Isolate* isolate = CcTest::isolate();
1524
Steve Block3ce2e202009-11-05 08:53:23 +00001525 uint32_t value = 239;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001526
1527 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529
1530 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1532}
1533
1534
1535THREADED_TEST(BigUnsignedSmiInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001536 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 v8::HandleScope scope(env->GetIsolate());
1538 v8::Isolate* isolate = CcTest::isolate();
1539
Steve Block3ce2e202009-11-05 08:53:23 +00001540 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1541 CHECK(i::Smi::IsValid(value));
1542 CHECK(!i::Smi::IsValid(value + 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001543
1544 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1545 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1546
1547 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001548 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1549}
1550
1551
1552THREADED_TEST(BigUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001553 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001554 v8::HandleScope scope(env->GetIsolate());
1555 v8::Isolate* isolate = CcTest::isolate();
1556
Steve Block3ce2e202009-11-05 08:53:23 +00001557 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1558 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1559 CHECK(!i::Smi::IsValid(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560
1561 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1562 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1563
1564 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001565 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1566}
1567
1568
1569THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001570 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 v8::HandleScope scope(env->GetIsolate());
1572 v8::Isolate* isolate = CcTest::isolate();
1573
Steve Block3ce2e202009-11-05 08:53:23 +00001574 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1575 uint32_t value = INT32_MAX_AS_UINT + 1;
1576 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001577
1578 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1579 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1580
1581 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001582 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1583}
1584
1585
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001586THREADED_TEST(IsNativeError) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001587 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001589 v8::Handle<Value> syntax_error = CompileRun(
1590 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1591 CHECK(syntax_error->IsNativeError());
1592 v8::Handle<Value> not_error = CompileRun("{a:42}");
1593 CHECK(!not_error->IsNativeError());
1594 v8::Handle<Value> not_object = CompileRun("42");
1595 CHECK(!not_object->IsNativeError());
1596}
1597
1598
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001599THREADED_TEST(IsGeneratorFunctionOrObject) {
1600 LocalContext env;
1601 v8::HandleScope scope(env->GetIsolate());
1602
1603 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1604 v8::Handle<Value> gen = CompileRun("gen");
1605 v8::Handle<Value> genObj = CompileRun("gen()");
1606 v8::Handle<Value> object = CompileRun("{a:42}");
1607 v8::Handle<Value> func = CompileRun("func");
1608
1609 CHECK(gen->IsGeneratorFunction());
1610 CHECK(gen->IsFunction());
1611 CHECK(!gen->IsGeneratorObject());
1612
1613 CHECK(!genObj->IsGeneratorFunction());
1614 CHECK(!genObj->IsFunction());
1615 CHECK(genObj->IsGeneratorObject());
1616
1617 CHECK(!object->IsGeneratorFunction());
1618 CHECK(!object->IsFunction());
1619 CHECK(!object->IsGeneratorObject());
1620
1621 CHECK(!func->IsGeneratorFunction());
1622 CHECK(func->IsFunction());
1623 CHECK(!func->IsGeneratorObject());
1624}
1625
1626
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627THREADED_TEST(ArgumentsObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001628 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001629 v8::HandleScope scope(env->GetIsolate());
1630 v8::Handle<Value> arguments_object =
1631 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1632 CHECK(arguments_object->IsArgumentsObject());
1633 v8::Handle<Value> array = CompileRun("[1,2,3]");
1634 CHECK(!array->IsArgumentsObject());
1635 v8::Handle<Value> object = CompileRun("{a:42}");
1636 CHECK(!object->IsArgumentsObject());
1637}
1638
1639
1640THREADED_TEST(IsMapOrSet) {
1641 LocalContext env;
1642 v8::HandleScope scope(env->GetIsolate());
1643 v8::Handle<Value> map = CompileRun("new Map()");
1644 v8::Handle<Value> set = CompileRun("new Set()");
1645 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1646 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1647 CHECK(map->IsMap());
1648 CHECK(set->IsSet());
1649 CHECK(weak_map->IsWeakMap());
1650 CHECK(weak_set->IsWeakSet());
1651
1652 CHECK(!map->IsSet());
1653 CHECK(!map->IsWeakMap());
1654 CHECK(!map->IsWeakSet());
1655
1656 CHECK(!set->IsMap());
1657 CHECK(!set->IsWeakMap());
1658 CHECK(!set->IsWeakSet());
1659
1660 CHECK(!weak_map->IsMap());
1661 CHECK(!weak_map->IsSet());
1662 CHECK(!weak_map->IsWeakSet());
1663
1664 CHECK(!weak_set->IsMap());
1665 CHECK(!weak_set->IsSet());
1666 CHECK(!weak_set->IsWeakMap());
1667
1668 v8::Handle<Value> object = CompileRun("{a:42}");
1669 CHECK(!object->IsMap());
1670 CHECK(!object->IsSet());
1671 CHECK(!object->IsWeakMap());
1672 CHECK(!object->IsWeakSet());
1673}
1674
1675
1676THREADED_TEST(StringObject) {
1677 LocalContext env;
1678 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001679 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1680 CHECK(boxed_string->IsStringObject());
1681 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1682 CHECK(!unboxed_string->IsStringObject());
1683 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1684 CHECK(!boxed_not_string->IsStringObject());
1685 v8::Handle<Value> not_object = CompileRun("0");
1686 CHECK(!not_object->IsStringObject());
1687 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1688 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689 Local<v8::String> the_string = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001690 CHECK(!the_string.IsEmpty());
1691 ExpectObject("\"test\"", the_string);
1692 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1693 CHECK(new_boxed_string->IsStringObject());
1694 as_boxed = new_boxed_string.As<v8::StringObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001695 the_string = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001696 CHECK(!the_string.IsEmpty());
1697 ExpectObject("\"test\"", the_string);
1698}
1699
1700
1701THREADED_TEST(NumberObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001702 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001703 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001704 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1705 CHECK(boxed_number->IsNumberObject());
1706 v8::Handle<Value> unboxed_number = CompileRun("42");
1707 CHECK(!unboxed_number->IsNumberObject());
1708 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1709 CHECK(!boxed_not_number->IsNumberObject());
1710 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1711 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 double the_number = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001713 CHECK_EQ(42.0, the_number);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001714 v8::Handle<v8::Value> new_boxed_number =
1715 v8::NumberObject::New(env->GetIsolate(), 43);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001716 CHECK(new_boxed_number->IsNumberObject());
1717 as_boxed = new_boxed_number.As<v8::NumberObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001718 the_number = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001719 CHECK_EQ(43.0, the_number);
1720}
1721
1722
1723THREADED_TEST(BooleanObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001724 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001726 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1727 CHECK(boxed_boolean->IsBooleanObject());
1728 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1729 CHECK(!unboxed_boolean->IsBooleanObject());
1730 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1731 CHECK(!boxed_not_boolean->IsBooleanObject());
1732 v8::Handle<v8::BooleanObject> as_boxed =
1733 boxed_boolean.As<v8::BooleanObject>();
1734 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 bool the_boolean = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001736 CHECK_EQ(true, the_boolean);
1737 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1738 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1739 CHECK(boxed_true->IsBooleanObject());
1740 CHECK(boxed_false->IsBooleanObject());
1741 as_boxed = boxed_true.As<v8::BooleanObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001742 CHECK_EQ(true, as_boxed->ValueOf());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001743 as_boxed = boxed_false.As<v8::BooleanObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001744 CHECK_EQ(false, as_boxed->ValueOf());
1745}
1746
1747
1748THREADED_TEST(PrimitiveAndWrappedBooleans) {
1749 LocalContext env;
1750 v8::HandleScope scope(env->GetIsolate());
1751
1752 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1753 CHECK(primitive_false->IsBoolean());
1754 CHECK(!primitive_false->IsBooleanObject());
1755 CHECK(!primitive_false->BooleanValue());
1756 CHECK(!primitive_false->IsTrue());
1757 CHECK(primitive_false->IsFalse());
1758
1759 Local<Value> false_value = BooleanObject::New(false);
1760 CHECK(!false_value->IsBoolean());
1761 CHECK(false_value->IsBooleanObject());
1762 CHECK(false_value->BooleanValue());
1763 CHECK(!false_value->IsTrue());
1764 CHECK(!false_value->IsFalse());
1765
1766 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1767 CHECK(!false_boolean_object->IsBoolean());
1768 CHECK(false_boolean_object->IsBooleanObject());
1769 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1770 // CHECK(false_boolean_object->BooleanValue());
1771 CHECK(!false_boolean_object->ValueOf());
1772 CHECK(!false_boolean_object->IsTrue());
1773 CHECK(!false_boolean_object->IsFalse());
1774
1775 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1776 CHECK(primitive_true->IsBoolean());
1777 CHECK(!primitive_true->IsBooleanObject());
1778 CHECK(primitive_true->BooleanValue());
1779 CHECK(primitive_true->IsTrue());
1780 CHECK(!primitive_true->IsFalse());
1781
1782 Local<Value> true_value = BooleanObject::New(true);
1783 CHECK(!true_value->IsBoolean());
1784 CHECK(true_value->IsBooleanObject());
1785 CHECK(true_value->BooleanValue());
1786 CHECK(!true_value->IsTrue());
1787 CHECK(!true_value->IsFalse());
1788
1789 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1790 CHECK(!true_boolean_object->IsBoolean());
1791 CHECK(true_boolean_object->IsBooleanObject());
1792 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1793 // CHECK(true_boolean_object->BooleanValue());
1794 CHECK(true_boolean_object->ValueOf());
1795 CHECK(!true_boolean_object->IsTrue());
1796 CHECK(!true_boolean_object->IsFalse());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001797}
1798
1799
Steve Blocka7e24c12009-10-30 11:49:00 +00001800THREADED_TEST(Number) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001801 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001802 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001803 double PI = 3.1415926;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001804 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 CHECK_EQ(PI, pi_obj->NumberValue());
1806}
1807
1808
1809THREADED_TEST(ToNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001810 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001811 v8::Isolate* isolate = CcTest::isolate();
1812 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001813 Local<String> str = v8_str("3.1415926");
1814 CHECK_EQ(3.1415926, str->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 v8::Handle<v8::Boolean> t = v8::True(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001816 CHECK_EQ(1.0, t->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001817 v8::Handle<v8::Boolean> f = v8::False(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001818 CHECK_EQ(0.0, f->NumberValue());
1819}
1820
1821
1822THREADED_TEST(Date) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001823 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001824 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001825 double PI = 3.1415926;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001826 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
Ben Murdoch257744e2011-11-30 15:57:28 +00001827 CHECK_EQ(3.0, date->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828 date.As<v8::Date>()->Set(v8_str("property"),
1829 v8::Integer::New(env->GetIsolate(), 42));
Ben Murdoch257744e2011-11-30 15:57:28 +00001830 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001831}
1832
1833
1834THREADED_TEST(Boolean) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001835 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001836 v8::Isolate* isolate = env->GetIsolate();
1837 v8::HandleScope scope(isolate);
1838 v8::Handle<v8::Boolean> t = v8::True(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 CHECK(t->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840 v8::Handle<v8::Boolean> f = v8::False(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 CHECK(!f->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 CHECK(!u->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001844 v8::Handle<v8::Primitive> n = v8::Null(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001845 CHECK(!n->BooleanValue());
1846 v8::Handle<String> str1 = v8_str("");
1847 CHECK(!str1->BooleanValue());
1848 v8::Handle<String> str2 = v8_str("x");
1849 CHECK(str2->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1851 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1852 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1853 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001854 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1855}
1856
1857
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001858static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001859 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001860 args.GetReturnValue().Set(v8_num(13.4));
Steve Blocka7e24c12009-10-30 11:49:00 +00001861}
1862
1863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001864static void GetM(Local<String> name,
1865 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001866 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 info.GetReturnValue().Set(v8_num(876));
Steve Blocka7e24c12009-10-30 11:49:00 +00001868}
1869
1870
1871THREADED_TEST(GlobalPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872 v8::Isolate* isolate = CcTest::isolate();
1873 v8::HandleScope scope(isolate);
1874 v8::Handle<v8::FunctionTemplate> func_templ =
1875 v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001876 func_templ->PrototypeTemplate()->Set(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001877 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 templ->Set(isolate, "x", v8_num(200));
Steve Blocka7e24c12009-10-30 11:49:00 +00001880 templ->SetAccessor(v8_str("m"), GetM);
1881 LocalContext env(0, templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001882 v8::Handle<Script> script(v8_compile("dummy()"));
1883 v8::Handle<Value> result(script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00001884 CHECK_EQ(13.4, result->NumberValue());
1885 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1886 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1887}
1888
1889
Steve Blocka7e24c12009-10-30 11:49:00 +00001890THREADED_TEST(ObjectTemplate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001891 v8::Isolate* isolate = CcTest::isolate();
1892 v8::HandleScope scope(isolate);
1893 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1894 templ1->Set(isolate, "x", v8_num(10));
1895 templ1->Set(isolate, "y", v8_num(13));
Steve Blocka7e24c12009-10-30 11:49:00 +00001896 LocalContext env;
1897 Local<v8::Object> instance1 = templ1->NewInstance();
1898 env->Global()->Set(v8_str("p"), instance1);
1899 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1900 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001901 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1902 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001904 templ2->Set(isolate, "a", v8_num(12));
1905 templ2->Set(isolate, "b", templ1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 Local<v8::Object> instance2 = templ2->NewInstance();
1907 env->Global()->Set(v8_str("q"), instance2);
1908 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1909 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1910 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1911 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1912}
1913
1914
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001915static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001916 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001917 args.GetReturnValue().Set(v8_num(17.2));
Steve Blocka7e24c12009-10-30 11:49:00 +00001918}
1919
1920
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921static void GetKnurd(Local<String> property,
1922 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001924 info.GetReturnValue().Set(v8_num(15.2));
Steve Blocka7e24c12009-10-30 11:49:00 +00001925}
1926
1927
1928THREADED_TEST(DescriptorInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 v8::Isolate* isolate = CcTest::isolate();
1930 v8::HandleScope scope(isolate);
1931 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1932 super->PrototypeTemplate()->Set(isolate, "flabby",
1933 v8::FunctionTemplate::New(isolate,
1934 GetFlabby));
1935 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
Steve Blocka7e24c12009-10-30 11:49:00 +00001936
1937 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1938
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001940 base1->Inherit(super);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001941 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001942
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001943 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001944 base2->Inherit(super);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001945 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001946
1947 LocalContext env;
1948
1949 env->Global()->Set(v8_str("s"), super->GetFunction());
1950 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1951 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1952
1953 // Checks right __proto__ chain.
1954 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1955 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1956
1957 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1958
1959 // Instance accessor should not be visible on function object or its prototype
1960 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1961 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1962 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1963
1964 env->Global()->Set(v8_str("obj"),
1965 base1->GetFunction()->NewInstance());
1966 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1967 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1968 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1969 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1970 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1971
1972 env->Global()->Set(v8_str("obj2"),
1973 base2->GetFunction()->NewInstance());
1974 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1975 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1976 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1977 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1978 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1979
1980 // base1 and base2 cannot cross reference to each's prototype
1981 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1982 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1983}
1984
1985
1986int echo_named_call_count;
1987
1988
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001989static void EchoNamedProperty(Local<Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001990 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001991 ApiTestFuzzer::Fuzz();
1992 CHECK_EQ(v8_str("data"), info.Data());
1993 echo_named_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001994 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001995}
1996
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001997
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001998// Helper functions for Interceptor/Accessor interaction tests
1999
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000void SimpleAccessorGetter(Local<String> name,
2001 const v8::PropertyCallbackInfo<v8::Value>& info) {
2002 Handle<Object> self = Handle<Object>::Cast(info.This());
2003 info.GetReturnValue().Set(
2004 self->Get(String::Concat(v8_str("accessor_"), name)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002005}
2006
2007void SimpleAccessorSetter(Local<String> name, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002008 const v8::PropertyCallbackInfo<void>& info) {
2009 Handle<Object> self = Handle<Object>::Cast(info.This());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002010 self->Set(String::Concat(v8_str("accessor_"), name), value);
2011}
2012
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002013void SymbolAccessorGetter(Local<Name> name,
2014 const v8::PropertyCallbackInfo<v8::Value>& info) {
2015 CHECK(name->IsSymbol());
2016 Local<Symbol> sym = Local<Symbol>::Cast(name);
2017 if (sym->Name()->IsUndefined())
2018 return;
2019 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002020}
2021
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002022void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2023 const v8::PropertyCallbackInfo<void>& info) {
2024 CHECK(name->IsSymbol());
2025 Local<Symbol> sym = Local<Symbol>::Cast(name);
2026 if (sym->Name()->IsUndefined())
2027 return;
2028 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002029}
2030
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002031void SymbolAccessorGetterReturnsDefault(
2032 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2033 CHECK(name->IsSymbol());
2034 Local<Symbol> sym = Local<Symbol>::Cast(name);
2035 if (sym->Name()->IsUndefined()) return;
2036 info.GetReturnValue().Set(info.Data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002037}
2038
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002039static void ThrowingSymbolAccessorGetter(
2040 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2041 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002042}
2043
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002044
2045void EmptyInterceptorGetter(Local<Name> name,
2046 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2047
2048
2049void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
2050 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2051
2052
2053void EmptyGenericInterceptorGetter(
2054 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
2055
2056
2057void EmptyGenericInterceptorSetter(
2058 Local<Name> name, Local<Value> value,
2059 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2060
2061
2062void StringInterceptorGetter(
2063 Local<String> name,
2064 const v8::PropertyCallbackInfo<v8::Value>&
2065 info) { // Intercept names that start with 'interceptor_'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002066 String::Utf8Value utf8(name);
2067 char* name_str = *utf8;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002068 char prefix[] = "interceptor_";
2069 int i;
2070 for (i = 0; name_str[i] && prefix[i]; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 if (name_str[i] != prefix[i]) return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002072 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 Handle<Object> self = Handle<Object>::Cast(info.This());
2074 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002075}
2076
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002077
2078void StringInterceptorSetter(Local<String> name, Local<Value> value,
2079 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002080 // Intercept accesses that set certain integer values, for which the name does
2081 // not start with 'accessor_'.
2082 String::Utf8Value utf8(name);
2083 char* name_str = *utf8;
2084 char prefix[] = "accessor_";
2085 int i;
2086 for (i = 0; name_str[i] && prefix[i]; ++i) {
2087 if (name_str[i] != prefix[i]) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002088 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089 if (!prefix[i]) return;
2090
2091 if (value->IsInt32() && value->Int32Value() < 10000) {
2092 Handle<Object> self = Handle<Object>::Cast(info.This());
2093 self->SetHiddenValue(name, value);
2094 info.GetReturnValue().Set(value);
2095 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002096}
2097
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002098void InterceptorGetter(Local<Name> generic_name,
2099 const v8::PropertyCallbackInfo<v8::Value>& info) {
2100 if (generic_name->IsSymbol()) return;
2101 StringInterceptorGetter(Local<String>::Cast(generic_name), info);
2102}
2103
2104void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
2105 const v8::PropertyCallbackInfo<v8::Value>& info) {
2106 if (generic_name->IsSymbol()) return;
2107 StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
2108}
2109
2110void GenericInterceptorGetter(Local<Name> generic_name,
2111 const v8::PropertyCallbackInfo<v8::Value>& info) {
2112 Local<String> str;
2113 if (generic_name->IsSymbol()) {
2114 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2115 if (name->IsUndefined()) return;
2116 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2117 } else {
2118 Local<String> name = Local<String>::Cast(generic_name);
2119 String::Utf8Value utf8(name);
2120 char* name_str = *utf8;
2121 if (*name_str == '_') return;
2122 str = String::Concat(v8_str("_str_"), name);
2123 }
2124
2125 Handle<Object> self = Handle<Object>::Cast(info.This());
2126 info.GetReturnValue().Set(self->Get(str));
2127}
2128
2129void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
2130 const v8::PropertyCallbackInfo<v8::Value>& info) {
2131 Local<String> str;
2132 if (generic_name->IsSymbol()) {
2133 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2134 if (name->IsUndefined()) return;
2135 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2136 } else {
2137 Local<String> name = Local<String>::Cast(generic_name);
2138 String::Utf8Value utf8(name);
2139 char* name_str = *utf8;
2140 if (*name_str == '_') return;
2141 str = String::Concat(v8_str("_str_"), name);
2142 }
2143
2144 Handle<Object> self = Handle<Object>::Cast(info.This());
2145 self->Set(str, value);
2146 info.GetReturnValue().Set(value);
2147}
2148
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002149void AddAccessor(Handle<FunctionTemplate> templ,
2150 Handle<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002151 v8::AccessorGetterCallback getter,
2152 v8::AccessorSetterCallback setter) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002153 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2154}
2155
2156void AddInterceptor(Handle<FunctionTemplate> templ,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002157 v8::NamedPropertyGetterCallback getter,
2158 v8::NamedPropertySetterCallback setter) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002159 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2160}
2161
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002162
2163void AddAccessor(Handle<FunctionTemplate> templ,
2164 Handle<Name> name,
2165 v8::AccessorNameGetterCallback getter,
2166 v8::AccessorNameSetterCallback setter) {
2167 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2168}
2169
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002170void AddInterceptor(Handle<FunctionTemplate> templ,
2171 v8::GenericNamedPropertyGetterCallback getter,
2172 v8::GenericNamedPropertySetterCallback setter) {
2173 templ->InstanceTemplate()->SetHandler(
2174 v8::NamedPropertyHandlerConfiguration(getter, setter));
2175}
2176
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002177
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002178THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002179 v8::HandleScope scope(CcTest::isolate());
2180 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2181 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002182 child->Inherit(parent);
2183 AddAccessor(parent, v8_str("age"),
2184 SimpleAccessorGetter, SimpleAccessorSetter);
2185 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2186 LocalContext env;
2187 env->Global()->Set(v8_str("Child"), child->GetFunction());
2188 CompileRun("var child = new Child;"
2189 "child.age = 10;");
2190 ExpectBoolean("child.hasOwnProperty('age')", false);
2191 ExpectInt32("child.age", 10);
2192 ExpectInt32("child.accessor_age", 10);
2193}
2194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002195
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002196THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
2197 LocalContext env;
2198 v8::Isolate* isolate = CcTest::isolate();
2199 v8::HandleScope scope(isolate);
2200 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2201 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2202 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2203
2204 child->Inherit(parent);
2205 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2206 AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
2207
2208 env->Global()->Set(v8_str("Child"), child->GetFunction());
2209 env->Global()->Set(v8_str("age"), age);
2210 CompileRun(
2211 "var child = new Child;"
2212 "child[age] = 10;");
2213 ExpectInt32("child[age]", 10);
2214 ExpectBoolean("child.hasOwnProperty('age')", false);
2215 ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
2216}
2217
2218
2219THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
2220 LocalContext env;
2221 v8::Isolate* isolate = CcTest::isolate();
2222 v8::HandleScope scope(isolate);
2223 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2224 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2225 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2226 v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
2227
2228 child->Inherit(parent);
2229 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2230 AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
2231
2232 env->Global()->Set(v8_str("Child"), child->GetFunction());
2233 env->Global()->Set(v8_str("age"), age);
2234 env->Global()->Set(v8_str("anon"), anon);
2235 CompileRun(
2236 "var child = new Child;"
2237 "child[age] = 10;");
2238 ExpectInt32("child[age]", 10);
2239 ExpectInt32("child._sym_age", 10);
2240
2241 // Check that it also sees strings.
2242 CompileRun("child.foo = 47");
2243 ExpectInt32("child.foo", 47);
2244 ExpectInt32("child._str_foo", 47);
2245
2246 // Check that the interceptor can punt (in this case, on anonymous symbols).
2247 CompileRun("child[anon] = 31337");
2248 ExpectInt32("child[anon]", 31337);
2249}
2250
2251
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002252THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2253 v8::Isolate* isolate = CcTest::isolate();
2254 v8::HandleScope scope(isolate);
2255 LocalContext env;
2256 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2257 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2258 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2259 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2260 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2261 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2262 // But we should still have an ExecutableAccessorInfo.
2263 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2264 i::LookupResult lookup(i_isolate);
2265 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2266 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2267 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2268 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2269}
2270
2271
2272THREADED_TEST(EmptyInterceptorBreakTransitions) {
2273 v8::HandleScope scope(CcTest::isolate());
2274 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2275 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2276 LocalContext env;
2277 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2278 CompileRun("var o1 = new Constructor;"
2279 "o1.a = 1;" // Ensure a and x share the descriptor array.
2280 "Object.defineProperty(o1, 'x', {value: 10});");
2281 CompileRun("var o2 = new Constructor;"
2282 "o2.a = 1;"
2283 "Object.defineProperty(o2, 'x', {value: 10});");
2284}
2285
2286
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002287THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002288 v8::Isolate* isolate = CcTest::isolate();
2289 v8::HandleScope scope(isolate);
2290 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2291 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002292 child->Inherit(parent);
2293 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2294 LocalContext env;
2295 env->Global()->Set(v8_str("Child"), child->GetFunction());
2296 CompileRun("var child = new Child;"
2297 "var parent = child.__proto__;"
2298 "Object.defineProperty(parent, 'age', "
2299 " {get: function(){ return this.accessor_age; }, "
2300 " set: function(v){ this.accessor_age = v; }, "
2301 " enumerable: true, configurable: true});"
2302 "child.age = 10;");
2303 ExpectBoolean("child.hasOwnProperty('age')", false);
2304 ExpectInt32("child.age", 10);
2305 ExpectInt32("child.accessor_age", 10);
2306}
2307
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002308
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002309THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310 v8::Isolate* isolate = CcTest::isolate();
2311 v8::HandleScope scope(isolate);
2312 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2313 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002314 child->Inherit(parent);
2315 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2316 LocalContext env;
2317 env->Global()->Set(v8_str("Child"), child->GetFunction());
2318 CompileRun("var child = new Child;"
2319 "var parent = child.__proto__;"
2320 "parent.name = 'Alice';");
2321 ExpectBoolean("child.hasOwnProperty('name')", false);
2322 ExpectString("child.name", "Alice");
2323 CompileRun("child.name = 'Bob';");
2324 ExpectString("child.name", "Bob");
2325 ExpectBoolean("child.hasOwnProperty('name')", true);
2326 ExpectString("parent.name", "Alice");
2327}
2328
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002329
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002330THREADED_TEST(SwitchFromInterceptorToAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331 v8::HandleScope scope(CcTest::isolate());
2332 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002333 AddAccessor(templ, v8_str("age"),
2334 SimpleAccessorGetter, SimpleAccessorSetter);
2335 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2336 LocalContext env;
2337 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2338 CompileRun("var obj = new Obj;"
2339 "function setAge(i){ obj.age = i; };"
2340 "for(var i = 0; i <= 10000; i++) setAge(i);");
2341 // All i < 10000 go to the interceptor.
2342 ExpectInt32("obj.interceptor_age", 9999);
2343 // The last i goes to the accessor.
2344 ExpectInt32("obj.accessor_age", 10000);
2345}
2346
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002347
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002348THREADED_TEST(SwitchFromAccessorToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002349 v8::HandleScope scope(CcTest::isolate());
2350 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002351 AddAccessor(templ, v8_str("age"),
2352 SimpleAccessorGetter, SimpleAccessorSetter);
2353 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2354 LocalContext env;
2355 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2356 CompileRun("var obj = new Obj;"
2357 "function setAge(i){ obj.age = i; };"
2358 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2359 // All i >= 10000 go to the accessor.
2360 ExpectInt32("obj.accessor_age", 10000);
2361 // The last i goes to the interceptor.
2362 ExpectInt32("obj.interceptor_age", 9999);
2363}
2364
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002365
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002366THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002367 v8::HandleScope scope(CcTest::isolate());
2368 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2369 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002370 child->Inherit(parent);
2371 AddAccessor(parent, v8_str("age"),
2372 SimpleAccessorGetter, SimpleAccessorSetter);
2373 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2374 LocalContext env;
2375 env->Global()->Set(v8_str("Child"), child->GetFunction());
2376 CompileRun("var child = new Child;"
2377 "function setAge(i){ child.age = i; };"
2378 "for(var i = 0; i <= 10000; i++) setAge(i);");
2379 // All i < 10000 go to the interceptor.
2380 ExpectInt32("child.interceptor_age", 9999);
2381 // The last i goes to the accessor.
2382 ExpectInt32("child.accessor_age", 10000);
2383}
2384
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002385
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002386THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002387 v8::HandleScope scope(CcTest::isolate());
2388 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2389 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002390 child->Inherit(parent);
2391 AddAccessor(parent, v8_str("age"),
2392 SimpleAccessorGetter, SimpleAccessorSetter);
2393 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2394 LocalContext env;
2395 env->Global()->Set(v8_str("Child"), child->GetFunction());
2396 CompileRun("var child = new Child;"
2397 "function setAge(i){ child.age = i; };"
2398 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2399 // All i >= 10000 go to the accessor.
2400 ExpectInt32("child.accessor_age", 10000);
2401 // The last i goes to the interceptor.
2402 ExpectInt32("child.interceptor_age", 9999);
2403}
2404
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002405
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002406THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002407 v8::HandleScope scope(CcTest::isolate());
2408 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002409 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2410 LocalContext env;
2411 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2412 CompileRun("var obj = new Obj;"
2413 "function setter(i) { this.accessor_age = i; };"
2414 "function getter() { return this.accessor_age; };"
2415 "function setAge(i) { obj.age = i; };"
2416 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2417 "for(var i = 0; i <= 10000; i++) setAge(i);");
2418 // All i < 10000 go to the interceptor.
2419 ExpectInt32("obj.interceptor_age", 9999);
2420 // The last i goes to the JavaScript accessor.
2421 ExpectInt32("obj.accessor_age", 10000);
2422 // The installed JavaScript getter is still intact.
2423 // This last part is a regression test for issue 1651 and relies on the fact
2424 // that both interceptor and accessor are being installed on the same object.
2425 ExpectInt32("obj.age", 10000);
2426 ExpectBoolean("obj.hasOwnProperty('age')", true);
2427 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2428}
2429
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002431THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002432 v8::HandleScope scope(CcTest::isolate());
2433 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002434 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2435 LocalContext env;
2436 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2437 CompileRun("var obj = new Obj;"
2438 "function setter(i) { this.accessor_age = i; };"
2439 "function getter() { return this.accessor_age; };"
2440 "function setAge(i) { obj.age = i; };"
2441 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2442 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2443 // All i >= 10000 go to the accessor.
2444 ExpectInt32("obj.accessor_age", 10000);
2445 // The last i goes to the interceptor.
2446 ExpectInt32("obj.interceptor_age", 9999);
2447 // The installed JavaScript getter is still intact.
2448 // This last part is a regression test for issue 1651 and relies on the fact
2449 // that both interceptor and accessor are being installed on the same object.
2450 ExpectInt32("obj.age", 10000);
2451 ExpectBoolean("obj.hasOwnProperty('age')", true);
2452 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2453}
2454
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002455
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002456THREADED_TEST(SwitchFromInterceptorToProperty) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002457 v8::HandleScope scope(CcTest::isolate());
2458 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2459 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002460 child->Inherit(parent);
2461 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2462 LocalContext env;
2463 env->Global()->Set(v8_str("Child"), child->GetFunction());
2464 CompileRun("var child = new Child;"
2465 "function setAge(i){ child.age = i; };"
2466 "for(var i = 0; i <= 10000; i++) setAge(i);");
2467 // All i < 10000 go to the interceptor.
2468 ExpectInt32("child.interceptor_age", 9999);
2469 // The last i goes to child's own property.
2470 ExpectInt32("child.age", 10000);
2471}
2472
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002473
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002474THREADED_TEST(SwitchFromPropertyToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002475 v8::HandleScope scope(CcTest::isolate());
2476 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2477 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002478 child->Inherit(parent);
2479 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2480 LocalContext env;
2481 env->Global()->Set(v8_str("Child"), child->GetFunction());
2482 CompileRun("var child = new Child;"
2483 "function setAge(i){ child.age = i; };"
2484 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2485 // All i >= 10000 go to child's own property.
2486 ExpectInt32("child.age", 10000);
2487 // The last i goes to the interceptor.
2488 ExpectInt32("child.interceptor_age", 9999);
2489}
Steve Blocka7e24c12009-10-30 11:49:00 +00002490
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002491
Steve Blocka7e24c12009-10-30 11:49:00 +00002492THREADED_TEST(NamedPropertyHandlerGetter) {
2493 echo_named_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002494 v8::HandleScope scope(CcTest::isolate());
2495 v8::Handle<v8::FunctionTemplate> templ =
2496 v8::FunctionTemplate::New(CcTest::isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002497 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2498 EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
Steve Blocka7e24c12009-10-30 11:49:00 +00002499 LocalContext env;
2500 env->Global()->Set(v8_str("obj"),
2501 templ->GetFunction()->NewInstance());
2502 CHECK_EQ(echo_named_call_count, 0);
2503 v8_compile("obj.x")->Run();
2504 CHECK_EQ(echo_named_call_count, 1);
2505 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2506 v8::Handle<Value> str = CompileRun(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002507 String::Utf8Value value(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00002508 CHECK_EQ(*value, "oddlepoddle");
2509 // Check default behavior
2510 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2511 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2512 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2513}
2514
2515
2516int echo_indexed_call_count = 0;
2517
2518
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002519static void EchoIndexedProperty(
2520 uint32_t index,
2521 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002522 ApiTestFuzzer::Fuzz();
2523 CHECK_EQ(v8_num(637), info.Data());
2524 echo_indexed_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002525 info.GetReturnValue().Set(v8_num(index));
Steve Blocka7e24c12009-10-30 11:49:00 +00002526}
2527
2528
2529THREADED_TEST(IndexedPropertyHandlerGetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002530 v8::Isolate* isolate = CcTest::isolate();
2531 v8::HandleScope scope(isolate);
2532 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002533 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2534 EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 LocalContext env;
2536 env->Global()->Set(v8_str("obj"),
2537 templ->GetFunction()->NewInstance());
2538 Local<Script> script = v8_compile("obj[900]");
2539 CHECK_EQ(script->Run()->Int32Value(), 900);
2540}
2541
2542
2543v8::Handle<v8::Object> bottom;
2544
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002545static void CheckThisIndexedPropertyHandler(
Steve Blocka7e24c12009-10-30 11:49:00 +00002546 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002547 const v8::PropertyCallbackInfo<v8::Value>& info) {
2548 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00002549 ApiTestFuzzer::Fuzz();
2550 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002551}
2552
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002553static void CheckThisNamedPropertyHandler(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002554 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002555 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00002556 ApiTestFuzzer::Fuzz();
2557 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002558}
2559
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002560void CheckThisIndexedPropertySetter(
Steve Blocka7e24c12009-10-30 11:49:00 +00002561 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002562 Local<Value> value,
2563 const v8::PropertyCallbackInfo<v8::Value>& info) {
2564 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002565 ApiTestFuzzer::Fuzz();
2566 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002567}
2568
2569
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002570void CheckThisNamedPropertySetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002571 Local<Name> property, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002572 const v8::PropertyCallbackInfo<v8::Value>& info) {
2573 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002574 ApiTestFuzzer::Fuzz();
2575 CHECK(info.This()->Equals(bottom));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002576}
2577
2578void CheckThisIndexedPropertyQuery(
2579 uint32_t index,
2580 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2581 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2582 ApiTestFuzzer::Fuzz();
2583 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002584}
2585
2586
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002587void CheckThisNamedPropertyQuery(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002588 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002589 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
Steve Blocka7e24c12009-10-30 11:49:00 +00002590 ApiTestFuzzer::Fuzz();
2591 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002592}
2593
2594
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002595void CheckThisIndexedPropertyDeleter(
2596 uint32_t index,
2597 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2598 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002599 ApiTestFuzzer::Fuzz();
2600 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002601}
2602
2603
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002604void CheckThisNamedPropertyDeleter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002605 Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002606 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2607 ApiTestFuzzer::Fuzz();
2608 CHECK(info.This()->Equals(bottom));
2609}
2610
2611
2612void CheckThisIndexedPropertyEnumerator(
2613 const v8::PropertyCallbackInfo<v8::Array>& info) {
2614 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2615 ApiTestFuzzer::Fuzz();
2616 CHECK(info.This()->Equals(bottom));
2617}
2618
2619
2620void CheckThisNamedPropertyEnumerator(
2621 const v8::PropertyCallbackInfo<v8::Array>& info) {
2622 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2623 ApiTestFuzzer::Fuzz();
2624 CHECK(info.This()->Equals(bottom));
2625}
2626
2627
2628THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002629 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002630 v8::Isolate* isolate = env->GetIsolate();
2631 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002632
2633 // Set up a prototype chain with three interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002634 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002635 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2636 CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
2637 CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
2638 CheckThisIndexedPropertyEnumerator));
Steve Blocka7e24c12009-10-30 11:49:00 +00002639
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002640 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2641 CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
2642 CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
2643 CheckThisNamedPropertyEnumerator));
Steve Blocka7e24c12009-10-30 11:49:00 +00002644
2645 bottom = templ->GetFunction()->NewInstance();
2646 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2647 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2648
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002649 bottom->SetPrototype(middle);
2650 middle->SetPrototype(top);
Steve Blocka7e24c12009-10-30 11:49:00 +00002651 env->Global()->Set(v8_str("obj"), bottom);
2652
2653 // Indexed and named get.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002654 CompileRun("obj[0]");
2655 CompileRun("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00002656
2657 // Indexed and named set.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002658 CompileRun("obj[1] = 42");
2659 CompileRun("obj.y = 42");
Steve Blocka7e24c12009-10-30 11:49:00 +00002660
2661 // Indexed and named query.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002662 CompileRun("0 in obj");
2663 CompileRun("'x' in obj");
Steve Blocka7e24c12009-10-30 11:49:00 +00002664
2665 // Indexed and named deleter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002666 CompileRun("delete obj[0]");
2667 CompileRun("delete obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00002668
2669 // Enumerators.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002670 CompileRun("for (var p in obj) ;");
Steve Blocka7e24c12009-10-30 11:49:00 +00002671}
2672
2673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002674static void PrePropertyHandlerGet(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002675 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002676 ApiTestFuzzer::Fuzz();
2677 if (v8_str("pre")->Equals(key)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002678 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
Steve Blocka7e24c12009-10-30 11:49:00 +00002679 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002680}
2681
2682
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002683static void PrePropertyHandlerQuery(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002684 Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002685 if (v8_str("pre")->Equals(key)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002686 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
Steve Blocka7e24c12009-10-30 11:49:00 +00002687 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002688}
2689
2690
2691THREADED_TEST(PrePropertyHandler) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002692 v8::Isolate* isolate = CcTest::isolate();
2693 v8::HandleScope scope(isolate);
2694 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002695 desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2696 PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
Steve Blocka7e24c12009-10-30 11:49:00 +00002697 LocalContext env(NULL, desc->InstanceTemplate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002698 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2699 v8::Handle<Value> result_pre = CompileRun("pre");
Steve Blocka7e24c12009-10-30 11:49:00 +00002700 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002701 v8::Handle<Value> result_on = CompileRun("on");
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 CHECK_EQ(v8_str("Object: on"), result_on);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002703 v8::Handle<Value> result_post = CompileRun("post");
Steve Blocka7e24c12009-10-30 11:49:00 +00002704 CHECK(result_post.IsEmpty());
2705}
2706
2707
2708THREADED_TEST(UndefinedIsNotEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002709 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002710 v8::HandleScope scope(env->GetIsolate());
2711 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 CHECK(result->IsFalse());
2713}
2714
2715
2716v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00002717static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00002718
2719
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002720static void CallScriptRecursivelyCall(
2721 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002722 ApiTestFuzzer::Fuzz();
2723 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002724 if (depth == kTargetRecursionDepth) return;
2725 args.This()->Set(v8_str("depth"),
2726 v8::Integer::New(args.GetIsolate(), depth + 1));
2727 args.GetReturnValue().Set(call_recursively_script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00002728}
2729
2730
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002731static void CallFunctionRecursivelyCall(
2732 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002733 ApiTestFuzzer::Fuzz();
2734 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2735 if (depth == kTargetRecursionDepth) {
2736 printf("[depth = %d]\n", depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002737 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002738 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002739 args.This()->Set(v8_str("depth"),
2740 v8::Integer::New(args.GetIsolate(), depth + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00002741 v8::Handle<Value> function =
2742 args.This()->Get(v8_str("callFunctionRecursively"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002743 args.GetReturnValue().Set(
2744 function.As<Function>()->Call(args.This(), 0, NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00002745}
2746
2747
2748THREADED_TEST(DeepCrossLanguageRecursion) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002749 v8::Isolate* isolate = CcTest::isolate();
2750 v8::HandleScope scope(isolate);
2751 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002752 global->Set(v8_str("callScriptRecursively"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002753 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
Steve Blocka7e24c12009-10-30 11:49:00 +00002754 global->Set(v8_str("callFunctionRecursively"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002755 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
Steve Blocka7e24c12009-10-30 11:49:00 +00002756 LocalContext env(NULL, global);
2757
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002758 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00002759 call_recursively_script = v8_compile("callScriptRecursively()");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002760 call_recursively_script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00002761 call_recursively_script = v8::Handle<Script>();
2762
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002763 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2764 CompileRun("callFunctionRecursively()");
Steve Blocka7e24c12009-10-30 11:49:00 +00002765}
2766
2767
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002768static void ThrowingPropertyHandlerGet(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002769 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2770 // Since this interceptor is used on "with" objects, the runtime will look up
2771 // @@unscopables. Punt.
2772 if (key->IsSymbol()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002773 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002774 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
Steve Blocka7e24c12009-10-30 11:49:00 +00002775}
2776
2777
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002778static void ThrowingPropertyHandlerSet(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002779 Local<Name> key, Local<Value>,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002780 const v8::PropertyCallbackInfo<v8::Value>& info) {
2781 info.GetIsolate()->ThrowException(key);
2782 info.GetReturnValue().SetUndefined(); // not the same as empty handle
Steve Blocka7e24c12009-10-30 11:49:00 +00002783}
2784
2785
2786THREADED_TEST(CallbackExceptionRegression) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002787 v8::Isolate* isolate = CcTest::isolate();
2788 v8::HandleScope scope(isolate);
2789 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002790 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2791 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
Steve Blocka7e24c12009-10-30 11:49:00 +00002792 LocalContext env;
2793 env->Global()->Set(v8_str("obj"), obj->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002794 v8::Handle<Value> otto = CompileRun(
2795 "try { with (obj) { otto; } } catch (e) { e; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002796 CHECK_EQ(v8_str("otto"), otto);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002797 v8::Handle<Value> netto = CompileRun(
2798 "try { with (obj) { netto = 4; } } catch (e) { e; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002799 CHECK_EQ(v8_str("netto"), netto);
2800}
2801
2802
Steve Blocka7e24c12009-10-30 11:49:00 +00002803THREADED_TEST(FunctionPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002804 v8::Isolate* isolate = CcTest::isolate();
2805 v8::HandleScope scope(isolate);
2806 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002807 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2808 LocalContext env;
2809 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002810 Local<Script> script = v8_compile("Foo.prototype.plak");
Steve Blocka7e24c12009-10-30 11:49:00 +00002811 CHECK_EQ(script->Run()->Int32Value(), 321);
2812}
2813
2814
2815THREADED_TEST(InternalFields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002816 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002817 v8::Isolate* isolate = env->GetIsolate();
2818 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002819
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002820 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002821 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2822 instance_templ->SetInternalFieldCount(1);
2823 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2824 CHECK_EQ(1, obj->InternalFieldCount());
2825 CHECK(obj->GetInternalField(0)->IsUndefined());
2826 obj->SetInternalField(0, v8_num(17));
2827 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2828}
2829
2830
Steve Block6ded16b2010-05-10 14:33:55 +01002831THREADED_TEST(GlobalObjectInternalFields) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002832 v8::Isolate* isolate = CcTest::isolate();
2833 v8::HandleScope scope(isolate);
2834 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01002835 global_template->SetInternalFieldCount(1);
2836 LocalContext env(NULL, global_template);
2837 v8::Handle<v8::Object> global_proxy = env->Global();
2838 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2839 CHECK_EQ(1, global->InternalFieldCount());
2840 CHECK(global->GetInternalField(0)->IsUndefined());
2841 global->SetInternalField(0, v8_num(17));
2842 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2843}
2844
2845
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002846THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002847 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002848 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002849
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002850 v8::Local<v8::Object> global = env->Global();
2851 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2852 CHECK(global->HasRealIndexedProperty(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00002853}
2854
2855
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002856static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2857 void* value) {
2858 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2859 obj->SetAlignedPointerInInternalField(0, value);
2860 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2861 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2862}
Steve Block3ce2e202009-11-05 08:53:23 +00002863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002864
2865THREADED_TEST(InternalFieldsAlignedPointers) {
2866 LocalContext env;
2867 v8::Isolate* isolate = env->GetIsolate();
2868 v8::HandleScope scope(isolate);
2869
2870 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Block3ce2e202009-11-05 08:53:23 +00002871 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2872 instance_templ->SetInternalFieldCount(1);
2873 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2874 CHECK_EQ(1, obj->InternalFieldCount());
Steve Block3ce2e202009-11-05 08:53:23 +00002875
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002876 CheckAlignedPointerInInternalField(obj, NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00002877
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002878 int* heap_allocated = new int[100];
2879 CheckAlignedPointerInInternalField(obj, heap_allocated);
2880 delete[] heap_allocated;
Steve Block3ce2e202009-11-05 08:53:23 +00002881
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002882 int stack_allocated[100];
2883 CheckAlignedPointerInInternalField(obj, stack_allocated);
Steve Block3ce2e202009-11-05 08:53:23 +00002884
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002885 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2886 CheckAlignedPointerInInternalField(obj, huge);
Steve Block3ce2e202009-11-05 08:53:23 +00002887
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002888 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2889 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2890 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2891}
Steve Block3ce2e202009-11-05 08:53:23 +00002892
Steve Block3ce2e202009-11-05 08:53:23 +00002893
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002894static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2895 int index,
2896 void* value) {
2897 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2898 (*env)->SetAlignedPointerInEmbedderData(index, value);
2899 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2900 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2901}
2902
2903
2904static void* AlignedTestPointer(int i) {
2905 return reinterpret_cast<void*>(i * 1234);
2906}
2907
2908
2909THREADED_TEST(EmbedderDataAlignedPointers) {
2910 LocalContext env;
2911 v8::HandleScope scope(env->GetIsolate());
2912
2913 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2914
2915 int* heap_allocated = new int[100];
2916 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2917 delete[] heap_allocated;
2918
2919 int stack_allocated[100];
2920 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2921
2922 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2923 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2924
2925 // Test growing of the embedder data's backing store.
2926 for (int i = 0; i < 100; i++) {
2927 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2928 }
2929 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2930 for (int i = 0; i < 100; i++) {
2931 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2932 }
2933}
2934
2935
2936static void CheckEmbedderData(LocalContext* env,
2937 int index,
2938 v8::Handle<Value> data) {
2939 (*env)->SetEmbedderData(index, data);
2940 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2941}
2942
2943
2944THREADED_TEST(EmbedderData) {
2945 LocalContext env;
2946 v8::Isolate* isolate = env->GetIsolate();
2947 v8::HandleScope scope(isolate);
2948
2949 CheckEmbedderData(
2950 &env, 3,
2951 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2952 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2953 "over the lazy dog."));
2954 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2955 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
Steve Block3ce2e202009-11-05 08:53:23 +00002956}
2957
2958
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002959THREADED_TEST(GetIsolate) {
2960 LocalContext env;
2961 v8::Isolate* isolate = env->GetIsolate();
2962 v8::HandleScope scope(isolate);
2963 Local<v8::Object> obj = v8::Object::New(isolate);
2964 CHECK_EQ(isolate, obj->GetIsolate());
2965 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2966}
2967
2968
Steve Blocka7e24c12009-10-30 11:49:00 +00002969THREADED_TEST(IdentityHash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002970 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002971 v8::Isolate* isolate = env->GetIsolate();
2972 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002973
2974 // Ensure that the test starts with an fresh heap to test whether the hash
2975 // code is based on the address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2977 Local<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002978 int hash = obj->GetIdentityHash();
2979 int hash1 = obj->GetIdentityHash();
2980 CHECK_EQ(hash, hash1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002981 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
Steve Blocka7e24c12009-10-30 11:49:00 +00002982 // Since the identity hash is essentially a random number two consecutive
2983 // objects should not be assigned the same hash code. If the test below fails
2984 // the random number generator should be evaluated.
2985 CHECK_NE(hash, hash2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002986 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2987 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
Steve Blocka7e24c12009-10-30 11:49:00 +00002988 // Make sure that the identity hash is not based on the initial address of
2989 // the object alone. If the test below fails the random number generator
2990 // should be evaluated.
2991 CHECK_NE(hash, hash3);
2992 int hash4 = obj->GetIdentityHash();
2993 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01002994
2995 // Check identity hashes behaviour in the presence of JS accessors.
2996 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2997 {
2998 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002999 Local<v8::Object> o1 = v8::Object::New(isolate);
3000 Local<v8::Object> o2 = v8::Object::New(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +01003001 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3002 }
3003 {
3004 CompileRun(
3005 "function cnst() { return 42; };\n"
3006 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003007 Local<v8::Object> o1 = v8::Object::New(isolate);
3008 Local<v8::Object> o2 = v8::Object::New(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +01003009 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3010 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003011}
3012
3013
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003014THREADED_TEST(GlobalProxyIdentityHash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003015 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003016 v8::Isolate* isolate = env->GetIsolate();
3017 v8::HandleScope scope(isolate);
3018 Handle<Object> global_proxy = env->Global();
3019 int hash1 = global_proxy->GetIdentityHash();
3020 // Hash should be retained after being detached.
3021 env->DetachGlobal();
3022 int hash2 = global_proxy->GetIdentityHash();
3023 CHECK_EQ(hash1, hash2);
3024 {
3025 // Re-attach global proxy to a new context, hash should stay the same.
3026 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
3027 int hash3 = global_proxy->GetIdentityHash();
3028 CHECK_EQ(hash1, hash3);
3029 }
3030}
Steve Blocka7e24c12009-10-30 11:49:00 +00003031
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003032
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003033TEST(SymbolIdentityHash) {
3034 LocalContext env;
3035 v8::Isolate* isolate = env->GetIsolate();
3036 v8::HandleScope scope(isolate);
3037
3038 {
3039 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3040 int hash = symbol->GetIdentityHash();
3041 int hash1 = symbol->GetIdentityHash();
3042 CHECK_EQ(hash, hash1);
3043 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3044 int hash3 = symbol->GetIdentityHash();
3045 CHECK_EQ(hash, hash3);
3046 }
3047
3048 {
3049 v8::Handle<v8::Symbol> js_symbol =
3050 CompileRun("Symbol('foo')").As<v8::Symbol>();
3051 int hash = js_symbol->GetIdentityHash();
3052 int hash1 = js_symbol->GetIdentityHash();
3053 CHECK_EQ(hash, hash1);
3054 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3055 int hash3 = js_symbol->GetIdentityHash();
3056 CHECK_EQ(hash, hash3);
3057 }
3058}
3059
3060
3061TEST(StringIdentityHash) {
3062 LocalContext env;
3063 v8::Isolate* isolate = env->GetIsolate();
3064 v8::HandleScope scope(isolate);
3065
3066 Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
3067 int hash = str->GetIdentityHash();
3068 int hash1 = str->GetIdentityHash();
3069 CHECK_EQ(hash, hash1);
3070 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3071 int hash3 = str->GetIdentityHash();
3072 CHECK_EQ(hash, hash3);
3073
3074 Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
3075 int hash4 = str2->GetIdentityHash();
3076 CHECK_EQ(hash, hash4);
3077}
3078
3079
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003080THREADED_TEST(SymbolProperties) {
3081 LocalContext env;
3082 v8::Isolate* isolate = env->GetIsolate();
3083 v8::HandleScope scope(isolate);
3084
3085 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3086 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3087 v8::Local<v8::Symbol> sym2 =
3088 v8::Symbol::New(isolate, v8_str("my-symbol"));
3089 v8::Local<v8::Symbol> sym3 =
3090 v8::Symbol::New(isolate, v8_str("sym3"));
3091
3092 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3093
3094 // Check basic symbol functionality.
3095 CHECK(sym1->IsSymbol());
3096 CHECK(sym2->IsSymbol());
3097 CHECK(!obj->IsSymbol());
3098
3099 CHECK(sym1->Equals(sym1));
3100 CHECK(sym2->Equals(sym2));
3101 CHECK(!sym1->Equals(sym2));
3102 CHECK(!sym2->Equals(sym1));
3103 CHECK(sym1->StrictEquals(sym1));
3104 CHECK(sym2->StrictEquals(sym2));
3105 CHECK(!sym1->StrictEquals(sym2));
3106 CHECK(!sym2->StrictEquals(sym1));
3107
3108 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
3109
3110 v8::Local<v8::Value> sym_val = sym2;
3111 CHECK(sym_val->IsSymbol());
3112 CHECK(sym_val->Equals(sym2));
3113 CHECK(sym_val->StrictEquals(sym2));
3114 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
3115
3116 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3117 CHECK(sym_obj->IsSymbolObject());
3118 CHECK(!sym2->IsSymbolObject());
3119 CHECK(!obj->IsSymbolObject());
3120 CHECK(!sym_obj->Equals(sym2));
3121 CHECK(!sym_obj->StrictEquals(sym2));
3122 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
3123 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
3124
3125 // Make sure delete of a non-existent symbol property works.
3126 CHECK(obj->Delete(sym1));
3127 CHECK(!obj->Has(sym1));
3128
3129 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
3130 CHECK(obj->Has(sym1));
3131 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
3132 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
3133 CHECK(obj->Has(sym1));
3134 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3135 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
3136
3137 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3138 int num_props = obj->GetPropertyNames()->Length();
3139 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3140 v8::Integer::New(isolate, 20)));
3141 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3142 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3143
3144 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3145
3146 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
3147 CHECK(obj->Get(sym3)->IsUndefined());
3148 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
3149 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3150 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3151 v8::Integer::New(isolate, 42)));
3152
3153 // Add another property and delete it afterwards to force the object in
3154 // slow case.
3155 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
3156 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3157 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
3158 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3159 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3160
3161 CHECK(obj->Has(sym1));
3162 CHECK(obj->Has(sym2));
3163 CHECK(obj->Has(sym3));
3164 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3165 CHECK(obj->Delete(sym2));
3166 CHECK(obj->Has(sym1));
3167 CHECK(!obj->Has(sym2));
3168 CHECK(obj->Has(sym3));
3169 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3170 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3171 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3172 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3173 v8::Integer::New(isolate, 42)));
3174 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3175
3176 // Symbol properties are inherited.
3177 v8::Local<v8::Object> child = v8::Object::New(isolate);
3178 child->SetPrototype(obj);
3179 CHECK(child->Has(sym1));
3180 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
3181 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3182 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3183 v8::Integer::New(isolate, 42)));
3184 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3185}
3186
3187
3188THREADED_TEST(SymbolTemplateProperties) {
3189 LocalContext env;
3190 v8::Isolate* isolate = env->GetIsolate();
3191 v8::HandleScope scope(isolate);
3192 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3193 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3194 CHECK(!name.IsEmpty());
3195 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3196 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3197 CHECK(!new_instance.IsEmpty());
3198 CHECK(new_instance->Has(name));
3199}
3200
3201
3202THREADED_TEST(PrivateProperties) {
3203 LocalContext env;
3204 v8::Isolate* isolate = env->GetIsolate();
3205 v8::HandleScope scope(isolate);
3206
3207 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3208 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3209 v8::Local<v8::Private> priv2 =
3210 v8::Private::New(isolate, v8_str("my-private"));
3211
3212 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3213
3214 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3215
3216 // Make sure delete of a non-existent private symbol property works.
3217 CHECK(obj->DeletePrivate(priv1));
3218 CHECK(!obj->HasPrivate(priv1));
3219
3220 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3221 CHECK(obj->HasPrivate(priv1));
3222 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3223 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3224 CHECK(obj->HasPrivate(priv1));
3225 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3226
3227 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3228 int num_props = obj->GetPropertyNames()->Length();
3229 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3230 v8::Integer::New(isolate, 20)));
3231 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3232 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3233
3234 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3235
3236 // Add another property and delete it afterwards to force the object in
3237 // slow case.
3238 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3239 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3240 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3241 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3242 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3243
3244 CHECK(obj->HasPrivate(priv1));
3245 CHECK(obj->HasPrivate(priv2));
3246 CHECK(obj->DeletePrivate(priv2));
3247 CHECK(obj->HasPrivate(priv1));
3248 CHECK(!obj->HasPrivate(priv2));
3249 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3250 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3251
3252 // Private properties are inherited (for the time being).
3253 v8::Local<v8::Object> child = v8::Object::New(isolate);
3254 child->SetPrototype(obj);
3255 CHECK(child->HasPrivate(priv1));
3256 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3257 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3258}
3259
3260
3261THREADED_TEST(GlobalSymbols) {
3262 LocalContext env;
3263 v8::Isolate* isolate = env->GetIsolate();
3264 v8::HandleScope scope(isolate);
3265
3266 v8::Local<String> name = v8_str("my-symbol");
3267 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3268 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3269 CHECK(glob2->SameValue(glob));
3270
3271 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3272 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3273 CHECK(glob_api2->SameValue(glob_api));
3274 CHECK(!glob_api->SameValue(glob));
3275
3276 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3277 CHECK(!sym->SameValue(glob));
3278
3279 CompileRun("var sym2 = Symbol.for('my-symbol')");
3280 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3281 CHECK(sym2->SameValue(glob));
3282 CHECK(!sym2->SameValue(glob_api));
3283}
3284
3285
3286static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3287 const char* name) {
3288 LocalContext env;
3289 v8::Isolate* isolate = env->GetIsolate();
3290 v8::HandleScope scope(isolate);
3291
3292 v8::Local<v8::Symbol> symbol = getter(isolate);
3293 std::string script = std::string("var sym = ") + name;
3294 CompileRun(script.c_str());
3295 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3296
3297 CHECK(!value.IsEmpty());
3298 CHECK(!symbol.IsEmpty());
3299 CHECK(value->SameValue(symbol));
3300}
3301
3302
3303THREADED_TEST(WellKnownSymbols) {
3304 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3305 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3306}
3307
3308
3309THREADED_TEST(GlobalPrivates) {
3310 LocalContext env;
3311 v8::Isolate* isolate = env->GetIsolate();
3312 v8::HandleScope scope(isolate);
3313
3314 v8::Local<String> name = v8_str("my-private");
3315 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3316 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3317 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3318
3319 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3320 CHECK(obj->HasPrivate(glob2));
3321
3322 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3323 CHECK(!obj->HasPrivate(priv));
3324
3325 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3326 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3327 CHECK(!obj->Has(intern));
3328}
3329
3330
3331class ScopedArrayBufferContents {
3332 public:
3333 explicit ScopedArrayBufferContents(
3334 const v8::ArrayBuffer::Contents& contents)
3335 : contents_(contents) {}
3336 ~ScopedArrayBufferContents() { free(contents_.Data()); }
3337 void* Data() const { return contents_.Data(); }
3338 size_t ByteLength() const { return contents_.ByteLength(); }
3339 private:
3340 const v8::ArrayBuffer::Contents contents_;
3341};
3342
3343template <typename T>
3344static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3345 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3346 for (int i = 0; i < value->InternalFieldCount(); i++) {
3347 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3348 }
3349}
3350
3351
3352THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3353 LocalContext env;
3354 v8::Isolate* isolate = env->GetIsolate();
3355 v8::HandleScope handle_scope(isolate);
3356
3357 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3358 CheckInternalFieldsAreZero(ab);
3359 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3360 CHECK(!ab->IsExternal());
3361 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3362
3363 ScopedArrayBufferContents ab_contents(ab->Externalize());
3364 CHECK(ab->IsExternal());
3365
3366 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3367 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3368 DCHECK(data != NULL);
3369 env->Global()->Set(v8_str("ab"), ab);
3370
3371 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3372 CHECK_EQ(1024, result->Int32Value());
3373
3374 result = CompileRun("var u8 = new Uint8Array(ab);"
3375 "u8[0] = 0xFF;"
3376 "u8[1] = 0xAA;"
3377 "u8.length");
3378 CHECK_EQ(1024, result->Int32Value());
3379 CHECK_EQ(0xFF, data[0]);
3380 CHECK_EQ(0xAA, data[1]);
3381 data[0] = 0xCC;
3382 data[1] = 0x11;
3383 result = CompileRun("u8[0] + u8[1]");
3384 CHECK_EQ(0xDD, result->Int32Value());
3385}
3386
3387
3388THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3389 LocalContext env;
3390 v8::Isolate* isolate = env->GetIsolate();
3391 v8::HandleScope handle_scope(isolate);
3392
3393
3394 v8::Local<v8::Value> result =
3395 CompileRun("var ab1 = new ArrayBuffer(2);"
3396 "var u8_a = new Uint8Array(ab1);"
3397 "u8_a[0] = 0xAA;"
3398 "u8_a[1] = 0xFF; u8_a.buffer");
3399 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3400 CheckInternalFieldsAreZero(ab1);
3401 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3402 CHECK(!ab1->IsExternal());
3403 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3404 CHECK(ab1->IsExternal());
3405
3406 result = CompileRun("ab1.byteLength");
3407 CHECK_EQ(2, result->Int32Value());
3408 result = CompileRun("u8_a[0]");
3409 CHECK_EQ(0xAA, result->Int32Value());
3410 result = CompileRun("u8_a[1]");
3411 CHECK_EQ(0xFF, result->Int32Value());
3412 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3413 "u8_b[0] = 0xBB;"
3414 "u8_a[0]");
3415 CHECK_EQ(0xBB, result->Int32Value());
3416 result = CompileRun("u8_b[1]");
3417 CHECK_EQ(0xFF, result->Int32Value());
3418
3419 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3420 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3421 CHECK_EQ(0xBB, ab1_data[0]);
3422 CHECK_EQ(0xFF, ab1_data[1]);
3423 ab1_data[0] = 0xCC;
3424 ab1_data[1] = 0x11;
3425 result = CompileRun("u8_a[0] + u8_a[1]");
3426 CHECK_EQ(0xDD, result->Int32Value());
3427}
3428
3429
3430THREADED_TEST(ArrayBuffer_External) {
3431 LocalContext env;
3432 v8::Isolate* isolate = env->GetIsolate();
3433 v8::HandleScope handle_scope(isolate);
3434
3435 i::ScopedVector<uint8_t> my_data(100);
3436 memset(my_data.start(), 0, 100);
3437 Local<v8::ArrayBuffer> ab3 =
3438 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3439 CheckInternalFieldsAreZero(ab3);
3440 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3441 CHECK(ab3->IsExternal());
3442
3443 env->Global()->Set(v8_str("ab3"), ab3);
3444
3445 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3446 CHECK_EQ(100, result->Int32Value());
3447
3448 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3449 "u8_b[0] = 0xBB;"
3450 "u8_b[1] = 0xCC;"
3451 "u8_b.length");
3452 CHECK_EQ(100, result->Int32Value());
3453 CHECK_EQ(0xBB, my_data[0]);
3454 CHECK_EQ(0xCC, my_data[1]);
3455 my_data[0] = 0xCC;
3456 my_data[1] = 0x11;
3457 result = CompileRun("u8_b[0] + u8_b[1]");
3458 CHECK_EQ(0xDD, result->Int32Value());
3459}
3460
3461
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003462THREADED_TEST(ArrayBuffer_DisableNeuter) {
3463 LocalContext env;
3464 v8::Isolate* isolate = env->GetIsolate();
3465 v8::HandleScope handle_scope(isolate);
3466
3467 i::ScopedVector<uint8_t> my_data(100);
3468 memset(my_data.start(), 0, 100);
3469 Local<v8::ArrayBuffer> ab =
3470 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3471 CHECK(ab->IsNeuterable());
3472
3473 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3474 buf->set_is_neuterable(false);
3475
3476 CHECK(!ab->IsNeuterable());
3477}
3478
3479
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003480static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3481 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3482 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3483}
3484
3485
3486static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3487 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3488 CHECK_EQ(0, static_cast<int>(ta->Length()));
3489 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3490}
3491
3492
3493static void CheckIsTypedArrayVarNeutered(const char* name) {
3494 i::ScopedVector<char> source(1024);
3495 i::SNPrintF(source,
3496 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3497 name, name, name);
3498 CHECK(CompileRun(source.start())->IsTrue());
3499 v8::Handle<v8::TypedArray> ta =
3500 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3501 CheckIsNeutered(ta);
3502}
3503
3504
3505template <typename TypedArray, int kElementSize>
3506static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3507 int byteOffset,
3508 int length) {
3509 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3510 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3511 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3512 CHECK_EQ(length, static_cast<int>(ta->Length()));
3513 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3514 return ta;
3515}
3516
3517
3518THREADED_TEST(ArrayBuffer_NeuteringApi) {
3519 LocalContext env;
3520 v8::Isolate* isolate = env->GetIsolate();
3521 v8::HandleScope handle_scope(isolate);
3522
3523 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3524
3525 v8::Handle<v8::Uint8Array> u8a =
3526 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3527 v8::Handle<v8::Uint8ClampedArray> u8c =
3528 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3529 v8::Handle<v8::Int8Array> i8a =
3530 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3531
3532 v8::Handle<v8::Uint16Array> u16a =
3533 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3534 v8::Handle<v8::Int16Array> i16a =
3535 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3536
3537 v8::Handle<v8::Uint32Array> u32a =
3538 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3539 v8::Handle<v8::Int32Array> i32a =
3540 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3541
3542 v8::Handle<v8::Float32Array> f32a =
3543 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3544 v8::Handle<v8::Float64Array> f64a =
3545 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3546
3547 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3548 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3549 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3550 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3551
3552 ScopedArrayBufferContents contents(buffer->Externalize());
3553 buffer->Neuter();
3554 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3555 CheckIsNeutered(u8a);
3556 CheckIsNeutered(u8c);
3557 CheckIsNeutered(i8a);
3558 CheckIsNeutered(u16a);
3559 CheckIsNeutered(i16a);
3560 CheckIsNeutered(u32a);
3561 CheckIsNeutered(i32a);
3562 CheckIsNeutered(f32a);
3563 CheckIsNeutered(f64a);
3564 CheckDataViewIsNeutered(dv);
3565}
3566
3567
3568THREADED_TEST(ArrayBuffer_NeuteringScript) {
3569 LocalContext env;
3570 v8::Isolate* isolate = env->GetIsolate();
3571 v8::HandleScope handle_scope(isolate);
3572
3573 CompileRun(
3574 "var ab = new ArrayBuffer(1024);"
3575 "var u8a = new Uint8Array(ab, 1, 1023);"
3576 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3577 "var i8a = new Int8Array(ab, 1, 1023);"
3578 "var u16a = new Uint16Array(ab, 2, 511);"
3579 "var i16a = new Int16Array(ab, 2, 511);"
3580 "var u32a = new Uint32Array(ab, 4, 255);"
3581 "var i32a = new Int32Array(ab, 4, 255);"
3582 "var f32a = new Float32Array(ab, 4, 255);"
3583 "var f64a = new Float64Array(ab, 8, 127);"
3584 "var dv = new DataView(ab, 1, 1023);");
3585
3586 v8::Handle<v8::ArrayBuffer> ab =
3587 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3588
3589 v8::Handle<v8::DataView> dv =
3590 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3591
3592 ScopedArrayBufferContents contents(ab->Externalize());
3593 ab->Neuter();
3594 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3595 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3596
3597 CheckIsTypedArrayVarNeutered("u8a");
3598 CheckIsTypedArrayVarNeutered("u8c");
3599 CheckIsTypedArrayVarNeutered("i8a");
3600 CheckIsTypedArrayVarNeutered("u16a");
3601 CheckIsTypedArrayVarNeutered("i16a");
3602 CheckIsTypedArrayVarNeutered("u32a");
3603 CheckIsTypedArrayVarNeutered("i32a");
3604 CheckIsTypedArrayVarNeutered("f32a");
3605 CheckIsTypedArrayVarNeutered("f64a");
3606
3607 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3608 CheckDataViewIsNeutered(dv);
3609}
3610
3611
3612
3613THREADED_TEST(HiddenProperties) {
3614 LocalContext env;
3615 v8::Isolate* isolate = env->GetIsolate();
3616 v8::HandleScope scope(isolate);
3617
3618 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003619 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3620 v8::Local<v8::String> empty = v8_str("");
3621 v8::Local<v8::String> prop_name = v8_str("prop_name");
3622
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003623 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003624
3625 // Make sure delete of a non-existent hidden value works
3626 CHECK(obj->DeleteHiddenValue(key));
3627
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003628 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003629 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003630 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003631 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3632
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003633 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003634
3635 // Make sure we do not find the hidden property.
3636 CHECK(!obj->Has(empty));
3637 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3638 CHECK(obj->Get(empty)->IsUndefined());
3639 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003640 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003641 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3642 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003644 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003645
3646 // Add another property and delete it afterwards to force the object in
3647 // slow case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003648 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003649 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3650 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3651 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3652 CHECK(obj->Delete(prop_name));
3653 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3654
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003655 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003657 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3658 CHECK(obj->GetHiddenValue(key).IsEmpty());
3659
3660 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003661 CHECK(obj->DeleteHiddenValue(key));
3662 CHECK(obj->GetHiddenValue(key).IsEmpty());
3663}
3664
3665
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003666THREADED_TEST(Regress97784) {
3667 // Regression test for crbug.com/97784
3668 // Messing with the Object.prototype should not have effect on
3669 // hidden properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003670 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003671 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003672
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003673 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003674 v8::Local<v8::String> key = v8_str("hidden");
3675
3676 CompileRun(
3677 "set_called = false;"
3678 "Object.defineProperty("
3679 " Object.prototype,"
3680 " 'hidden',"
3681 " {get: function() { return 45; },"
3682 " set: function() { set_called = true; }})");
3683
3684 CHECK(obj->GetHiddenValue(key).IsEmpty());
3685 // Make sure that the getter and setter from Object.prototype is not invoked.
3686 // If it did we would have full access to the hidden properties in
3687 // the accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003688 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003689 ExpectFalse("set_called");
3690 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3691}
3692
3693
Steve Blockd0582a62009-12-15 09:54:21 +00003694static bool interceptor_for_hidden_properties_called;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003695static void InterceptorForHiddenProperties(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003696 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00003697 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003698}
3699
3700
3701THREADED_TEST(HiddenPropertiesWithInterceptors) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003702 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003703 v8::Isolate* isolate = context->GetIsolate();
3704 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003705
Steve Blockd0582a62009-12-15 09:54:21 +00003706 interceptor_for_hidden_properties_called = false;
3707
Steve Blocka7e24c12009-10-30 11:49:00 +00003708 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3709
3710 // Associate an interceptor with an object and start setting hidden values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003711 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003712 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003713 instance_templ->SetHandler(
3714 v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
Steve Blocka7e24c12009-10-30 11:49:00 +00003715 Local<v8::Function> function = fun_templ->GetFunction();
3716 Local<v8::Object> obj = function->NewInstance();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003717 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003718 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00003719 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00003720}
3721
3722
3723THREADED_TEST(External) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003724 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003725 int x = 3;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003726 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
Steve Blocka7e24c12009-10-30 11:49:00 +00003727 LocalContext env;
3728 env->Global()->Set(v8_str("ext"), ext);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003729 Local<Value> reext_obj = CompileRun("this.ext");
Steve Block6ded16b2010-05-10 14:33:55 +01003730 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003731 int* ptr = static_cast<int*>(reext->Value());
3732 CHECK_EQ(x, 3);
3733 *ptr = 10;
3734 CHECK_EQ(x, 10);
3735
3736 // Make sure unaligned pointers are wrapped properly.
3737 char* data = i::StrDup("0123456789");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003738 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3739 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3740 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3741 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003742
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003743 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003744 CHECK_EQ('0', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003745 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003746 CHECK_EQ('1', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003747 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003748 CHECK_EQ('2', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003749 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003750 CHECK_EQ('3', *char_ptr);
3751 i::DeleteArray(data);
3752}
3753
3754
3755THREADED_TEST(GlobalHandle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003756 v8::Isolate* isolate = CcTest::isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003757 v8::Persistent<String> global;
3758 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003759 v8::HandleScope scope(isolate);
3760 global.Reset(isolate, v8_str("str"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003761 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003762 {
3763 v8::HandleScope scope(isolate);
3764 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3765 }
3766 global.Reset();
3767 {
3768 v8::HandleScope scope(isolate);
3769 global.Reset(isolate, v8_str("str"));
3770 }
3771 {
3772 v8::HandleScope scope(isolate);
3773 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3774 }
3775 global.Reset();
3776}
3777
3778
3779THREADED_TEST(ResettingGlobalHandle) {
3780 v8::Isolate* isolate = CcTest::isolate();
3781 v8::Persistent<String> global;
3782 {
3783 v8::HandleScope scope(isolate);
3784 global.Reset(isolate, v8_str("str"));
3785 }
3786 v8::internal::GlobalHandles* global_handles =
3787 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3788 int initial_handle_count = global_handles->global_handles_count();
3789 {
3790 v8::HandleScope scope(isolate);
3791 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3792 }
3793 {
3794 v8::HandleScope scope(isolate);
3795 global.Reset(isolate, v8_str("longer"));
3796 }
3797 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3798 {
3799 v8::HandleScope scope(isolate);
3800 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3801 }
3802 global.Reset();
3803 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3804}
3805
3806
3807THREADED_TEST(ResettingGlobalHandleToEmpty) {
3808 v8::Isolate* isolate = CcTest::isolate();
3809 v8::Persistent<String> global;
3810 {
3811 v8::HandleScope scope(isolate);
3812 global.Reset(isolate, v8_str("str"));
3813 }
3814 v8::internal::GlobalHandles* global_handles =
3815 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3816 int initial_handle_count = global_handles->global_handles_count();
3817 {
3818 v8::HandleScope scope(isolate);
3819 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3820 }
3821 {
3822 v8::HandleScope scope(isolate);
3823 Local<String> empty;
3824 global.Reset(isolate, empty);
3825 }
3826 CHECK(global.IsEmpty());
3827 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3828}
3829
3830
3831template<class T>
3832static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3833 return unique.Pass();
3834}
3835
3836
3837template<class T>
3838static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3839 const v8::Persistent<T> & global) {
3840 v8::UniquePersistent<String> unique(isolate, global);
3841 return unique.Pass();
3842}
3843
3844
3845THREADED_TEST(UniquePersistent) {
3846 v8::Isolate* isolate = CcTest::isolate();
3847 v8::Persistent<String> global;
3848 {
3849 v8::HandleScope scope(isolate);
3850 global.Reset(isolate, v8_str("str"));
3851 }
3852 v8::internal::GlobalHandles* global_handles =
3853 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3854 int initial_handle_count = global_handles->global_handles_count();
3855 {
3856 v8::UniquePersistent<String> unique(isolate, global);
3857 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3858 // Test assignment via Pass
3859 {
3860 v8::UniquePersistent<String> copy = unique.Pass();
3861 CHECK(unique.IsEmpty());
3862 CHECK(copy == global);
3863 CHECK_EQ(initial_handle_count + 1,
3864 global_handles->global_handles_count());
3865 unique = copy.Pass();
3866 }
3867 // Test ctor via Pass
3868 {
3869 v8::UniquePersistent<String> copy(unique.Pass());
3870 CHECK(unique.IsEmpty());
3871 CHECK(copy == global);
3872 CHECK_EQ(initial_handle_count + 1,
3873 global_handles->global_handles_count());
3874 unique = copy.Pass();
3875 }
3876 // Test pass through function call
3877 {
3878 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3879 CHECK(unique.IsEmpty());
3880 CHECK(copy == global);
3881 CHECK_EQ(initial_handle_count + 1,
3882 global_handles->global_handles_count());
3883 unique = copy.Pass();
3884 }
3885 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3886 }
3887 // Test pass from function call
3888 {
3889 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3890 CHECK(unique == global);
3891 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3892 }
3893 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3894 global.Reset();
3895}
3896
3897
3898template<typename K, typename V>
3899class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3900 public:
3901 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3902 MapType;
3903 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3904 struct WeakCallbackDataType {
3905 MapType* map;
3906 K key;
3907 };
3908 static WeakCallbackDataType* WeakCallbackParameter(
3909 MapType* map, const K& key, Local<V> value) {
3910 WeakCallbackDataType* data = new WeakCallbackDataType;
3911 data->map = map;
3912 data->key = key;
3913 return data;
3914 }
3915 static MapType* MapFromWeakCallbackData(
3916 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3917 return data.GetParameter()->map;
3918 }
3919 static K KeyFromWeakCallbackData(
3920 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3921 return data.GetParameter()->key;
3922 }
3923 static void DisposeCallbackData(WeakCallbackDataType* data) {
3924 delete data;
3925 }
3926 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3927 K key) { }
3928};
3929
3930
3931template<typename Map>
3932static void TestPersistentValueMap() {
3933 LocalContext env;
3934 v8::Isolate* isolate = env->GetIsolate();
3935 Map map(isolate);
3936 v8::internal::GlobalHandles* global_handles =
3937 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3938 int initial_handle_count = global_handles->global_handles_count();
3939 CHECK_EQ(0, static_cast<int>(map.Size()));
3940 {
3941 HandleScope scope(isolate);
3942 Local<v8::Object> obj = map.Get(7);
3943 CHECK(obj.IsEmpty());
3944 Local<v8::Object> expected = v8::Object::New(isolate);
3945 map.Set(7, expected);
3946 CHECK_EQ(1, static_cast<int>(map.Size()));
3947 obj = map.Get(7);
3948 CHECK_EQ(expected, obj);
3949 {
3950 typename Map::PersistentValueReference ref = map.GetReference(7);
3951 CHECK_EQ(expected, ref.NewLocal(isolate));
3952 }
3953 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3954 CHECK_EQ(0, static_cast<int>(map.Size()));
3955 CHECK(expected == removed);
3956 removed = map.Remove(7);
3957 CHECK(removed.IsEmpty());
3958 map.Set(8, expected);
3959 CHECK_EQ(1, static_cast<int>(map.Size()));
3960 map.Set(8, expected);
3961 CHECK_EQ(1, static_cast<int>(map.Size()));
3962 {
3963 typename Map::PersistentValueReference ref;
3964 Local<v8::Object> expected2 = v8::Object::New(isolate);
3965 removed = map.Set(8,
3966 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3967 CHECK_EQ(1, static_cast<int>(map.Size()));
3968 CHECK(expected == removed);
3969 CHECK_EQ(expected2, ref.NewLocal(isolate));
3970 }
3971 }
3972 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3973 if (map.IsWeak()) {
3974 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3975 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3976 } else {
3977 map.Clear();
3978 }
3979 CHECK_EQ(0, static_cast<int>(map.Size()));
3980 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3981}
3982
3983
3984TEST(PersistentValueMap) {
3985 // Default case, w/o weak callbacks:
3986 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3987
3988 // Custom traits with weak callbacks:
3989 typedef v8::PersistentValueMap<int, v8::Object,
3990 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3991 TestPersistentValueMap<WeakPersistentValueMap>();
3992}
3993
3994
3995TEST(PersistentValueVector) {
3996 LocalContext env;
3997 v8::Isolate* isolate = env->GetIsolate();
3998 v8::internal::GlobalHandles* global_handles =
3999 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4000 int handle_count = global_handles->global_handles_count();
4001 HandleScope scope(isolate);
4002
4003 v8::PersistentValueVector<v8::Object> vector(isolate);
4004
4005 Local<v8::Object> obj1 = v8::Object::New(isolate);
4006 Local<v8::Object> obj2 = v8::Object::New(isolate);
4007 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
4008
4009 CHECK(vector.IsEmpty());
4010 CHECK_EQ(0, static_cast<int>(vector.Size()));
4011
4012 vector.ReserveCapacity(3);
4013 CHECK(vector.IsEmpty());
4014
4015 vector.Append(obj1);
4016 vector.Append(obj2);
4017 vector.Append(obj1);
4018 vector.Append(obj3.Pass());
4019 vector.Append(obj1);
4020
4021 CHECK(!vector.IsEmpty());
4022 CHECK_EQ(5, static_cast<int>(vector.Size()));
4023 CHECK(obj3.IsEmpty());
4024 CHECK_EQ(obj1, vector.Get(0));
4025 CHECK_EQ(obj1, vector.Get(2));
4026 CHECK_EQ(obj1, vector.Get(4));
4027 CHECK_EQ(obj2, vector.Get(1));
4028
4029 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4030
4031 vector.Clear();
4032 CHECK(vector.IsEmpty());
4033 CHECK_EQ(0, static_cast<int>(vector.Size()));
4034 CHECK_EQ(handle_count, global_handles->global_handles_count());
4035}
4036
4037
4038THREADED_TEST(GlobalHandleUpcast) {
4039 v8::Isolate* isolate = CcTest::isolate();
4040 v8::HandleScope scope(isolate);
4041 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4042 v8::Persistent<String> global_string(isolate, local);
4043 v8::Persistent<Value>& global_value =
4044 v8::Persistent<Value>::Cast(global_string);
4045 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4046 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4047 global_string.Reset();
4048}
4049
4050
4051THREADED_TEST(HandleEquality) {
4052 v8::Isolate* isolate = CcTest::isolate();
4053 v8::Persistent<String> global1;
4054 v8::Persistent<String> global2;
4055 {
4056 v8::HandleScope scope(isolate);
4057 global1.Reset(isolate, v8_str("str"));
4058 global2.Reset(isolate, v8_str("str2"));
4059 }
4060 CHECK_EQ(global1 == global1, true);
4061 CHECK_EQ(global1 != global1, false);
4062 {
4063 v8::HandleScope scope(isolate);
4064 Local<String> local1 = Local<String>::New(isolate, global1);
4065 Local<String> local2 = Local<String>::New(isolate, global2);
4066
4067 CHECK_EQ(global1 == local1, true);
4068 CHECK_EQ(global1 != local1, false);
4069 CHECK_EQ(local1 == global1, true);
4070 CHECK_EQ(local1 != global1, false);
4071
4072 CHECK_EQ(global1 == local2, false);
4073 CHECK_EQ(global1 != local2, true);
4074 CHECK_EQ(local2 == global1, false);
4075 CHECK_EQ(local2 != global1, true);
4076
4077 CHECK_EQ(local1 == local2, false);
4078 CHECK_EQ(local1 != local2, true);
4079
4080 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4081 CHECK_EQ(local1 == anotherLocal1, true);
4082 CHECK_EQ(local1 != anotherLocal1, false);
4083 }
4084 global1.Reset();
4085 global2.Reset();
4086}
4087
4088
4089THREADED_TEST(LocalHandle) {
4090 v8::HandleScope scope(CcTest::isolate());
4091 v8::Local<String> local =
4092 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4093 CHECK_EQ(local->Length(), 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00004094}
4095
4096
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004097class WeakCallCounter {
4098 public:
4099 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
4100 int id() { return id_; }
4101 void increment() { number_of_weak_calls_++; }
4102 int NumberOfWeakCalls() { return number_of_weak_calls_; }
4103 private:
4104 int id_;
4105 int number_of_weak_calls_;
4106};
4107
4108
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004109template<typename T>
4110struct WeakCallCounterAndPersistent {
4111 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4112 : counter(counter) {}
4113 WeakCallCounter* counter;
4114 v8::Persistent<T> handle;
4115};
4116
4117
4118template <typename T>
4119static void WeakPointerCallback(
4120 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
4121 CHECK_EQ(1234, data.GetParameter()->counter->id());
4122 data.GetParameter()->counter->increment();
4123 data.GetParameter()->handle.Reset();
4124}
4125
4126
4127template<typename T>
4128static UniqueId MakeUniqueId(const Persistent<T>& p) {
4129 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
Steve Block44f0eee2011-05-26 01:26:41 +01004130}
4131
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004132
Steve Block44f0eee2011-05-26 01:26:41 +01004133THREADED_TEST(ApiObjectGroups) {
Steve Block44f0eee2011-05-26 01:26:41 +01004134 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004135 v8::Isolate* iso = env->GetIsolate();
4136 HandleScope scope(iso);
Steve Block44f0eee2011-05-26 01:26:41 +01004137
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004138 WeakCallCounter counter(1234);
4139
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004140 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4141 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4142 WeakCallCounterAndPersistent<Value> g1c1(&counter);
4143 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4144 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4145 WeakCallCounterAndPersistent<Value> g2c1(&counter);
Steve Block44f0eee2011-05-26 01:26:41 +01004146
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004147 {
4148 HandleScope scope(iso);
4149 g1s1.handle.Reset(iso, Object::New(iso));
4150 g1s2.handle.Reset(iso, Object::New(iso));
4151 g1c1.handle.Reset(iso, Object::New(iso));
4152 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4153 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4154 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4155
4156 g2s1.handle.Reset(iso, Object::New(iso));
4157 g2s2.handle.Reset(iso, Object::New(iso));
4158 g2c1.handle.Reset(iso, Object::New(iso));
4159 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4160 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4161 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01004162 }
4163
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004164 WeakCallCounterAndPersistent<Value> root(&counter);
4165 root.handle.Reset(iso, g1s1.handle); // make a root.
Steve Block44f0eee2011-05-26 01:26:41 +01004166
4167 // Connect group 1 and 2, make a cycle.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004168 {
4169 HandleScope scope(iso);
4170 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
4171 Set(0, Local<Value>::New(iso, g2s2.handle)));
4172 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
4173 Set(0, Local<Value>::New(iso, g1s1.handle)));
4174 }
Steve Block44f0eee2011-05-26 01:26:41 +01004175
4176 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004177 UniqueId id1 = MakeUniqueId(g1s1.handle);
4178 UniqueId id2 = MakeUniqueId(g2s2.handle);
4179 iso->SetObjectGroupId(g1s1.handle, id1);
4180 iso->SetObjectGroupId(g1s2.handle, id1);
4181 iso->SetReferenceFromGroup(id1, g1c1.handle);
4182 iso->SetObjectGroupId(g2s1.handle, id2);
4183 iso->SetObjectGroupId(g2s2.handle, id2);
4184 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01004185 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004186 // Do a single full GC, ensure incremental marking is stopped.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004187 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4188 iso)->heap();
4189 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01004190
4191 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004192 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004193
4194 // Weaken the root.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004195 root.handle.SetWeak(&root, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01004196 // But make children strong roots---all the objects (except for children)
4197 // should be collectable now.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004198 g1c1.handle.ClearWeak();
4199 g2c1.handle.ClearWeak();
Steve Block44f0eee2011-05-26 01:26:41 +01004200
4201 // Groups are deleted, rebuild groups.
4202 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004203 UniqueId id1 = MakeUniqueId(g1s1.handle);
4204 UniqueId id2 = MakeUniqueId(g2s2.handle);
4205 iso->SetObjectGroupId(g1s1.handle, id1);
4206 iso->SetObjectGroupId(g1s2.handle, id1);
4207 iso->SetReferenceFromGroup(id1, g1c1.handle);
4208 iso->SetObjectGroupId(g2s1.handle, id2);
4209 iso->SetObjectGroupId(g2s2.handle, id2);
4210 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01004211 }
4212
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004213 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01004214
4215 // All objects should be gone. 5 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004216 CHECK_EQ(5, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004217
4218 // And now make children weak again and collect them.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004219 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4220 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01004221
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004222 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004223 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004224}
4225
4226
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004227THREADED_TEST(ApiObjectGroupsForSubtypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01004228 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004229 v8::Isolate* iso = env->GetIsolate();
4230 HandleScope scope(iso);
Steve Block44f0eee2011-05-26 01:26:41 +01004231
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004232 WeakCallCounter counter(1234);
Steve Block44f0eee2011-05-26 01:26:41 +01004233
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004234 WeakCallCounterAndPersistent<Object> g1s1(&counter);
4235 WeakCallCounterAndPersistent<String> g1s2(&counter);
4236 WeakCallCounterAndPersistent<String> g1c1(&counter);
4237 WeakCallCounterAndPersistent<Object> g2s1(&counter);
4238 WeakCallCounterAndPersistent<String> g2s2(&counter);
4239 WeakCallCounterAndPersistent<String> g2c1(&counter);
Steve Block44f0eee2011-05-26 01:26:41 +01004240
4241 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004242 HandleScope scope(iso);
4243 g1s1.handle.Reset(iso, Object::New(iso));
4244 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4245 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4246 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4247 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4248 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01004249
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004250 g2s1.handle.Reset(iso, Object::New(iso));
4251 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4252 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4253 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4254 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4255 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01004256 }
4257
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004258 WeakCallCounterAndPersistent<Value> root(&counter);
4259 root.handle.Reset(iso, g1s1.handle); // make a root.
Steve Block44f0eee2011-05-26 01:26:41 +01004260
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004261 // Connect group 1 and 2, make a cycle.
Steve Block44f0eee2011-05-26 01:26:41 +01004262 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004263 HandleScope scope(iso);
4264 CHECK(Local<Object>::New(iso, g1s1.handle)
4265 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4266 CHECK(Local<Object>::New(iso, g2s1.handle)
4267 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
Steve Block44f0eee2011-05-26 01:26:41 +01004268 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004269
4270 {
4271 UniqueId id1 = MakeUniqueId(g1s1.handle);
4272 UniqueId id2 = MakeUniqueId(g2s2.handle);
4273 iso->SetObjectGroupId(g1s1.handle, id1);
4274 iso->SetObjectGroupId(g1s2.handle, id1);
4275 iso->SetReference(g1s1.handle, g1c1.handle);
4276 iso->SetObjectGroupId(g2s1.handle, id2);
4277 iso->SetObjectGroupId(g2s2.handle, id2);
4278 iso->SetReferenceFromGroup(id2, g2c1.handle);
4279 }
4280 // Do a single full GC, ensure incremental marking is stopped.
4281 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4282 iso)->heap();
4283 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01004284
4285 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004286 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004287
4288 // Weaken the root.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004289 root.handle.SetWeak(&root, &WeakPointerCallback);
4290 // But make children strong roots---all the objects (except for children)
4291 // should be collectable now.
4292 g1c1.handle.ClearWeak();
4293 g2c1.handle.ClearWeak();
Steve Block44f0eee2011-05-26 01:26:41 +01004294
4295 // Groups are deleted, rebuild groups.
4296 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004297 UniqueId id1 = MakeUniqueId(g1s1.handle);
4298 UniqueId id2 = MakeUniqueId(g2s2.handle);
4299 iso->SetObjectGroupId(g1s1.handle, id1);
4300 iso->SetObjectGroupId(g1s2.handle, id1);
4301 iso->SetReference(g1s1.handle, g1c1.handle);
4302 iso->SetObjectGroupId(g2s1.handle, id2);
4303 iso->SetObjectGroupId(g2s2.handle, id2);
4304 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01004305 }
4306
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004307 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4308
4309 // All objects should be gone. 5 global handles in total.
4310 CHECK_EQ(5, counter.NumberOfWeakCalls());
4311
4312 // And now make children weak again and collect them.
4313 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4314 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4315
4316 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4317 CHECK_EQ(7, counter.NumberOfWeakCalls());
4318}
4319
4320
4321THREADED_TEST(ApiObjectGroupsCycle) {
4322 LocalContext env;
4323 v8::Isolate* iso = env->GetIsolate();
4324 HandleScope scope(iso);
4325
4326 WeakCallCounter counter(1234);
4327
4328 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4329 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4330 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4331 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4332 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4333 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4334 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4335 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4336
4337 {
4338 HandleScope scope(iso);
4339 g1s1.handle.Reset(iso, Object::New(iso));
4340 g1s2.handle.Reset(iso, Object::New(iso));
4341 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4342 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4343 CHECK(g1s1.handle.IsWeak());
4344 CHECK(g1s2.handle.IsWeak());
4345
4346 g2s1.handle.Reset(iso, Object::New(iso));
4347 g2s2.handle.Reset(iso, Object::New(iso));
4348 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4349 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4350 CHECK(g2s1.handle.IsWeak());
4351 CHECK(g2s2.handle.IsWeak());
4352
4353 g3s1.handle.Reset(iso, Object::New(iso));
4354 g3s2.handle.Reset(iso, Object::New(iso));
4355 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4356 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4357 CHECK(g3s1.handle.IsWeak());
4358 CHECK(g3s2.handle.IsWeak());
4359
4360 g4s1.handle.Reset(iso, Object::New(iso));
4361 g4s2.handle.Reset(iso, Object::New(iso));
4362 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4363 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4364 CHECK(g4s1.handle.IsWeak());
4365 CHECK(g4s2.handle.IsWeak());
4366 }
4367
4368 WeakCallCounterAndPersistent<Value> root(&counter);
4369 root.handle.Reset(iso, g1s1.handle); // make a root.
4370
4371 // Connect groups. We're building the following cycle:
4372 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4373 // groups.
4374 {
4375 UniqueId id1 = MakeUniqueId(g1s1.handle);
4376 UniqueId id2 = MakeUniqueId(g2s1.handle);
4377 UniqueId id3 = MakeUniqueId(g3s1.handle);
4378 UniqueId id4 = MakeUniqueId(g4s1.handle);
4379 iso->SetObjectGroupId(g1s1.handle, id1);
4380 iso->SetObjectGroupId(g1s2.handle, id1);
4381 iso->SetReferenceFromGroup(id1, g2s1.handle);
4382 iso->SetObjectGroupId(g2s1.handle, id2);
4383 iso->SetObjectGroupId(g2s2.handle, id2);
4384 iso->SetReferenceFromGroup(id2, g3s1.handle);
4385 iso->SetObjectGroupId(g3s1.handle, id3);
4386 iso->SetObjectGroupId(g3s2.handle, id3);
4387 iso->SetReferenceFromGroup(id3, g4s1.handle);
4388 iso->SetObjectGroupId(g4s1.handle, id4);
4389 iso->SetObjectGroupId(g4s2.handle, id4);
4390 iso->SetReferenceFromGroup(id4, g1s1.handle);
4391 }
4392 // Do a single full GC
4393 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4394 iso)->heap();
4395 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4396
4397 // All object should be alive.
4398 CHECK_EQ(0, counter.NumberOfWeakCalls());
4399
4400 // Weaken the root.
4401 root.handle.SetWeak(&root, &WeakPointerCallback);
4402
4403 // Groups are deleted, rebuild groups.
4404 {
4405 UniqueId id1 = MakeUniqueId(g1s1.handle);
4406 UniqueId id2 = MakeUniqueId(g2s1.handle);
4407 UniqueId id3 = MakeUniqueId(g3s1.handle);
4408 UniqueId id4 = MakeUniqueId(g4s1.handle);
4409 iso->SetObjectGroupId(g1s1.handle, id1);
4410 iso->SetObjectGroupId(g1s2.handle, id1);
4411 iso->SetReferenceFromGroup(id1, g2s1.handle);
4412 iso->SetObjectGroupId(g2s1.handle, id2);
4413 iso->SetObjectGroupId(g2s2.handle, id2);
4414 iso->SetReferenceFromGroup(id2, g3s1.handle);
4415 iso->SetObjectGroupId(g3s1.handle, id3);
4416 iso->SetObjectGroupId(g3s2.handle, id3);
4417 iso->SetReferenceFromGroup(id3, g4s1.handle);
4418 iso->SetObjectGroupId(g4s1.handle, id4);
4419 iso->SetObjectGroupId(g4s2.handle, id4);
4420 iso->SetReferenceFromGroup(id4, g1s1.handle);
4421 }
4422
4423 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4424
4425 // All objects should be gone. 9 global handles in total.
4426 CHECK_EQ(9, counter.NumberOfWeakCalls());
4427}
4428
4429
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004430THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
4431 LocalContext env;
4432 v8::Isolate* iso = env->GetIsolate();
4433 HandleScope scope(iso);
4434
4435 WeakCallCounter counter(1234);
4436
4437 WeakCallCounterAndPersistent<Value> weak_obj(&counter);
4438
4439 // Create a weak object that references a internalized string.
4440 {
4441 HandleScope scope(iso);
4442 weak_obj.handle.Reset(iso, Object::New(iso));
4443 weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
4444 CHECK(weak_obj.handle.IsWeak());
4445 Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
4446 v8_str("x"),
4447 String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
4448 }
4449 // Do a single full GC
4450 i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
4451 i::Heap* heap = i_iso->heap();
4452 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4453
4454 // We should have received the weak callback.
4455 CHECK_EQ(1, counter.NumberOfWeakCalls());
4456
4457 // Check that the string is still alive.
4458 {
4459 HandleScope scope(iso);
4460 i::MaybeHandle<i::String> magic_string =
4461 i::StringTable::LookupStringIfExists(
4462 i_iso,
4463 v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
4464 magic_string.Check();
4465 }
4466}
4467
4468
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004469// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4470// on the buildbots, so was made non-threaded for the time being.
4471TEST(ApiObjectGroupsCycleForScavenger) {
4472 i::FLAG_stress_compaction = false;
4473 i::FLAG_gc_global = false;
4474 LocalContext env;
4475 v8::Isolate* iso = env->GetIsolate();
4476 HandleScope scope(iso);
4477
4478 WeakCallCounter counter(1234);
4479
4480 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4481 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4482 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4483 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4484 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4485 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4486
4487 {
4488 HandleScope scope(iso);
4489 g1s1.handle.Reset(iso, Object::New(iso));
4490 g1s2.handle.Reset(iso, Object::New(iso));
4491 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4492 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4493
4494 g2s1.handle.Reset(iso, Object::New(iso));
4495 g2s2.handle.Reset(iso, Object::New(iso));
4496 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4497 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4498
4499 g3s1.handle.Reset(iso, Object::New(iso));
4500 g3s2.handle.Reset(iso, Object::New(iso));
4501 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4502 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4503 }
4504
4505 // Make a root.
4506 WeakCallCounterAndPersistent<Value> root(&counter);
4507 root.handle.Reset(iso, g1s1.handle);
4508 root.handle.MarkPartiallyDependent();
4509
4510 // Connect groups. We're building the following cycle:
4511 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4512 // groups.
4513 {
4514 HandleScope handle_scope(iso);
4515 g1s1.handle.MarkPartiallyDependent();
4516 g1s2.handle.MarkPartiallyDependent();
4517 g2s1.handle.MarkPartiallyDependent();
4518 g2s2.handle.MarkPartiallyDependent();
4519 g3s1.handle.MarkPartiallyDependent();
4520 g3s2.handle.MarkPartiallyDependent();
4521 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4522 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4523 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4524 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4525 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4526 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4527 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4528 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4529 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4530 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4531 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4532 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4533 }
4534
4535 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4536 iso)->heap();
4537 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4538
4539 // All objects should be alive.
4540 CHECK_EQ(0, counter.NumberOfWeakCalls());
4541
4542 // Weaken the root.
4543 root.handle.SetWeak(&root, &WeakPointerCallback);
4544 root.handle.MarkPartiallyDependent();
4545
4546 // Groups are deleted, rebuild groups.
4547 {
4548 HandleScope handle_scope(iso);
4549 g1s1.handle.MarkPartiallyDependent();
4550 g1s2.handle.MarkPartiallyDependent();
4551 g2s1.handle.MarkPartiallyDependent();
4552 g2s2.handle.MarkPartiallyDependent();
4553 g3s1.handle.MarkPartiallyDependent();
4554 g3s2.handle.MarkPartiallyDependent();
4555 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4556 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4557 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4558 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4559 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4560 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4561 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4562 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4563 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4564 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4565 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4566 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4567 }
4568
4569 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block44f0eee2011-05-26 01:26:41 +01004570
4571 // All objects should be gone. 7 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004572 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004573}
4574
4575
Steve Blocka7e24c12009-10-30 11:49:00 +00004576THREADED_TEST(ScriptException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004577 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004578 v8::HandleScope scope(env->GetIsolate());
4579 Local<Script> script = v8_compile("throw 'panama!';");
Steve Blocka7e24c12009-10-30 11:49:00 +00004580 v8::TryCatch try_catch;
4581 Local<Value> result = script->Run();
4582 CHECK(result.IsEmpty());
4583 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004584 String::Utf8Value exception_value(try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00004585 CHECK_EQ(*exception_value, "panama!");
4586}
4587
4588
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004589TEST(TryCatchCustomException) {
4590 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004591 v8::Isolate* isolate = env->GetIsolate();
4592 v8::HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004593 v8::TryCatch try_catch;
4594 CompileRun("function CustomError() { this.a = 'b'; }"
4595 "(function f() { throw new CustomError(); })();");
4596 CHECK(try_catch.HasCaught());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004597 CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
4598 v8_str("b")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004599}
4600
4601
Steve Blocka7e24c12009-10-30 11:49:00 +00004602bool message_received;
4603
4604
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004605static void check_message_0(v8::Handle<v8::Message> message,
4606 v8::Handle<Value> data) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004607 CHECK_EQ(5.76, data->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004608 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4609 CHECK(!message->IsSharedCrossOrigin());
Steve Blocka7e24c12009-10-30 11:49:00 +00004610 message_received = true;
4611}
4612
4613
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004614THREADED_TEST(MessageHandler0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004615 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004616 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004617 CHECK(!message_received);
Steve Blocka7e24c12009-10-30 11:49:00 +00004618 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004619 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4620 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
Steve Blocka7e24c12009-10-30 11:49:00 +00004621 script->Run();
4622 CHECK(message_received);
4623 // clear out the message listener
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004624 v8::V8::RemoveMessageListeners(check_message_0);
4625}
4626
4627
4628static void check_message_1(v8::Handle<v8::Message> message,
4629 v8::Handle<Value> data) {
4630 CHECK(data->IsNumber());
4631 CHECK_EQ(1337, data->Int32Value());
4632 CHECK(!message->IsSharedCrossOrigin());
4633 message_received = true;
4634}
4635
4636
4637TEST(MessageHandler1) {
4638 message_received = false;
4639 v8::HandleScope scope(CcTest::isolate());
4640 CHECK(!message_received);
4641 v8::V8::AddMessageListener(check_message_1);
4642 LocalContext context;
4643 CompileRun("throw 1337;");
4644 CHECK(message_received);
4645 // clear out the message listener
4646 v8::V8::RemoveMessageListeners(check_message_1);
4647}
4648
4649
4650static void check_message_2(v8::Handle<v8::Message> message,
4651 v8::Handle<Value> data) {
4652 LocalContext context;
4653 CHECK(data->IsObject());
4654 v8::Local<v8::Value> hidden_property =
4655 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4656 CHECK(v8_str("hidden value")->Equals(hidden_property));
4657 CHECK(!message->IsSharedCrossOrigin());
4658 message_received = true;
4659}
4660
4661
4662TEST(MessageHandler2) {
4663 message_received = false;
4664 v8::HandleScope scope(CcTest::isolate());
4665 CHECK(!message_received);
4666 v8::V8::AddMessageListener(check_message_2);
4667 LocalContext context;
4668 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4669 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4670 v8_str("hidden value"));
4671 context->Global()->Set(v8_str("error"), error);
4672 CompileRun("throw error;");
4673 CHECK(message_received);
4674 // clear out the message listener
4675 v8::V8::RemoveMessageListeners(check_message_2);
4676}
4677
4678
4679static void check_message_3(v8::Handle<v8::Message> message,
4680 v8::Handle<Value> data) {
4681 CHECK(message->IsSharedCrossOrigin());
4682 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4683 message_received = true;
4684}
4685
4686
4687TEST(MessageHandler3) {
4688 message_received = false;
4689 v8::Isolate* isolate = CcTest::isolate();
4690 v8::HandleScope scope(isolate);
4691 CHECK(!message_received);
4692 v8::V8::AddMessageListener(check_message_3);
4693 LocalContext context;
4694 v8::ScriptOrigin origin =
4695 v8::ScriptOrigin(v8_str("6.75"),
4696 v8::Integer::New(isolate, 1),
4697 v8::Integer::New(isolate, 2),
4698 v8::True(isolate));
4699 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4700 &origin);
4701 script->Run();
4702 CHECK(message_received);
4703 // clear out the message listener
4704 v8::V8::RemoveMessageListeners(check_message_3);
4705}
4706
4707
4708static void check_message_4(v8::Handle<v8::Message> message,
4709 v8::Handle<Value> data) {
4710 CHECK(!message->IsSharedCrossOrigin());
4711 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4712 message_received = true;
4713}
4714
4715
4716TEST(MessageHandler4) {
4717 message_received = false;
4718 v8::Isolate* isolate = CcTest::isolate();
4719 v8::HandleScope scope(isolate);
4720 CHECK(!message_received);
4721 v8::V8::AddMessageListener(check_message_4);
4722 LocalContext context;
4723 v8::ScriptOrigin origin =
4724 v8::ScriptOrigin(v8_str("6.75"),
4725 v8::Integer::New(isolate, 1),
4726 v8::Integer::New(isolate, 2),
4727 v8::False(isolate));
4728 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4729 &origin);
4730 script->Run();
4731 CHECK(message_received);
4732 // clear out the message listener
4733 v8::V8::RemoveMessageListeners(check_message_4);
4734}
4735
4736
4737static void check_message_5a(v8::Handle<v8::Message> message,
4738 v8::Handle<Value> data) {
4739 CHECK(message->IsSharedCrossOrigin());
4740 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4741 message_received = true;
4742}
4743
4744
4745static void check_message_5b(v8::Handle<v8::Message> message,
4746 v8::Handle<Value> data) {
4747 CHECK(!message->IsSharedCrossOrigin());
4748 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4749 message_received = true;
4750}
4751
4752
4753TEST(MessageHandler5) {
4754 message_received = false;
4755 v8::Isolate* isolate = CcTest::isolate();
4756 v8::HandleScope scope(isolate);
4757 CHECK(!message_received);
4758 v8::V8::AddMessageListener(check_message_5a);
4759 LocalContext context;
4760 v8::ScriptOrigin origin =
4761 v8::ScriptOrigin(v8_str("6.75"),
4762 v8::Integer::New(isolate, 1),
4763 v8::Integer::New(isolate, 2),
4764 v8::True(isolate));
4765 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4766 &origin);
4767 script->Run();
4768 CHECK(message_received);
4769 // clear out the message listener
4770 v8::V8::RemoveMessageListeners(check_message_5a);
4771
4772 message_received = false;
4773 v8::V8::AddMessageListener(check_message_5b);
4774 origin =
4775 v8::ScriptOrigin(v8_str("6.75"),
4776 v8::Integer::New(isolate, 1),
4777 v8::Integer::New(isolate, 2),
4778 v8::False(isolate));
4779 script = Script::Compile(v8_str("throw 'error'"),
4780 &origin);
4781 script->Run();
4782 CHECK(message_received);
4783 // clear out the message listener
4784 v8::V8::RemoveMessageListeners(check_message_5b);
Steve Blocka7e24c12009-10-30 11:49:00 +00004785}
4786
4787
4788THREADED_TEST(GetSetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004789 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004790 v8::Isolate* isolate = context->GetIsolate();
4791 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004792 context->Global()->Set(v8_str("foo"), v8_num(14));
4793 context->Global()->Set(v8_str("12"), v8_num(92));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004794 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
Steve Blocka7e24c12009-10-30 11:49:00 +00004795 context->Global()->Set(v8_num(13), v8_num(56));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004796 Local<Value> foo = CompileRun("this.foo");
Steve Blocka7e24c12009-10-30 11:49:00 +00004797 CHECK_EQ(14, foo->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004798 Local<Value> twelve = CompileRun("this[12]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004799 CHECK_EQ(92, twelve->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004800 Local<Value> sixteen = CompileRun("this[16]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004801 CHECK_EQ(32, sixteen->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004802 Local<Value> thirteen = CompileRun("this[13]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004803 CHECK_EQ(56, thirteen->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004804 CHECK_EQ(92,
4805 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004806 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4807 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004808 CHECK_EQ(32,
4809 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004810 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4811 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004812 CHECK_EQ(56,
4813 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004814 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4815 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4816}
4817
4818
4819THREADED_TEST(PropertyAttributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004820 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004821 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004822 // none
4823 Local<String> prop = v8_str("none");
4824 context->Global()->Set(prop, v8_num(7));
4825 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00004826 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004827 prop = v8_str("read_only");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004828 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +00004829 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004830 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004831 CompileRun("read_only = 9");
Steve Blocka7e24c12009-10-30 11:49:00 +00004832 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4833 context->Global()->Set(prop, v8_num(10));
4834 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4835 // dont-delete
4836 prop = v8_str("dont_delete");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004837 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +00004838 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004839 CompileRun("delete dont_delete");
Steve Blocka7e24c12009-10-30 11:49:00 +00004840 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004841 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4842 // dont-enum
4843 prop = v8_str("dont_enum");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004844 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004845 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4846 // absent
4847 prop = v8_str("absent");
4848 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4849 Local<Value> fake_prop = v8_num(1);
4850 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4851 // exception
4852 TryCatch try_catch;
4853 Local<Value> exception =
4854 CompileRun("({ toString: function() { throw 'exception';} })");
4855 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4856 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004857 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004858 CHECK_EQ("exception", *exception_value);
4859 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00004860}
4861
4862
4863THREADED_TEST(Array) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004864 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004865 v8::HandleScope scope(context->GetIsolate());
4866 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004867 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004868 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00004869 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01004870 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00004871 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01004872 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00004873 CHECK_EQ(3, array->Length());
4874 CHECK(!array->Has(0));
4875 CHECK(!array->Has(1));
4876 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01004877 CHECK_EQ(7, array->Get(2)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004878 Local<Value> obj = CompileRun("[1, 2, 3]");
Steve Block6ded16b2010-05-10 14:33:55 +01004879 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004880 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004881 CHECK_EQ(1, arr->Get(0)->Int32Value());
4882 CHECK_EQ(2, arr->Get(1)->Int32Value());
4883 CHECK_EQ(3, arr->Get(2)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004884 array = v8::Array::New(context->GetIsolate(), 27);
Steve Block44f0eee2011-05-26 01:26:41 +01004885 CHECK_EQ(27, array->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004886 array = v8::Array::New(context->GetIsolate(), -27);
Steve Block44f0eee2011-05-26 01:26:41 +01004887 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004888}
4889
4890
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004891void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4892 v8::EscapableHandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004893 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004894 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004895 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01004896 result->Set(i, args[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004897 args.GetReturnValue().Set(scope.Escape(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00004898}
4899
4900
4901THREADED_TEST(Vector) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004902 v8::Isolate* isolate = CcTest::isolate();
4903 v8::HandleScope scope(isolate);
4904 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4905 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
Steve Blocka7e24c12009-10-30 11:49:00 +00004906 LocalContext context(0, global);
4907
4908 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01004909 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004910 CHECK_EQ(0, a0->Length());
4911
4912 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01004913 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004914 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004915 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004916
4917 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01004918 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004919 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004920 CHECK_EQ(12, a2->Get(0)->Int32Value());
4921 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004922
4923 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01004924 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004925 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004926 CHECK_EQ(14, a3->Get(0)->Int32Value());
4927 CHECK_EQ(15, a3->Get(1)->Int32Value());
4928 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004929
4930 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01004931 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004932 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004933 CHECK_EQ(17, a4->Get(0)->Int32Value());
4934 CHECK_EQ(18, a4->Get(1)->Int32Value());
4935 CHECK_EQ(19, a4->Get(2)->Int32Value());
4936 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004937}
4938
4939
4940THREADED_TEST(FunctionCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004941 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004942 v8::Isolate* isolate = context->GetIsolate();
4943 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004944 CompileRun(
4945 "function Foo() {"
4946 " var result = [];"
4947 " for (var i = 0; i < arguments.length; i++) {"
4948 " result.push(arguments[i]);"
4949 " }"
4950 " return result;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004951 "}"
4952 "function ReturnThisSloppy() {"
4953 " return this;"
4954 "}"
4955 "function ReturnThisStrict() {"
4956 " 'use strict';"
4957 " return this;"
Steve Blocka7e24c12009-10-30 11:49:00 +00004958 "}");
4959 Local<Function> Foo =
4960 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004961 Local<Function> ReturnThisSloppy =
4962 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4963 Local<Function> ReturnThisStrict =
4964 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
Steve Blocka7e24c12009-10-30 11:49:00 +00004965
4966 v8::Handle<Value>* args0 = NULL;
4967 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4968 CHECK_EQ(0, a0->Length());
4969
4970 v8::Handle<Value> args1[] = { v8_num(1.1) };
4971 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4972 CHECK_EQ(1, a1->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004973 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004974
4975 v8::Handle<Value> args2[] = { v8_num(2.2),
4976 v8_num(3.3) };
4977 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4978 CHECK_EQ(2, a2->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004979 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4980 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004981
4982 v8::Handle<Value> args3[] = { v8_num(4.4),
4983 v8_num(5.5),
4984 v8_num(6.6) };
4985 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4986 CHECK_EQ(3, a3->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004987 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4988 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4989 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004990
4991 v8::Handle<Value> args4[] = { v8_num(7.7),
4992 v8_num(8.8),
4993 v8_num(9.9),
4994 v8_num(10.11) };
4995 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4996 CHECK_EQ(4, a4->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004997 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4998 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4999 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5000 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005001
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005002 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
5003 CHECK(r1->StrictEquals(context->Global()));
5004 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
5005 CHECK(r2->StrictEquals(context->Global()));
5006 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
5007 CHECK(r3->IsNumberObject());
5008 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5009 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
5010 CHECK(r4->IsStringObject());
5011 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5012 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
5013 CHECK(r5->IsBooleanObject());
5014 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
Steve Blocka7e24c12009-10-30 11:49:00 +00005015
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005016 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
5017 CHECK(r6->IsUndefined());
5018 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
5019 CHECK(r7->IsNull());
5020 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
5021 CHECK(r8->StrictEquals(v8_num(42)));
5022 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
5023 CHECK(r9->StrictEquals(v8_str("hello")));
5024 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
5025 CHECK(r10->StrictEquals(v8::True(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00005026}
5027
5028
5029THREADED_TEST(ConstructCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005030 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005031 v8::Isolate* isolate = context->GetIsolate();
5032 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005033 CompileRun(
5034 "function Foo() {"
5035 " var result = [];"
5036 " for (var i = 0; i < arguments.length; i++) {"
5037 " result.push(arguments[i]);"
5038 " }"
5039 " return result;"
5040 "}");
5041 Local<Function> Foo =
5042 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
5043
5044 v8::Handle<Value>* args0 = NULL;
5045 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
5046 CHECK_EQ(0, a0->Length());
5047
5048 v8::Handle<Value> args1[] = { v8_num(1.1) };
5049 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
5050 CHECK_EQ(1, a1->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005051 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005052
5053 v8::Handle<Value> args2[] = { v8_num(2.2),
5054 v8_num(3.3) };
5055 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
5056 CHECK_EQ(2, a2->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005057 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
5058 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005059
5060 v8::Handle<Value> args3[] = { v8_num(4.4),
5061 v8_num(5.5),
5062 v8_num(6.6) };
5063 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
5064 CHECK_EQ(3, a3->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005065 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
5066 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
5067 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005068
5069 v8::Handle<Value> args4[] = { v8_num(7.7),
5070 v8_num(8.8),
5071 v8_num(9.9),
5072 v8_num(10.11) };
5073 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
5074 CHECK_EQ(4, a4->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005075 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
5076 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
5077 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5078 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005079}
5080
5081
5082static void CheckUncle(v8::TryCatch* try_catch) {
5083 CHECK(try_catch->HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005084 String::Utf8Value str_value(try_catch->Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00005085 CHECK_EQ(*str_value, "uncle?");
5086 try_catch->Reset();
5087}
5088
5089
Steve Block6ded16b2010-05-10 14:33:55 +01005090THREADED_TEST(ConversionNumber) {
Steve Block6ded16b2010-05-10 14:33:55 +01005091 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005092 v8::Isolate* isolate = env->GetIsolate();
5093 v8::HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01005094 // Very large number.
5095 CompileRun("var obj = Math.pow(2,32) * 1237;");
5096 Local<Value> obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005097 CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
5098 CHECK_EQ(0, obj->ToInt32(isolate)->Value());
5099 CHECK(0u ==
5100 obj->ToUint32(isolate)->Value()); // NOLINT - no CHECK_EQ for unsigned.
Steve Block6ded16b2010-05-10 14:33:55 +01005101 // Large number.
5102 CompileRun("var obj = -1234567890123;");
5103 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005104 CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
5105 CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
5106 CHECK(2382691125u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005107 // Small positive integer.
5108 CompileRun("var obj = 42;");
5109 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005110 CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
5111 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5112 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005113 // Negative integer.
5114 CompileRun("var obj = -37;");
5115 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005116 CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
5117 CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
5118 CHECK(4294967259u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005119 // Positive non-int32 integer.
5120 CompileRun("var obj = 0x81234567;");
5121 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005122 CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
5123 CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
5124 CHECK(2166572391u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005125 // Fraction.
5126 CompileRun("var obj = 42.3;");
5127 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005128 CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
5129 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5130 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005131 // Large negative fraction.
5132 CompileRun("var obj = -5726623061.75;");
5133 obj = env->Global()->Get(v8_str("obj"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005134 CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
5135 CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
5136 CHECK(2863311531u == obj->ToUint32(isolate)->Value()); // NOLINT
Steve Block6ded16b2010-05-10 14:33:55 +01005137}
5138
5139
5140THREADED_TEST(isNumberType) {
Steve Block6ded16b2010-05-10 14:33:55 +01005141 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005142 v8::HandleScope scope(env->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01005143 // Very large number.
5144 CompileRun("var obj = Math.pow(2,32) * 1237;");
5145 Local<Value> obj = env->Global()->Get(v8_str("obj"));
5146 CHECK(!obj->IsInt32());
5147 CHECK(!obj->IsUint32());
5148 // Large negative number.
5149 CompileRun("var obj = -1234567890123;");
5150 obj = env->Global()->Get(v8_str("obj"));
5151 CHECK(!obj->IsInt32());
5152 CHECK(!obj->IsUint32());
5153 // Small positive integer.
5154 CompileRun("var obj = 42;");
5155 obj = env->Global()->Get(v8_str("obj"));
5156 CHECK(obj->IsInt32());
5157 CHECK(obj->IsUint32());
5158 // Negative integer.
5159 CompileRun("var obj = -37;");
5160 obj = env->Global()->Get(v8_str("obj"));
5161 CHECK(obj->IsInt32());
5162 CHECK(!obj->IsUint32());
5163 // Positive non-int32 integer.
5164 CompileRun("var obj = 0x81234567;");
5165 obj = env->Global()->Get(v8_str("obj"));
5166 CHECK(!obj->IsInt32());
5167 CHECK(obj->IsUint32());
5168 // Fraction.
5169 CompileRun("var obj = 42.3;");
5170 obj = env->Global()->Get(v8_str("obj"));
5171 CHECK(!obj->IsInt32());
5172 CHECK(!obj->IsUint32());
5173 // Large negative fraction.
5174 CompileRun("var obj = -5726623061.75;");
5175 obj = env->Global()->Get(v8_str("obj"));
5176 CHECK(!obj->IsInt32());
5177 CHECK(!obj->IsUint32());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005178 // Positive zero
5179 CompileRun("var obj = 0.0;");
5180 obj = env->Global()->Get(v8_str("obj"));
5181 CHECK(obj->IsInt32());
5182 CHECK(obj->IsUint32());
5183 // Positive zero
5184 CompileRun("var obj = -0.0;");
5185 obj = env->Global()->Get(v8_str("obj"));
5186 CHECK(!obj->IsInt32());
5187 CHECK(!obj->IsUint32());
Steve Block6ded16b2010-05-10 14:33:55 +01005188}
5189
5190
Steve Blocka7e24c12009-10-30 11:49:00 +00005191THREADED_TEST(ConversionException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005192 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005193 v8::Isolate* isolate = env->GetIsolate();
5194 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005195 CompileRun(
5196 "function TestClass() { };"
5197 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5198 "var obj = new TestClass();");
5199 Local<Value> obj = env->Global()->Get(v8_str("obj"));
5200
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005201 v8::TryCatch try_catch(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005202
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005203 Local<Value> to_string_result = obj->ToString(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005204 CHECK(to_string_result.IsEmpty());
5205 CheckUncle(&try_catch);
5206
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005207 Local<Value> to_number_result = obj->ToNumber(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005208 CHECK(to_number_result.IsEmpty());
5209 CheckUncle(&try_catch);
5210
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005211 Local<Value> to_integer_result = obj->ToInteger(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005212 CHECK(to_integer_result.IsEmpty());
5213 CheckUncle(&try_catch);
5214
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005215 Local<Value> to_uint32_result = obj->ToUint32(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005216 CHECK(to_uint32_result.IsEmpty());
5217 CheckUncle(&try_catch);
5218
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005219 Local<Value> to_int32_result = obj->ToInt32(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005220 CHECK(to_int32_result.IsEmpty());
5221 CheckUncle(&try_catch);
5222
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005223 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005224 CHECK(to_object_result.IsEmpty());
5225 CHECK(try_catch.HasCaught());
5226 try_catch.Reset();
5227
5228 int32_t int32_value = obj->Int32Value();
5229 CHECK_EQ(0, int32_value);
5230 CheckUncle(&try_catch);
5231
5232 uint32_t uint32_value = obj->Uint32Value();
5233 CHECK_EQ(0, uint32_value);
5234 CheckUncle(&try_catch);
5235
5236 double number_value = obj->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005237 CHECK_NE(0, std::isnan(number_value));
Steve Blocka7e24c12009-10-30 11:49:00 +00005238 CheckUncle(&try_catch);
5239
5240 int64_t integer_value = obj->IntegerValue();
5241 CHECK_EQ(0.0, static_cast<double>(integer_value));
5242 CheckUncle(&try_catch);
5243}
5244
5245
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005246void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005247 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005248 args.GetIsolate()->ThrowException(v8_str("konto"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005249}
5250
5251
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005252void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5253 if (args.Length() < 1) {
5254 args.GetReturnValue().Set(false);
5255 return;
5256 }
5257 v8::HandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005258 v8::TryCatch try_catch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005259 Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +00005260 CHECK(!try_catch.HasCaught() || result.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005261 args.GetReturnValue().Set(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00005262}
5263
5264
5265THREADED_TEST(APICatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005266 v8::Isolate* isolate = CcTest::isolate();
5267 v8::HandleScope scope(isolate);
5268 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005269 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005270 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 LocalContext context(0, templ);
5272 CompileRun(
5273 "var thrown = false;"
5274 "try {"
5275 " ThrowFromC();"
5276 "} catch (e) {"
5277 " thrown = true;"
5278 "}");
5279 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5280 CHECK(thrown->BooleanValue());
5281}
5282
5283
5284THREADED_TEST(APIThrowTryCatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005285 v8::Isolate* isolate = CcTest::isolate();
5286 v8::HandleScope scope(isolate);
5287 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005288 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005289 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005290 LocalContext context(0, templ);
5291 v8::TryCatch try_catch;
5292 CompileRun("ThrowFromC();");
5293 CHECK(try_catch.HasCaught());
5294}
5295
5296
5297// Test that a try-finally block doesn't shadow a try-catch block
5298// when setting up an external handler.
5299//
5300// BUG(271): Some of the exception propagation does not work on the
5301// ARM simulator because the simulator separates the C++ stack and the
5302// JS stack. This test therefore fails on the simulator. The test is
5303// not threaded to allow the threading tests to run on the simulator.
5304TEST(TryCatchInTryFinally) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005305 v8::Isolate* isolate = CcTest::isolate();
5306 v8::HandleScope scope(isolate);
5307 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005308 templ->Set(v8_str("CCatcher"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005309 v8::FunctionTemplate::New(isolate, CCatcher));
Steve Blocka7e24c12009-10-30 11:49:00 +00005310 LocalContext context(0, templ);
5311 Local<Value> result = CompileRun("try {"
5312 " try {"
5313 " CCatcher('throw 7;');"
5314 " } finally {"
5315 " }"
5316 "} catch (e) {"
5317 "}");
5318 CHECK(result->IsTrue());
5319}
5320
5321
Ben Murdochb8e0da22011-05-16 14:20:40 +01005322static void check_reference_error_message(
5323 v8::Handle<v8::Message> message,
5324 v8::Handle<v8::Value> data) {
5325 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5326 CHECK(message->Get()->Equals(v8_str(reference_error)));
5327}
5328
5329
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005330static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block1e0659c2011-05-24 12:43:12 +01005331 ApiTestFuzzer::Fuzz();
5332 CHECK(false);
Steve Block1e0659c2011-05-24 12:43:12 +01005333}
5334
5335
5336// Test that overwritten methods are not invoked on uncaught exception
5337// formatting. However, they are invoked when performing normal error
5338// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01005339TEST(APIThrowMessageOverwrittenToString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005340 v8::Isolate* isolate = CcTest::isolate();
5341 v8::HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005342 v8::V8::AddMessageListener(check_reference_error_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005343 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5344 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
Steve Block1e0659c2011-05-24 12:43:12 +01005345 LocalContext context(NULL, templ);
5346 CompileRun("asdf;");
5347 CompileRun("var limit = {};"
5348 "limit.valueOf = fail;"
5349 "Error.stackTraceLimit = limit;");
5350 CompileRun("asdf");
5351 CompileRun("Array.prototype.pop = fail;");
5352 CompileRun("Object.prototype.hasOwnProperty = fail;");
5353 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5354 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5355 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01005356 CompileRun("ReferenceError.prototype.toString ="
5357 " function() { return 'Whoops' }");
5358 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01005359 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5360 CompileRun("asdf;");
5361 CompileRun("ReferenceError.prototype.constructor = void 0;");
5362 CompileRun("asdf;");
5363 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5364 CompileRun("asdf;");
5365 CompileRun("ReferenceError.prototype = new Object();");
5366 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01005367 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5368 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01005369 CompileRun("ReferenceError.prototype.constructor = new Object();"
5370 "ReferenceError.prototype.constructor.name = 1;"
5371 "Number.prototype.toString = function() { return 'Whoops'; };"
5372 "ReferenceError.prototype.toString = Object.prototype.toString;");
5373 CompileRun("asdf;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005374 v8::V8::RemoveMessageListeners(check_reference_error_message);
5375}
5376
5377
5378static void check_custom_error_tostring(
5379 v8::Handle<v8::Message> message,
5380 v8::Handle<v8::Value> data) {
5381 const char* uncaught_error = "Uncaught MyError toString";
5382 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5383}
5384
5385
5386TEST(CustomErrorToString) {
5387 LocalContext context;
5388 v8::HandleScope scope(context->GetIsolate());
5389 v8::V8::AddMessageListener(check_custom_error_tostring);
5390 CompileRun(
5391 "function MyError(name, message) { "
5392 " this.name = name; "
5393 " this.message = message; "
5394 "} "
5395 "MyError.prototype = Object.create(Error.prototype); "
5396 "MyError.prototype.toString = function() { "
5397 " return 'MyError toString'; "
5398 "}; "
5399 "throw new MyError('my name', 'my message'); ");
5400 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5401}
5402
5403
5404static void check_custom_error_message(
5405 v8::Handle<v8::Message> message,
5406 v8::Handle<v8::Value> data) {
5407 const char* uncaught_error = "Uncaught MyError: my message";
5408 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5409 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5410}
5411
5412
5413TEST(CustomErrorMessage) {
5414 LocalContext context;
5415 v8::HandleScope scope(context->GetIsolate());
5416 v8::V8::AddMessageListener(check_custom_error_message);
5417
5418 // Handlebars.
5419 CompileRun(
5420 "function MyError(msg) { "
5421 " this.name = 'MyError'; "
5422 " this.message = msg; "
5423 "} "
5424 "MyError.prototype = new Error(); "
5425 "throw new MyError('my message'); ");
5426
5427 // Closure.
5428 CompileRun(
5429 "function MyError(msg) { "
5430 " this.name = 'MyError'; "
5431 " this.message = msg; "
5432 "} "
5433 "inherits = function(childCtor, parentCtor) { "
5434 " function tempCtor() {}; "
5435 " tempCtor.prototype = parentCtor.prototype; "
5436 " childCtor.superClass_ = parentCtor.prototype; "
5437 " childCtor.prototype = new tempCtor(); "
5438 " childCtor.prototype.constructor = childCtor; "
5439 "}; "
5440 "inherits(MyError, Error); "
5441 "throw new MyError('my message'); ");
5442
5443 // Object.create.
5444 CompileRun(
5445 "function MyError(msg) { "
5446 " this.name = 'MyError'; "
5447 " this.message = msg; "
5448 "} "
5449 "MyError.prototype = Object.create(Error.prototype); "
5450 "throw new MyError('my message'); ");
5451
5452 v8::V8::RemoveMessageListeners(check_custom_error_message);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005453}
5454
5455
Steve Blocka7e24c12009-10-30 11:49:00 +00005456static void receive_message(v8::Handle<v8::Message> message,
5457 v8::Handle<v8::Value> data) {
5458 message->Get();
5459 message_received = true;
5460}
5461
5462
5463TEST(APIThrowMessage) {
5464 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005465 v8::Isolate* isolate = CcTest::isolate();
5466 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005467 v8::V8::AddMessageListener(receive_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005468 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005469 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005470 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005471 LocalContext context(0, templ);
5472 CompileRun("ThrowFromC();");
5473 CHECK(message_received);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005474 v8::V8::RemoveMessageListeners(receive_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00005475}
5476
5477
5478TEST(APIThrowMessageAndVerboseTryCatch) {
5479 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005480 v8::Isolate* isolate = CcTest::isolate();
5481 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005482 v8::V8::AddMessageListener(receive_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005483 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005484 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005485 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005486 LocalContext context(0, templ);
5487 v8::TryCatch try_catch;
5488 try_catch.SetVerbose(true);
5489 Local<Value> result = CompileRun("ThrowFromC();");
5490 CHECK(try_catch.HasCaught());
5491 CHECK(result.IsEmpty());
5492 CHECK(message_received);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005493 v8::V8::RemoveMessageListeners(receive_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00005494}
5495
5496
Ben Murdoch8b112d22011-06-08 16:22:53 +01005497TEST(APIStackOverflowAndVerboseTryCatch) {
5498 message_received = false;
Ben Murdoch8b112d22011-06-08 16:22:53 +01005499 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005500 v8::HandleScope scope(context->GetIsolate());
5501 v8::V8::AddMessageListener(receive_message);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005502 v8::TryCatch try_catch;
5503 try_catch.SetVerbose(true);
5504 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5505 CHECK(try_catch.HasCaught());
5506 CHECK(result.IsEmpty());
5507 CHECK(message_received);
5508 v8::V8::RemoveMessageListeners(receive_message);
5509}
5510
5511
Steve Blocka7e24c12009-10-30 11:49:00 +00005512THREADED_TEST(ExternalScriptException) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005513 v8::Isolate* isolate = CcTest::isolate();
5514 v8::HandleScope scope(isolate);
5515 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005516 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005517 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005518 LocalContext context(0, templ);
5519
5520 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005521 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
Steve Blocka7e24c12009-10-30 11:49:00 +00005522 CHECK(result.IsEmpty());
5523 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005524 String::Utf8Value exception_value(try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00005525 CHECK_EQ("konto", *exception_value);
5526}
5527
5528
5529
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005530void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005531 ApiTestFuzzer::Fuzz();
5532 CHECK_EQ(4, args.Length());
5533 int count = args[0]->Int32Value();
5534 int cInterval = args[2]->Int32Value();
5535 if (count == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005536 args.GetIsolate()->ThrowException(v8_str("FromC"));
5537 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005538 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005539 Local<v8::Object> global =
5540 args.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00005541 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5542 v8::Handle<Value> argv[] = { v8_num(count - 1),
5543 args[1],
5544 args[2],
5545 args[3] };
5546 if (count % cInterval == 0) {
5547 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01005548 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00005549 int expected = args[3]->Int32Value();
5550 if (try_catch.HasCaught()) {
5551 CHECK_EQ(expected, count);
5552 CHECK(result.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005553 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00005554 } else {
5555 CHECK_NE(expected, count);
5556 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005557 args.GetReturnValue().Set(result);
5558 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005559 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005560 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5561 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005562 }
5563 }
5564}
5565
5566
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005567void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005568 ApiTestFuzzer::Fuzz();
5569 CHECK_EQ(3, args.Length());
5570 bool equality = args[0]->BooleanValue();
5571 int count = args[1]->Int32Value();
5572 int expected = args[2]->Int32Value();
5573 if (equality) {
5574 CHECK_EQ(count, expected);
5575 } else {
5576 CHECK_NE(count, expected);
5577 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005578}
5579
5580
5581THREADED_TEST(EvalInTryFinally) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005582 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005583 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005584 v8::TryCatch try_catch;
5585 CompileRun("(function() {"
5586 " try {"
5587 " eval('asldkf (*&^&*^');"
5588 " } finally {"
5589 " return;"
5590 " }"
5591 "})()");
5592 CHECK(!try_catch.HasCaught());
5593}
5594
5595
5596// This test works by making a stack of alternating JavaScript and C
5597// activations. These activations set up exception handlers with regular
5598// intervals, one interval for C activations and another for JavaScript
5599// activations. When enough activations have been created an exception is
5600// thrown and we check that the right activation catches the exception and that
5601// no other activations do. The right activation is always the topmost one with
5602// a handler, regardless of whether it is in JavaScript or C.
5603//
5604// The notation used to describe a test case looks like this:
5605//
5606// *JS[4] *C[3] @JS[2] C[1] JS[0]
5607//
5608// Each entry is an activation, either JS or C. The index is the count at that
5609// level. Stars identify activations with exception handlers, the @ identifies
5610// the exception handler that should catch the exception.
5611//
5612// BUG(271): Some of the exception propagation does not work on the
5613// ARM simulator because the simulator separates the C++ stack and the
5614// JS stack. This test therefore fails on the simulator. The test is
5615// not threaded to allow the threading tests to run on the simulator.
5616TEST(ExceptionOrder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005617 v8::Isolate* isolate = CcTest::isolate();
5618 v8::HandleScope scope(isolate);
5619 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5620 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
Steve Blocka7e24c12009-10-30 11:49:00 +00005621 templ->Set(v8_str("CThrowCountDown"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005622 v8::FunctionTemplate::New(isolate, CThrowCountDown));
Steve Blocka7e24c12009-10-30 11:49:00 +00005623 LocalContext context(0, templ);
5624 CompileRun(
5625 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5626 " if (count == 0) throw 'FromJS';"
5627 " if (count % jsInterval == 0) {"
5628 " try {"
5629 " var value = CThrowCountDown(count - 1,"
5630 " jsInterval,"
5631 " cInterval,"
5632 " expected);"
5633 " check(false, count, expected);"
5634 " return value;"
5635 " } catch (e) {"
5636 " check(true, count, expected);"
5637 " }"
5638 " } else {"
5639 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5640 " }"
5641 "}");
5642 Local<Function> fun =
5643 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5644
5645 const int argc = 4;
5646 // count jsInterval cInterval expected
5647
5648 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5649 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5650 fun->Call(fun, argc, a0);
5651
5652 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5653 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5654 fun->Call(fun, argc, a1);
5655
5656 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5657 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5658 fun->Call(fun, argc, a2);
5659
5660 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5661 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5662 fun->Call(fun, argc, a3);
5663
5664 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5665 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5666 fun->Call(fun, argc, a4);
5667
5668 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5669 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5670 fun->Call(fun, argc, a5);
5671}
5672
5673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005674void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005675 ApiTestFuzzer::Fuzz();
5676 CHECK_EQ(1, args.Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005677 args.GetIsolate()->ThrowException(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00005678}
5679
5680
5681THREADED_TEST(ThrowValues) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005682 v8::Isolate* isolate = CcTest::isolate();
5683 v8::HandleScope scope(isolate);
5684 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5685 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
Steve Blocka7e24c12009-10-30 11:49:00 +00005686 LocalContext context(0, templ);
5687 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5688 "function Run(obj) {"
5689 " try {"
5690 " Throw(obj);"
5691 " } catch (e) {"
5692 " return e;"
5693 " }"
5694 " return 'no exception';"
5695 "}"
5696 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5697 CHECK_EQ(5, result->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005698 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5699 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5700 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5701 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5702 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5703 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5704 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00005705}
5706
5707
5708THREADED_TEST(CatchZero) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005709 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005710 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005711 v8::TryCatch try_catch;
5712 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005713 CompileRun("throw 10");
Steve Blocka7e24c12009-10-30 11:49:00 +00005714 CHECK(try_catch.HasCaught());
5715 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5716 try_catch.Reset();
5717 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005718 CompileRun("throw 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00005719 CHECK(try_catch.HasCaught());
5720 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5721}
5722
5723
5724THREADED_TEST(CatchExceptionFromWith) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005725 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005726 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005727 v8::TryCatch try_catch;
5728 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005729 CompileRun("var o = {}; with (o) { throw 42; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00005730 CHECK(try_catch.HasCaught());
5731}
5732
5733
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005734THREADED_TEST(TryCatchAndFinallyHidingException) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005735 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005736 v8::HandleScope scope(context->GetIsolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005737 v8::TryCatch try_catch;
5738 CHECK(!try_catch.HasCaught());
5739 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5740 CompileRun("f({toString: function() { throw 42; }});");
5741 CHECK(!try_catch.HasCaught());
5742}
5743
5744
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005745void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005746 v8::TryCatch try_catch;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005747}
5748
5749
5750THREADED_TEST(TryCatchAndFinally) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005751 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005752 v8::Isolate* isolate = context->GetIsolate();
5753 v8::HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005754 context->Global()->Set(
5755 v8_str("native_with_try_catch"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005756 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005757 v8::TryCatch try_catch;
5758 CHECK(!try_catch.HasCaught());
5759 CompileRun(
5760 "try {\n"
5761 " throw new Error('a');\n"
5762 "} finally {\n"
5763 " native_with_try_catch();\n"
5764 "}\n");
5765 CHECK(try_catch.HasCaught());
5766}
5767
5768
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005769static void TryCatchNested1Helper(int depth) {
5770 if (depth > 0) {
5771 v8::TryCatch try_catch;
5772 try_catch.SetVerbose(true);
5773 TryCatchNested1Helper(depth - 1);
5774 CHECK(try_catch.HasCaught());
5775 try_catch.ReThrow();
5776 } else {
5777 CcTest::isolate()->ThrowException(v8_str("E1"));
5778 }
5779}
5780
5781
5782static void TryCatchNested2Helper(int depth) {
5783 if (depth > 0) {
5784 v8::TryCatch try_catch;
5785 try_catch.SetVerbose(true);
5786 TryCatchNested2Helper(depth - 1);
5787 CHECK(try_catch.HasCaught());
5788 try_catch.ReThrow();
5789 } else {
5790 CompileRun("throw 'E2';");
5791 }
5792}
5793
5794
5795TEST(TryCatchNested) {
5796 v8::V8::Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00005797 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005798 v8::HandleScope scope(context->GetIsolate());
5799
5800 {
5801 // Test nested try-catch with a native throw in the end.
5802 v8::TryCatch try_catch;
5803 TryCatchNested1Helper(5);
5804 CHECK(try_catch.HasCaught());
5805 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5806 }
5807
5808 {
5809 // Test nested try-catch with a JavaScript throw in the end.
5810 v8::TryCatch try_catch;
5811 TryCatchNested2Helper(5);
5812 CHECK(try_catch.HasCaught());
5813 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5814 }
5815}
5816
5817
5818void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5819 CHECK(try_catch->HasCaught());
5820 Handle<Message> message = try_catch->Message();
5821 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5822 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5823 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5824 "Uncaught Error: a"));
5825 CHECK_EQ(1, message->GetLineNumber());
5826 CHECK_EQ(6, message->GetStartColumn());
5827}
5828
5829
5830void TryCatchMixedNestingHelper(
5831 const v8::FunctionCallbackInfo<v8::Value>& args) {
5832 ApiTestFuzzer::Fuzz();
5833 v8::TryCatch try_catch;
5834 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5835 CHECK(try_catch.HasCaught());
5836 TryCatchMixedNestingCheck(&try_catch);
5837 try_catch.ReThrow();
5838}
5839
5840
5841// This test ensures that an outer TryCatch in the following situation:
5842// C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5843// does not clobber the Message object generated for the inner TryCatch.
5844// This exercises the ability of TryCatch.ReThrow() to restore the
5845// inner pending Message before throwing the exception again.
5846TEST(TryCatchMixedNesting) {
5847 v8::Isolate* isolate = CcTest::isolate();
5848 v8::HandleScope scope(isolate);
5849 v8::V8::Initialize();
5850 v8::TryCatch try_catch;
5851 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5852 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5853 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5854 LocalContext context(0, templ);
5855 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5856 TryCatchMixedNestingCheck(&try_catch);
5857}
5858
5859
5860void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5861 ApiTestFuzzer::Fuzz();
5862 v8::TryCatch try_catch;
5863 args.GetIsolate()->ThrowException(v8_str("boom"));
5864 CHECK(try_catch.HasCaught());
5865}
5866
5867
5868TEST(TryCatchNative) {
5869 v8::Isolate* isolate = CcTest::isolate();
5870 v8::HandleScope scope(isolate);
5871 v8::V8::Initialize();
5872 v8::TryCatch try_catch;
5873 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5874 templ->Set(v8_str("TryCatchNativeHelper"),
5875 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5876 LocalContext context(0, templ);
5877 CompileRun("TryCatchNativeHelper();");
5878 CHECK(!try_catch.HasCaught());
5879}
5880
5881
5882void TryCatchNativeResetHelper(
5883 const v8::FunctionCallbackInfo<v8::Value>& args) {
5884 ApiTestFuzzer::Fuzz();
5885 v8::TryCatch try_catch;
5886 args.GetIsolate()->ThrowException(v8_str("boom"));
5887 CHECK(try_catch.HasCaught());
5888 try_catch.Reset();
5889 CHECK(!try_catch.HasCaught());
5890}
5891
5892
5893TEST(TryCatchNativeReset) {
5894 v8::Isolate* isolate = CcTest::isolate();
5895 v8::HandleScope scope(isolate);
5896 v8::V8::Initialize();
5897 v8::TryCatch try_catch;
5898 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5899 templ->Set(v8_str("TryCatchNativeResetHelper"),
5900 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5901 LocalContext context(0, templ);
5902 CompileRun("TryCatchNativeResetHelper();");
5903 CHECK(!try_catch.HasCaught());
5904}
5905
5906
5907THREADED_TEST(Equality) {
5908 LocalContext context;
5909 v8::Isolate* isolate = context->GetIsolate();
5910 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005911 // Check that equality works at all before relying on CHECK_EQ
5912 CHECK(v8_str("a")->Equals(v8_str("a")));
5913 CHECK(!v8_str("a")->Equals(v8_str("b")));
5914
5915 CHECK_EQ(v8_str("a"), v8_str("a"));
5916 CHECK_NE(v8_str("a"), v8_str("b"));
5917 CHECK_EQ(v8_num(1), v8_num(1));
5918 CHECK_EQ(v8_num(1.00), v8_num(1));
5919 CHECK_NE(v8_num(1), v8_num(2));
5920
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005921 // Assume String is not internalized.
Steve Blocka7e24c12009-10-30 11:49:00 +00005922 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5923 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5924 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5925 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5926 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005927 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5928 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005929 CHECK(!not_a_number->StrictEquals(not_a_number));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005930 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5931 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00005932
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005933 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5934 v8::Persistent<v8::Object> alias(isolate, obj);
5935 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5936 alias.Reset();
5937
5938 CHECK(v8_str("a")->SameValue(v8_str("a")));
5939 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5940 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5941 CHECK(v8_num(1)->SameValue(v8_num(1)));
5942 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5943 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5944 CHECK(not_a_number->SameValue(not_a_number));
5945 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5946 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00005947}
5948
5949
5950THREADED_TEST(MultiRun) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005951 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005952 v8::HandleScope scope(context->GetIsolate());
5953 Local<Script> script = v8_compile("x");
Steve Blocka7e24c12009-10-30 11:49:00 +00005954 for (int i = 0; i < 10; i++)
5955 script->Run();
5956}
5957
5958
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005959static void GetXValue(Local<String> name,
5960 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005961 ApiTestFuzzer::Fuzz();
5962 CHECK_EQ(info.Data(), v8_str("donut"));
5963 CHECK_EQ(name, v8_str("x"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005964 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00005965}
5966
5967
5968THREADED_TEST(SimplePropertyRead) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005969 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005970 v8::Isolate* isolate = context->GetIsolate();
5971 v8::HandleScope scope(isolate);
5972 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5973 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005974 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005975 Local<Script> script = v8_compile("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00005976 for (int i = 0; i < 10; i++) {
5977 Local<Value> result = script->Run();
5978 CHECK_EQ(result, v8_str("x"));
5979 }
5980}
5981
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005982
Andrei Popescu31002712010-02-23 13:46:05 +00005983THREADED_TEST(DefinePropertyOnAPIAccessor) {
Andrei Popescu31002712010-02-23 13:46:05 +00005984 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005985 v8::Isolate* isolate = context->GetIsolate();
5986 v8::HandleScope scope(isolate);
5987 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5988 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
Andrei Popescu31002712010-02-23 13:46:05 +00005989 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5990
5991 // Uses getOwnPropertyDescriptor to check the configurable status
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005992 Local<Script> script_desc = v8_compile(
5993 "var prop = Object.getOwnPropertyDescriptor( "
5994 "obj, 'x');"
5995 "prop.configurable;");
Andrei Popescu31002712010-02-23 13:46:05 +00005996 Local<Value> result = script_desc->Run();
5997 CHECK_EQ(result->BooleanValue(), true);
5998
5999 // Redefine get - but still configurable
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006000 Local<Script> script_define = v8_compile(
6001 "var desc = { get: function(){return 42; },"
6002 " configurable: true };"
6003 "Object.defineProperty(obj, 'x', desc);"
6004 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00006005 result = script_define->Run();
6006 CHECK_EQ(result, v8_num(42));
6007
6008 // Check that the accessor is still configurable
6009 result = script_desc->Run();
6010 CHECK_EQ(result->BooleanValue(), true);
6011
6012 // Redefine to a non-configurable
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006013 script_define = v8_compile(
6014 "var desc = { get: function(){return 43; },"
6015 " configurable: false };"
6016 "Object.defineProperty(obj, 'x', desc);"
6017 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00006018 result = script_define->Run();
6019 CHECK_EQ(result, v8_num(43));
6020 result = script_desc->Run();
6021 CHECK_EQ(result->BooleanValue(), false);
6022
6023 // Make sure that it is not possible to redefine again
6024 v8::TryCatch try_catch;
6025 result = script_define->Run();
6026 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006027 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006028 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00006029}
6030
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006031
Andrei Popescu31002712010-02-23 13:46:05 +00006032THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006033 v8::Isolate* isolate = CcTest::isolate();
6034 v8::HandleScope scope(isolate);
6035 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00006036 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6037 LocalContext context;
6038 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6039
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006040 Local<Script> script_desc = v8_compile(
6041 "var prop ="
6042 "Object.getOwnPropertyDescriptor( "
6043 "obj, 'x');"
6044 "prop.configurable;");
Andrei Popescu31002712010-02-23 13:46:05 +00006045 Local<Value> result = script_desc->Run();
6046 CHECK_EQ(result->BooleanValue(), true);
6047
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006048 Local<Script> script_define = v8_compile(
6049 "var desc = {get: function(){return 42; },"
6050 " configurable: true };"
6051 "Object.defineProperty(obj, 'x', desc);"
6052 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00006053 result = script_define->Run();
6054 CHECK_EQ(result, v8_num(42));
6055
6056
6057 result = script_desc->Run();
6058 CHECK_EQ(result->BooleanValue(), true);
6059
6060
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006061 script_define = v8_compile(
6062 "var desc = {get: function(){return 43; },"
6063 " configurable: false };"
6064 "Object.defineProperty(obj, 'x', desc);"
6065 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00006066 result = script_define->Run();
6067 CHECK_EQ(result, v8_num(43));
6068 result = script_desc->Run();
6069
6070 CHECK_EQ(result->BooleanValue(), false);
6071
6072 v8::TryCatch try_catch;
6073 result = script_define->Run();
6074 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006075 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006076 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00006077}
6078
6079
Leon Clarkef7060e22010-06-03 12:02:55 +01006080static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
6081 char const* name) {
6082 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
6083}
Andrei Popescu31002712010-02-23 13:46:05 +00006084
6085
Leon Clarkef7060e22010-06-03 12:02:55 +01006086THREADED_TEST(DefineAPIAccessorOnObject) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006087 v8::Isolate* isolate = CcTest::isolate();
6088 v8::HandleScope scope(isolate);
6089 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01006090 LocalContext context;
6091
6092 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6093 CompileRun("var obj2 = {};");
6094
6095 CHECK(CompileRun("obj1.x")->IsUndefined());
6096 CHECK(CompileRun("obj2.x")->IsUndefined());
6097
6098 CHECK(GetGlobalProperty(&context, "obj1")->
6099 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6100
6101 ExpectString("obj1.x", "x");
6102 CHECK(CompileRun("obj2.x")->IsUndefined());
6103
6104 CHECK(GetGlobalProperty(&context, "obj2")->
6105 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6106
6107 ExpectString("obj1.x", "x");
6108 ExpectString("obj2.x", "x");
6109
6110 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6111 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6112
6113 CompileRun("Object.defineProperty(obj1, 'x',"
6114 "{ get: function() { return 'y'; }, configurable: true })");
6115
6116 ExpectString("obj1.x", "y");
6117 ExpectString("obj2.x", "x");
6118
6119 CompileRun("Object.defineProperty(obj2, 'x',"
6120 "{ get: function() { return 'y'; }, configurable: true })");
6121
6122 ExpectString("obj1.x", "y");
6123 ExpectString("obj2.x", "y");
6124
6125 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6126 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6127
6128 CHECK(GetGlobalProperty(&context, "obj1")->
6129 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6130 CHECK(GetGlobalProperty(&context, "obj2")->
6131 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6132
6133 ExpectString("obj1.x", "x");
6134 ExpectString("obj2.x", "x");
6135
6136 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6137 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6138
6139 // Define getters/setters, but now make them not configurable.
6140 CompileRun("Object.defineProperty(obj1, 'x',"
6141 "{ get: function() { return 'z'; }, configurable: false })");
6142 CompileRun("Object.defineProperty(obj2, 'x',"
6143 "{ get: function() { return 'z'; }, configurable: false })");
6144
6145 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6146 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6147
6148 ExpectString("obj1.x", "z");
6149 ExpectString("obj2.x", "z");
6150
6151 CHECK(!GetGlobalProperty(&context, "obj1")->
6152 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6153 CHECK(!GetGlobalProperty(&context, "obj2")->
6154 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6155
6156 ExpectString("obj1.x", "z");
6157 ExpectString("obj2.x", "z");
6158}
6159
6160
6161THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006162 v8::Isolate* isolate = CcTest::isolate();
6163 v8::HandleScope scope(isolate);
6164 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01006165 LocalContext context;
6166
6167 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6168 CompileRun("var obj2 = {};");
6169
6170 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6171 v8_str("x"),
6172 GetXValue, NULL,
6173 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6174 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6175 v8_str("x"),
6176 GetXValue, NULL,
6177 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6178
6179 ExpectString("obj1.x", "x");
6180 ExpectString("obj2.x", "x");
6181
6182 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6183 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6184
6185 CHECK(!GetGlobalProperty(&context, "obj1")->
6186 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6187 CHECK(!GetGlobalProperty(&context, "obj2")->
6188 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6189
6190 {
6191 v8::TryCatch try_catch;
6192 CompileRun("Object.defineProperty(obj1, 'x',"
6193 "{get: function() { return 'func'; }})");
6194 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006195 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006196 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01006197 }
6198 {
6199 v8::TryCatch try_catch;
6200 CompileRun("Object.defineProperty(obj2, 'x',"
6201 "{get: function() { return 'func'; }})");
6202 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006203 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006204 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01006205 }
6206}
6207
6208
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006209static void Get239Value(Local<String> name,
6210 const v8::PropertyCallbackInfo<v8::Value>& info) {
Leon Clarkef7060e22010-06-03 12:02:55 +01006211 ApiTestFuzzer::Fuzz();
6212 CHECK_EQ(info.Data(), v8_str("donut"));
6213 CHECK_EQ(name, v8_str("239"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006214 info.GetReturnValue().Set(name);
Leon Clarkef7060e22010-06-03 12:02:55 +01006215}
6216
6217
6218THREADED_TEST(ElementAPIAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006219 v8::Isolate* isolate = CcTest::isolate();
6220 v8::HandleScope scope(isolate);
6221 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01006222 LocalContext context;
6223
6224 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6225 CompileRun("var obj2 = {};");
6226
6227 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6228 v8_str("239"),
6229 Get239Value, NULL,
6230 v8_str("donut")));
6231 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6232 v8_str("239"),
6233 Get239Value, NULL,
6234 v8_str("donut")));
6235
6236 ExpectString("obj1[239]", "239");
6237 ExpectString("obj2[239]", "239");
6238 ExpectString("obj1['239']", "239");
6239 ExpectString("obj2['239']", "239");
6240}
6241
Steve Blocka7e24c12009-10-30 11:49:00 +00006242
6243v8::Persistent<Value> xValue;
6244
6245
6246static void SetXValue(Local<String> name,
6247 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006248 const v8::PropertyCallbackInfo<void>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006249 CHECK_EQ(value, v8_num(4));
6250 CHECK_EQ(info.Data(), v8_str("donut"));
6251 CHECK_EQ(name, v8_str("x"));
6252 CHECK(xValue.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006253 xValue.Reset(info.GetIsolate(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006254}
6255
6256
6257THREADED_TEST(SimplePropertyWrite) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006258 v8::Isolate* isolate = CcTest::isolate();
6259 v8::HandleScope scope(isolate);
6260 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006261 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6262 LocalContext context;
6263 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006264 Local<Script> script = v8_compile("obj.x = 4");
Steve Blocka7e24c12009-10-30 11:49:00 +00006265 for (int i = 0; i < 10; i++) {
6266 CHECK(xValue.IsEmpty());
6267 script->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006268 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6269 xValue.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00006270 }
6271}
6272
6273
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006274THREADED_TEST(SetterOnly) {
6275 v8::Isolate* isolate = CcTest::isolate();
6276 v8::HandleScope scope(isolate);
6277 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6278 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6279 LocalContext context;
6280 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6281 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6282 for (int i = 0; i < 10; i++) {
6283 CHECK(xValue.IsEmpty());
6284 script->Run();
6285 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6286 xValue.Reset();
6287 }
6288}
6289
6290
6291THREADED_TEST(NoAccessors) {
6292 v8::Isolate* isolate = CcTest::isolate();
6293 v8::HandleScope scope(isolate);
6294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6295 templ->SetAccessor(v8_str("x"),
6296 static_cast<v8::AccessorGetterCallback>(NULL),
6297 NULL,
6298 v8_str("donut"));
6299 LocalContext context;
6300 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6301 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6302 for (int i = 0; i < 10; i++) {
6303 script->Run();
6304 }
6305}
6306
6307
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006308static void XPropertyGetter(Local<Name> property,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006309 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006310 ApiTestFuzzer::Fuzz();
6311 CHECK(info.Data()->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006312 info.GetReturnValue().Set(property);
Steve Blocka7e24c12009-10-30 11:49:00 +00006313}
6314
6315
6316THREADED_TEST(NamedInterceptorPropertyRead) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006317 v8::Isolate* isolate = CcTest::isolate();
6318 v8::HandleScope scope(isolate);
6319 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006320 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00006321 LocalContext context;
6322 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006323 Local<Script> script = v8_compile("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00006324 for (int i = 0; i < 10; i++) {
6325 Local<Value> result = script->Run();
6326 CHECK_EQ(result, v8_str("x"));
6327 }
6328}
6329
6330
Steve Block6ded16b2010-05-10 14:33:55 +01006331THREADED_TEST(NamedInterceptorDictionaryIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006332 v8::Isolate* isolate = CcTest::isolate();
6333 v8::HandleScope scope(isolate);
6334 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006335 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
Steve Block6ded16b2010-05-10 14:33:55 +01006336 LocalContext context;
6337 // Create an object with a named interceptor.
6338 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006339 Local<Script> script = v8_compile("interceptor_obj.x");
Steve Block6ded16b2010-05-10 14:33:55 +01006340 for (int i = 0; i < 10; i++) {
6341 Local<Value> result = script->Run();
6342 CHECK_EQ(result, v8_str("x"));
6343 }
6344 // Create a slow case object and a function accessing a property in
6345 // that slow case object (with dictionary probing in generated
6346 // code). Then force object with a named interceptor into slow-case,
6347 // pass it to the function, and check that the interceptor is called
6348 // instead of accessing the local property.
6349 Local<Value> result =
6350 CompileRun("function get_x(o) { return o.x; };"
6351 "var obj = { x : 42, y : 0 };"
6352 "delete obj.y;"
6353 "for (var i = 0; i < 10; i++) get_x(obj);"
6354 "interceptor_obj.x = 42;"
6355 "interceptor_obj.y = 10;"
6356 "delete interceptor_obj.y;"
6357 "get_x(interceptor_obj)");
6358 CHECK_EQ(result, v8_str("x"));
6359}
6360
6361
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006362THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006363 v8::Isolate* isolate = CcTest::isolate();
6364 v8::HandleScope scope(isolate);
6365 v8::Local<Context> context1 = Context::New(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006366
6367 context1->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006368 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006369 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006370 // Create an object with a named interceptor.
6371 v8::Local<v8::Object> object = templ->NewInstance();
6372 context1->Global()->Set(v8_str("interceptor_obj"), object);
6373
6374 // Force the object into the slow case.
6375 CompileRun("interceptor_obj.y = 0;"
6376 "delete interceptor_obj.y;");
6377 context1->Exit();
6378
6379 {
6380 // Introduce the object into a different context.
6381 // Repeat named loads to exercise ICs.
6382 LocalContext context2;
6383 context2->Global()->Set(v8_str("interceptor_obj"), object);
6384 Local<Value> result =
6385 CompileRun("function get_x(o) { return o.x; }"
6386 "interceptor_obj.x = 42;"
6387 "for (var i=0; i != 10; i++) {"
6388 " get_x(interceptor_obj);"
6389 "}"
6390 "get_x(interceptor_obj)");
6391 // Check that the interceptor was actually invoked.
6392 CHECK_EQ(result, v8_str("x"));
6393 }
6394
6395 // Return to the original context and force some object to the slow case
6396 // to cause the NormalizedMapCache to verify.
6397 context1->Enter();
6398 CompileRun("var obj = { x : 0 }; delete obj.x;");
6399 context1->Exit();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006400}
6401
6402
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006403static void SetXOnPrototypeGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006404 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006405 // Set x on the prototype object and do not handle the get request.
6406 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006407 proto.As<v8::Object>()->Set(v8_str("x"),
6408 v8::Integer::New(info.GetIsolate(), 23));
Andrei Popescu402d9372010-02-26 13:31:12 +00006409}
6410
6411
6412// This is a regression test for http://crbug.com/20104. Map
6413// transitions should not interfere with post interceptor lookup.
6414THREADED_TEST(NamedInterceptorMapTransitionRead) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006415 v8::Isolate* isolate = CcTest::isolate();
6416 v8::HandleScope scope(isolate);
6417 Local<v8::FunctionTemplate> function_template =
6418 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006419 Local<v8::ObjectTemplate> instance_template
6420 = function_template->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006421 instance_template->SetHandler(
6422 v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006423 LocalContext context;
6424 context->Global()->Set(v8_str("F"), function_template->GetFunction());
6425 // Create an instance of F and introduce a map transition for x.
6426 CompileRun("var o = new F(); o.x = 23;");
6427 // Create an instance of F and invoke the getter. The result should be 23.
6428 Local<Value> result = CompileRun("o = new F(); o.x");
6429 CHECK_EQ(result->Int32Value(), 23);
6430}
6431
6432
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006433static void IndexedPropertyGetter(
6434 uint32_t index,
6435 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006436 ApiTestFuzzer::Fuzz();
6437 if (index == 37) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006438 info.GetReturnValue().Set(v8_num(625));
Steve Blocka7e24c12009-10-30 11:49:00 +00006439 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006440}
6441
6442
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006443static void IndexedPropertySetter(
6444 uint32_t index,
6445 Local<Value> value,
6446 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006447 ApiTestFuzzer::Fuzz();
6448 if (index == 39) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006449 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006450 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006451}
6452
6453
6454THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006455 v8::Isolate* isolate = CcTest::isolate();
6456 v8::HandleScope scope(isolate);
6457 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006458 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6459 IndexedPropertyGetter, IndexedPropertySetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00006460 LocalContext context;
6461 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006462 Local<Script> getter_script = v8_compile(
6463 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6464 Local<Script> setter_script = v8_compile(
Steve Blocka7e24c12009-10-30 11:49:00 +00006465 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6466 "obj[17] = 23;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006467 "obj.foo;");
6468 Local<Script> interceptor_setter_script = v8_compile(
Steve Blocka7e24c12009-10-30 11:49:00 +00006469 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6470 "obj[39] = 47;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006471 "obj.foo;"); // This setter should not run, due to the interceptor.
6472 Local<Script> interceptor_getter_script = v8_compile(
6473 "obj[37];");
Steve Blocka7e24c12009-10-30 11:49:00 +00006474 Local<Value> result = getter_script->Run();
6475 CHECK_EQ(v8_num(5), result);
6476 result = setter_script->Run();
6477 CHECK_EQ(v8_num(23), result);
6478 result = interceptor_setter_script->Run();
6479 CHECK_EQ(v8_num(23), result);
6480 result = interceptor_getter_script->Run();
6481 CHECK_EQ(v8_num(625), result);
6482}
6483
6484
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006485static void UnboxedDoubleIndexedPropertyGetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006486 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006487 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006488 ApiTestFuzzer::Fuzz();
6489 if (index < 25) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006490 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006491 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006492}
6493
6494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006495static void UnboxedDoubleIndexedPropertySetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006496 uint32_t index,
6497 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006498 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006499 ApiTestFuzzer::Fuzz();
6500 if (index < 25) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006501 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006502 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006503}
6504
6505
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006506void UnboxedDoubleIndexedPropertyEnumerator(
6507 const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006508 // Force the list of returned keys to be stored in a FastDoubleArray.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006509 Local<Script> indexed_property_names_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006510 "keys = new Array(); keys[125000] = 1;"
6511 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006512 "keys.length = 25; keys;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006513 Local<Value> result = indexed_property_names_script->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006514 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006515}
6516
6517
6518// Make sure that the the interceptor code in the runtime properly handles
6519// merging property name lists for double-array-backed arrays.
6520THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006521 v8::Isolate* isolate = CcTest::isolate();
6522 v8::HandleScope scope(isolate);
6523 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006524 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6525 UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
6526 0, UnboxedDoubleIndexedPropertyEnumerator));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006527 LocalContext context;
6528 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6529 // When obj is created, force it to be Stored in a FastDoubleArray.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006530 Local<Script> create_unboxed_double_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006531 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6532 "key_count = 0; "
6533 "for (x in obj) {key_count++;};"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006534 "obj;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006535 Local<Value> result = create_unboxed_double_script->Run();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006536 CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006537 Local<Script> key_count_check = v8_compile("key_count;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006538 result = key_count_check->Run();
6539 CHECK_EQ(v8_num(40013), result);
6540}
6541
6542
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006543void SloppyArgsIndexedPropertyEnumerator(
6544 const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006545 // Force the list of returned keys to be stored in a Arguments object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006546 Local<Script> indexed_property_names_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006547 "function f(w,x) {"
6548 " return arguments;"
6549 "}"
6550 "keys = f(0, 1, 2, 3);"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006551 "keys;");
6552 Local<Object> result =
6553 Local<Object>::Cast(indexed_property_names_script->Run());
6554 // Have to populate the handle manually, as it's not Cast-able.
6555 i::Handle<i::JSObject> o =
6556 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6557 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6558 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006559}
6560
6561
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006562static void SloppyIndexedPropertyGetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006563 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006564 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006565 ApiTestFuzzer::Fuzz();
6566 if (index < 4) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006567 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006568 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006569}
6570
6571
6572// Make sure that the the interceptor code in the runtime properly handles
6573// merging property name lists for non-string arguments arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006574THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6575 v8::Isolate* isolate = CcTest::isolate();
6576 v8::HandleScope scope(isolate);
6577 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006578 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6579 SloppyIndexedPropertyGetter, 0, 0, 0,
6580 SloppyArgsIndexedPropertyEnumerator));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006581 LocalContext context;
6582 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006583 Local<Script> create_args_script = v8_compile(
6584 "var key_count = 0;"
6585 "for (x in obj) {key_count++;} key_count;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006586 Local<Value> result = create_args_script->Run();
6587 CHECK_EQ(v8_num(4), result);
6588}
6589
6590
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006591static void IdentityIndexedPropertyGetter(
Leon Clarked91b9f72010-01-27 17:25:45 +00006592 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006593 const v8::PropertyCallbackInfo<v8::Value>& info) {
6594 info.GetReturnValue().Set(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00006595}
6596
6597
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006598THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006599 v8::Isolate* isolate = CcTest::isolate();
6600 v8::HandleScope scope(isolate);
6601 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006602 templ->SetHandler(
6603 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006604
6605 LocalContext context;
6606 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6607
6608 // Check fast object case.
6609 const char* fast_case_code =
6610 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6611 ExpectString(fast_case_code, "0");
6612
6613 // Check slow case.
6614 const char* slow_case_code =
6615 "obj.x = 1; delete obj.x;"
6616 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6617 ExpectString(slow_case_code, "1");
6618}
6619
6620
Leon Clarked91b9f72010-01-27 17:25:45 +00006621THREADED_TEST(IndexedInterceptorWithNoSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006622 v8::Isolate* isolate = CcTest::isolate();
6623 v8::HandleScope scope(isolate);
6624 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006625 templ->SetHandler(
6626 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Leon Clarked91b9f72010-01-27 17:25:45 +00006627
6628 LocalContext context;
6629 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6630
6631 const char* code =
6632 "try {"
6633 " obj[0] = 239;"
6634 " for (var i = 0; i < 100; i++) {"
6635 " var v = obj[0];"
6636 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6637 " }"
6638 " 'PASSED'"
6639 "} catch(e) {"
6640 " e"
6641 "}";
6642 ExpectString(code, "PASSED");
6643}
6644
6645
Andrei Popescu402d9372010-02-26 13:31:12 +00006646THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006647 v8::Isolate* isolate = CcTest::isolate();
6648 v8::HandleScope scope(isolate);
6649 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006650 templ->SetHandler(
6651 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006652
6653 LocalContext context;
6654 Local<v8::Object> obj = templ->NewInstance();
6655 obj->TurnOnAccessCheck();
6656 context->Global()->Set(v8_str("obj"), obj);
6657
6658 const char* code =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006659 "var result = 'PASSED';"
6660 "for (var i = 0; i < 100; i++) {"
6661 " try {"
Andrei Popescu402d9372010-02-26 13:31:12 +00006662 " var v = obj[0];"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006663 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6664 " break;"
6665 " } catch (e) {"
6666 " /* pass */"
Andrei Popescu402d9372010-02-26 13:31:12 +00006667 " }"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006668 "}"
6669 "result";
Andrei Popescu402d9372010-02-26 13:31:12 +00006670 ExpectString(code, "PASSED");
6671}
6672
6673
6674THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6675 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006676 v8::Isolate* isolate = CcTest::isolate();
6677 v8::HandleScope scope(isolate);
6678 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006679 templ->SetHandler(
6680 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006681
6682 LocalContext context;
6683 Local<v8::Object> obj = templ->NewInstance();
6684 context->Global()->Set(v8_str("obj"), obj);
6685
6686 const char* code =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006687 "var result = 'PASSED';"
6688 "for (var i = 0; i < 100; i++) {"
6689 " var expected = i;"
6690 " if (i == 5) {"
6691 " %EnableAccessChecks(obj);"
Andrei Popescu402d9372010-02-26 13:31:12 +00006692 " }"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006693 " try {"
6694 " var v = obj[i];"
6695 " if (i == 5) {"
6696 " result = 'Should not have reached this!';"
6697 " break;"
6698 " } else if (v != expected) {"
6699 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6700 " break;"
6701 " }"
6702 " } catch (e) {"
6703 " if (i != 5) {"
6704 " result = e;"
6705 " }"
6706 " }"
6707 " if (i == 5) %DisableAccessChecks(obj);"
6708 "}"
6709 "result";
Andrei Popescu402d9372010-02-26 13:31:12 +00006710 ExpectString(code, "PASSED");
6711}
6712
6713
6714THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006715 v8::Isolate* isolate = CcTest::isolate();
6716 v8::HandleScope scope(isolate);
6717 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006718 templ->SetHandler(
6719 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006720
6721 LocalContext context;
6722 Local<v8::Object> obj = templ->NewInstance();
6723 context->Global()->Set(v8_str("obj"), obj);
6724
6725 const char* code =
6726 "try {"
6727 " for (var i = 0; i < 100; i++) {"
6728 " var v = obj[i];"
6729 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6730 " }"
6731 " 'PASSED'"
6732 "} catch(e) {"
6733 " e"
6734 "}";
6735 ExpectString(code, "PASSED");
6736}
6737
6738
Ben Murdochf87a2032010-10-22 12:50:53 +01006739THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006740 v8::Isolate* isolate = CcTest::isolate();
6741 v8::HandleScope scope(isolate);
6742 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006743 templ->SetHandler(
6744 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Ben Murdochf87a2032010-10-22 12:50:53 +01006745
6746 LocalContext context;
6747 Local<v8::Object> obj = templ->NewInstance();
6748 context->Global()->Set(v8_str("obj"), obj);
6749
6750 const char* code =
6751 "try {"
6752 " for (var i = 0; i < 100; i++) {"
6753 " var expected = i;"
6754 " var key = i;"
6755 " if (i == 25) {"
6756 " key = -1;"
6757 " expected = undefined;"
6758 " }"
6759 " if (i == 50) {"
6760 " /* probe minimal Smi number on 32-bit platforms */"
6761 " key = -(1 << 30);"
6762 " expected = undefined;"
6763 " }"
6764 " if (i == 75) {"
6765 " /* probe minimal Smi number on 64-bit platforms */"
6766 " key = 1 << 31;"
6767 " expected = undefined;"
6768 " }"
6769 " var v = obj[key];"
6770 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6771 " }"
6772 " 'PASSED'"
6773 "} catch(e) {"
6774 " e"
6775 "}";
6776 ExpectString(code, "PASSED");
6777}
6778
6779
Andrei Popescu402d9372010-02-26 13:31:12 +00006780THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006781 v8::Isolate* isolate = CcTest::isolate();
6782 v8::HandleScope scope(isolate);
6783 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006784 templ->SetHandler(
6785 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006786
6787 LocalContext context;
6788 Local<v8::Object> obj = templ->NewInstance();
6789 context->Global()->Set(v8_str("obj"), obj);
6790
6791 const char* code =
6792 "try {"
6793 " for (var i = 0; i < 100; i++) {"
6794 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01006795 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00006796 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01006797 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00006798 " expected = undefined;"
6799 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01006800 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00006801 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6802 " }"
6803 " 'PASSED'"
6804 "} catch(e) {"
6805 " e"
6806 "}";
6807 ExpectString(code, "PASSED");
6808}
6809
6810
6811THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006812 v8::Isolate* isolate = CcTest::isolate();
6813 v8::HandleScope scope(isolate);
6814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006815 templ->SetHandler(
6816 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006817
6818 LocalContext context;
6819 Local<v8::Object> obj = templ->NewInstance();
6820 context->Global()->Set(v8_str("obj"), obj);
6821
6822 const char* code =
6823 "var original = obj;"
6824 "try {"
6825 " for (var i = 0; i < 100; i++) {"
6826 " var expected = i;"
6827 " if (i == 50) {"
6828 " obj = {50: 'foobar'};"
6829 " expected = 'foobar';"
6830 " }"
6831 " var v = obj[i];"
6832 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6833 " if (i == 50) obj = original;"
6834 " }"
6835 " 'PASSED'"
6836 "} catch(e) {"
6837 " e"
6838 "}";
6839 ExpectString(code, "PASSED");
6840}
6841
6842
6843THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006844 v8::Isolate* isolate = CcTest::isolate();
6845 v8::HandleScope scope(isolate);
6846 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006847 templ->SetHandler(
6848 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006849
6850 LocalContext context;
6851 Local<v8::Object> obj = templ->NewInstance();
6852 context->Global()->Set(v8_str("obj"), obj);
6853
6854 const char* code =
6855 "var original = obj;"
6856 "try {"
6857 " for (var i = 0; i < 100; i++) {"
6858 " var expected = i;"
6859 " if (i == 5) {"
6860 " obj = 239;"
6861 " expected = undefined;"
6862 " }"
6863 " var v = obj[i];"
6864 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6865 " if (i == 5) obj = original;"
6866 " }"
6867 " 'PASSED'"
6868 "} catch(e) {"
6869 " e"
6870 "}";
6871 ExpectString(code, "PASSED");
6872}
6873
6874
6875THREADED_TEST(IndexedInterceptorOnProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006876 v8::Isolate* isolate = CcTest::isolate();
6877 v8::HandleScope scope(isolate);
6878 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006879 templ->SetHandler(
6880 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
Andrei Popescu402d9372010-02-26 13:31:12 +00006881
6882 LocalContext context;
6883 Local<v8::Object> obj = templ->NewInstance();
6884 context->Global()->Set(v8_str("obj"), obj);
6885
6886 const char* code =
6887 "var o = {__proto__: obj};"
6888 "try {"
6889 " for (var i = 0; i < 100; i++) {"
6890 " var v = o[i];"
6891 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6892 " }"
6893 " 'PASSED'"
6894 "} catch(e) {"
6895 " e"
6896 "}";
6897 ExpectString(code, "PASSED");
6898}
6899
6900
Steve Blocka7e24c12009-10-30 11:49:00 +00006901THREADED_TEST(MultiContexts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006902 v8::Isolate* isolate = CcTest::isolate();
6903 v8::HandleScope scope(isolate);
6904 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6905 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6906 DummyCallHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00006907
6908 Local<String> password = v8_str("Password");
6909
6910 // Create an environment
6911 LocalContext context0(0, templ);
6912 context0->SetSecurityToken(password);
6913 v8::Handle<v8::Object> global0 = context0->Global();
6914 global0->Set(v8_str("custom"), v8_num(1234));
6915 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6916
6917 // Create an independent environment
6918 LocalContext context1(0, templ);
6919 context1->SetSecurityToken(password);
6920 v8::Handle<v8::Object> global1 = context1->Global();
6921 global1->Set(v8_str("custom"), v8_num(1234));
6922 CHECK_NE(global0, global1);
6923 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6924 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6925
6926 // Now create a new context with the old global
6927 LocalContext context2(0, templ, global1);
6928 context2->SetSecurityToken(password);
6929 v8::Handle<v8::Object> global2 = context2->Global();
6930 CHECK_EQ(global1, global2);
6931 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6932 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6933}
6934
6935
6936THREADED_TEST(FunctionPrototypeAcrossContexts) {
6937 // Make sure that functions created by cloning boilerplates cannot
6938 // communicate through their __proto__ field.
6939
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006940 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006941
6942 LocalContext env0;
6943 v8::Handle<v8::Object> global0 =
6944 env0->Global();
6945 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006946 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006947 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006948 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006949 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006950 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006951 proto0->Set(v8_str("custom"), v8_num(1234));
6952
6953 LocalContext env1;
6954 v8::Handle<v8::Object> global1 =
6955 env1->Global();
6956 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006957 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006958 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006959 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006960 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006961 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006962 CHECK(!proto1->Has(v8_str("custom")));
6963}
6964
6965
6966THREADED_TEST(Regress892105) {
6967 // Make sure that object and array literals created by cloning
6968 // boilerplates cannot communicate through their __proto__
6969 // field. This is rather difficult to check, but we try to add stuff
6970 // to Object.prototype and Array.prototype and create a new
6971 // environment. This should succeed.
6972
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006973 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006974
6975 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6976 "Array.prototype.arr = 4567;"
6977 "8901");
6978
6979 LocalContext env0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006980 Local<Script> script0 = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +00006981 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6982
6983 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006984 Local<Script> script1 = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +00006985 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6986}
6987
6988
Steve Blocka7e24c12009-10-30 11:49:00 +00006989THREADED_TEST(UndetectableObject) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006990 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006991 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006992
6993 Local<v8::FunctionTemplate> desc =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006994 v8::FunctionTemplate::New(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006995 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6996
6997 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6998 env->Global()->Set(v8_str("undetectable"), obj);
6999
7000 ExpectString("undetectable.toString()", "[object Object]");
7001 ExpectString("typeof undetectable", "undefined");
7002 ExpectString("typeof(undetectable)", "undefined");
7003 ExpectBoolean("typeof undetectable == 'undefined'", true);
7004 ExpectBoolean("typeof undetectable == 'object'", false);
7005 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7006 ExpectBoolean("!undetectable", true);
7007
7008 ExpectObject("true&&undetectable", obj);
7009 ExpectBoolean("false&&undetectable", false);
7010 ExpectBoolean("true||undetectable", true);
7011 ExpectObject("false||undetectable", obj);
7012
7013 ExpectObject("undetectable&&true", obj);
7014 ExpectObject("undetectable&&false", obj);
7015 ExpectBoolean("undetectable||true", true);
7016 ExpectBoolean("undetectable||false", false);
7017
7018 ExpectBoolean("undetectable==null", true);
7019 ExpectBoolean("null==undetectable", true);
7020 ExpectBoolean("undetectable==undefined", true);
7021 ExpectBoolean("undefined==undetectable", true);
7022 ExpectBoolean("undetectable==undetectable", true);
7023
7024
7025 ExpectBoolean("undetectable===null", false);
7026 ExpectBoolean("null===undetectable", false);
7027 ExpectBoolean("undetectable===undefined", false);
7028 ExpectBoolean("undefined===undetectable", false);
7029 ExpectBoolean("undetectable===undetectable", true);
7030}
7031
7032
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007033THREADED_TEST(VoidLiteral) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007034 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007035 v8::Isolate* isolate = env->GetIsolate();
7036 v8::HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007037
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007038 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007039 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7040
7041 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7042 env->Global()->Set(v8_str("undetectable"), obj);
7043
7044 ExpectBoolean("undefined == void 0", true);
7045 ExpectBoolean("undetectable == void 0", true);
7046 ExpectBoolean("null == void 0", true);
7047 ExpectBoolean("undefined === void 0", true);
7048 ExpectBoolean("undetectable === void 0", false);
7049 ExpectBoolean("null === void 0", false);
7050
7051 ExpectBoolean("void 0 == undefined", true);
7052 ExpectBoolean("void 0 == undetectable", true);
7053 ExpectBoolean("void 0 == null", true);
7054 ExpectBoolean("void 0 === undefined", true);
7055 ExpectBoolean("void 0 === undetectable", false);
7056 ExpectBoolean("void 0 === null", false);
7057
7058 ExpectString("(function() {"
7059 " try {"
7060 " return x === void 0;"
7061 " } catch(e) {"
7062 " return e.toString();"
7063 " }"
7064 "})()",
7065 "ReferenceError: x is not defined");
7066 ExpectString("(function() {"
7067 " try {"
7068 " return void 0 === x;"
7069 " } catch(e) {"
7070 " return e.toString();"
7071 " }"
7072 "})()",
7073 "ReferenceError: x is not defined");
7074}
7075
Steve Block8defd9f2010-07-08 12:39:36 +01007076
7077THREADED_TEST(ExtensibleOnUndetectable) {
Steve Block8defd9f2010-07-08 12:39:36 +01007078 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007079 v8::Isolate* isolate = env->GetIsolate();
7080 v8::HandleScope scope(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +01007081
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007082 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +01007083 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7084
7085 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7086 env->Global()->Set(v8_str("undetectable"), obj);
7087
7088 Local<String> source = v8_str("undetectable.x = 42;"
7089 "undetectable.x");
7090
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007091 Local<Script> script = v8_compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01007092
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007093 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
Steve Block8defd9f2010-07-08 12:39:36 +01007094
7095 ExpectBoolean("Object.isExtensible(undetectable)", true);
7096
7097 source = v8_str("Object.preventExtensions(undetectable);");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007098 script = v8_compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01007099 script->Run();
7100 ExpectBoolean("Object.isExtensible(undetectable)", false);
7101
7102 source = v8_str("undetectable.y = 2000;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007103 script = v8_compile(source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007104 script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01007105 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01007106}
7107
7108
7109
Steve Blocka7e24c12009-10-30 11:49:00 +00007110THREADED_TEST(UndetectableString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007111 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007112 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007113
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007114 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7115 String::kUndetectableString);
Steve Blocka7e24c12009-10-30 11:49:00 +00007116 env->Global()->Set(v8_str("undetectable"), obj);
7117
7118 ExpectString("undetectable", "foo");
7119 ExpectString("typeof undetectable", "undefined");
7120 ExpectString("typeof(undetectable)", "undefined");
7121 ExpectBoolean("typeof undetectable == 'undefined'", true);
7122 ExpectBoolean("typeof undetectable == 'string'", false);
7123 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7124 ExpectBoolean("!undetectable", true);
7125
7126 ExpectObject("true&&undetectable", obj);
7127 ExpectBoolean("false&&undetectable", false);
7128 ExpectBoolean("true||undetectable", true);
7129 ExpectObject("false||undetectable", obj);
7130
7131 ExpectObject("undetectable&&true", obj);
7132 ExpectObject("undetectable&&false", obj);
7133 ExpectBoolean("undetectable||true", true);
7134 ExpectBoolean("undetectable||false", false);
7135
7136 ExpectBoolean("undetectable==null", true);
7137 ExpectBoolean("null==undetectable", true);
7138 ExpectBoolean("undetectable==undefined", true);
7139 ExpectBoolean("undefined==undetectable", true);
7140 ExpectBoolean("undetectable==undetectable", true);
7141
7142
7143 ExpectBoolean("undetectable===null", false);
7144 ExpectBoolean("null===undetectable", false);
7145 ExpectBoolean("undetectable===undefined", false);
7146 ExpectBoolean("undefined===undetectable", false);
7147 ExpectBoolean("undetectable===undetectable", true);
7148}
7149
7150
Ben Murdoch257744e2011-11-30 15:57:28 +00007151TEST(UndetectableOptimized) {
7152 i::FLAG_allow_natives_syntax = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007153 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007154 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +00007155
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007156 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7157 String::kUndetectableString);
Ben Murdoch257744e2011-11-30 15:57:28 +00007158 env->Global()->Set(v8_str("undetectable"), obj);
7159 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
7160
7161 ExpectString(
7162 "function testBranch() {"
7163 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
7164 " if (%_IsUndetectableObject(detectable)) throw 2;"
7165 "}\n"
7166 "function testBool() {"
7167 " var b1 = !%_IsUndetectableObject(undetectable);"
7168 " var b2 = %_IsUndetectableObject(detectable);"
7169 " if (b1) throw 3;"
7170 " if (b2) throw 4;"
7171 " return b1 == b2;"
7172 "}\n"
7173 "%OptimizeFunctionOnNextCall(testBranch);"
7174 "%OptimizeFunctionOnNextCall(testBool);"
7175 "for (var i = 0; i < 10; i++) {"
7176 " testBranch();"
7177 " testBool();"
7178 "}\n"
7179 "\"PASS\"",
7180 "PASS");
7181}
7182
7183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007184// The point of this test is type checking. We run it only so compilers
7185// don't complain about an unused function.
7186TEST(PersistentHandles) {
7187 LocalContext env;
7188 v8::Isolate* isolate = CcTest::isolate();
7189 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007190 Local<String> str = v8_str("foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007191 v8::Persistent<String> p_str(isolate, str);
7192 p_str.Reset();
7193 Local<Script> scr = v8_compile("");
7194 v8::Persistent<Script> p_scr(isolate, scr);
7195 p_scr.Reset();
7196 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7197 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7198 p_templ.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00007199}
7200
7201
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007202static void HandleLogDelegator(
7203 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007204 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00007205}
7206
7207
7208THREADED_TEST(GlobalObjectTemplate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007209 v8::Isolate* isolate = CcTest::isolate();
7210 v8::HandleScope handle_scope(isolate);
7211 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007212 global_template->Set(v8_str("JSNI_Log"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007213 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7214 v8::Local<Context> context = Context::New(isolate, 0, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00007215 Context::Scope context_scope(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007216 CompileRun("JSNI_Log('LOG')");
Steve Blocka7e24c12009-10-30 11:49:00 +00007217}
7218
7219
7220static const char* kSimpleExtensionSource =
7221 "function Foo() {"
7222 " return 4;"
7223 "}";
7224
7225
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007226TEST(SimpleExtensions) {
7227 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007228 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7229 const char* extension_names[] = { "simpletest" };
7230 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007231 v8::Handle<Context> context =
7232 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00007233 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007234 v8::Handle<Value> result = CompileRun("Foo()");
7235 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7236}
7237
7238
7239static const char* kStackTraceFromExtensionSource =
7240 "function foo() {"
7241 " throw new Error();"
7242 "}"
7243 "function bar() {"
7244 " foo();"
7245 "}";
7246
7247
7248TEST(StackTraceInExtension) {
7249 v8::HandleScope handle_scope(CcTest::isolate());
7250 v8::RegisterExtension(new Extension("stacktracetest",
7251 kStackTraceFromExtensionSource));
7252 const char* extension_names[] = { "stacktracetest" };
7253 v8::ExtensionConfiguration extensions(1, extension_names);
7254 v8::Handle<Context> context =
7255 Context::New(CcTest::isolate(), &extensions);
7256 Context::Scope lock(context);
7257 CompileRun("function user() { bar(); }"
7258 "var error;"
7259 "try{ user(); } catch (e) { error = e; }");
7260 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7261 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7262 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7263}
7264
7265
7266TEST(NullExtensions) {
7267 v8::HandleScope handle_scope(CcTest::isolate());
7268 v8::RegisterExtension(new Extension("nulltest", NULL));
7269 const char* extension_names[] = { "nulltest" };
7270 v8::ExtensionConfiguration extensions(1, extension_names);
7271 v8::Handle<Context> context =
7272 Context::New(CcTest::isolate(), &extensions);
7273 Context::Scope lock(context);
7274 v8::Handle<Value> result = CompileRun("1+3");
7275 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
Steve Blocka7e24c12009-10-30 11:49:00 +00007276}
7277
7278
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007279static const char* kEmbeddedExtensionSource =
7280 "function Ret54321(){return 54321;}~~@@$"
7281 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7282static const int kEmbeddedExtensionSourceValidLen = 34;
7283
7284
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007285TEST(ExtensionMissingSourceLength) {
7286 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007287 v8::RegisterExtension(new Extension("srclentest_fail",
7288 kEmbeddedExtensionSource));
7289 const char* extension_names[] = { "srclentest_fail" };
7290 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007291 v8::Handle<Context> context =
7292 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007293 CHECK_EQ(0, *context);
7294}
7295
7296
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007297TEST(ExtensionWithSourceLength) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007298 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7299 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007300 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007301 i::ScopedVector<char> extension_name(32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007302 i::SNPrintF(extension_name, "ext #%d", source_len);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007303 v8::RegisterExtension(new Extension(extension_name.start(),
7304 kEmbeddedExtensionSource, 0, 0,
7305 source_len));
7306 const char* extension_names[1] = { extension_name.start() };
7307 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007308 v8::Handle<Context> context =
7309 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007310 if (source_len == kEmbeddedExtensionSourceValidLen) {
7311 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007312 v8::Handle<Value> result = CompileRun("Ret54321()");
7313 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007314 } else {
7315 // Anything but exactly the right length should fail to compile.
7316 CHECK_EQ(0, *context);
7317 }
7318 }
7319}
7320
7321
Steve Blocka7e24c12009-10-30 11:49:00 +00007322static const char* kEvalExtensionSource1 =
7323 "function UseEval1() {"
7324 " var x = 42;"
7325 " return eval('x');"
7326 "}";
7327
7328
7329static const char* kEvalExtensionSource2 =
7330 "(function() {"
7331 " var x = 42;"
7332 " function e() {"
7333 " return eval('x');"
7334 " }"
7335 " this.UseEval2 = e;"
7336 "})()";
7337
7338
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007339TEST(UseEvalFromExtension) {
7340 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007341 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7342 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7343 const char* extension_names[] = { "evaltest1", "evaltest2" };
7344 v8::ExtensionConfiguration extensions(2, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007345 v8::Handle<Context> context =
7346 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00007347 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007348 v8::Handle<Value> result = CompileRun("UseEval1()");
7349 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7350 result = CompileRun("UseEval2()");
7351 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
Steve Blocka7e24c12009-10-30 11:49:00 +00007352}
7353
7354
7355static const char* kWithExtensionSource1 =
7356 "function UseWith1() {"
7357 " var x = 42;"
7358 " with({x:87}) { return x; }"
7359 "}";
7360
7361
7362
7363static const char* kWithExtensionSource2 =
7364 "(function() {"
7365 " var x = 42;"
7366 " function e() {"
7367 " with ({x:87}) { return x; }"
7368 " }"
7369 " this.UseWith2 = e;"
7370 "})()";
7371
7372
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007373TEST(UseWithFromExtension) {
7374 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007375 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7376 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7377 const char* extension_names[] = { "withtest1", "withtest2" };
7378 v8::ExtensionConfiguration extensions(2, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007379 v8::Handle<Context> context =
7380 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00007381 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007382 v8::Handle<Value> result = CompileRun("UseWith1()");
7383 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7384 result = CompileRun("UseWith2()");
7385 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
Steve Blocka7e24c12009-10-30 11:49:00 +00007386}
7387
7388
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007389TEST(AutoExtensions) {
7390 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007391 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7392 extension->set_auto_enable(true);
7393 v8::RegisterExtension(extension);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007394 v8::Handle<Context> context =
7395 Context::New(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007396 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007397 v8::Handle<Value> result = CompileRun("Foo()");
7398 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
Steve Blocka7e24c12009-10-30 11:49:00 +00007399}
7400
7401
Steve Blockd0582a62009-12-15 09:54:21 +00007402static const char* kSyntaxErrorInExtensionSource =
7403 "[";
7404
7405
7406// Test that a syntax error in an extension does not cause a fatal
7407// error but results in an empty context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007408TEST(SyntaxErrorExtensions) {
7409 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007410 v8::RegisterExtension(new Extension("syntaxerror",
7411 kSyntaxErrorInExtensionSource));
7412 const char* extension_names[] = { "syntaxerror" };
7413 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007414 v8::Handle<Context> context =
7415 Context::New(CcTest::isolate(), &extensions);
Steve Blockd0582a62009-12-15 09:54:21 +00007416 CHECK(context.IsEmpty());
7417}
7418
7419
7420static const char* kExceptionInExtensionSource =
7421 "throw 42";
7422
7423
7424// Test that an exception when installing an extension does not cause
7425// a fatal error but results in an empty context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007426TEST(ExceptionExtensions) {
7427 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007428 v8::RegisterExtension(new Extension("exception",
7429 kExceptionInExtensionSource));
7430 const char* extension_names[] = { "exception" };
7431 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007432 v8::Handle<Context> context =
7433 Context::New(CcTest::isolate(), &extensions);
Steve Blockd0582a62009-12-15 09:54:21 +00007434 CHECK(context.IsEmpty());
7435}
7436
7437
Iain Merrick9ac36c92010-09-13 15:29:50 +01007438static const char* kNativeCallInExtensionSource =
7439 "function call_runtime_last_index_of(x) {"
7440 " return %StringLastIndexOf(x, 'bob', 10);"
7441 "}";
7442
7443
7444static const char* kNativeCallTest =
7445 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7446
7447// Test that a native runtime calls are supported in extensions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007448TEST(NativeCallInExtensions) {
7449 v8::HandleScope handle_scope(CcTest::isolate());
Iain Merrick9ac36c92010-09-13 15:29:50 +01007450 v8::RegisterExtension(new Extension("nativecall",
7451 kNativeCallInExtensionSource));
7452 const char* extension_names[] = { "nativecall" };
7453 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007454 v8::Handle<Context> context =
7455 Context::New(CcTest::isolate(), &extensions);
Iain Merrick9ac36c92010-09-13 15:29:50 +01007456 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007457 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7458 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
Iain Merrick9ac36c92010-09-13 15:29:50 +01007459}
7460
7461
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007462class NativeFunctionExtension : public Extension {
7463 public:
7464 NativeFunctionExtension(const char* name,
7465 const char* source,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007466 v8::FunctionCallback fun = &Echo)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007467 : Extension(name, source),
7468 function_(fun) { }
7469
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007470 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7471 v8::Isolate* isolate,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007472 v8::Handle<v8::String> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007473 return v8::FunctionTemplate::New(isolate, function_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007474 }
7475
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007476 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7477 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007478 }
7479 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007480 v8::FunctionCallback function_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007481};
7482
7483
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007484TEST(NativeFunctionDeclaration) {
7485 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007486 const char* name = "nativedecl";
7487 v8::RegisterExtension(new NativeFunctionExtension(name,
7488 "native function foo();"));
7489 const char* extension_names[] = { name };
7490 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007491 v8::Handle<Context> context =
7492 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007493 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007494 v8::Handle<Value> result = CompileRun("foo(42);");
7495 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007496}
7497
7498
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007499TEST(NativeFunctionDeclarationError) {
7500 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007501 const char* name = "nativedeclerr";
7502 // Syntax error in extension code.
7503 v8::RegisterExtension(new NativeFunctionExtension(name,
7504 "native\nfunction foo();"));
7505 const char* extension_names[] = { name };
7506 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007507 v8::Handle<Context> context =
7508 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007509 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007510}
7511
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007512
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007513TEST(NativeFunctionDeclarationErrorEscape) {
7514 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007515 const char* name = "nativedeclerresc";
7516 // Syntax error in extension code - escape code in "native" means that
7517 // it's not treated as a keyword.
7518 v8::RegisterExtension(new NativeFunctionExtension(
7519 name,
7520 "nativ\\u0065 function foo();"));
7521 const char* extension_names[] = { name };
7522 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007523 v8::Handle<Context> context =
7524 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007525 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007526}
7527
7528
Steve Blocka7e24c12009-10-30 11:49:00 +00007529static void CheckDependencies(const char* name, const char* expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007530 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007531 v8::ExtensionConfiguration config(1, &name);
7532 LocalContext context(&config);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007533 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7534 context->Global()->Get(v8_str("loaded")));
Steve Blocka7e24c12009-10-30 11:49:00 +00007535}
7536
7537
7538/*
7539 * Configuration:
7540 *
7541 * /-- B <--\
7542 * A <- -- D <-- E
7543 * \-- C <--/
7544 */
7545THREADED_TEST(ExtensionDependency) {
7546 static const char* kEDeps[] = { "D" };
7547 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7548 static const char* kDDeps[] = { "B", "C" };
7549 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7550 static const char* kBCDeps[] = { "A" };
7551 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7552 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7553 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7554 CheckDependencies("A", "undefinedA");
7555 CheckDependencies("B", "undefinedAB");
7556 CheckDependencies("C", "undefinedAC");
7557 CheckDependencies("D", "undefinedABCD");
7558 CheckDependencies("E", "undefinedABCDE");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007559 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007560 static const char* exts[2] = { "C", "E" };
7561 v8::ExtensionConfiguration config(2, exts);
7562 LocalContext context(&config);
7563 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7564}
7565
7566
7567static const char* kExtensionTestScript =
7568 "native function A();"
7569 "native function B();"
7570 "native function C();"
7571 "function Foo(i) {"
7572 " if (i == 0) return A();"
7573 " if (i == 1) return B();"
7574 " if (i == 2) return C();"
7575 "}";
7576
7577
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007578static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007579 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00007580 if (args.IsConstructCall()) {
7581 args.This()->Set(v8_str("data"), args.Data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007582 args.GetReturnValue().SetNull();
7583 return;
Leon Clarkee46be812010-01-19 14:06:41 +00007584 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007585 args.GetReturnValue().Set(args.Data());
Steve Blocka7e24c12009-10-30 11:49:00 +00007586}
7587
7588
7589class FunctionExtension : public Extension {
7590 public:
7591 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007592 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7593 v8::Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +00007594 v8::Handle<String> name);
7595};
7596
7597
7598static int lookup_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007599v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7600 v8::Isolate* isolate, v8::Handle<String> name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007601 lookup_count++;
7602 if (name->Equals(v8_str("A"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007603 return v8::FunctionTemplate::New(
7604 isolate, CallFun, v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +00007605 } else if (name->Equals(v8_str("B"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007606 return v8::FunctionTemplate::New(
7607 isolate, CallFun, v8::Integer::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +00007608 } else if (name->Equals(v8_str("C"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007609 return v8::FunctionTemplate::New(
7610 isolate, CallFun, v8::Integer::New(isolate, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00007611 } else {
7612 return v8::Handle<v8::FunctionTemplate>();
7613 }
7614}
7615
7616
7617THREADED_TEST(FunctionLookup) {
7618 v8::RegisterExtension(new FunctionExtension());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007619 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007620 static const char* exts[1] = { "functiontest" };
7621 v8::ExtensionConfiguration config(1, exts);
7622 LocalContext context(&config);
7623 CHECK_EQ(3, lookup_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007624 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7625 CompileRun("Foo(0)"));
7626 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7627 CompileRun("Foo(1)"));
7628 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7629 CompileRun("Foo(2)"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007630}
7631
7632
Leon Clarkee46be812010-01-19 14:06:41 +00007633THREADED_TEST(NativeFunctionConstructCall) {
7634 v8::RegisterExtension(new FunctionExtension());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007635 v8::HandleScope handle_scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +00007636 static const char* exts[1] = { "functiontest" };
7637 v8::ExtensionConfiguration config(1, exts);
7638 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00007639 for (int i = 0; i < 10; i++) {
7640 // Run a few times to ensure that allocation of objects doesn't
7641 // change behavior of a constructor function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007642 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7643 CompileRun("(new A()).data"));
7644 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7645 CompileRun("(new B()).data"));
7646 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7647 CompileRun("(new C()).data"));
Leon Clarked91b9f72010-01-27 17:25:45 +00007648 }
Leon Clarkee46be812010-01-19 14:06:41 +00007649}
7650
7651
Steve Blocka7e24c12009-10-30 11:49:00 +00007652static const char* last_location;
7653static const char* last_message;
7654void StoringErrorCallback(const char* location, const char* message) {
7655 if (last_location == NULL) {
7656 last_location = location;
7657 last_message = message;
7658 }
7659}
7660
7661
7662// ErrorReporting creates a circular extensions configuration and
7663// tests that the fatal error handler gets called. This renders V8
7664// unusable and therefore this test cannot be run in parallel.
7665TEST(ErrorReporting) {
7666 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7667 static const char* aDeps[] = { "B" };
7668 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7669 static const char* bDeps[] = { "A" };
7670 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7671 last_location = NULL;
7672 v8::ExtensionConfiguration config(1, bDeps);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007673 v8::Handle<Context> context =
7674 Context::New(CcTest::isolate(), &config);
Steve Blocka7e24c12009-10-30 11:49:00 +00007675 CHECK(context.IsEmpty());
7676 CHECK_NE(last_location, NULL);
7677}
7678
7679
Steve Blocka7e24c12009-10-30 11:49:00 +00007680static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7681 v8::Handle<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007682 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7683 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7684 message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +00007685 message->GetLineNumber();
7686 message->GetSourceLine();
7687}
7688
7689
7690THREADED_TEST(ErrorWithMissingScriptInfo) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007691 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007692 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007693 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007694 CompileRun("throw Error()");
Steve Blocka7e24c12009-10-30 11:49:00 +00007695 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7696}
7697
7698
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007699struct FlagAndPersistent {
7700 bool flag;
7701 v8::Persistent<v8::Object> handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00007702};
7703
Steve Blocka7e24c12009-10-30 11:49:00 +00007704
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007705static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007706 data.GetParameter()->flag = true;
Steve Blockd0582a62009-12-15 09:54:21 +00007707}
7708
Steve Blockd0582a62009-12-15 09:54:21 +00007709
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007710static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7711 v8::Isolate* iso = CcTest::isolate();
7712 v8::HandleScope scope(iso);
7713 v8::Handle<Context> context = Context::New(iso);
7714 Context::Scope context_scope(context);
7715
7716 FlagAndPersistent object_a, object_b;
7717
7718 intptr_t big_heap_size;
7719
7720 {
7721 v8::HandleScope handle_scope(iso);
7722 Local<Object> a(v8::Object::New(iso));
7723 Local<Object> b(v8::Object::New(iso));
7724 object_a.handle.Reset(iso, a);
7725 object_b.handle.Reset(iso, b);
7726 if (interlinked) {
7727 a->Set(v8_str("x"), b);
7728 b->Set(v8_str("x"), a);
7729 }
7730 if (global_gc) {
7731 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7732 } else {
7733 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7734 }
7735 // We are relying on this creating a big flag array and reserving the space
7736 // up front.
7737 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
7738 a->Set(v8_str("y"), big_array);
7739 big_heap_size = CcTest::heap()->SizeOfObjects();
7740 }
7741
7742 object_a.flag = false;
7743 object_b.flag = false;
7744 object_a.handle.SetPhantom(&object_a, &SetFlag);
7745 object_b.handle.SetPhantom(&object_b, &SetFlag);
7746 CHECK(!object_b.handle.IsIndependent());
7747 object_a.handle.MarkIndependent();
7748 object_b.handle.MarkIndependent();
7749 CHECK(object_b.handle.IsIndependent());
7750 if (global_gc) {
7751 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7752 } else {
7753 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7754 }
7755 // A single GC should be enough to reclaim the memory, since we are using
7756 // phantom handles.
7757 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
7758 CHECK(object_a.flag);
7759 CHECK(object_b.flag);
7760}
7761
7762
Ben Murdoch257744e2011-11-30 15:57:28 +00007763THREADED_TEST(IndependentWeakHandle) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007764 IndependentWeakHandle(false, false);
7765 IndependentWeakHandle(false, true);
7766 IndependentWeakHandle(true, false);
7767 IndependentWeakHandle(true, true);
7768}
7769
7770
7771class Trivial {
7772 public:
7773 explicit Trivial(int x) : x_(x) {}
7774
7775 int x() { return x_; }
7776 void set_x(int x) { x_ = x; }
7777
7778 private:
7779 int x_;
7780};
7781
7782
7783class Trivial2 {
7784 public:
7785 Trivial2(int x, int y) : y_(y), x_(x) {}
7786
7787 int x() { return x_; }
7788 void set_x(int x) { x_ = x; }
7789
7790 int y() { return y_; }
7791 void set_y(int y) { y_ = y; }
7792
7793 private:
7794 int y_;
7795 int x_;
7796};
7797
7798
7799void CheckInternalFields(
7800 const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
7801 Trivial* t1 = data.GetInternalField1();
7802 Trivial2* t2 = data.GetInternalField2();
7803 CHECK_EQ(42, t1->x());
7804 CHECK_EQ(103, t2->x());
7805 t1->set_x(1729);
7806 t2->set_x(33550336);
7807}
7808
7809
7810void InternalFieldCallback(bool global_gc) {
7811 LocalContext env;
7812 v8::Isolate* isolate = env->GetIsolate();
7813 v8::HandleScope scope(isolate);
7814
7815 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
7816 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
7817 Trivial* t1;
7818 Trivial2* t2;
7819 instance_templ->SetInternalFieldCount(2);
7820 {
7821 v8::HandleScope scope(isolate);
7822 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
7823 v8::Persistent<v8::Object> handle(isolate, obj);
7824 CHECK_EQ(2, obj->InternalFieldCount());
7825 CHECK(obj->GetInternalField(0)->IsUndefined());
7826 t1 = new Trivial(42);
7827 t2 = new Trivial2(103, 9);
7828
7829 obj->SetAlignedPointerInInternalField(0, t1);
7830 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
7831 CHECK_EQ(42, t1->x());
7832
7833 obj->SetAlignedPointerInInternalField(1, t2);
7834 t2 =
7835 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
7836 CHECK_EQ(103, t2->x());
7837
7838 handle.SetPhantom(CheckInternalFields, 0, 1);
7839 if (!global_gc) {
7840 handle.MarkIndependent();
7841 }
7842 }
7843 if (global_gc) {
7844 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7845 } else {
7846 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7847 }
7848
7849 CHECK_EQ(1729, t1->x());
7850 CHECK_EQ(33550336, t2->x());
7851
7852 delete t1;
7853 delete t2;
7854}
7855
7856
7857THREADED_TEST(InternalFieldCallback) {
7858 InternalFieldCallback(false);
7859 InternalFieldCallback(true);
7860}
7861
7862
7863static void ResetUseValueAndSetFlag(
7864 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7865 // Blink will reset the handle, and then use the other handle, so they
7866 // can't use the same backing slot.
7867 data.GetParameter()->handle.Reset();
7868 data.GetValue()->IsBoolean(); // Make sure the handle still works.
7869 data.GetParameter()->flag = true;
7870}
7871
7872
7873static void ResetWeakHandle(bool global_gc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007874 v8::Isolate* iso = CcTest::isolate();
7875 v8::HandleScope scope(iso);
7876 v8::Handle<Context> context = Context::New(iso);
Steve Blockd0582a62009-12-15 09:54:21 +00007877 Context::Scope context_scope(context);
7878
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007879 FlagAndPersistent object_a, object_b;
Steve Blockd0582a62009-12-15 09:54:21 +00007880
7881 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007882 v8::HandleScope handle_scope(iso);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007883 Local<Object> a(v8::Object::New(iso));
7884 Local<Object> b(v8::Object::New(iso));
7885 object_a.handle.Reset(iso, a);
7886 object_b.handle.Reset(iso, b);
7887 if (global_gc) {
7888 CcTest::heap()->CollectAllGarbage(
7889 TestHeap::Heap::kAbortIncrementalMarkingMask);
7890 } else {
7891 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7892 }
Steve Blockd0582a62009-12-15 09:54:21 +00007893 }
7894
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007895 object_a.flag = false;
7896 object_b.flag = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007897 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
7898 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
7899 if (!global_gc) {
7900 object_a.handle.MarkIndependent();
7901 object_b.handle.MarkIndependent();
7902 CHECK(object_b.handle.IsIndependent());
7903 }
7904 if (global_gc) {
7905 CcTest::heap()->CollectAllGarbage(
7906 TestHeap::Heap::kAbortIncrementalMarkingMask);
7907 } else {
7908 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7909 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007910 CHECK(object_a.flag);
7911 CHECK(object_b.flag);
Ben Murdoch257744e2011-11-30 15:57:28 +00007912}
Steve Blockd0582a62009-12-15 09:54:21 +00007913
Ben Murdoch257744e2011-11-30 15:57:28 +00007914
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007915THREADED_TEST(ResetWeakHandle) {
7916 ResetWeakHandle(false);
7917 ResetWeakHandle(true);
7918}
7919
7920
Ben Murdoch257744e2011-11-30 15:57:28 +00007921static void InvokeScavenge() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007922 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Ben Murdoch257744e2011-11-30 15:57:28 +00007923}
7924
7925
7926static void InvokeMarkSweep() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007927 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch257744e2011-11-30 15:57:28 +00007928}
7929
7930
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007931static void ForceScavenge(
7932 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7933 data.GetParameter()->handle.Reset();
7934 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007935 InvokeScavenge();
7936}
7937
7938
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007939static void ForceMarkSweep(
7940 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7941 data.GetParameter()->handle.Reset();
7942 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007943 InvokeMarkSweep();
7944}
7945
7946
7947THREADED_TEST(GCFromWeakCallbacks) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007948 v8::Isolate* isolate = CcTest::isolate();
7949 v8::HandleScope scope(isolate);
7950 v8::Handle<Context> context = Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +00007951 Context::Scope context_scope(context);
7952
7953 static const int kNumberOfGCTypes = 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007954 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7955 Callback;
7956 Callback gc_forcing_callback[kNumberOfGCTypes] =
Ben Murdoch257744e2011-11-30 15:57:28 +00007957 {&ForceScavenge, &ForceMarkSweep};
7958
7959 typedef void (*GCInvoker)();
7960 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7961
7962 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7963 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007964 FlagAndPersistent object;
Ben Murdoch257744e2011-11-30 15:57:28 +00007965 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007966 v8::HandleScope handle_scope(isolate);
7967 object.handle.Reset(isolate, v8::Object::New(isolate));
Ben Murdoch257744e2011-11-30 15:57:28 +00007968 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007969 object.flag = false;
7970 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7971 object.handle.MarkIndependent();
Ben Murdoch257744e2011-11-30 15:57:28 +00007972 invoke_gc[outer_gc]();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007973 CHECK(object.flag);
Ben Murdoch257744e2011-11-30 15:57:28 +00007974 }
Steve Blockd0582a62009-12-15 09:54:21 +00007975 }
Ben Murdoch257744e2011-11-30 15:57:28 +00007976}
7977
7978
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007979static void RevivingCallback(
7980 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7981 data.GetParameter()->handle.ClearWeak();
7982 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007983}
7984
7985
7986THREADED_TEST(IndependentHandleRevival) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007987 v8::Isolate* isolate = CcTest::isolate();
7988 v8::HandleScope scope(isolate);
7989 v8::Handle<Context> context = Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +00007990 Context::Scope context_scope(context);
7991
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007992 FlagAndPersistent object;
Ben Murdoch257744e2011-11-30 15:57:28 +00007993 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007994 v8::HandleScope handle_scope(isolate);
7995 v8::Local<v8::Object> o = v8::Object::New(isolate);
7996 object.handle.Reset(isolate, o);
7997 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
Ben Murdoch257744e2011-11-30 15:57:28 +00007998 v8::Local<String> y_str = v8_str("y");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007999 o->Set(y_str, y_str);
Ben Murdoch257744e2011-11-30 15:57:28 +00008000 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008001 object.flag = false;
8002 object.handle.SetWeak(&object, &RevivingCallback);
8003 object.handle.MarkIndependent();
8004 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
8005 CHECK(object.flag);
8006 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch257744e2011-11-30 15:57:28 +00008007 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008008 v8::HandleScope handle_scope(isolate);
8009 v8::Local<v8::Object> o =
8010 v8::Local<v8::Object>::New(isolate, object.handle);
Ben Murdoch257744e2011-11-30 15:57:28 +00008011 v8::Local<String> y_str = v8_str("y");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008012 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
8013 CHECK(o->Get(y_str)->Equals(y_str));
Ben Murdoch257744e2011-11-30 15:57:28 +00008014 }
Steve Blockd0582a62009-12-15 09:54:21 +00008015}
8016
8017
Steve Blocka7e24c12009-10-30 11:49:00 +00008018v8::Handle<Function> args_fun;
8019
8020
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008021static void ArgumentsTestCallback(
8022 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008023 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008024 v8::Isolate* isolate = args.GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008025 CHECK_EQ(args_fun, args.Callee());
8026 CHECK_EQ(3, args.Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008027 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
8028 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
8029 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
8030 CHECK_EQ(v8::Undefined(isolate), args[3]);
8031 v8::HandleScope scope(args.GetIsolate());
8032 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008033}
8034
8035
8036THREADED_TEST(Arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008037 v8::Isolate* isolate = CcTest::isolate();
8038 v8::HandleScope scope(isolate);
8039 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8040 global->Set(v8_str("f"),
8041 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +00008042 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01008043 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008044 v8_compile("f(1, 2, 3)")->Run();
8045}
8046
8047
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008048static void NoBlockGetterX(Local<Name> name,
8049 const v8::PropertyCallbackInfo<v8::Value>&) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00008050
8051
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008052static void NoBlockGetterI(uint32_t index,
8053 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008054}
8055
8056
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008057static void PDeleter(Local<Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008058 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008059 if (!name->Equals(v8_str("foo"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008060 return; // not intercepted
Steve Blocka7e24c12009-10-30 11:49:00 +00008061 }
8062
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008063 info.GetReturnValue().Set(false); // intercepted, don't delete the property
Steve Blocka7e24c12009-10-30 11:49:00 +00008064}
8065
8066
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008067static void IDeleter(uint32_t index,
8068 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008069 if (index != 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008070 return; // not intercepted
Steve Blocka7e24c12009-10-30 11:49:00 +00008071 }
8072
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008073 info.GetReturnValue().Set(false); // intercepted, don't delete the property
Steve Blocka7e24c12009-10-30 11:49:00 +00008074}
8075
8076
8077THREADED_TEST(Deleter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008078 v8::Isolate* isolate = CcTest::isolate();
8079 v8::HandleScope scope(isolate);
8080 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008081 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
8082 NULL, PDeleter, NULL));
8083 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8084 NoBlockGetterI, NULL, NULL, IDeleter, NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00008085 LocalContext context;
8086 context->Global()->Set(v8_str("k"), obj->NewInstance());
8087 CompileRun(
8088 "k.foo = 'foo';"
8089 "k.bar = 'bar';"
8090 "k[2] = 2;"
8091 "k[4] = 4;");
8092 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
8093 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
8094
8095 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
8096 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
8097
8098 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
8099 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
8100
8101 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
8102 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
8103}
8104
8105
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008106static void GetK(Local<Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008107 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008108 ApiTestFuzzer::Fuzz();
8109 if (name->Equals(v8_str("foo")) ||
8110 name->Equals(v8_str("bar")) ||
8111 name->Equals(v8_str("baz"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008112 info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00008113 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008114}
8115
8116
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008117static void IndexedGetK(uint32_t index,
8118 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008119 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008120 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00008121}
8122
8123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008124static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008125 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008126 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
8127 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
8128 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
8129 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
8130 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008131}
8132
8133
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008134static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008135 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008136 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
8137 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
8138 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
8139 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008140}
8141
8142
8143THREADED_TEST(Enumerators) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008144 v8::Isolate* isolate = CcTest::isolate();
8145 v8::HandleScope scope(isolate);
8146 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008147 obj->SetHandler(
8148 v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
8149 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8150 IndexedGetK, NULL, NULL, NULL, IndexedEnum));
Steve Blocka7e24c12009-10-30 11:49:00 +00008151 LocalContext context;
8152 context->Global()->Set(v8_str("k"), obj->NewInstance());
8153 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
8154 "k[10] = 0;"
8155 "k.a = 0;"
8156 "k[5] = 0;"
8157 "k.b = 0;"
8158 "k[4294967295] = 0;"
8159 "k.c = 0;"
8160 "k[4294967296] = 0;"
8161 "k.d = 0;"
8162 "k[140000] = 0;"
8163 "k.e = 0;"
8164 "k[30000000000] = 0;"
8165 "k.f = 0;"
8166 "var result = [];"
8167 "for (var prop in k) {"
8168 " result.push(prop);"
8169 "}"
8170 "result"));
8171 // Check that we get all the property names returned including the
8172 // ones from the enumerators in the right order: indexed properties
8173 // in numerical order, indexed interceptor properties, named
8174 // properties in insertion order, named interceptor properties.
8175 // This order is not mandated by the spec, so this test is just
8176 // documenting our behavior.
8177 CHECK_EQ(17, result->Length());
8178 // Indexed properties in numerical order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008179 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
8180 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
8181 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
8182 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008183 // Indexed interceptor properties in the order they are returned
8184 // from the enumerator interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008185 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
8186 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008187 // Named properties in insertion order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008188 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
8189 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
8190 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
8191 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
8192 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
8193 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
8194 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
8195 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008196 // Named interceptor properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008197 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
8198 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
8199 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008200}
8201
8202
8203int p_getter_count;
8204int p_getter_count2;
8205
8206
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008207static void PGetter(Local<String> name,
8208 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008209 ApiTestFuzzer::Fuzz();
8210 p_getter_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008211 v8::Handle<v8::Object> global =
8212 info.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00008213 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8214 if (name->Equals(v8_str("p1"))) {
8215 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8216 } else if (name->Equals(v8_str("p2"))) {
8217 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8218 } else if (name->Equals(v8_str("p3"))) {
8219 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8220 } else if (name->Equals(v8_str("p4"))) {
8221 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8222 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008223}
8224
8225
8226static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
8227 ApiTestFuzzer::Fuzz();
8228 LocalContext context;
8229 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8230 CompileRun(
8231 "o1.__proto__ = { };"
8232 "var o2 = { __proto__: o1 };"
8233 "var o3 = { __proto__: o2 };"
8234 "var o4 = { __proto__: o3 };"
8235 "for (var i = 0; i < 10; i++) o4.p4;"
8236 "for (var i = 0; i < 10; i++) o3.p3;"
8237 "for (var i = 0; i < 10; i++) o2.p2;"
8238 "for (var i = 0; i < 10; i++) o1.p1;");
8239}
8240
8241
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008242static void PGetter2(Local<Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008243 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008244 ApiTestFuzzer::Fuzz();
8245 p_getter_count2++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008246 v8::Handle<v8::Object> global =
8247 info.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00008248 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8249 if (name->Equals(v8_str("p1"))) {
8250 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8251 } else if (name->Equals(v8_str("p2"))) {
8252 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8253 } else if (name->Equals(v8_str("p3"))) {
8254 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8255 } else if (name->Equals(v8_str("p4"))) {
8256 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8257 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008258}
8259
8260
8261THREADED_TEST(GetterHolders) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008262 v8::Isolate* isolate = CcTest::isolate();
8263 v8::HandleScope scope(isolate);
8264 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008265 obj->SetAccessor(v8_str("p1"), PGetter);
8266 obj->SetAccessor(v8_str("p2"), PGetter);
8267 obj->SetAccessor(v8_str("p3"), PGetter);
8268 obj->SetAccessor(v8_str("p4"), PGetter);
8269 p_getter_count = 0;
8270 RunHolderTest(obj);
8271 CHECK_EQ(40, p_getter_count);
8272}
8273
8274
8275THREADED_TEST(PreInterceptorHolders) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008276 v8::Isolate* isolate = CcTest::isolate();
8277 v8::HandleScope scope(isolate);
8278 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008279 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
Steve Blocka7e24c12009-10-30 11:49:00 +00008280 p_getter_count2 = 0;
8281 RunHolderTest(obj);
8282 CHECK_EQ(40, p_getter_count2);
8283}
8284
8285
8286THREADED_TEST(ObjectInstantiation) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008287 v8::Isolate* isolate = CcTest::isolate();
8288 v8::HandleScope scope(isolate);
8289 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008290 templ->SetAccessor(v8_str("t"), PGetter2);
8291 LocalContext context;
8292 context->Global()->Set(v8_str("o"), templ->NewInstance());
8293 for (int i = 0; i < 100; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008294 v8::HandleScope inner_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008295 v8::Handle<v8::Object> obj = templ->NewInstance();
8296 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
8297 context->Global()->Set(v8_str("o2"), obj);
8298 v8::Handle<Value> value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008299 CompileRun("o.__proto__ === o2.__proto__");
8300 CHECK_EQ(v8::True(isolate), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008301 context->Global()->Set(v8_str("o"), obj);
8302 }
8303}
8304
8305
Ben Murdochb0fe1622011-05-05 13:52:32 +01008306static int StrCmp16(uint16_t* a, uint16_t* b) {
8307 while (true) {
8308 if (*a == 0 && *b == 0) return 0;
8309 if (*a != *b) return 0 + *a - *b;
8310 a++;
8311 b++;
8312 }
8313}
8314
8315
8316static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8317 while (true) {
8318 if (n-- == 0) return 0;
8319 if (*a == 0 && *b == 0) return 0;
8320 if (*a != *b) return 0 + *a - *b;
8321 a++;
8322 b++;
8323 }
8324}
8325
8326
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008327int GetUtf8Length(Handle<String> str) {
8328 int len = str->Utf8Length();
8329 if (len < 0) {
8330 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008331 i::String::Flatten(istr);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008332 len = str->Utf8Length();
8333 }
8334 return len;
8335}
8336
8337
Steve Blocka7e24c12009-10-30 11:49:00 +00008338THREADED_TEST(StringWrite) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008339 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008340 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008341 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008342 // abc<Icelandic eth><Unicode snowman>.
8343 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008344 v8::Handle<String> str3 = v8::String::NewFromUtf8(
8345 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
8346 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8347 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8348 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
8349 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
8350 // single lead surrogate
8351 uint16_t lead[1] = { 0xd800 };
8352 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
8353 context->GetIsolate(), lead, v8::String::kNormalString, 1);
8354 // single trail surrogate
8355 uint16_t trail[1] = { 0xdc00 };
8356 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
8357 context->GetIsolate(), trail, v8::String::kNormalString, 1);
8358 // surrogate pair
8359 uint16_t pair[2] = { 0xd800, 0xdc00 };
8360 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
8361 context->GetIsolate(), pair, v8::String::kNormalString, 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008362 const int kStride = 4; // Must match stride in for loops in JS below.
8363 CompileRun(
8364 "var left = '';"
8365 "for (var i = 0; i < 0xd800; i += 4) {"
8366 " left = left + String.fromCharCode(i);"
8367 "}");
8368 CompileRun(
8369 "var right = '';"
8370 "for (var i = 0; i < 0xd800; i += 4) {"
8371 " right = String.fromCharCode(i) + right;"
8372 "}");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008373 v8::Handle<v8::Object> global = context->Global();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008374 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
8375 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008376
8377 CHECK_EQ(5, str2->Length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008378 CHECK_EQ(0xd800 / kStride, left_tree->Length());
8379 CHECK_EQ(0xd800 / kStride, right_tree->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008380
8381 char buf[100];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008382 char utf8buf[0xd800 * 3];
Ben Murdochb0fe1622011-05-05 13:52:32 +01008383 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00008384 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008385 int charlen;
8386
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008387 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008388 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008389 CHECK_EQ(9, len);
8390 CHECK_EQ(5, charlen);
8391 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008392
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008393 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008394 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008395 CHECK_EQ(8, len);
8396 CHECK_EQ(5, charlen);
8397 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008398
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008399 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008400 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008401 CHECK_EQ(5, len);
8402 CHECK_EQ(4, charlen);
8403 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008404
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008405 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008406 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008407 CHECK_EQ(5, len);
8408 CHECK_EQ(4, charlen);
8409 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008410
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008411 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008412 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008413 CHECK_EQ(5, len);
8414 CHECK_EQ(4, charlen);
8415 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008416
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008417 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008418 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008419 CHECK_EQ(3, len);
8420 CHECK_EQ(3, charlen);
8421 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008422
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008423 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008424 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008425 CHECK_EQ(3, len);
8426 CHECK_EQ(3, charlen);
8427 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008428
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008429 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008430 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01008431 CHECK_EQ(2, len);
8432 CHECK_EQ(2, charlen);
8433 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00008434
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008435 // allow orphan surrogates by default
8436 memset(utf8buf, 0x1, 1000);
8437 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8438 CHECK_EQ(13, len);
8439 CHECK_EQ(8, charlen);
8440 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8441
8442 // replace orphan surrogates with unicode replacement character
8443 memset(utf8buf, 0x1, 1000);
8444 len = orphans_str->WriteUtf8(utf8buf,
8445 sizeof(utf8buf),
8446 &charlen,
8447 String::REPLACE_INVALID_UTF8);
8448 CHECK_EQ(13, len);
8449 CHECK_EQ(8, charlen);
8450 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8451
8452 // replace single lead surrogate with unicode replacement character
8453 memset(utf8buf, 0x1, 1000);
8454 len = lead_str->WriteUtf8(utf8buf,
8455 sizeof(utf8buf),
8456 &charlen,
8457 String::REPLACE_INVALID_UTF8);
8458 CHECK_EQ(4, len);
8459 CHECK_EQ(1, charlen);
8460 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8461
8462 // replace single trail surrogate with unicode replacement character
8463 memset(utf8buf, 0x1, 1000);
8464 len = trail_str->WriteUtf8(utf8buf,
8465 sizeof(utf8buf),
8466 &charlen,
8467 String::REPLACE_INVALID_UTF8);
8468 CHECK_EQ(4, len);
8469 CHECK_EQ(1, charlen);
8470 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8471
8472 // do not replace / write anything if surrogate pair does not fit the buffer
8473 // space
8474 memset(utf8buf, 0x1, 1000);
8475 len = pair_str->WriteUtf8(utf8buf,
8476 3,
8477 &charlen,
8478 String::REPLACE_INVALID_UTF8);
8479 CHECK_EQ(0, len);
8480 CHECK_EQ(0, charlen);
8481
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008482 memset(utf8buf, 0x1, sizeof(utf8buf));
8483 len = GetUtf8Length(left_tree);
8484 int utf8_expected =
8485 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8486 CHECK_EQ(utf8_expected, len);
8487 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8488 CHECK_EQ(utf8_expected, len);
8489 CHECK_EQ(0xd800 / kStride, charlen);
8490 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8491 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8492 CHECK_EQ(0xc0 - kStride,
8493 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8494 CHECK_EQ(1, utf8buf[utf8_expected]);
8495
8496 memset(utf8buf, 0x1, sizeof(utf8buf));
8497 len = GetUtf8Length(right_tree);
8498 CHECK_EQ(utf8_expected, len);
8499 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8500 CHECK_EQ(utf8_expected, len);
8501 CHECK_EQ(0xd800 / kStride, charlen);
8502 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8503 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8504 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8505 CHECK_EQ(1, utf8buf[utf8_expected]);
8506
Steve Blocka7e24c12009-10-30 11:49:00 +00008507 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008508 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008509 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
Steve Block44f0eee2011-05-26 01:26:41 +01008510 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008511 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01008512 CHECK_EQ(5, len);
8513 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008514 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008515 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008516
8517 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008518 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008519 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01008520 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008521 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01008522 CHECK_EQ(4, len);
8523 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008524 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008525 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00008526
8527 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008528 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008529 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01008530 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008531 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01008532 CHECK_EQ(5, len);
8533 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008534 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008535 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00008536
8537 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008538 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008539 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008540 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008541 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008542 CHECK_EQ(5, len);
8543 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008544 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008545 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008546
8547 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008548 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008549 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01008550 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008551 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01008552 CHECK_EQ(1, len);
8553 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008554 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008555 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008556
8557 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008558 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008559 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008560 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008561 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008562 CHECK_EQ(1, len);
8563 CHECK_EQ(0, strcmp("e", buf));
8564 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008565
8566 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008567 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008568 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008569 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008570 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008571 CHECK_EQ(1, len);
8572 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008573 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008574 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008575
8576 memset(buf, 0x1, sizeof(buf));
8577 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008578 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008579 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008580 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008581 CHECK_EQ(1, len);
8582 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008583 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008584 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008585
8586 memset(wbuf, 0x1, sizeof(wbuf));
8587 wbuf[5] = 'X';
8588 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8589 CHECK_EQ(5, len);
8590 CHECK_EQ('X', wbuf[5]);
8591 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8592 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8593 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8594 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8595 wbuf[5] = '\0';
8596 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8597
8598 memset(buf, 0x1, sizeof(buf));
8599 buf[5] = 'X';
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008600 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8601 0,
8602 6,
8603 String::NO_NULL_TERMINATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008604 CHECK_EQ(5, len);
8605 CHECK_EQ('X', buf[5]);
8606 CHECK_EQ(0, strncmp("abcde", buf, 5));
8607 CHECK_NE(0, strcmp("abcde", buf));
8608 buf[5] = '\0';
8609 CHECK_EQ(0, strcmp("abcde", buf));
8610
8611 memset(utf8buf, 0x1, sizeof(utf8buf));
8612 utf8buf[8] = 'X';
8613 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8614 String::NO_NULL_TERMINATION);
8615 CHECK_EQ(8, len);
8616 CHECK_EQ('X', utf8buf[8]);
8617 CHECK_EQ(5, charlen);
8618 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8619 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8620 utf8buf[8] = '\0';
8621 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008622
8623 memset(utf8buf, 0x1, sizeof(utf8buf));
8624 utf8buf[5] = 'X';
8625 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8626 String::NO_NULL_TERMINATION);
8627 CHECK_EQ(5, len);
8628 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8629 CHECK_EQ(5, charlen);
8630 utf8buf[5] = '\0';
8631 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8632
8633 memset(buf, 0x1, sizeof(buf));
8634 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8635 CHECK_EQ(7, len);
8636 CHECK_EQ(0, strcmp("abc", buf));
8637 CHECK_EQ(0, buf[3]);
8638 CHECK_EQ(0, strcmp("def", buf + 4));
8639
8640 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8641 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8642 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
Steve Blocka7e24c12009-10-30 11:49:00 +00008643}
8644
8645
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008646static void Utf16Helper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008647 LocalContext& context, // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008648 const char* name,
8649 const char* lengths_name,
8650 int len) {
8651 Local<v8::Array> a =
8652 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8653 Local<v8::Array> alens =
8654 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8655 for (int i = 0; i < len; i++) {
8656 Local<v8::String> string =
8657 Local<v8::String>::Cast(a->Get(i));
8658 Local<v8::Number> expected_len =
8659 Local<v8::Number>::Cast(alens->Get(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008660 int length = GetUtf8Length(string);
8661 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8662 }
8663}
8664
8665
8666static uint16_t StringGet(Handle<String> str, int index) {
8667 i::Handle<i::String> istring =
8668 v8::Utils::OpenHandle(String::Cast(*str));
8669 return istring->Get(index);
8670}
8671
8672
8673static void WriteUtf8Helper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008674 LocalContext& context, // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008675 const char* name,
8676 const char* lengths_name,
8677 int len) {
8678 Local<v8::Array> b =
8679 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8680 Local<v8::Array> alens =
8681 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8682 char buffer[1000];
8683 char buffer2[1000];
8684 for (int i = 0; i < len; i++) {
8685 Local<v8::String> string =
8686 Local<v8::String>::Cast(b->Get(i));
8687 Local<v8::Number> expected_len =
8688 Local<v8::Number>::Cast(alens->Get(i));
8689 int utf8_length = static_cast<int>(expected_len->Value());
8690 for (int j = utf8_length + 1; j >= 0; j--) {
8691 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8692 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8693 int nchars;
8694 int utf8_written =
8695 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8696 int utf8_written2 =
8697 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8698 CHECK_GE(utf8_length + 1, utf8_written);
8699 CHECK_GE(utf8_length, utf8_written2);
8700 for (int k = 0; k < utf8_written2; k++) {
8701 CHECK_EQ(buffer[k], buffer2[k]);
8702 }
8703 CHECK(nchars * 3 >= utf8_written - 1);
8704 CHECK(nchars <= utf8_written);
8705 if (j == utf8_length + 1) {
8706 CHECK_EQ(utf8_written2, utf8_length);
8707 CHECK_EQ(utf8_written2 + 1, utf8_written);
8708 }
8709 CHECK_EQ(buffer[utf8_written], 42);
8710 if (j > utf8_length) {
8711 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8712 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8713 Handle<String> roundtrip = v8_str(buffer);
8714 CHECK(roundtrip->Equals(string));
8715 } else {
8716 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8717 }
8718 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8719 if (nchars >= 2) {
8720 uint16_t trail = StringGet(string, nchars - 1);
8721 uint16_t lead = StringGet(string, nchars - 2);
8722 if (((lead & 0xfc00) == 0xd800) &&
8723 ((trail & 0xfc00) == 0xdc00)) {
8724 unsigned char u1 = buffer2[utf8_written2 - 4];
8725 unsigned char u2 = buffer2[utf8_written2 - 3];
8726 unsigned char u3 = buffer2[utf8_written2 - 2];
8727 unsigned char u4 = buffer2[utf8_written2 - 1];
8728 CHECK_EQ((u1 & 0xf8), 0xf0);
8729 CHECK_EQ((u2 & 0xc0), 0x80);
8730 CHECK_EQ((u3 & 0xc0), 0x80);
8731 CHECK_EQ((u4 & 0xc0), 0x80);
8732 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8733 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8734 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8735 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8736 CHECK_EQ((u1 & 0x3), c >> 18);
8737 }
8738 }
8739 }
8740 }
8741}
8742
8743
8744THREADED_TEST(Utf16) {
8745 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008746 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008747 CompileRun(
8748 "var pad = '01234567890123456789';"
8749 "var p = [];"
8750 "var plens = [20, 3, 3];"
8751 "p.push('01234567890123456789');"
8752 "var lead = 0xd800;"
8753 "var trail = 0xdc00;"
8754 "p.push(String.fromCharCode(0xd800));"
8755 "p.push(String.fromCharCode(0xdc00));"
8756 "var a = [];"
8757 "var b = [];"
8758 "var c = [];"
8759 "var alens = [];"
8760 "for (var i = 0; i < 3; i++) {"
8761 " p[1] = String.fromCharCode(lead++);"
8762 " for (var j = 0; j < 3; j++) {"
8763 " p[2] = String.fromCharCode(trail++);"
8764 " a.push(p[i] + p[j]);"
8765 " b.push(p[i] + p[j]);"
8766 " c.push(p[i] + p[j]);"
8767 " alens.push(plens[i] + plens[j]);"
8768 " }"
8769 "}"
8770 "alens[5] -= 2;" // Here the surrogate pairs match up.
8771 "var a2 = [];"
8772 "var b2 = [];"
8773 "var c2 = [];"
8774 "var a2lens = [];"
8775 "for (var m = 0; m < 9; m++) {"
8776 " for (var n = 0; n < 9; n++) {"
8777 " a2.push(a[m] + a[n]);"
8778 " b2.push(b[m] + b[n]);"
8779 " var newc = 'x' + c[m] + c[n] + 'y';"
8780 " c2.push(newc.substring(1, newc.length - 1));"
8781 " var utf = alens[m] + alens[n];" // And here.
8782 // The 'n's that start with 0xdc.. are 6-8
8783 // The 'm's that end with 0xd8.. are 1, 4 and 7
8784 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8785 " a2lens.push(utf);"
8786 " }"
8787 "}");
8788 Utf16Helper(context, "a", "alens", 9);
8789 Utf16Helper(context, "a2", "a2lens", 81);
8790 WriteUtf8Helper(context, "b", "alens", 9);
8791 WriteUtf8Helper(context, "b2", "a2lens", 81);
8792 WriteUtf8Helper(context, "c2", "a2lens", 81);
8793}
8794
8795
8796static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8797 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8798 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8799 return *is1 == *is2;
8800}
8801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008802static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8803 const char* b) {
8804 Handle<String> symbol1 =
8805 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8806 Handle<String> symbol2 =
8807 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008808 CHECK(SameSymbol(symbol1, symbol2));
8809}
8810
8811
8812THREADED_TEST(Utf16Symbol) {
8813 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008814 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008815
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008816 Handle<String> symbol1 = v8::String::NewFromUtf8(
8817 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8818 Handle<String> symbol2 = v8::String::NewFromUtf8(
8819 context->GetIsolate(), "abc", v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008820 CHECK(SameSymbol(symbol1, symbol2));
8821
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008822 SameSymbolHelper(context->GetIsolate(),
8823 "\360\220\220\205", // 4 byte encoding.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008824 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008825 SameSymbolHelper(context->GetIsolate(),
8826 "\355\240\201\355\260\206", // 2 3-byte surrogates.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008827 "\360\220\220\206"); // 4 byte encoding.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008828 SameSymbolHelper(context->GetIsolate(),
8829 "x\360\220\220\205", // 4 byte encoding.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008830 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008831 SameSymbolHelper(context->GetIsolate(),
8832 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008833 "x\360\220\220\206"); // 4 byte encoding.
8834 CompileRun(
8835 "var sym0 = 'benedictus';"
8836 "var sym0b = 'S\303\270ren';"
8837 "var sym1 = '\355\240\201\355\260\207';"
8838 "var sym2 = '\360\220\220\210';"
8839 "var sym3 = 'x\355\240\201\355\260\207';"
8840 "var sym4 = 'x\360\220\220\210';"
8841 "if (sym1.length != 2) throw sym1;"
8842 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8843 "if (sym2.length != 2) throw sym2;"
8844 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8845 "if (sym3.length != 3) throw sym3;"
8846 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8847 "if (sym4.length != 3) throw sym4;"
8848 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008849 Handle<String> sym0 = v8::String::NewFromUtf8(
8850 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8851 Handle<String> sym0b = v8::String::NewFromUtf8(
8852 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8853 Handle<String> sym1 =
8854 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8855 v8::String::kInternalizedString);
8856 Handle<String> sym2 =
8857 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8858 v8::String::kInternalizedString);
8859 Handle<String> sym3 = v8::String::NewFromUtf8(
8860 context->GetIsolate(), "x\355\240\201\355\260\207",
8861 v8::String::kInternalizedString);
8862 Handle<String> sym4 =
8863 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8864 v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008865 v8::Local<v8::Object> global = context->Global();
8866 Local<Value> s0 = global->Get(v8_str("sym0"));
8867 Local<Value> s0b = global->Get(v8_str("sym0b"));
8868 Local<Value> s1 = global->Get(v8_str("sym1"));
8869 Local<Value> s2 = global->Get(v8_str("sym2"));
8870 Local<Value> s3 = global->Get(v8_str("sym3"));
8871 Local<Value> s4 = global->Get(v8_str("sym4"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008872 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8873 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8874 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8875 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8876 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8877 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008878}
8879
8880
Steve Blocka7e24c12009-10-30 11:49:00 +00008881THREADED_TEST(ToArrayIndex) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008882 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008883 v8::Isolate* isolate = context->GetIsolate();
8884 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008885
8886 v8::Handle<String> str = v8_str("42");
8887 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8888 CHECK(!index.IsEmpty());
8889 CHECK_EQ(42.0, index->Uint32Value());
8890 str = v8_str("42asdf");
8891 index = str->ToArrayIndex();
8892 CHECK(index.IsEmpty());
8893 str = v8_str("-42");
8894 index = str->ToArrayIndex();
8895 CHECK(index.IsEmpty());
8896 str = v8_str("4294967295");
8897 index = str->ToArrayIndex();
8898 CHECK(!index.IsEmpty());
8899 CHECK_EQ(4294967295.0, index->Uint32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008900 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00008901 index = num->ToArrayIndex();
8902 CHECK(!index.IsEmpty());
8903 CHECK_EQ(1.0, index->Uint32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008904 num = v8::Number::New(isolate, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00008905 index = num->ToArrayIndex();
8906 CHECK(index.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008907 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008908 index = obj->ToArrayIndex();
8909 CHECK(index.IsEmpty());
8910}
8911
8912
8913THREADED_TEST(ErrorConstruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008914 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008915 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008916
8917 v8::Handle<String> foo = v8_str("foo");
8918 v8::Handle<String> message = v8_str("message");
8919 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8920 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008921 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008922 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8923 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008924 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008925 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8926 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008927 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008928 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8929 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008930 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008931 v8::Handle<Value> error = v8::Exception::Error(foo);
8932 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008933 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008934}
8935
8936
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008937static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8938 ApiTestFuzzer::Fuzz();
8939 v8::Handle<String> foo = v8_str("foo");
8940 v8::Handle<String> message = v8_str("message");
8941 v8::Handle<Value> error = v8::Exception::Error(foo);
8942 CHECK(error->IsObject());
8943 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8944 info.GetIsolate()->ThrowException(error);
8945 info.GetReturnValue().SetUndefined();
8946}
8947
8948
8949THREADED_TEST(ExceptionCreateMessage) {
8950 LocalContext context;
8951 v8::HandleScope scope(context->GetIsolate());
8952 v8::Handle<String> foo_str = v8_str("foo");
8953 v8::Handle<String> message_str = v8_str("message");
8954
8955 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
8956
8957 Local<v8::FunctionTemplate> fun =
8958 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8959 v8::Local<v8::Object> global = context->Global();
8960 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
8961
8962 TryCatch try_catch;
8963 CompileRun(
8964 "function f1() {\n"
8965 " throwV8Exception();\n"
8966 "};\n"
8967 "f1();");
8968 CHECK(try_catch.HasCaught());
8969
8970 v8::Handle<v8::Value> error = try_catch.Exception();
8971 CHECK(error->IsObject());
8972 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8973
8974 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
8975 CHECK(!message.IsEmpty());
8976 CHECK_EQ(2, message->GetLineNumber());
8977 CHECK_EQ(2, message->GetStartColumn());
8978
8979 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
8980 CHECK(!stackTrace.IsEmpty());
8981 CHECK_EQ(2, stackTrace->GetFrameCount());
8982
8983 stackTrace = v8::Exception::GetStackTrace(error);
8984 CHECK(!stackTrace.IsEmpty());
8985 CHECK_EQ(2, stackTrace->GetFrameCount());
8986
8987 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
8988
8989 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8990 // is false.
8991 try_catch.Reset();
8992
8993 CompileRun(
8994 "function f2() {\n"
8995 " return throwV8Exception();\n"
8996 "};\n"
8997 "f2();");
8998 CHECK(try_catch.HasCaught());
8999
9000 error = try_catch.Exception();
9001 CHECK(error->IsObject());
9002 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
9003
9004 message = v8::Exception::CreateMessage(error);
9005 CHECK(!message.IsEmpty());
9006 CHECK_EQ(2, message->GetLineNumber());
9007 CHECK_EQ(9, message->GetStartColumn());
9008
9009 // Should be empty stack trace.
9010 stackTrace = message->GetStackTrace();
9011 CHECK(stackTrace.IsEmpty());
9012 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9013}
9014
9015
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009016static void YGetter(Local<String> name,
9017 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009018 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009019 info.GetReturnValue().Set(v8_num(10));
Steve Blocka7e24c12009-10-30 11:49:00 +00009020}
9021
9022
9023static void YSetter(Local<String> name,
9024 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009025 const v8::PropertyCallbackInfo<void>& info) {
9026 Local<Object> this_obj = Local<Object>::Cast(info.This());
9027 if (this_obj->Has(name)) this_obj->Delete(name);
9028 this_obj->Set(name, value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009029}
9030
9031
9032THREADED_TEST(DeleteAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009033 v8::Isolate* isolate = CcTest::isolate();
9034 v8::HandleScope scope(isolate);
9035 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009036 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9037 LocalContext context;
9038 v8::Handle<v8::Object> holder = obj->NewInstance();
9039 context->Global()->Set(v8_str("holder"), holder);
9040 v8::Handle<Value> result = CompileRun(
9041 "holder.y = 11; holder.y = 12; holder.y");
9042 CHECK_EQ(12, result->Uint32Value());
9043}
9044
9045
9046THREADED_TEST(TypeSwitch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009047 v8::Isolate* isolate = CcTest::isolate();
9048 v8::HandleScope scope(isolate);
9049 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
9050 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
9051 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009052 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
9053 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
9054 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009055 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009056 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
9057 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
9058 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
9059 for (int i = 0; i < 10; i++) {
9060 CHECK_EQ(0, type_switch->match(obj0));
9061 CHECK_EQ(1, type_switch->match(obj1));
9062 CHECK_EQ(2, type_switch->match(obj2));
9063 CHECK_EQ(3, type_switch->match(obj3));
9064 CHECK_EQ(3, type_switch->match(obj3));
9065 CHECK_EQ(2, type_switch->match(obj2));
9066 CHECK_EQ(1, type_switch->match(obj1));
9067 CHECK_EQ(0, type_switch->match(obj0));
9068 }
9069}
9070
9071
Steve Blocka7e24c12009-10-30 11:49:00 +00009072static int trouble_nesting = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009073static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009074 ApiTestFuzzer::Fuzz();
9075 trouble_nesting++;
9076
9077 // Call a JS function that throws an uncaught exception.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009078 Local<v8::Object> arg_this =
9079 args.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00009080 Local<Value> trouble_callee = (trouble_nesting == 3) ?
9081 arg_this->Get(v8_str("trouble_callee")) :
9082 arg_this->Get(v8_str("trouble_caller"));
9083 CHECK(trouble_callee->IsFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009084 args.GetReturnValue().Set(
9085 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00009086}
9087
9088
9089static int report_count = 0;
9090static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
9091 v8::Handle<Value>) {
9092 report_count++;
9093}
9094
9095
9096// Counts uncaught exceptions, but other tests running in parallel
9097// also have uncaught exceptions.
9098TEST(ApiUncaughtException) {
9099 report_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009100 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009101 v8::Isolate* isolate = env->GetIsolate();
9102 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009103 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9104
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009105 Local<v8::FunctionTemplate> fun =
9106 v8::FunctionTemplate::New(isolate, TroubleCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +00009107 v8::Local<v8::Object> global = env->Global();
9108 global->Set(v8_str("trouble"), fun->GetFunction());
9109
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009110 CompileRun(
9111 "function trouble_callee() {"
9112 " var x = null;"
9113 " return x.foo;"
9114 "};"
9115 "function trouble_caller() {"
9116 " trouble();"
9117 "};");
Steve Blocka7e24c12009-10-30 11:49:00 +00009118 Local<Value> trouble = global->Get(v8_str("trouble"));
9119 CHECK(trouble->IsFunction());
9120 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
9121 CHECK(trouble_callee->IsFunction());
9122 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
9123 CHECK(trouble_caller->IsFunction());
9124 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
9125 CHECK_EQ(1, report_count);
9126 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9127}
9128
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009129
9130TEST(ApiUncaughtExceptionInObjectObserve) {
9131 v8::internal::FLAG_stack_size = 150;
9132 report_count = 0;
9133 LocalContext env;
9134 v8::Isolate* isolate = env->GetIsolate();
9135 v8::HandleScope scope(isolate);
9136 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9137 CompileRun(
9138 "var obj = {};"
9139 "var observe_count = 0;"
9140 "function observer1() { ++observe_count; };"
9141 "function observer2() { ++observe_count; };"
9142 "function observer_throws() { throw new Error(); };"
9143 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
9144 "Object.observe(obj, observer_throws.bind());"
9145 "Object.observe(obj, observer1);"
9146 "Object.observe(obj, stack_overflow);"
9147 "Object.observe(obj, observer2);"
9148 "Object.observe(obj, observer_throws.bind());"
9149 "obj.foo = 'bar';");
9150 CHECK_EQ(3, report_count);
9151 ExpectInt32("observe_count", 2);
9152 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9153}
9154
9155
Leon Clarke4515c472010-02-03 11:58:03 +00009156static const char* script_resource_name = "ExceptionInNativeScript.js";
9157static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
9158 v8::Handle<Value>) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009159 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
Leon Clarke4515c472010-02-03 11:58:03 +00009160 CHECK(!name_val.IsEmpty() && name_val->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009161 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
Leon Clarke4515c472010-02-03 11:58:03 +00009162 CHECK_EQ(script_resource_name, *name);
9163 CHECK_EQ(3, message->GetLineNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009164 v8::String::Utf8Value source_line(message->GetSourceLine());
Leon Clarke4515c472010-02-03 11:58:03 +00009165 CHECK_EQ(" new o.foo();", *source_line);
9166}
9167
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009168
Leon Clarke4515c472010-02-03 11:58:03 +00009169TEST(ExceptionInNativeScript) {
Leon Clarke4515c472010-02-03 11:58:03 +00009170 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009171 v8::Isolate* isolate = env->GetIsolate();
9172 v8::HandleScope scope(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +00009173 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
9174
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009175 Local<v8::FunctionTemplate> fun =
9176 v8::FunctionTemplate::New(isolate, TroubleCallback);
Leon Clarke4515c472010-02-03 11:58:03 +00009177 v8::Local<v8::Object> global = env->Global();
9178 global->Set(v8_str("trouble"), fun->GetFunction());
9179
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009180 CompileRunWithOrigin(
9181 "function trouble() {\n"
9182 " var o = {};\n"
9183 " new o.foo();\n"
9184 "};",
9185 script_resource_name);
Leon Clarke4515c472010-02-03 11:58:03 +00009186 Local<Value> trouble = global->Get(v8_str("trouble"));
9187 CHECK(trouble->IsFunction());
9188 Function::Cast(*trouble)->Call(global, 0, NULL);
9189 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9190}
9191
Steve Blocka7e24c12009-10-30 11:49:00 +00009192
9193TEST(CompilationErrorUsingTryCatchHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009194 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009195 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009196 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009197 v8_compile("This doesn't &*&@#$&*^ compile.");
Steve Blocka7e24c12009-10-30 11:49:00 +00009198 CHECK_NE(NULL, *try_catch.Exception());
9199 CHECK(try_catch.HasCaught());
9200}
9201
9202
9203TEST(TryCatchFinallyUsingTryCatchHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009204 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009205 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009206 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009207 CompileRun("try { throw ''; } catch (e) {}");
Steve Blocka7e24c12009-10-30 11:49:00 +00009208 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009209 CompileRun("try { throw ''; } finally {}");
Steve Blocka7e24c12009-10-30 11:49:00 +00009210 CHECK(try_catch.HasCaught());
9211 try_catch.Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009212 CompileRun(
9213 "(function() {"
9214 "try { throw ''; } finally { return; }"
9215 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00009216 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009217 CompileRun(
9218 "(function()"
9219 " { try { throw ''; } finally { throw 0; }"
9220 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00009221 CHECK(try_catch.HasCaught());
9222}
9223
9224
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009225void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9226 v8::HandleScope scope(args.GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009227 CompileRun(args[0]->ToString(args.GetIsolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009228}
9229
9230
9231TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9232 v8::Isolate* isolate = CcTest::isolate();
9233 v8::HandleScope scope(isolate);
9234 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9235 templ->Set(v8_str("CEvaluate"),
9236 v8::FunctionTemplate::New(isolate, CEvaluate));
9237 LocalContext context(0, templ);
9238 v8::TryCatch try_catch;
9239 CompileRun("try {"
9240 " CEvaluate('throw 1;');"
9241 "} finally {"
9242 "}");
9243 CHECK(try_catch.HasCaught());
9244 CHECK(!try_catch.Message().IsEmpty());
9245 String::Utf8Value exception_value(try_catch.Exception());
9246 CHECK_EQ(*exception_value, "1");
9247 try_catch.Reset();
9248 CompileRun("try {"
9249 " CEvaluate('throw 1;');"
9250 "} finally {"
9251 " throw 2;"
9252 "}");
9253 CHECK(try_catch.HasCaught());
9254 CHECK(!try_catch.Message().IsEmpty());
9255 String::Utf8Value finally_exception_value(try_catch.Exception());
9256 CHECK_EQ(*finally_exception_value, "2");
9257}
9258
9259
9260// For use within the TestSecurityHandler() test.
9261static bool g_security_callback_result = false;
9262static bool NamedSecurityTestCallback(Local<v8::Object> global,
9263 Local<Value> name,
9264 v8::AccessType type,
9265 Local<Value> data) {
9266 printf("a\n");
9267 // Always allow read access.
9268 if (type == v8::ACCESS_GET)
9269 return true;
9270
9271 // Sometimes allow other access.
9272 return g_security_callback_result;
9273}
9274
9275
9276static bool IndexedSecurityTestCallback(Local<v8::Object> global,
9277 uint32_t key,
9278 v8::AccessType type,
9279 Local<Value> data) {
9280 printf("b\n");
9281 // Always allow read access.
9282 if (type == v8::ACCESS_GET)
9283 return true;
9284
9285 // Sometimes allow other access.
9286 return g_security_callback_result;
9287}
9288
9289
Steve Blocka7e24c12009-10-30 11:49:00 +00009290// SecurityHandler can't be run twice
9291TEST(SecurityHandler) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009292 v8::Isolate* isolate = CcTest::isolate();
9293 v8::HandleScope scope0(isolate);
9294 v8::Handle<v8::ObjectTemplate> global_template =
9295 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009296 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
9297 IndexedSecurityTestCallback);
9298 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009299 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00009300 context0->Enter();
9301
9302 v8::Handle<v8::Object> global0 = context0->Global();
9303 v8::Handle<Script> script0 = v8_compile("foo = 111");
9304 script0->Run();
9305 global0->Set(v8_str("0"), v8_num(999));
9306 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
9307 CHECK_EQ(111, foo0->Int32Value());
9308 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
9309 CHECK_EQ(999, z0->Int32Value());
9310
9311 // Create another environment, should fail security checks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009312 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009313
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009314 v8::Handle<Context> context1 =
9315 Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00009316 context1->Enter();
9317
9318 v8::Handle<v8::Object> global1 = context1->Global();
9319 global1->Set(v8_str("othercontext"), global0);
9320 // This set will fail the security check.
9321 v8::Handle<Script> script1 =
9322 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9323 script1->Run();
9324 // This read will pass the security check.
9325 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
9326 CHECK_EQ(111, foo1->Int32Value());
9327 // This read will pass the security check.
9328 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
9329 CHECK_EQ(999, z1->Int32Value());
9330
9331 // Create another environment, should pass security checks.
9332 { g_security_callback_result = true; // allow security handler to pass.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009333 v8::HandleScope scope2(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009334 LocalContext context2;
9335 v8::Handle<v8::Object> global2 = context2->Global();
9336 global2->Set(v8_str("othercontext"), global0);
9337 v8::Handle<Script> script2 =
9338 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9339 script2->Run();
9340 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
9341 CHECK_EQ(333, foo2->Int32Value());
9342 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
9343 CHECK_EQ(888, z2->Int32Value());
9344 }
9345
9346 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009347 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009348}
9349
9350
9351THREADED_TEST(SecurityChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009352 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009353 v8::HandleScope handle_scope(env1->GetIsolate());
9354 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009355
9356 Local<Value> foo = v8_str("foo");
9357 Local<Value> bar = v8_str("bar");
9358
9359 // Set to the same domain.
9360 env1->SetSecurityToken(foo);
9361
9362 // Create a function in env1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009363 CompileRun("spy=function(){return spy;}");
Steve Blocka7e24c12009-10-30 11:49:00 +00009364 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
9365 CHECK(spy->IsFunction());
9366
9367 // Create another function accessing global objects.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009368 CompileRun("spy2=function(){return new this.Array();}");
Steve Blocka7e24c12009-10-30 11:49:00 +00009369 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
9370 CHECK(spy2->IsFunction());
9371
9372 // Switch to env2 in the same domain and invoke spy on env2.
9373 {
9374 env2->SetSecurityToken(foo);
9375 // Enter env2
9376 Context::Scope scope_env2(env2);
9377 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
9378 CHECK(result->IsFunction());
9379 }
9380
9381 {
9382 env2->SetSecurityToken(bar);
9383 Context::Scope scope_env2(env2);
9384
9385 // Call cross_domain_call, it should throw an exception
9386 v8::TryCatch try_catch;
9387 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
9388 CHECK(try_catch.HasCaught());
9389 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009390}
9391
9392
9393// Regression test case for issue 1183439.
9394THREADED_TEST(SecurityChecksForPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009395 LocalContext current;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009396 v8::HandleScope scope(current->GetIsolate());
9397 v8::Handle<Context> other = Context::New(current->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009398
9399 // Change context to be able to get to the Object function in the
9400 // other context without hitting the security checks.
9401 v8::Local<Value> other_object;
9402 { Context::Scope scope(other);
9403 other_object = other->Global()->Get(v8_str("Object"));
9404 other->Global()->Set(v8_num(42), v8_num(87));
9405 }
9406
9407 current->Global()->Set(v8_str("other"), other->Global());
9408 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
9409
9410 // Make sure the security check fails here and we get an undefined
9411 // result instead of getting the Object function. Repeat in a loop
9412 // to make sure to exercise the IC code.
9413 v8::Local<Script> access_other0 = v8_compile("other.Object");
9414 v8::Local<Script> access_other1 = v8_compile("other[42]");
9415 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009416 CHECK(access_other0->Run().IsEmpty());
9417 CHECK(access_other1->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009418 }
9419
9420 // Create an object that has 'other' in its prototype chain and make
9421 // sure we cannot access the Object function indirectly through
9422 // that. Repeat in a loop to make sure to exercise the IC code.
9423 v8_compile("function F() { };"
9424 "F.prototype = other;"
9425 "var f = new F();")->Run();
9426 v8::Local<Script> access_f0 = v8_compile("f.Object");
9427 v8::Local<Script> access_f1 = v8_compile("f[42]");
9428 for (int j = 0; j < 5; j++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009429 CHECK(access_f0->Run().IsEmpty());
9430 CHECK(access_f1->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009431 }
9432
9433 // Now it gets hairy: Set the prototype for the other global object
9434 // to be the current global object. The prototype chain for 'f' now
9435 // goes through 'other' but ends up in the current global object.
9436 { Context::Scope scope(other);
9437 other->Global()->Set(v8_str("__proto__"), current->Global());
9438 }
9439 // Set a named and an index property on the current global
9440 // object. To force the lookup to go through the other global object,
9441 // the properties must not exist in the other global object.
9442 current->Global()->Set(v8_str("foo"), v8_num(100));
9443 current->Global()->Set(v8_num(99), v8_num(101));
9444 // Try to read the properties from f and make sure that the access
9445 // gets stopped by the security checks on the other global object.
9446 Local<Script> access_f2 = v8_compile("f.foo");
9447 Local<Script> access_f3 = v8_compile("f[99]");
9448 for (int k = 0; k < 5; k++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009449 CHECK(access_f2->Run().IsEmpty());
9450 CHECK(access_f3->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009451 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009452}
9453
9454
9455static bool named_security_check_with_gc_called;
9456
9457static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
9458 Local<Value> name,
9459 v8::AccessType type,
9460 Local<Value> data) {
9461 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9462 named_security_check_with_gc_called = true;
9463 return true;
9464}
9465
9466
9467static bool indexed_security_check_with_gc_called;
9468
9469static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
9470 uint32_t key,
9471 v8::AccessType type,
9472 Local<Value> data) {
9473 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9474 indexed_security_check_with_gc_called = true;
9475 return true;
9476}
9477
9478
9479TEST(SecurityTestGCAllowed) {
9480 v8::Isolate* isolate = CcTest::isolate();
9481 v8::HandleScope handle_scope(isolate);
9482 v8::Handle<v8::ObjectTemplate> object_template =
9483 v8::ObjectTemplate::New(isolate);
9484 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
9485 IndexedSecurityTestCallbackWithGC);
9486
9487 v8::Handle<Context> context = Context::New(isolate);
9488 v8::Context::Scope context_scope(context);
9489
9490 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
9491
9492 named_security_check_with_gc_called = false;
9493 CompileRun("obj.foo = new String(1001);");
9494 CHECK(named_security_check_with_gc_called);
9495
9496 indexed_security_check_with_gc_called = false;
9497 CompileRun("obj[0] = new String(1002);");
9498 CHECK(indexed_security_check_with_gc_called);
9499
9500 named_security_check_with_gc_called = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009501 CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009502 CHECK(named_security_check_with_gc_called);
9503
9504 indexed_security_check_with_gc_called = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009505 CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009506 CHECK(indexed_security_check_with_gc_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00009507}
9508
9509
9510THREADED_TEST(CrossDomainDelete) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009511 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009512 v8::HandleScope handle_scope(env1->GetIsolate());
9513 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009514
9515 Local<Value> foo = v8_str("foo");
9516 Local<Value> bar = v8_str("bar");
9517
9518 // Set to the same domain.
9519 env1->SetSecurityToken(foo);
9520 env2->SetSecurityToken(foo);
9521
9522 env1->Global()->Set(v8_str("prop"), v8_num(3));
9523 env2->Global()->Set(v8_str("env1"), env1->Global());
9524
9525 // Change env2 to a different domain and delete env1.prop.
9526 env2->SetSecurityToken(bar);
9527 {
9528 Context::Scope scope_env2(env2);
9529 Local<Value> result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009530 CompileRun("delete env1.prop");
9531 CHECK(result.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009532 }
9533
9534 // Check that env1.prop still exists.
9535 Local<Value> v = env1->Global()->Get(v8_str("prop"));
9536 CHECK(v->IsNumber());
9537 CHECK_EQ(3, v->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009538}
9539
9540
9541THREADED_TEST(CrossDomainIsPropertyEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009542 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009543 v8::HandleScope handle_scope(env1->GetIsolate());
9544 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009545
9546 Local<Value> foo = v8_str("foo");
9547 Local<Value> bar = v8_str("bar");
9548
9549 // Set to the same domain.
9550 env1->SetSecurityToken(foo);
9551 env2->SetSecurityToken(foo);
9552
9553 env1->Global()->Set(v8_str("prop"), v8_num(3));
9554 env2->Global()->Set(v8_str("env1"), env1->Global());
9555
9556 // env1.prop is enumerable in env2.
9557 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9558 {
9559 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009560 Local<Value> result = CompileRun(test);
Steve Blocka7e24c12009-10-30 11:49:00 +00009561 CHECK(result->IsTrue());
9562 }
9563
9564 // Change env2 to a different domain and test again.
9565 env2->SetSecurityToken(bar);
9566 {
9567 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009568 Local<Value> result = CompileRun(test);
9569 CHECK(result.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009570 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009571}
9572
9573
9574THREADED_TEST(CrossDomainForIn) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009575 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009576 v8::HandleScope handle_scope(env1->GetIsolate());
9577 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009578
9579 Local<Value> foo = v8_str("foo");
9580 Local<Value> bar = v8_str("bar");
9581
9582 // Set to the same domain.
9583 env1->SetSecurityToken(foo);
9584 env2->SetSecurityToken(foo);
9585
9586 env1->Global()->Set(v8_str("prop"), v8_num(3));
9587 env2->Global()->Set(v8_str("env1"), env1->Global());
9588
9589 // Change env2 to a different domain and set env1's global object
9590 // as the __proto__ of an object in env2 and enumerate properties
9591 // in for-in. It shouldn't enumerate properties on env1's global
9592 // object.
9593 env2->SetSecurityToken(bar);
9594 {
9595 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009596 Local<Value> result = CompileRun(
9597 "(function() {"
9598 " var obj = { '__proto__': env1 };"
9599 " try {"
9600 " for (var p in obj) {"
9601 " if (p == 'prop') return false;"
9602 " }"
9603 " return false;"
9604 " } catch (e) {"
9605 " return true;"
9606 " }"
9607 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00009608 CHECK(result->IsTrue());
9609 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009610}
9611
9612
9613TEST(ContextDetachGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009614 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009615 v8::HandleScope handle_scope(env1->GetIsolate());
9616 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009617
9618 Local<v8::Object> global1 = env1->Global();
9619
9620 Local<Value> foo = v8_str("foo");
9621
9622 // Set to the same domain.
9623 env1->SetSecurityToken(foo);
9624 env2->SetSecurityToken(foo);
9625
9626 // Enter env2
9627 env2->Enter();
9628
Andrei Popescu74b3c142010-03-29 12:03:09 +01009629 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00009630 Local<v8::Object> global2 = env2->Global();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009631 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009632 CompileRun("function getProp() {return prop;}");
9633
9634 env1->Global()->Set(v8_str("getProp"),
9635 global2->Get(v8_str("getProp")));
9636
Andrei Popescu74b3c142010-03-29 12:03:09 +01009637 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00009638 env2->Exit();
9639 env2->DetachGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00009640
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009641 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9642 0,
9643 v8::Handle<v8::ObjectTemplate>(),
9644 global2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009645 env3->SetSecurityToken(v8_str("bar"));
9646 env3->Enter();
9647
9648 Local<v8::Object> global3 = env3->Global();
9649 CHECK_EQ(global2, global3);
9650 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9651 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009652 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9653 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
Steve Blocka7e24c12009-10-30 11:49:00 +00009654 env3->Exit();
9655
9656 // Call getProp in env1, and it should return the value 1
9657 {
9658 Local<Value> get_prop = global1->Get(v8_str("getProp"));
9659 CHECK(get_prop->IsFunction());
9660 v8::TryCatch try_catch;
9661 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9662 CHECK(!try_catch.HasCaught());
9663 CHECK_EQ(1, r->Int32Value());
9664 }
9665
9666 // Check that env3 is not accessible from env1
9667 {
9668 Local<Value> r = global3->Get(v8_str("prop2"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009669 CHECK(r.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009670 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009671}
9672
9673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009674TEST(DetachGlobal) {
Andrei Popescu74b3c142010-03-29 12:03:09 +01009675 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009676 v8::HandleScope scope(env1->GetIsolate());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009677
9678 // Create second environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009679 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009680
9681 Local<Value> foo = v8_str("foo");
9682
9683 // Set same security token for env1 and env2.
9684 env1->SetSecurityToken(foo);
9685 env2->SetSecurityToken(foo);
9686
9687 // Create a property on the global object in env2.
9688 {
9689 v8::Context::Scope scope(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009690 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
Andrei Popescu74b3c142010-03-29 12:03:09 +01009691 }
9692
9693 // Create a reference to env2 global from env1 global.
9694 env1->Global()->Set(v8_str("other"), env2->Global());
9695
9696 // Check that we have access to other.p in env2 from env1.
9697 Local<Value> result = CompileRun("other.p");
9698 CHECK(result->IsInt32());
9699 CHECK_EQ(42, result->Int32Value());
9700
9701 // Hold on to global from env2 and detach global from env2.
9702 Local<v8::Object> global2 = env2->Global();
9703 env2->DetachGlobal();
9704
9705 // Check that the global has been detached. No other.p property can
9706 // be found.
9707 result = CompileRun("other.p");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009708 CHECK(result.IsEmpty());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009709
9710 // Reuse global2 for env3.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009711 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9712 0,
9713 v8::Handle<v8::ObjectTemplate>(),
9714 global2);
Andrei Popescu74b3c142010-03-29 12:03:09 +01009715 CHECK_EQ(global2, env3->Global());
9716
9717 // Start by using the same security token for env3 as for env1 and env2.
9718 env3->SetSecurityToken(foo);
9719
9720 // Create a property on the global object in env3.
9721 {
9722 v8::Context::Scope scope(env3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009723 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
Andrei Popescu74b3c142010-03-29 12:03:09 +01009724 }
9725
9726 // Check that other.p is now the property in env3 and that we have access.
9727 result = CompileRun("other.p");
9728 CHECK(result->IsInt32());
9729 CHECK_EQ(24, result->Int32Value());
9730
9731 // Change security token for env3 to something different from env1 and env2.
9732 env3->SetSecurityToken(v8_str("bar"));
9733
9734 // Check that we do not have access to other.p in env1. |other| is now
9735 // the global object for env3 which has a different security token,
9736 // so access should be blocked.
9737 result = CompileRun("other.p");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009738 CHECK(result.IsEmpty());
9739}
Andrei Popescu74b3c142010-03-29 12:03:09 +01009740
Andrei Popescu74b3c142010-03-29 12:03:09 +01009741
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009742void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9743 info.GetReturnValue().Set(
9744 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9745}
Andrei Popescu74b3c142010-03-29 12:03:09 +01009746
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009747
9748TEST(DetachedAccesses) {
9749 LocalContext env1;
9750 v8::HandleScope scope(env1->GetIsolate());
9751
9752 // Create second environment.
9753 Local<ObjectTemplate> inner_global_template =
9754 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9755 inner_global_template ->SetAccessorProperty(
9756 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9757 v8::Local<Context> env2 =
9758 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9759
9760 Local<Value> foo = v8_str("foo");
9761
9762 // Set same security token for env1 and env2.
9763 env1->SetSecurityToken(foo);
9764 env2->SetSecurityToken(foo);
9765
9766 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9767
9768 {
9769 v8::Context::Scope scope(env2);
9770 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9771 CompileRun(
9772 "function bound_x() { return x; }"
9773 "function get_x() { return this.x; }"
9774 "function get_x_w() { return (function() {return this.x;})(); }");
9775 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9776 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9777 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9778 env1->Global()->Set(
9779 v8_str("this_x"),
9780 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9781 }
9782
9783 Local<Object> env2_global = env2->Global();
9784 env2_global->TurnOnAccessCheck();
9785 env2->DetachGlobal();
9786
9787 Local<Value> result;
9788 result = CompileRun("bound_x()");
9789 CHECK_EQ(v8_str("env2_x"), result);
9790 result = CompileRun("get_x()");
9791 CHECK(result.IsEmpty());
9792 result = CompileRun("get_x_w()");
9793 CHECK(result.IsEmpty());
9794 result = CompileRun("this_x()");
9795 CHECK_EQ(v8_str("env2_x"), result);
9796
9797 // Reattach env2's proxy
9798 env2 = Context::New(env1->GetIsolate(),
9799 0,
9800 v8::Handle<v8::ObjectTemplate>(),
9801 env2_global);
9802 env2->SetSecurityToken(foo);
9803 {
9804 v8::Context::Scope scope(env2);
9805 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9806 env2->Global()->Set(v8_str("env1"), env1->Global());
9807 result = CompileRun(
9808 "results = [];"
9809 "for (var i = 0; i < 4; i++ ) {"
9810 " results.push(env1.bound_x());"
9811 " results.push(env1.get_x());"
9812 " results.push(env1.get_x_w());"
9813 " results.push(env1.this_x());"
9814 "}"
9815 "results");
9816 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9817 CHECK_EQ(16, results->Length());
9818 for (int i = 0; i < 16; i += 4) {
9819 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9820 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9821 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9822 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9823 }
9824 }
9825
9826 result = CompileRun(
9827 "results = [];"
9828 "for (var i = 0; i < 4; i++ ) {"
9829 " results.push(bound_x());"
9830 " results.push(get_x());"
9831 " results.push(get_x_w());"
9832 " results.push(this_x());"
9833 "}"
9834 "results");
9835 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9836 CHECK_EQ(16, results->Length());
9837 for (int i = 0; i < 16; i += 4) {
9838 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9839 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9840 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9841 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9842 }
9843
9844 result = CompileRun(
9845 "results = [];"
9846 "for (var i = 0; i < 4; i++ ) {"
9847 " results.push(this.bound_x());"
9848 " results.push(this.get_x());"
9849 " results.push(this.get_x_w());"
9850 " results.push(this.this_x());"
9851 "}"
9852 "results");
9853 results = Local<v8::Array>::Cast(result);
9854 CHECK_EQ(16, results->Length());
9855 for (int i = 0; i < 16; i += 4) {
9856 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9857 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9858 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9859 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9860 }
Andrei Popescu74b3c142010-03-29 12:03:09 +01009861}
9862
9863
Steve Block1e0659c2011-05-24 12:43:12 +01009864static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00009865static bool NamedAccessBlocker(Local<v8::Object> global,
9866 Local<Value> name,
9867 v8::AccessType type,
9868 Local<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009869 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
Steve Block1e0659c2011-05-24 12:43:12 +01009870 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00009871}
9872
9873
9874static bool IndexedAccessBlocker(Local<v8::Object> global,
9875 uint32_t key,
9876 v8::AccessType type,
9877 Local<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009878 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
Steve Block1e0659c2011-05-24 12:43:12 +01009879 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00009880}
9881
9882
9883static int g_echo_value = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009884
9885
9886static void EchoGetter(
9887 Local<String> name,
9888 const v8::PropertyCallbackInfo<v8::Value>& info) {
9889 info.GetReturnValue().Set(v8_num(g_echo_value));
Steve Blocka7e24c12009-10-30 11:49:00 +00009890}
9891
9892
9893static void EchoSetter(Local<String> name,
9894 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009895 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009896 if (value->IsNumber())
9897 g_echo_value = value->Int32Value();
9898}
9899
9900
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009901static void UnreachableGetter(
9902 Local<String> name,
9903 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009904 CHECK(false); // This function should not be called..
Steve Blocka7e24c12009-10-30 11:49:00 +00009905}
9906
9907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009908static void UnreachableSetter(Local<String>,
9909 Local<Value>,
9910 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009911 CHECK(false); // This function should nto be called.
9912}
9913
9914
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009915static void UnreachableFunction(
9916 const v8::FunctionCallbackInfo<v8::Value>& info) {
9917 CHECK(false); // This function should not be called..
9918}
9919
9920
Steve Block1e0659c2011-05-24 12:43:12 +01009921TEST(AccessControl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009922 v8::Isolate* isolate = CcTest::isolate();
9923 v8::HandleScope handle_scope(isolate);
9924 v8::Handle<v8::ObjectTemplate> global_template =
9925 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009926
9927 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9928 IndexedAccessBlocker);
9929
9930 // Add an accessor accessible by cross-domain JS code.
9931 global_template->SetAccessor(
9932 v8_str("accessible_prop"),
9933 EchoGetter, EchoSetter,
9934 v8::Handle<Value>(),
9935 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9936
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009937
Steve Blocka7e24c12009-10-30 11:49:00 +00009938 // Add an accessor that is not accessible by cross-domain JS code.
9939 global_template->SetAccessor(v8_str("blocked_prop"),
9940 UnreachableGetter, UnreachableSetter,
9941 v8::Handle<Value>(),
9942 v8::DEFAULT);
9943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009944 global_template->SetAccessorProperty(
9945 v8_str("blocked_js_prop"),
9946 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9947 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9948 v8::None,
9949 v8::DEFAULT);
9950
Steve Blocka7e24c12009-10-30 11:49:00 +00009951 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009952 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00009953 context0->Enter();
9954
9955 v8::Handle<v8::Object> global0 = context0->Global();
9956
Steve Block1e0659c2011-05-24 12:43:12 +01009957 // Define a property with JS getter and setter.
9958 CompileRun(
9959 "function getter() { return 'getter'; };\n"
9960 "function setter() { return 'setter'; }\n"
9961 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9962
9963 Local<Value> getter = global0->Get(v8_str("getter"));
9964 Local<Value> setter = global0->Get(v8_str("setter"));
9965
9966 // And define normal element.
9967 global0->Set(239, v8_str("239"));
9968
9969 // Define an element with JS getter and setter.
9970 CompileRun(
9971 "function el_getter() { return 'el_getter'; };\n"
9972 "function el_setter() { return 'el_setter'; };\n"
9973 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9974
9975 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9976 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9977
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009978 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009979
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009980 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009981 context1->Enter();
9982
9983 v8::Handle<v8::Object> global1 = context1->Global();
9984 global1->Set(v8_str("other"), global0);
9985
Steve Block1e0659c2011-05-24 12:43:12 +01009986 // Access blocked property.
9987 CompileRun("other.blocked_prop = 1");
9988
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009989 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9990 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9991 .IsEmpty());
9992 CHECK(
9993 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009994
9995 // Access blocked element.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009996 CHECK(CompileRun("other[239] = 1").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009997
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009998 CHECK(CompileRun("other[239]").IsEmpty());
9999 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10000 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010001
10002 // Enable ACCESS_HAS
10003 allowed_access_type[v8::ACCESS_HAS] = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010004 CHECK(CompileRun("other[239]").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010005 // ... and now we can get the descriptor...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010006 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
10007 .IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010008 // ... and enumerate the property.
10009 ExpectTrue("propertyIsEnumerable.call(other, '239')");
10010 allowed_access_type[v8::ACCESS_HAS] = false;
10011
10012 // Access a property with JS accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010013 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010014
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010015 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10016 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10017 .IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010018
10019 // Enable both ACCESS_HAS and ACCESS_GET.
10020 allowed_access_type[v8::ACCESS_HAS] = true;
10021 allowed_access_type[v8::ACCESS_GET] = true;
10022
10023 ExpectString("other.js_accessor_p", "getter");
10024 ExpectObject(
10025 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
Steve Block1e0659c2011-05-24 12:43:12 +010010026 ExpectObject(
10027 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10028 ExpectUndefined(
10029 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10030
Steve Block1e0659c2011-05-24 12:43:12 +010010031 allowed_access_type[v8::ACCESS_HAS] = false;
Steve Block1e0659c2011-05-24 12:43:12 +010010032 allowed_access_type[v8::ACCESS_GET] = false;
Steve Block1e0659c2011-05-24 12:43:12 +010010033
10034 // Access an element with JS accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010035 CHECK(CompileRun("other[42] = 2").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010036
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010037 CHECK(CompileRun("other[42]").IsEmpty());
10038 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +010010039
10040 // Enable both ACCESS_HAS and ACCESS_GET.
10041 allowed_access_type[v8::ACCESS_HAS] = true;
10042 allowed_access_type[v8::ACCESS_GET] = true;
10043
10044 ExpectString("other[42]", "el_getter");
10045 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
Steve Block1e0659c2011-05-24 12:43:12 +010010046 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10047 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10048
Steve Block1e0659c2011-05-24 12:43:12 +010010049 allowed_access_type[v8::ACCESS_HAS] = false;
Steve Block1e0659c2011-05-24 12:43:12 +010010050 allowed_access_type[v8::ACCESS_GET] = false;
Steve Block1e0659c2011-05-24 12:43:12 +010010051
Steve Blocka7e24c12009-10-30 11:49:00 +000010052 v8::Handle<Value> value;
10053
Steve Blocka7e24c12009-10-30 11:49:00 +000010054 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +010010055 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +000010056 CHECK(value->IsNumber());
10057 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +000010058 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010059
Steve Block1e0659c2011-05-24 12:43:12 +010010060 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +000010061 CHECK(value->IsNumber());
10062 CHECK_EQ(3, value->Int32Value());
10063
Steve Block1e0659c2011-05-24 12:43:12 +010010064 value = CompileRun(
10065 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10066 CHECK(value->IsNumber());
10067 CHECK_EQ(3, value->Int32Value());
10068
10069 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010070 CHECK(value->IsTrue());
10071
10072 // Enumeration doesn't enumerate accessors from inaccessible objects in
10073 // the prototype chain even if the accessors are in themselves accessible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010074 value = CompileRun(
10075 "(function() {"
10076 " var obj = { '__proto__': other };"
10077 " try {"
10078 " for (var p in obj) {"
10079 " if (p == 'accessible_prop' ||"
10080 " p == 'blocked_js_prop' ||"
10081 " p == 'blocked_js_prop') {"
10082 " return false;"
10083 " }"
10084 " }"
10085 " return false;"
10086 " } catch (e) {"
10087 " return true;"
10088 " }"
10089 "})()");
Steve Block1e0659c2011-05-24 12:43:12 +010010090 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +000010091
10092 context1->Exit();
10093 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010094}
10095
10096
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010097TEST(AccessControlES5) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010098 v8::Isolate* isolate = CcTest::isolate();
10099 v8::HandleScope handle_scope(isolate);
10100 v8::Handle<v8::ObjectTemplate> global_template =
10101 v8::ObjectTemplate::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010102
10103 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
10104 IndexedAccessBlocker);
10105
Steve Block44f0eee2011-05-26 01:26:41 +010010106 // Add accessible accessor.
10107 global_template->SetAccessor(
10108 v8_str("accessible_prop"),
10109 EchoGetter, EchoSetter,
10110 v8::Handle<Value>(),
10111 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10112
10113
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010114 // Add an accessor that is not accessible by cross-domain JS code.
10115 global_template->SetAccessor(v8_str("blocked_prop"),
10116 UnreachableGetter, UnreachableSetter,
10117 v8::Handle<Value>(),
10118 v8::DEFAULT);
10119
10120 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010121 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010122 context0->Enter();
10123
10124 v8::Handle<v8::Object> global0 = context0->Global();
10125
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010126 v8::Local<Context> context1 = Context::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010127 context1->Enter();
10128 v8::Handle<v8::Object> global1 = context1->Global();
10129 global1->Set(v8_str("other"), global0);
10130
10131 // Regression test for issue 1154.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010132 CHECK(CompileRun("Object.keys(other)").IsEmpty());
10133 CHECK(CompileRun("other.blocked_prop").IsEmpty());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010134
10135 // Regression test for issue 1027.
10136 CompileRun("Object.defineProperty(\n"
10137 " other, 'blocked_prop', {configurable: false})");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010138 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10139 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10140 .IsEmpty());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010141
10142 // Regression test for issue 1171.
10143 ExpectTrue("Object.isExtensible(other)");
10144 CompileRun("Object.preventExtensions(other)");
10145 ExpectTrue("Object.isExtensible(other)");
10146
10147 // Object.seal and Object.freeze.
10148 CompileRun("Object.freeze(other)");
10149 ExpectTrue("Object.isExtensible(other)");
10150
10151 CompileRun("Object.seal(other)");
10152 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +010010153
10154 // Regression test for issue 1250.
10155 // Make sure that we can set the accessible accessors value using normal
10156 // assignment.
10157 CompileRun("other.accessible_prop = 42");
10158 CHECK_EQ(42, g_echo_value);
10159
10160 v8::Handle<Value> value;
Steve Block44f0eee2011-05-26 01:26:41 +010010161 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
10162 value = CompileRun("other.accessible_prop == 42");
10163 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010164}
10165
10166
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010167static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
10168 v8::AccessType type, Local<Value> data) {
Leon Clarke4515c472010-02-03 11:58:03 +000010169 return false;
10170}
10171
10172
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010173static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
10174 v8::AccessType type, Local<Value> data) {
Leon Clarke4515c472010-02-03 11:58:03 +000010175 return false;
10176}
10177
10178
10179THREADED_TEST(AccessControlGetOwnPropertyNames) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010180 v8::Isolate* isolate = CcTest::isolate();
10181 v8::HandleScope handle_scope(isolate);
10182 v8::Handle<v8::ObjectTemplate> obj_template =
10183 v8::ObjectTemplate::New(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +000010184
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010185 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10186 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10187 BlockEverythingIndexed);
Leon Clarke4515c472010-02-03 11:58:03 +000010188
10189 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010190 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
Leon Clarke4515c472010-02-03 11:58:03 +000010191 context0->Enter();
10192
10193 v8::Handle<v8::Object> global0 = context0->Global();
10194
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010195 v8::HandleScope scope1(CcTest::isolate());
Leon Clarke4515c472010-02-03 11:58:03 +000010196
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010197 v8::Local<Context> context1 = Context::New(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +000010198 context1->Enter();
10199
10200 v8::Handle<v8::Object> global1 = context1->Global();
10201 global1->Set(v8_str("other"), global0);
10202 global1->Set(v8_str("object"), obj_template->NewInstance());
10203
10204 v8::Handle<Value> value;
10205
10206 // Attempt to get the property names of the other global object and
10207 // of an object that requires access checks. Accessing the other
10208 // global object should be blocked by access checks on the global
10209 // proxy object. Accessing the object that requires access checks
10210 // is blocked by the access checks on the object itself.
10211 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010212 CHECK(value.IsEmpty());
Leon Clarke4515c472010-02-03 11:58:03 +000010213
10214 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010215 CHECK(value.IsEmpty());
Leon Clarke4515c472010-02-03 11:58:03 +000010216
10217 context1->Exit();
10218 context0->Exit();
Leon Clarke4515c472010-02-03 11:58:03 +000010219}
10220
10221
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010222TEST(SuperAccessControl) {
10223 i::FLAG_harmony_classes = true;
10224 v8::Isolate* isolate = CcTest::isolate();
10225 v8::HandleScope handle_scope(isolate);
10226 v8::Handle<v8::ObjectTemplate> obj_template =
10227 v8::ObjectTemplate::New(isolate);
10228 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10229 BlockEverythingIndexed);
10230 LocalContext env;
10231 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
10232
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010233 {
10234 v8::TryCatch try_catch;
10235 CompileRun(
10236 "function f() { return super.hasOwnProperty; };"
10237 "var m = f.toMethod(prohibited);"
10238 "m();");
10239 CHECK(try_catch.HasCaught());
10240 }
10241
10242 {
10243 v8::TryCatch try_catch;
10244 CompileRun(
10245 "function f() { return super[42]; };"
10246 "var m = f.toMethod(prohibited);"
10247 "m();");
10248 CHECK(try_catch.HasCaught());
10249 }
10250
10251 {
10252 v8::TryCatch try_catch;
10253 CompileRun(
10254 "function f() { super.hasOwnProperty = function () {}; };"
10255 "var m = f.toMethod(prohibited);"
10256 "m();");
10257 CHECK(try_catch.HasCaught());
10258 }
10259
10260 {
10261 v8::TryCatch try_catch;
10262 CompileRun(
10263 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
10264 "function f() { "
10265 " 'use strict';"
10266 " super.x = function () {}; "
10267 "};"
10268 "var m = f.toMethod(prohibited);"
10269 "m();");
10270 CHECK(try_catch.HasCaught());
10271 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010272}
10273
10274
10275static void IndexedPropertyEnumerator(
10276 const v8::PropertyCallbackInfo<v8::Array>& info) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010277 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010278 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010279 info.GetReturnValue().Set(result);
10280}
10281
10282
10283static void NamedPropertyEnumerator(
10284 const v8::PropertyCallbackInfo<v8::Array>& info) {
10285 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
Steve Block8defd9f2010-07-08 12:39:36 +010010286 result->Set(0, v8_str("x"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010287 result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010288 info.GetReturnValue().Set(result);
Steve Block8defd9f2010-07-08 12:39:36 +010010289}
10290
10291
10292THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010293 v8::Isolate* isolate = CcTest::isolate();
10294 v8::HandleScope handle_scope(isolate);
10295 v8::Handle<v8::ObjectTemplate> obj_template =
10296 v8::ObjectTemplate::New(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +010010297
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010298 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
10299 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010300 obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10301 NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
10302 obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10303 NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
Steve Block8defd9f2010-07-08 12:39:36 +010010304
10305 LocalContext context;
10306 v8::Handle<v8::Object> global = context->Global();
10307 global->Set(v8_str("object"), obj_template->NewInstance());
10308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010309 v8::Handle<v8::Value> result =
10310 CompileRun("Object.getOwnPropertyNames(object)");
10311 CHECK(result->IsArray());
10312 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010313 CHECK_EQ(2, result_array->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010314 CHECK(result_array->Get(0)->IsString());
10315 CHECK(result_array->Get(1)->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010316 CHECK_EQ(v8_str("7"), result_array->Get(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010317 CHECK_EQ(v8_str("x"), result_array->Get(1));
10318
10319 result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
10320 CHECK(result->IsArray());
10321 result_array = v8::Handle<v8::Array>::Cast(result);
10322 CHECK_EQ(2, result_array->Length());
10323 CHECK(result_array->Get(0)->IsString());
10324 CHECK(result_array->Get(1)->IsString());
10325 CHECK_EQ(v8_str("7"), result_array->Get(0));
10326 CHECK_EQ(v8_str("x"), result_array->Get(1));
10327
10328 result = CompileRun("Object.getOwnPropertySymbols(object)");
10329 CHECK(result->IsArray());
10330 result_array = v8::Handle<v8::Array>::Cast(result);
10331 CHECK_EQ(1, result_array->Length());
10332 CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
Steve Block8defd9f2010-07-08 12:39:36 +010010333}
10334
10335
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010336static void ConstTenGetter(Local<String> name,
10337 const v8::PropertyCallbackInfo<v8::Value>& info) {
10338 info.GetReturnValue().Set(v8_num(10));
Steve Blocka7e24c12009-10-30 11:49:00 +000010339}
10340
10341
10342THREADED_TEST(CrossDomainAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010343 v8::Isolate* isolate = CcTest::isolate();
10344 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010345
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010346 v8::Handle<v8::FunctionTemplate> func_template =
10347 v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010348
10349 v8::Handle<v8::ObjectTemplate> global_template =
10350 func_template->InstanceTemplate();
10351
10352 v8::Handle<v8::ObjectTemplate> proto_template =
10353 func_template->PrototypeTemplate();
10354
10355 // Add an accessor to proto that's accessible by cross-domain JS code.
10356 proto_template->SetAccessor(v8_str("accessible"),
10357 ConstTenGetter, 0,
10358 v8::Handle<Value>(),
10359 v8::ALL_CAN_READ);
10360
10361 // Add an accessor that is not accessible by cross-domain JS code.
10362 global_template->SetAccessor(v8_str("unreachable"),
10363 UnreachableGetter, 0,
10364 v8::Handle<Value>(),
10365 v8::DEFAULT);
10366
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010367 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +000010368 context0->Enter();
10369
10370 Local<v8::Object> global = context0->Global();
10371 // Add a normal property that shadows 'accessible'
10372 global->Set(v8_str("accessible"), v8_num(11));
10373
10374 // Enter a new context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010375 v8::HandleScope scope1(CcTest::isolate());
10376 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010377 context1->Enter();
10378
10379 v8::Handle<v8::Object> global1 = context1->Global();
10380 global1->Set(v8_str("other"), global);
10381
10382 // Should return 10, instead of 11
10383 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
10384 CHECK(value->IsNumber());
10385 CHECK_EQ(10, value->Int32Value());
10386
10387 value = v8_compile("other.unreachable")->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010388 CHECK(value.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010389
10390 context1->Exit();
10391 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010392}
10393
10394
10395static int named_access_count = 0;
10396static int indexed_access_count = 0;
10397
10398static bool NamedAccessCounter(Local<v8::Object> global,
10399 Local<Value> name,
10400 v8::AccessType type,
10401 Local<Value> data) {
10402 named_access_count++;
10403 return true;
10404}
10405
10406
10407static bool IndexedAccessCounter(Local<v8::Object> global,
10408 uint32_t key,
10409 v8::AccessType type,
10410 Local<Value> data) {
10411 indexed_access_count++;
10412 return true;
10413}
10414
10415
10416// This one is too easily disturbed by other tests.
10417TEST(AccessControlIC) {
10418 named_access_count = 0;
10419 indexed_access_count = 0;
10420
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010421 v8::Isolate* isolate = CcTest::isolate();
10422 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010423
10424 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010425 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010426 context0->Enter();
10427
10428 // Create an object that requires access-check functions to be
10429 // called for cross-domain access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010430 v8::Handle<v8::ObjectTemplate> object_template =
10431 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010432 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10433 IndexedAccessCounter);
10434 Local<v8::Object> object = object_template->NewInstance();
10435
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010436 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010437
10438 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010439 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010440 context1->Enter();
10441
10442 // Make easy access to the object from the other environment.
10443 v8::Handle<v8::Object> global1 = context1->Global();
10444 global1->Set(v8_str("obj"), object);
10445
10446 v8::Handle<Value> value;
10447
10448 // Check that the named access-control function is called every time.
10449 CompileRun("function testProp(obj) {"
10450 " for (var i = 0; i < 10; i++) obj.prop = 1;"
10451 " for (var j = 0; j < 10; j++) obj.prop;"
10452 " return obj.prop"
10453 "}");
10454 value = CompileRun("testProp(obj)");
10455 CHECK(value->IsNumber());
10456 CHECK_EQ(1, value->Int32Value());
10457 CHECK_EQ(21, named_access_count);
10458
10459 // Check that the named access-control function is called every time.
10460 CompileRun("var p = 'prop';"
10461 "function testKeyed(obj) {"
10462 " for (var i = 0; i < 10; i++) obj[p] = 1;"
10463 " for (var j = 0; j < 10; j++) obj[p];"
10464 " return obj[p];"
10465 "}");
10466 // Use obj which requires access checks. No inline caching is used
10467 // in that case.
10468 value = CompileRun("testKeyed(obj)");
10469 CHECK(value->IsNumber());
10470 CHECK_EQ(1, value->Int32Value());
10471 CHECK_EQ(42, named_access_count);
10472 // Force the inline caches into generic state and try again.
10473 CompileRun("testKeyed({ a: 0 })");
10474 CompileRun("testKeyed({ b: 0 })");
10475 value = CompileRun("testKeyed(obj)");
10476 CHECK(value->IsNumber());
10477 CHECK_EQ(1, value->Int32Value());
10478 CHECK_EQ(63, named_access_count);
10479
10480 // Check that the indexed access-control function is called every time.
10481 CompileRun("function testIndexed(obj) {"
10482 " for (var i = 0; i < 10; i++) obj[0] = 1;"
10483 " for (var j = 0; j < 10; j++) obj[0];"
10484 " return obj[0]"
10485 "}");
10486 value = CompileRun("testIndexed(obj)");
10487 CHECK(value->IsNumber());
10488 CHECK_EQ(1, value->Int32Value());
10489 CHECK_EQ(21, indexed_access_count);
10490 // Force the inline caches into generic state.
10491 CompileRun("testIndexed(new Array(1))");
10492 // Test that the indexed access check is called.
10493 value = CompileRun("testIndexed(obj)");
10494 CHECK(value->IsNumber());
10495 CHECK_EQ(1, value->Int32Value());
10496 CHECK_EQ(42, indexed_access_count);
10497
10498 // Check that the named access check is called when invoking
10499 // functions on an object that requires access checks.
10500 CompileRun("obj.f = function() {}");
10501 CompileRun("function testCallNormal(obj) {"
10502 " for (var i = 0; i < 10; i++) obj.f();"
10503 "}");
10504 CompileRun("testCallNormal(obj)");
10505 CHECK_EQ(74, named_access_count);
10506
10507 // Force obj into slow case.
10508 value = CompileRun("delete obj.prop");
10509 CHECK(value->BooleanValue());
10510 // Force inline caches into dictionary probing mode.
10511 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10512 // Test that the named access check is called.
10513 value = CompileRun("testProp(obj);");
10514 CHECK(value->IsNumber());
10515 CHECK_EQ(1, value->Int32Value());
10516 CHECK_EQ(96, named_access_count);
10517
10518 // Force the call inline cache into dictionary probing mode.
10519 CompileRun("o.f = function() {}; testCallNormal(o)");
10520 // Test that the named access check is still called for each
10521 // invocation of the function.
10522 value = CompileRun("testCallNormal(obj)");
10523 CHECK_EQ(106, named_access_count);
10524
10525 context1->Exit();
10526 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010527}
10528
10529
10530static bool NamedAccessFlatten(Local<v8::Object> global,
10531 Local<Value> name,
10532 v8::AccessType type,
10533 Local<Value> data) {
10534 char buf[100];
10535 int len;
10536
10537 CHECK(name->IsString());
10538
10539 memset(buf, 0x1, sizeof(buf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010540 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
Steve Blocka7e24c12009-10-30 11:49:00 +000010541 CHECK_EQ(4, len);
10542
10543 uint16_t buf2[100];
10544
10545 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +010010546 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010547 CHECK_EQ(4, len);
10548
10549 return true;
10550}
10551
10552
10553static bool IndexedAccessFlatten(Local<v8::Object> global,
10554 uint32_t key,
10555 v8::AccessType type,
10556 Local<Value> data) {
10557 return true;
10558}
10559
10560
10561// Regression test. In access checks, operations that may cause
10562// garbage collection are not allowed. It used to be the case that
10563// using the Write operation on a string could cause a garbage
10564// collection due to flattening of the string. This is no longer the
10565// case.
10566THREADED_TEST(AccessControlFlatten) {
10567 named_access_count = 0;
10568 indexed_access_count = 0;
10569
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010570 v8::Isolate* isolate = CcTest::isolate();
10571 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010572
10573 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010574 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010575 context0->Enter();
10576
10577 // Create an object that requires access-check functions to be
10578 // called for cross-domain access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010579 v8::Handle<v8::ObjectTemplate> object_template =
10580 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010581 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10582 IndexedAccessFlatten);
10583 Local<v8::Object> object = object_template->NewInstance();
10584
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010585 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010586
10587 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010588 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010589 context1->Enter();
10590
10591 // Make easy access to the object from the other environment.
10592 v8::Handle<v8::Object> global1 = context1->Global();
10593 global1->Set(v8_str("obj"), object);
10594
10595 v8::Handle<Value> value;
10596
10597 value = v8_compile("var p = 'as' + 'df';")->Run();
10598 value = v8_compile("obj[p];")->Run();
10599
10600 context1->Exit();
10601 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010602}
10603
10604
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010605static void AccessControlNamedGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010606 Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010607 info.GetReturnValue().Set(42);
Steve Blocka7e24c12009-10-30 11:49:00 +000010608}
10609
10610
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010611static void AccessControlNamedSetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010612 Local<Name>, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010613 const v8::PropertyCallbackInfo<v8::Value>& info) {
10614 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010615}
10616
10617
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010618static void AccessControlIndexedGetter(
Steve Blocka7e24c12009-10-30 11:49:00 +000010619 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010620 const v8::PropertyCallbackInfo<v8::Value>& info) {
10621 info.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000010622}
10623
10624
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010625static void AccessControlIndexedSetter(
10626 uint32_t,
10627 Local<Value> value,
10628 const v8::PropertyCallbackInfo<v8::Value>& info) {
10629 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010630}
10631
10632
10633THREADED_TEST(AccessControlInterceptorIC) {
10634 named_access_count = 0;
10635 indexed_access_count = 0;
10636
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010637 v8::Isolate* isolate = CcTest::isolate();
10638 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010639
10640 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010641 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010642 context0->Enter();
10643
10644 // Create an object that requires access-check functions to be
10645 // called for cross-domain access. The object also has interceptors
10646 // interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010647 v8::Handle<v8::ObjectTemplate> object_template =
10648 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010649 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10650 IndexedAccessCounter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010651 object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10652 AccessControlNamedGetter, AccessControlNamedSetter));
10653 object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10654 AccessControlIndexedGetter, AccessControlIndexedSetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000010655 Local<v8::Object> object = object_template->NewInstance();
10656
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010657 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010658
10659 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010660 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010661 context1->Enter();
10662
10663 // Make easy access to the object from the other environment.
10664 v8::Handle<v8::Object> global1 = context1->Global();
10665 global1->Set(v8_str("obj"), object);
10666
10667 v8::Handle<Value> value;
10668
10669 // Check that the named access-control function is called every time
10670 // eventhough there is an interceptor on the object.
10671 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10672 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10673 "obj.x")->Run();
10674 CHECK(value->IsNumber());
10675 CHECK_EQ(42, value->Int32Value());
10676 CHECK_EQ(21, named_access_count);
10677
10678 value = v8_compile("var p = 'x';")->Run();
10679 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10680 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10681 "obj[p]")->Run();
10682 CHECK(value->IsNumber());
10683 CHECK_EQ(42, value->Int32Value());
10684 CHECK_EQ(42, named_access_count);
10685
10686 // Check that the indexed access-control function is called every
10687 // time eventhough there is an interceptor on the object.
10688 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10689 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10690 "obj[0]")->Run();
10691 CHECK(value->IsNumber());
10692 CHECK_EQ(42, value->Int32Value());
10693 CHECK_EQ(21, indexed_access_count);
10694
10695 context1->Exit();
10696 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010697}
10698
10699
10700THREADED_TEST(Version) {
10701 v8::V8::GetVersion();
10702}
10703
10704
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010705static void InstanceFunctionCallback(
10706 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010707 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010708 args.GetReturnValue().Set(v8_num(12));
Steve Blocka7e24c12009-10-30 11:49:00 +000010709}
10710
10711
10712THREADED_TEST(InstanceProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010713 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010714 v8::Isolate* isolate = context->GetIsolate();
10715 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010716
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010717 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010718 Local<ObjectTemplate> instance = t->InstanceTemplate();
10719
10720 instance->Set(v8_str("x"), v8_num(42));
10721 instance->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010722 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000010723
10724 Local<Value> o = t->GetFunction()->NewInstance();
10725
10726 context->Global()->Set(v8_str("i"), o);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010727 Local<Value> value = CompileRun("i.x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010728 CHECK_EQ(42, value->Int32Value());
10729
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010730 value = CompileRun("i.f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010731 CHECK_EQ(12, value->Int32Value());
10732}
10733
10734
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010735static void GlobalObjectInstancePropertiesGet(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010736 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010737 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000010738}
10739
10740
10741THREADED_TEST(GlobalObjectInstanceProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010742 v8::Isolate* isolate = CcTest::isolate();
10743 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010744
10745 Local<Value> global_object;
10746
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010747 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010748 t->InstanceTemplate()->SetHandler(
10749 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
Steve Blocka7e24c12009-10-30 11:49:00 +000010750 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10751 instance_template->Set(v8_str("x"), v8_num(42));
10752 instance_template->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010753 v8::FunctionTemplate::New(isolate,
10754 InstanceFunctionCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000010755
Ben Murdochb0fe1622011-05-05 13:52:32 +010010756 // The script to check how Crankshaft compiles missing global function
10757 // invocations. function g is not defined and should throw on call.
10758 const char* script =
10759 "function wrapper(call) {"
10760 " var x = 0, y = 1;"
10761 " for (var i = 0; i < 1000; i++) {"
10762 " x += i * 100;"
10763 " y += i * 100;"
10764 " }"
10765 " if (call) g();"
10766 "}"
10767 "for (var i = 0; i < 17; i++) wrapper(false);"
10768 "var thrown = 0;"
10769 "try { wrapper(true); } catch (e) { thrown = 1; };"
10770 "thrown";
10771
Steve Blocka7e24c12009-10-30 11:49:00 +000010772 {
10773 LocalContext env(NULL, instance_template);
10774 // Hold on to the global object so it can be used again in another
10775 // environment initialization.
10776 global_object = env->Global();
10777
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010778 Local<Value> value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010779 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010780 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010781 CHECK_EQ(12, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010782 value = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010783 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010784 }
10785
10786 {
10787 // Create new environment reusing the global object.
10788 LocalContext env(NULL, instance_template, global_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010789 Local<Value> value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010790 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010791 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010792 CHECK_EQ(12, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010793 value = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010794 CHECK_EQ(1, value->Int32Value());
10795 }
10796}
10797
10798
10799THREADED_TEST(CallKnownGlobalReceiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010800 v8::Isolate* isolate = CcTest::isolate();
10801 v8::HandleScope handle_scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010802
10803 Local<Value> global_object;
10804
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010805 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010806 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10807
10808 // The script to check that we leave global object not
10809 // global object proxy on stack when we deoptimize from inside
10810 // arguments evaluation.
10811 // To provoke error we need to both force deoptimization
10812 // from arguments evaluation and to force CallIC to take
10813 // CallIC_Miss code path that can't cope with global proxy.
10814 const char* script =
10815 "function bar(x, y) { try { } finally { } }"
10816 "function baz(x) { try { } finally { } }"
10817 "function bom(x) { try { } finally { } }"
10818 "function foo(x) { bar([x], bom(2)); }"
10819 "for (var i = 0; i < 10000; i++) foo(1);"
10820 "foo";
10821
10822 Local<Value> foo;
10823 {
10824 LocalContext env(NULL, instance_template);
10825 // Hold on to the global object so it can be used again in another
10826 // environment initialization.
10827 global_object = env->Global();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010828 foo = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010829 }
10830
10831 {
10832 // Create new environment reusing the global object.
10833 LocalContext env(NULL, instance_template, global_object);
10834 env->Global()->Set(v8_str("foo"), foo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010835 CompileRun("foo()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010836 }
10837}
10838
10839
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010840static void ShadowFunctionCallback(
10841 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010842 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010843 args.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000010844}
10845
10846
10847static int shadow_y;
10848static int shadow_y_setter_call_count;
10849static int shadow_y_getter_call_count;
10850
10851
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010852static void ShadowYSetter(Local<String>,
10853 Local<Value>,
10854 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010855 shadow_y_setter_call_count++;
10856 shadow_y = 42;
10857}
10858
10859
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010860static void ShadowYGetter(Local<String> name,
10861 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010862 ApiTestFuzzer::Fuzz();
10863 shadow_y_getter_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010864 info.GetReturnValue().Set(v8_num(shadow_y));
Steve Blocka7e24c12009-10-30 11:49:00 +000010865}
10866
10867
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010868static void ShadowIndexedGet(uint32_t index,
10869 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010870}
10871
10872
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010873static void ShadowNamedGet(Local<Name> key,
10874 const v8::PropertyCallbackInfo<v8::Value>&) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000010875
10876
10877THREADED_TEST(ShadowObject) {
10878 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010879 v8::Isolate* isolate = CcTest::isolate();
10880 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010881
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010882 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010883 LocalContext context(NULL, global_template);
10884
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010885 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010886 t->InstanceTemplate()->SetHandler(
10887 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10888 t->InstanceTemplate()->SetHandler(
10889 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
Steve Blocka7e24c12009-10-30 11:49:00 +000010890 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10891 Local<ObjectTemplate> instance = t->InstanceTemplate();
10892
Steve Blocka7e24c12009-10-30 11:49:00 +000010893 proto->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010894 v8::FunctionTemplate::New(isolate,
10895 ShadowFunctionCallback,
10896 Local<Value>()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010897 proto->Set(v8_str("x"), v8_num(12));
10898
10899 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10900
10901 Local<Value> o = t->GetFunction()->NewInstance();
10902 context->Global()->Set(v8_str("__proto__"), o);
10903
10904 Local<Value> value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010905 CompileRun("this.propertyIsEnumerable(0)");
Steve Blocka7e24c12009-10-30 11:49:00 +000010906 CHECK(value->IsBoolean());
10907 CHECK(!value->BooleanValue());
10908
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010909 value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010910 CHECK_EQ(12, value->Int32Value());
10911
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010912 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010913 CHECK_EQ(42, value->Int32Value());
10914
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010915 CompileRun("y = 43");
Steve Blocka7e24c12009-10-30 11:49:00 +000010916 CHECK_EQ(1, shadow_y_setter_call_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010917 value = CompileRun("y");
Steve Blocka7e24c12009-10-30 11:49:00 +000010918 CHECK_EQ(1, shadow_y_getter_call_count);
10919 CHECK_EQ(42, value->Int32Value());
10920}
10921
10922
10923THREADED_TEST(HiddenPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010924 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010925 v8::Isolate* isolate = context->GetIsolate();
10926 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010927
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010928 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010929 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010930 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010931 t1->SetHiddenPrototype(true);
10932 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010933 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010934 t2->SetHiddenPrototype(true);
10935 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010936 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010937 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10938
10939 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10940 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10941 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10942 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10943
10944 // Setting the prototype on an object skips hidden prototypes.
10945 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10946 o0->Set(v8_str("__proto__"), o1);
10947 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10948 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10949 o0->Set(v8_str("__proto__"), o2);
10950 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10951 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10952 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10953 o0->Set(v8_str("__proto__"), o3);
10954 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10955 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10956 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10957 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10958
10959 // Getting the prototype of o0 should get the first visible one
10960 // which is o3. Therefore, z should not be defined on the prototype
10961 // object.
10962 Local<Value> proto = o0->Get(v8_str("__proto__"));
10963 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010964 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +000010965}
10966
10967
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010968THREADED_TEST(HiddenPrototypeSet) {
Andrei Popescu402d9372010-02-26 13:31:12 +000010969 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010970 v8::Isolate* isolate = context->GetIsolate();
10971 v8::HandleScope handle_scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010972
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010973 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10974 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10975 ht->SetHiddenPrototype(true);
10976 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10977 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10978
10979 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10980 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10981 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10982 o->Set(v8_str("__proto__"), h);
10983 h->Set(v8_str("__proto__"), p);
10984
10985 // Setting a property that exists on the hidden prototype goes there.
10986 o->Set(v8_str("x"), v8_num(7));
10987 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10988 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10989 CHECK(p->Get(v8_str("x"))->IsUndefined());
10990
10991 // Setting a new property should not be forwarded to the hidden prototype.
10992 o->Set(v8_str("y"), v8_num(6));
10993 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10994 CHECK(h->Get(v8_str("y"))->IsUndefined());
10995 CHECK(p->Get(v8_str("y"))->IsUndefined());
10996
10997 // Setting a property that only exists on a prototype of the hidden prototype
10998 // is treated normally again.
10999 p->Set(v8_str("z"), v8_num(8));
11000 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
11001 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11002 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11003 o->Set(v8_str("z"), v8_num(9));
11004 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
11005 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11006 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11007}
11008
11009
11010// Regression test for issue 2457.
11011THREADED_TEST(HiddenPrototypeIdentityHash) {
11012 LocalContext context;
11013 v8::HandleScope handle_scope(context->GetIsolate());
11014
11015 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
11016 t->SetHiddenPrototype(true);
11017 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
11018 Handle<Object> p = t->GetFunction()->NewInstance();
11019 Handle<Object> o = Object::New(context->GetIsolate());
11020 o->SetPrototype(p);
11021
11022 int hash = o->GetIdentityHash();
11023 USE(hash);
11024 o->Set(v8_str("foo"), v8_num(42));
11025 DCHECK_EQ(hash, o->GetIdentityHash());
11026}
11027
11028
11029THREADED_TEST(SetPrototype) {
11030 LocalContext context;
11031 v8::Isolate* isolate = context->GetIsolate();
11032 v8::HandleScope handle_scope(isolate);
11033
11034 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011035 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011036 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011037 t1->SetHiddenPrototype(true);
11038 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011039 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011040 t2->SetHiddenPrototype(true);
11041 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011042 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011043 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11044
11045 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
11046 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11047 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11048 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11049
11050 // Setting the prototype on an object does not skip hidden prototypes.
11051 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11052 CHECK(o0->SetPrototype(o1));
11053 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11054 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11055 CHECK(o1->SetPrototype(o2));
11056 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11057 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11058 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11059 CHECK(o2->SetPrototype(o3));
11060 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11061 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11062 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11063 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
11064
11065 // Getting the prototype of o0 should get the first visible one
11066 // which is o3. Therefore, z should not be defined on the prototype
11067 // object.
11068 Local<Value> proto = o0->Get(v8_str("__proto__"));
11069 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011070 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +000011071
11072 // However, Object::GetPrototype ignores hidden prototype.
11073 Local<Value> proto0 = o0->GetPrototype();
11074 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011075 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +000011076
11077 Local<Value> proto1 = o1->GetPrototype();
11078 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011079 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +000011080
11081 Local<Value> proto2 = o2->GetPrototype();
11082 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010011083 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +000011084}
11085
11086
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011087// Getting property names of an object with a prototype chain that
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011088// triggers dictionary elements in GetOwnPropertyNames() shouldn't
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011089// crash the runtime.
11090THREADED_TEST(Regress91517) {
11091 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011092 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011093 v8::Isolate* isolate = context->GetIsolate();
11094 v8::HandleScope handle_scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011096 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011097 t1->SetHiddenPrototype(true);
11098 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011099 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011100 t2->SetHiddenPrototype(true);
11101 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011102 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011103 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011104 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011105 t3->SetHiddenPrototype(true);
11106 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011107 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011108 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11109
11110 // Force dictionary-based properties.
11111 i::ScopedVector<char> name_buf(1024);
11112 for (int i = 1; i <= 1000; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011113 i::SNPrintF(name_buf, "sdf%d", i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011114 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11115 }
11116
11117 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11118 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11119 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11120 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
11121
11122 // Create prototype chain of hidden prototypes.
11123 CHECK(o4->SetPrototype(o3));
11124 CHECK(o3->SetPrototype(o2));
11125 CHECK(o2->SetPrototype(o1));
11126
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011127 // Call the runtime version of GetOwnPropertyNames() on the natively
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011128 // created object through JavaScript.
11129 context->Global()->Set(v8_str("obj"), o4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011130 // PROPERTY_ATTRIBUTES_NONE = 0
11131 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011132
11133 ExpectInt32("names.length", 1006);
11134 ExpectTrue("names.indexOf(\"baz\") >= 0");
11135 ExpectTrue("names.indexOf(\"boo\") >= 0");
11136 ExpectTrue("names.indexOf(\"foo\") >= 0");
11137 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11138 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11139 ExpectFalse("names[1005] == undefined");
11140}
11141
11142
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011143// Getting property names of an object with a hidden and inherited
11144// prototype should not duplicate the accessor properties inherited.
11145THREADED_TEST(Regress269562) {
11146 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011147 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011148 v8::HandleScope handle_scope(context->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011149
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011150 Local<v8::FunctionTemplate> t1 =
11151 v8::FunctionTemplate::New(context->GetIsolate());
11152 t1->SetHiddenPrototype(true);
11153
11154 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11155 i1->SetAccessor(v8_str("foo"),
11156 SimpleAccessorGetter, SimpleAccessorSetter);
11157 i1->SetAccessor(v8_str("bar"),
11158 SimpleAccessorGetter, SimpleAccessorSetter);
11159 i1->SetAccessor(v8_str("baz"),
11160 SimpleAccessorGetter, SimpleAccessorSetter);
11161 i1->Set(v8_str("n1"), v8_num(1));
11162 i1->Set(v8_str("n2"), v8_num(2));
11163
11164 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11165 Local<v8::FunctionTemplate> t2 =
11166 v8::FunctionTemplate::New(context->GetIsolate());
11167 t2->SetHiddenPrototype(true);
11168
11169 // Inherit from t1 and mark prototype as hidden.
11170 t2->Inherit(t1);
11171 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11172
11173 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11174 CHECK(o2->SetPrototype(o1));
11175
11176 v8::Local<v8::Symbol> sym =
11177 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11178 o1->Set(sym, v8_num(3));
11179 o1->SetHiddenValue(
11180 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
11181
11182 // Call the runtime version of GetOwnPropertyNames() on
11183 // the natively created object through JavaScript.
11184 context->Global()->Set(v8_str("obj"), o2);
11185 context->Global()->Set(v8_str("sym"), sym);
11186 // PROPERTY_ATTRIBUTES_NONE = 0
11187 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
11188
11189 ExpectInt32("names.length", 7);
11190 ExpectTrue("names.indexOf(\"foo\") >= 0");
11191 ExpectTrue("names.indexOf(\"bar\") >= 0");
11192 ExpectTrue("names.indexOf(\"baz\") >= 0");
11193 ExpectTrue("names.indexOf(\"n1\") >= 0");
11194 ExpectTrue("names.indexOf(\"n2\") >= 0");
11195 ExpectTrue("names.indexOf(sym) >= 0");
11196 ExpectTrue("names.indexOf(\"mine\") >= 0");
11197}
11198
11199
11200THREADED_TEST(FunctionReadOnlyPrototype) {
11201 LocalContext context;
11202 v8::Isolate* isolate = context->GetIsolate();
11203 v8::HandleScope handle_scope(isolate);
11204
11205 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11206 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011207 t1->ReadOnlyPrototype();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011208 context->Global()->Set(v8_str("func1"), t1->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011209 // Configured value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011210 CHECK(CompileRun(
11211 "(function() {"
11212 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011213 " return (descriptor['writable'] == false);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011214 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011215 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
11216 CHECK_EQ(42,
11217 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011218
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011219 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11220 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011221 context->Global()->Set(v8_str("func2"), t2->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011222 // Default value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011223 CHECK(CompileRun(
11224 "(function() {"
11225 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011226 " return (descriptor['writable'] == true);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011227 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011228 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011229}
11230
11231
Andrei Popescu402d9372010-02-26 13:31:12 +000011232THREADED_TEST(SetPrototypeThrows) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011233 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011234 v8::Isolate* isolate = context->GetIsolate();
11235 v8::HandleScope handle_scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011236
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011237 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000011238
11239 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
11240 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
11241
11242 CHECK(o0->SetPrototype(o1));
11243 // If setting the prototype leads to the cycle, SetPrototype should
11244 // return false and keep VM in sane state.
11245 v8::TryCatch try_catch;
11246 CHECK(!o1->SetPrototype(o0));
11247 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011248 DCHECK(!CcTest::i_isolate()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +000011249
11250 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
11251}
11252
11253
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011254THREADED_TEST(FunctionRemovePrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011255 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011256 v8::Isolate* isolate = context->GetIsolate();
11257 v8::HandleScope handle_scope(isolate);
11258
11259 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11260 t1->RemovePrototype();
11261 Local<v8::Function> fun = t1->GetFunction();
11262 context->Global()->Set(v8_str("fun"), fun);
11263 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
11264
11265 v8::TryCatch try_catch;
11266 CompileRun("new fun()");
11267 CHECK(try_catch.HasCaught());
11268
11269 try_catch.Reset();
11270 fun->NewInstance();
11271 CHECK(try_catch.HasCaught());
11272}
11273
11274
11275THREADED_TEST(GetterSetterExceptions) {
11276 LocalContext context;
11277 v8::Isolate* isolate = context->GetIsolate();
11278 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011279 CompileRun(
11280 "function Foo() { };"
11281 "function Throw() { throw 5; };"
11282 "var x = { };"
11283 "x.__defineSetter__('set', Throw);"
11284 "x.__defineGetter__('get', Throw);");
11285 Local<v8::Object> x =
11286 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
11287 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011288 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000011289 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011290 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000011291 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011292 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000011293 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011294 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000011295 x->Get(v8_str("get"));
11296}
11297
11298
11299THREADED_TEST(Constructor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011300 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011301 v8::Isolate* isolate = context->GetIsolate();
11302 v8::HandleScope handle_scope(isolate);
11303 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011304 templ->SetClassName(v8_str("Fun"));
11305 Local<Function> cons = templ->GetFunction();
11306 context->Global()->Set(v8_str("Fun"), cons);
11307 Local<v8::Object> inst = cons->NewInstance();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011308 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
11309 CHECK(obj->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +000011310 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11311 CHECK(value->BooleanValue());
11312}
11313
Ben Murdoch257744e2011-11-30 15:57:28 +000011314
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011315static void ConstructorCallback(
11316 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000011317 ApiTestFuzzer::Fuzz();
11318 Local<Object> This;
11319
11320 if (args.IsConstructCall()) {
11321 Local<Object> Holder = args.Holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011322 This = Object::New(args.GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +000011323 Local<Value> proto = Holder->GetPrototype();
11324 if (proto->IsObject()) {
11325 This->SetPrototype(proto);
11326 }
11327 } else {
11328 This = args.This();
11329 }
11330
11331 This->Set(v8_str("a"), args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011332 args.GetReturnValue().Set(This);
Ben Murdoch257744e2011-11-30 15:57:28 +000011333}
11334
11335
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011336static void FakeConstructorCallback(
11337 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000011338 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011339 args.GetReturnValue().Set(args[0]);
Ben Murdoch257744e2011-11-30 15:57:28 +000011340}
11341
11342
11343THREADED_TEST(ConstructorForObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000011344 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011345 v8::Isolate* isolate = context->GetIsolate();
11346 v8::HandleScope handle_scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011347
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011348 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011349 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
11350 Local<Object> instance = instance_template->NewInstance();
11351 context->Global()->Set(v8_str("obj"), instance);
11352 v8::TryCatch try_catch;
11353 Local<Value> value;
11354 CHECK(!try_catch.HasCaught());
11355
11356 // Call the Object's constructor with a 32-bit signed integer.
11357 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11358 CHECK(!try_catch.HasCaught());
11359 CHECK(value->IsInt32());
11360 CHECK_EQ(28, value->Int32Value());
11361
11362 Local<Value> args1[] = { v8_num(28) };
11363 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
11364 CHECK(value_obj1->IsObject());
11365 Local<Object> object1 = Local<Object>::Cast(value_obj1);
11366 value = object1->Get(v8_str("a"));
11367 CHECK(value->IsInt32());
11368 CHECK(!try_catch.HasCaught());
11369 CHECK_EQ(28, value->Int32Value());
11370
11371 // Call the Object's constructor with a String.
11372 value = CompileRun(
11373 "(function() { var o = new obj('tipli'); return o.a; })()");
11374 CHECK(!try_catch.HasCaught());
11375 CHECK(value->IsString());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011376 String::Utf8Value string_value1(value->ToString(isolate));
Ben Murdoch257744e2011-11-30 15:57:28 +000011377 CHECK_EQ("tipli", *string_value1);
11378
11379 Local<Value> args2[] = { v8_str("tipli") };
11380 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
11381 CHECK(value_obj2->IsObject());
11382 Local<Object> object2 = Local<Object>::Cast(value_obj2);
11383 value = object2->Get(v8_str("a"));
11384 CHECK(!try_catch.HasCaught());
11385 CHECK(value->IsString());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011386 String::Utf8Value string_value2(value->ToString(isolate));
Ben Murdoch257744e2011-11-30 15:57:28 +000011387 CHECK_EQ("tipli", *string_value2);
11388
11389 // Call the Object's constructor with a Boolean.
11390 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11391 CHECK(!try_catch.HasCaught());
11392 CHECK(value->IsBoolean());
11393 CHECK_EQ(true, value->BooleanValue());
11394
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011395 Handle<Value> args3[] = { v8::True(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000011396 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
11397 CHECK(value_obj3->IsObject());
11398 Local<Object> object3 = Local<Object>::Cast(value_obj3);
11399 value = object3->Get(v8_str("a"));
11400 CHECK(!try_catch.HasCaught());
11401 CHECK(value->IsBoolean());
11402 CHECK_EQ(true, value->BooleanValue());
11403
11404 // Call the Object's constructor with undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011405 Handle<Value> args4[] = { v8::Undefined(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000011406 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
11407 CHECK(value_obj4->IsObject());
11408 Local<Object> object4 = Local<Object>::Cast(value_obj4);
11409 value = object4->Get(v8_str("a"));
11410 CHECK(!try_catch.HasCaught());
11411 CHECK(value->IsUndefined());
11412
11413 // Call the Object's constructor with null.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011414 Handle<Value> args5[] = { v8::Null(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000011415 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
11416 CHECK(value_obj5->IsObject());
11417 Local<Object> object5 = Local<Object>::Cast(value_obj5);
11418 value = object5->Get(v8_str("a"));
11419 CHECK(!try_catch.HasCaught());
11420 CHECK(value->IsNull());
11421 }
11422
11423 // Check exception handling when there is no constructor set for the Object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011424 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011425 Local<Object> instance = instance_template->NewInstance();
11426 context->Global()->Set(v8_str("obj2"), instance);
11427 v8::TryCatch try_catch;
11428 Local<Value> value;
11429 CHECK(!try_catch.HasCaught());
11430
11431 value = CompileRun("new obj2(28)");
11432 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011433 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011434 CHECK_EQ("TypeError: object is not a function", *exception_value1);
11435 try_catch.Reset();
11436
11437 Local<Value> args[] = { v8_num(29) };
11438 value = instance->CallAsConstructor(1, args);
11439 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011440 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011441 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
11442 try_catch.Reset();
11443 }
11444
11445 // Check the case when constructor throws exception.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011446 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011447 instance_template->SetCallAsFunctionHandler(ThrowValue);
11448 Local<Object> instance = instance_template->NewInstance();
11449 context->Global()->Set(v8_str("obj3"), instance);
11450 v8::TryCatch try_catch;
11451 Local<Value> value;
11452 CHECK(!try_catch.HasCaught());
11453
11454 value = CompileRun("new obj3(22)");
11455 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011456 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011457 CHECK_EQ("22", *exception_value1);
11458 try_catch.Reset();
11459
11460 Local<Value> args[] = { v8_num(23) };
11461 value = instance->CallAsConstructor(1, args);
11462 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011463 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011464 CHECK_EQ("23", *exception_value2);
11465 try_catch.Reset();
11466 }
11467
11468 // Check whether constructor returns with an object or non-object.
11469 { Local<FunctionTemplate> function_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011470 FunctionTemplate::New(isolate, FakeConstructorCallback);
Ben Murdoch257744e2011-11-30 15:57:28 +000011471 Local<Function> function = function_template->GetFunction();
11472 Local<Object> instance1 = function;
11473 context->Global()->Set(v8_str("obj4"), instance1);
11474 v8::TryCatch try_catch;
11475 Local<Value> value;
11476 CHECK(!try_catch.HasCaught());
11477
11478 CHECK(instance1->IsObject());
11479 CHECK(instance1->IsFunction());
11480
11481 value = CompileRun("new obj4(28)");
11482 CHECK(!try_catch.HasCaught());
11483 CHECK(value->IsObject());
11484
11485 Local<Value> args1[] = { v8_num(28) };
11486 value = instance1->CallAsConstructor(1, args1);
11487 CHECK(!try_catch.HasCaught());
11488 CHECK(value->IsObject());
11489
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011490 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011491 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11492 Local<Object> instance2 = instance_template->NewInstance();
11493 context->Global()->Set(v8_str("obj5"), instance2);
11494 CHECK(!try_catch.HasCaught());
11495
11496 CHECK(instance2->IsObject());
11497 CHECK(!instance2->IsFunction());
11498
11499 value = CompileRun("new obj5(28)");
11500 CHECK(!try_catch.HasCaught());
11501 CHECK(!value->IsObject());
11502
11503 Local<Value> args2[] = { v8_num(28) };
11504 value = instance2->CallAsConstructor(1, args2);
11505 CHECK(!try_catch.HasCaught());
11506 CHECK(!value->IsObject());
11507 }
11508}
11509
11510
Steve Blocka7e24c12009-10-30 11:49:00 +000011511THREADED_TEST(FunctionDescriptorException) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011512 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011513 v8::Isolate* isolate = context->GetIsolate();
11514 v8::HandleScope handle_scope(isolate);
11515 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011516 templ->SetClassName(v8_str("Fun"));
11517 Local<Function> cons = templ->GetFunction();
11518 context->Global()->Set(v8_str("Fun"), cons);
11519 Local<Value> value = CompileRun(
11520 "function test() {"
11521 " try {"
11522 " (new Fun()).blah()"
11523 " } catch (e) {"
11524 " var str = String(e);"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011525 // " if (str.indexOf('TypeError') == -1) return 1;"
11526 // " if (str.indexOf('[object Fun]') != -1) return 2;"
11527 // " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +000011528 " return 0;"
11529 " }"
11530 " return 4;"
11531 "}"
11532 "test();");
11533 CHECK_EQ(0, value->Int32Value());
11534}
11535
11536
11537THREADED_TEST(EvalAliasedDynamic) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011538 LocalContext current;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011539 v8::HandleScope scope(current->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011540
11541 // Tests where aliased eval can only be resolved dynamically.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011542 Local<Script> script = v8_compile(
11543 "function f(x) { "
11544 " var foo = 2;"
11545 " with (x) { return eval('foo'); }"
11546 "}"
11547 "foo = 0;"
11548 "result1 = f(new Object());"
11549 "result2 = f(this);"
11550 "var x = new Object();"
11551 "x.eval = function(x) { return 1; };"
11552 "result3 = f(x);");
Steve Blocka7e24c12009-10-30 11:49:00 +000011553 script->Run();
11554 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
11555 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
11556 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
11557
11558 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011559 script = v8_compile(
11560 "function f(x) { "
11561 " var bar = 2;"
11562 " with (x) { return eval('bar'); }"
11563 "}"
11564 "result4 = f(this)");
Steve Blocka7e24c12009-10-30 11:49:00 +000011565 script->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011566 CHECK(!try_catch.HasCaught());
11567 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11568
Steve Blocka7e24c12009-10-30 11:49:00 +000011569 try_catch.Reset();
11570}
11571
11572
11573THREADED_TEST(CrossEval) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011574 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011575 LocalContext other;
11576 LocalContext current;
11577
11578 Local<String> token = v8_str("<security token>");
11579 other->SetSecurityToken(token);
11580 current->SetSecurityToken(token);
11581
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011582 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +000011583 current->Global()->Set(v8_str("other"), other->Global());
11584
11585 // Check that new variables are introduced in other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011586 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011587 script->Run();
11588 Local<Value> foo = other->Global()->Get(v8_str("foo"));
11589 CHECK_EQ(1234, foo->Int32Value());
11590 CHECK(!current->Global()->Has(v8_str("foo")));
11591
11592 // Check that writing to non-existing properties introduces them in
11593 // the other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011594 script = v8_compile("other.eval('na = 1234')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011595 script->Run();
11596 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11597 CHECK(!current->Global()->Has(v8_str("na")));
11598
11599 // Check that global variables in current context are not visible in other
11600 // context.
11601 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011602 script = v8_compile("var bar = 42; other.eval('bar');");
Steve Blocka7e24c12009-10-30 11:49:00 +000011603 Local<Value> result = script->Run();
11604 CHECK(try_catch.HasCaught());
11605 try_catch.Reset();
11606
11607 // Check that local variables in current context are not visible in other
11608 // context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011609 script = v8_compile(
11610 "(function() { "
11611 " var baz = 87;"
11612 " return other.eval('baz');"
11613 "})();");
Steve Blocka7e24c12009-10-30 11:49:00 +000011614 result = script->Run();
11615 CHECK(try_catch.HasCaught());
11616 try_catch.Reset();
11617
11618 // Check that global variables in the other environment are visible
11619 // when evaluting code.
11620 other->Global()->Set(v8_str("bis"), v8_num(1234));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011621 script = v8_compile("other.eval('bis')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011622 CHECK_EQ(1234, script->Run()->Int32Value());
11623 CHECK(!try_catch.HasCaught());
11624
11625 // Check that the 'this' pointer points to the global object evaluating
11626 // code.
11627 other->Global()->Set(v8_str("t"), other->Global());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011628 script = v8_compile("other.eval('this == t')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011629 result = script->Run();
11630 CHECK(result->IsTrue());
11631 CHECK(!try_catch.HasCaught());
11632
11633 // Check that variables introduced in with-statement are not visible in
11634 // other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011635 script = v8_compile("with({x:2}){other.eval('x')}");
Steve Blocka7e24c12009-10-30 11:49:00 +000011636 result = script->Run();
11637 CHECK(try_catch.HasCaught());
11638 try_catch.Reset();
11639
11640 // Check that you cannot use 'eval.call' with another object than the
11641 // current global object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011642 script = v8_compile("other.y = 1; eval.call(other, 'y')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011643 result = script->Run();
11644 CHECK(try_catch.HasCaught());
11645}
11646
11647
11648// Test that calling eval in a context which has been detached from
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011649// its global proxy works.
Steve Blocka7e24c12009-10-30 11:49:00 +000011650THREADED_TEST(EvalInDetachedGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011651 v8::Isolate* isolate = CcTest::isolate();
11652 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011653
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011654 v8::Local<Context> context0 = Context::New(isolate);
11655 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011656
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011657 // Set up function in context0 that uses eval from context0.
Steve Blocka7e24c12009-10-30 11:49:00 +000011658 context0->Enter();
11659 v8::Handle<v8::Value> fun =
11660 CompileRun("var x = 42;"
11661 "(function() {"
11662 " var e = eval;"
11663 " return function(s) { return e(s); }"
11664 "})()");
11665 context0->Exit();
11666
11667 // Put the function into context1 and call it before and after
11668 // detaching the global. Before detaching, the call succeeds and
11669 // after detaching and exception is thrown.
11670 context1->Enter();
11671 context1->Global()->Set(v8_str("fun"), fun);
11672 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11673 CHECK_EQ(42, x_value->Int32Value());
11674 context0->DetachGlobal();
11675 v8::TryCatch catcher;
11676 x_value = CompileRun("fun('x')");
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011677 CHECK_EQ(42, x_value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011678 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000011679}
11680
11681
11682THREADED_TEST(CrossLazyLoad) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011683 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011684 LocalContext other;
11685 LocalContext current;
11686
11687 Local<String> token = v8_str("<security token>");
11688 other->SetSecurityToken(token);
11689 current->SetSecurityToken(token);
11690
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011691 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +000011692 current->Global()->Set(v8_str("other"), other->Global());
11693
11694 // Trigger lazy loading in other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011695 Local<Script> script = v8_compile("other.eval('new Date(42)')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011696 Local<Value> value = script->Run();
11697 CHECK_EQ(42.0, value->NumberValue());
11698}
11699
11700
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011701static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011702 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000011703 if (args.IsConstructCall()) {
11704 if (args[0]->IsInt32()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011705 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11706 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000011707 }
11708 }
11709
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011710 args.GetReturnValue().Set(args[0]);
11711}
11712
11713
11714static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11715 args.GetReturnValue().Set(args.This());
Steve Blocka7e24c12009-10-30 11:49:00 +000011716}
11717
11718
11719// Test that a call handler can be set for objects which will allow
11720// non-function objects created through the API to be called as
11721// functions.
11722THREADED_TEST(CallAsFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011723 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011724 v8::Isolate* isolate = context->GetIsolate();
11725 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011726
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011727 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011728 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11729 instance_template->SetCallAsFunctionHandler(call_as_function);
11730 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11731 context->Global()->Set(v8_str("obj"), instance);
11732 v8::TryCatch try_catch;
11733 Local<Value> value;
11734 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +000011735
Ben Murdoch257744e2011-11-30 15:57:28 +000011736 value = CompileRun("obj(42)");
11737 CHECK(!try_catch.HasCaught());
11738 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011739
Ben Murdoch257744e2011-11-30 15:57:28 +000011740 value = CompileRun("(function(o){return o(49)})(obj)");
11741 CHECK(!try_catch.HasCaught());
11742 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011743
Ben Murdoch257744e2011-11-30 15:57:28 +000011744 // test special case of call as function
11745 value = CompileRun("[obj]['0'](45)");
11746 CHECK(!try_catch.HasCaught());
11747 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011748
Ben Murdoch257744e2011-11-30 15:57:28 +000011749 value = CompileRun("obj.call = Function.prototype.call;"
11750 "obj.call(null, 87)");
11751 CHECK(!try_catch.HasCaught());
11752 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011753
Ben Murdoch257744e2011-11-30 15:57:28 +000011754 // Regression tests for bug #1116356: Calling call through call/apply
11755 // must work for non-function receivers.
11756 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11757 value = CompileRun(apply_99);
11758 CHECK(!try_catch.HasCaught());
11759 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011760
Ben Murdoch257744e2011-11-30 15:57:28 +000011761 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11762 value = CompileRun(call_17);
11763 CHECK(!try_catch.HasCaught());
11764 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011765
Ben Murdoch257744e2011-11-30 15:57:28 +000011766 // Check that the call-as-function handler can be called through
11767 // new.
11768 value = CompileRun("new obj(43)");
11769 CHECK(!try_catch.HasCaught());
11770 CHECK_EQ(-43, value->Int32Value());
11771
11772 // Check that the call-as-function handler can be called through
11773 // the API.
11774 v8::Handle<Value> args[] = { v8_num(28) };
11775 value = instance->CallAsFunction(instance, 1, args);
11776 CHECK(!try_catch.HasCaught());
11777 CHECK_EQ(28, value->Int32Value());
11778 }
11779
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011780 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011781 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11782 USE(instance_template);
Ben Murdoch257744e2011-11-30 15:57:28 +000011783 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11784 context->Global()->Set(v8_str("obj2"), instance);
11785 v8::TryCatch try_catch;
11786 Local<Value> value;
11787 CHECK(!try_catch.HasCaught());
11788
11789 // Call an object without call-as-function handler through the JS
11790 value = CompileRun("obj2(28)");
11791 CHECK(value.IsEmpty());
11792 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011793 String::Utf8Value exception_value1(try_catch.Exception());
11794 // TODO(verwaest): Better message
11795 CHECK_EQ("TypeError: object is not a function",
Ben Murdoch257744e2011-11-30 15:57:28 +000011796 *exception_value1);
11797 try_catch.Reset();
11798
11799 // Call an object without call-as-function handler through the API
11800 value = CompileRun("obj2(28)");
11801 v8::Handle<Value> args[] = { v8_num(28) };
11802 value = instance->CallAsFunction(instance, 1, args);
11803 CHECK(value.IsEmpty());
11804 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011805 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011806 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11807 try_catch.Reset();
11808 }
11809
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011810 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011811 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11812 instance_template->SetCallAsFunctionHandler(ThrowValue);
11813 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11814 context->Global()->Set(v8_str("obj3"), instance);
11815 v8::TryCatch try_catch;
11816 Local<Value> value;
11817 CHECK(!try_catch.HasCaught());
11818
11819 // Catch the exception which is thrown by call-as-function handler
11820 value = CompileRun("obj3(22)");
11821 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011822 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011823 CHECK_EQ("22", *exception_value1);
11824 try_catch.Reset();
11825
11826 v8::Handle<Value> args[] = { v8_num(23) };
11827 value = instance->CallAsFunction(instance, 1, args);
11828 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011829 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011830 CHECK_EQ("23", *exception_value2);
11831 try_catch.Reset();
11832 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011833
11834 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11835 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11836 instance_template->SetCallAsFunctionHandler(ReturnThis);
11837 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11838
11839 Local<v8::Value> a1 =
11840 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11841 CHECK(a1->StrictEquals(instance));
11842 Local<v8::Value> a2 =
11843 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11844 CHECK(a2->StrictEquals(instance));
11845 Local<v8::Value> a3 =
11846 instance->CallAsFunction(v8_num(42), 0, NULL);
11847 CHECK(a3->StrictEquals(instance));
11848 Local<v8::Value> a4 =
11849 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11850 CHECK(a4->StrictEquals(instance));
11851 Local<v8::Value> a5 =
11852 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11853 CHECK(a5->StrictEquals(instance));
11854 }
11855
11856 { CompileRun(
11857 "function ReturnThisSloppy() {"
11858 " return this;"
11859 "}"
11860 "function ReturnThisStrict() {"
11861 " 'use strict';"
11862 " return this;"
11863 "}");
11864 Local<Function> ReturnThisSloppy =
11865 Local<Function>::Cast(
11866 context->Global()->Get(v8_str("ReturnThisSloppy")));
11867 Local<Function> ReturnThisStrict =
11868 Local<Function>::Cast(
11869 context->Global()->Get(v8_str("ReturnThisStrict")));
11870
11871 Local<v8::Value> a1 =
11872 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11873 CHECK(a1->StrictEquals(context->Global()));
11874 Local<v8::Value> a2 =
11875 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11876 CHECK(a2->StrictEquals(context->Global()));
11877 Local<v8::Value> a3 =
11878 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11879 CHECK(a3->IsNumberObject());
11880 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11881 Local<v8::Value> a4 =
11882 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11883 CHECK(a4->IsStringObject());
11884 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11885 Local<v8::Value> a5 =
11886 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11887 CHECK(a5->IsBooleanObject());
11888 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11889
11890 Local<v8::Value> a6 =
11891 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11892 CHECK(a6->IsUndefined());
11893 Local<v8::Value> a7 =
11894 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11895 CHECK(a7->IsNull());
11896 Local<v8::Value> a8 =
11897 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11898 CHECK(a8->StrictEquals(v8_num(42)));
11899 Local<v8::Value> a9 =
11900 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11901 CHECK(a9->StrictEquals(v8_str("hello")));
11902 Local<v8::Value> a10 =
11903 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11904 CHECK(a10->StrictEquals(v8::True(isolate)));
11905 }
Ben Murdoch257744e2011-11-30 15:57:28 +000011906}
11907
11908
11909// Check whether a non-function object is callable.
11910THREADED_TEST(CallableObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000011911 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011912 v8::Isolate* isolate = context->GetIsolate();
11913 v8::HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011914
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011915 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011916 instance_template->SetCallAsFunctionHandler(call_as_function);
11917 Local<Object> instance = instance_template->NewInstance();
11918 v8::TryCatch try_catch;
11919
11920 CHECK(instance->IsCallable());
11921 CHECK(!try_catch.HasCaught());
11922 }
11923
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011924 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011925 Local<Object> instance = instance_template->NewInstance();
11926 v8::TryCatch try_catch;
11927
11928 CHECK(!instance->IsCallable());
11929 CHECK(!try_catch.HasCaught());
11930 }
11931
11932 { Local<FunctionTemplate> function_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011933 FunctionTemplate::New(isolate, call_as_function);
Ben Murdoch257744e2011-11-30 15:57:28 +000011934 Local<Function> function = function_template->GetFunction();
11935 Local<Object> instance = function;
11936 v8::TryCatch try_catch;
11937
11938 CHECK(instance->IsCallable());
11939 CHECK(!try_catch.HasCaught());
11940 }
11941
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011942 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011943 Local<Function> function = function_template->GetFunction();
11944 Local<Object> instance = function;
11945 v8::TryCatch try_catch;
11946
11947 CHECK(instance->IsCallable());
11948 CHECK(!try_catch.HasCaught());
11949 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011950}
11951
11952
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011953static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11954 v8::HandleScope scope(isolate);
11955 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011956 for (int i = 0; i < iterations; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011957 Local<v8::Number> n(v8::Integer::New(isolate, 42));
Steve Blocka7e24c12009-10-30 11:49:00 +000011958 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011959 return Recurse(isolate, depth - 1, iterations);
Steve Blocka7e24c12009-10-30 11:49:00 +000011960}
11961
11962
11963THREADED_TEST(HandleIteration) {
11964 static const int kIterations = 500;
11965 static const int kNesting = 200;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011966 LocalContext context;
11967 v8::Isolate* isolate = context->GetIsolate();
11968 v8::HandleScope scope0(isolate);
11969 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011970 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011971 v8::HandleScope scope1(isolate);
11972 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011973 for (int i = 0; i < kIterations; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011974 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11975 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011976 }
11977
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011978 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011979 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011980 v8::HandleScope scope2(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011981 for (int j = 0; j < kIterations; j++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011982 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11983 CHECK_EQ(j + 1 + kIterations,
11984 v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011985 }
11986 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011987 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011988 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011989 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11990 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
Steve Blocka7e24c12009-10-30 11:49:00 +000011991}
11992
11993
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011994static void InterceptorHasOwnPropertyGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011995 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011996 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000011997}
11998
11999
12000THREADED_TEST(InterceptorHasOwnProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012001 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012002 v8::Isolate* isolate = context->GetIsolate();
12003 v8::HandleScope scope(isolate);
12004 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012005 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012006 instance_templ->SetHandler(
12007 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000012008 Local<Function> function = fun_templ->GetFunction();
12009 context->Global()->Set(v8_str("constructor"), function);
12010 v8::Handle<Value> value = CompileRun(
12011 "var o = new constructor();"
12012 "o.hasOwnProperty('ostehaps');");
12013 CHECK_EQ(false, value->BooleanValue());
12014 value = CompileRun(
12015 "o.ostehaps = 42;"
12016 "o.hasOwnProperty('ostehaps');");
12017 CHECK_EQ(true, value->BooleanValue());
12018 value = CompileRun(
12019 "var p = new constructor();"
12020 "p.hasOwnProperty('ostehaps');");
12021 CHECK_EQ(false, value->BooleanValue());
12022}
12023
12024
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012025static void InterceptorHasOwnPropertyGetterGC(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012026 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012027 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012028 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000012029}
12030
12031
12032THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012033 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012034 v8::Isolate* isolate = context->GetIsolate();
12035 v8::HandleScope scope(isolate);
12036 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012037 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012038 instance_templ->SetHandler(
12039 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
Steve Blocka7e24c12009-10-30 11:49:00 +000012040 Local<Function> function = fun_templ->GetFunction();
12041 context->Global()->Set(v8_str("constructor"), function);
12042 // Let's first make some stuff so we can be sure to get a good GC.
12043 CompileRun(
12044 "function makestr(size) {"
12045 " switch (size) {"
12046 " case 1: return 'f';"
12047 " case 2: return 'fo';"
12048 " case 3: return 'foo';"
12049 " }"
12050 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
12051 "}"
12052 "var x = makestr(12345);"
12053 "x = makestr(31415);"
12054 "x = makestr(23456);");
12055 v8::Handle<Value> value = CompileRun(
12056 "var o = new constructor();"
12057 "o.__proto__ = new String(x);"
12058 "o.hasOwnProperty('ostehaps');");
12059 CHECK_EQ(false, value->BooleanValue());
12060}
12061
12062
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012063static void CheckInterceptorLoadIC(
12064 v8::GenericNamedPropertyGetterCallback getter, const char* source,
12065 int expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012066 v8::Isolate* isolate = CcTest::isolate();
12067 v8::HandleScope scope(isolate);
12068 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012069 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
12070 v8_str("data")));
Steve Blocka7e24c12009-10-30 11:49:00 +000012071 LocalContext context;
12072 context->Global()->Set(v8_str("o"), templ->NewInstance());
12073 v8::Handle<Value> value = CompileRun(source);
12074 CHECK_EQ(expected, value->Int32Value());
12075}
12076
12077
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012078static void InterceptorLoadICGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012079 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012080 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012081 v8::Isolate* isolate = CcTest::isolate();
12082 CHECK_EQ(isolate, info.GetIsolate());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080012083 CHECK_EQ(v8_str("data"), info.Data());
12084 CHECK_EQ(v8_str("x"), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012085 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
Steve Blocka7e24c12009-10-30 11:49:00 +000012086}
12087
12088
12089// This test should hit the load IC for the interceptor case.
12090THREADED_TEST(InterceptorLoadIC) {
12091 CheckInterceptorLoadIC(InterceptorLoadICGetter,
12092 "var result = 0;"
12093 "for (var i = 0; i < 1000; i++) {"
12094 " result = o.x;"
12095 "}",
12096 42);
12097}
12098
12099
12100// Below go several tests which verify that JITing for various
12101// configurations of interceptor and explicit fields works fine
12102// (those cases are special cased to get better performance).
12103
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012104static void InterceptorLoadXICGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012105 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012106 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012107 info.GetReturnValue().Set(
12108 v8_str("x")->Equals(name) ?
12109 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
12110 v8::Handle<v8::Value>());
Steve Blocka7e24c12009-10-30 11:49:00 +000012111}
12112
12113
12114THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
12115 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12116 "var result = 0;"
12117 "o.y = 239;"
12118 "for (var i = 0; i < 1000; i++) {"
12119 " result = o.y;"
12120 "}",
12121 239);
12122}
12123
12124
12125THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
12126 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12127 "var result = 0;"
12128 "o.__proto__ = { 'y': 239 };"
12129 "for (var i = 0; i < 1000; i++) {"
12130 " result = o.y + o.x;"
12131 "}",
12132 239 + 42);
12133}
12134
12135
12136THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
12137 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12138 "var result = 0;"
12139 "o.__proto__.y = 239;"
12140 "for (var i = 0; i < 1000; i++) {"
12141 " result = o.y + o.x;"
12142 "}",
12143 239 + 42);
12144}
12145
12146
12147THREADED_TEST(InterceptorLoadICUndefined) {
12148 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12149 "var result = 0;"
12150 "for (var i = 0; i < 1000; i++) {"
12151 " result = (o.y == undefined) ? 239 : 42;"
12152 "}",
12153 239);
12154}
12155
12156
12157THREADED_TEST(InterceptorLoadICWithOverride) {
12158 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12159 "fst = new Object(); fst.__proto__ = o;"
12160 "snd = new Object(); snd.__proto__ = fst;"
12161 "var result1 = 0;"
12162 "for (var i = 0; i < 1000; i++) {"
12163 " result1 = snd.x;"
12164 "}"
12165 "fst.x = 239;"
12166 "var result = 0;"
12167 "for (var i = 0; i < 1000; i++) {"
12168 " result = snd.x;"
12169 "}"
12170 "result + result1",
12171 239 + 42);
12172}
12173
12174
12175// Test the case when we stored field into
12176// a stub, but interceptor produced value on its own.
12177THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
12178 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12179 "proto = new Object();"
12180 "o.__proto__ = proto;"
12181 "proto.x = 239;"
12182 "for (var i = 0; i < 1000; i++) {"
12183 " o.x;"
12184 // Now it should be ICed and keep a reference to x defined on proto
12185 "}"
12186 "var result = 0;"
12187 "for (var i = 0; i < 1000; i++) {"
12188 " result += o.x;"
12189 "}"
12190 "result;",
12191 42 * 1000);
12192}
12193
12194
12195// Test the case when we stored field into
12196// a stub, but it got invalidated later on.
12197THREADED_TEST(InterceptorLoadICInvalidatedField) {
12198 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12199 "proto1 = new Object();"
12200 "proto2 = new Object();"
12201 "o.__proto__ = proto1;"
12202 "proto1.__proto__ = proto2;"
12203 "proto2.y = 239;"
12204 "for (var i = 0; i < 1000; i++) {"
12205 " o.y;"
12206 // Now it should be ICed and keep a reference to y defined on proto2
12207 "}"
12208 "proto1.y = 42;"
12209 "var result = 0;"
12210 "for (var i = 0; i < 1000; i++) {"
12211 " result += o.y;"
12212 "}"
12213 "result;",
12214 42 * 1000);
12215}
12216
12217
Steve Block6ded16b2010-05-10 14:33:55 +010012218static int interceptor_load_not_handled_calls = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012219static void InterceptorLoadNotHandled(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012220 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Block6ded16b2010-05-10 14:33:55 +010012221 ++interceptor_load_not_handled_calls;
Steve Block6ded16b2010-05-10 14:33:55 +010012222}
12223
12224
12225// Test how post-interceptor lookups are done in the non-cacheable
12226// case: the interceptor should not be invoked during this lookup.
12227THREADED_TEST(InterceptorLoadICPostInterceptor) {
12228 interceptor_load_not_handled_calls = 0;
12229 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
12230 "receiver = new Object();"
12231 "receiver.__proto__ = o;"
12232 "proto = new Object();"
12233 "/* Make proto a slow-case object. */"
12234 "for (var i = 0; i < 1000; i++) {"
12235 " proto[\"xxxxxxxx\" + i] = [];"
12236 "}"
12237 "proto.x = 17;"
12238 "o.__proto__ = proto;"
12239 "var result = 0;"
12240 "for (var i = 0; i < 1000; i++) {"
12241 " result += receiver.x;"
12242 "}"
12243 "result;",
12244 17 * 1000);
12245 CHECK_EQ(1000, interceptor_load_not_handled_calls);
12246}
12247
12248
Steve Blocka7e24c12009-10-30 11:49:00 +000012249// Test the case when we stored field into
12250// a stub, but it got invalidated later on due to override on
12251// global object which is between interceptor and fields' holders.
12252THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
12253 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12254 "o.__proto__ = this;" // set a global to be a proto of o.
12255 "this.__proto__.y = 239;"
12256 "for (var i = 0; i < 10; i++) {"
12257 " if (o.y != 239) throw 'oops: ' + o.y;"
12258 // Now it should be ICed and keep a reference to y defined on field_holder.
12259 "}"
12260 "this.y = 42;" // Assign on a global.
12261 "var result = 0;"
12262 "for (var i = 0; i < 10; i++) {"
12263 " result += o.y;"
12264 "}"
12265 "result;",
12266 42 * 10);
12267}
12268
12269
Steve Blocka7e24c12009-10-30 11:49:00 +000012270static void SetOnThis(Local<String> name,
12271 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012272 const v8::PropertyCallbackInfo<void>& info) {
12273 Local<Object>::Cast(info.This())->ForceSet(name, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000012274}
12275
12276
12277THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012278 v8::Isolate* isolate = CcTest::isolate();
12279 v8::HandleScope scope(isolate);
12280 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012281 templ->SetHandler(
12282 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012283 templ->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000012284 LocalContext context;
12285 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012286
12287 // Check the case when receiver and interceptor's holder
12288 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012289 v8::Handle<Value> value = CompileRun(
12290 "var result = 0;"
12291 "for (var i = 0; i < 7; i++) {"
12292 " result = o.y;"
12293 "}");
12294 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012295
12296 // Check the case when interceptor's holder is in proto chain
12297 // of receiver.
12298 value = CompileRun(
12299 "r = { __proto__: o };"
12300 "var result = 0;"
12301 "for (var i = 0; i < 7; i++) {"
12302 " result = r.y;"
12303 "}");
12304 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012305}
12306
12307
12308THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012309 v8::Isolate* isolate = CcTest::isolate();
12310 v8::HandleScope scope(isolate);
12311 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012312 templ_o->SetHandler(
12313 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012314 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12315 templ_p->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000012316
12317 LocalContext context;
12318 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12319 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12320
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012321 // Check the case when receiver and interceptor's holder
12322 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012323 v8::Handle<Value> value = CompileRun(
12324 "o.__proto__ = p;"
12325 "var result = 0;"
12326 "for (var i = 0; i < 7; i++) {"
12327 " result = o.x + o.y;"
12328 "}");
12329 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012330
12331 // Check the case when interceptor's holder is in proto chain
12332 // of receiver.
12333 value = CompileRun(
12334 "r = { __proto__: o };"
12335 "var result = 0;"
12336 "for (var i = 0; i < 7; i++) {"
12337 " result = r.x + r.y;"
12338 "}");
12339 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012340}
12341
12342
12343THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012344 v8::Isolate* isolate = CcTest::isolate();
12345 v8::HandleScope scope(isolate);
12346 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012347 templ->SetHandler(
12348 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012349 templ->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000012350
12351 LocalContext context;
12352 context->Global()->Set(v8_str("o"), templ->NewInstance());
12353
12354 v8::Handle<Value> value = CompileRun(
12355 "fst = new Object(); fst.__proto__ = o;"
12356 "snd = new Object(); snd.__proto__ = fst;"
12357 "var result1 = 0;"
12358 "for (var i = 0; i < 7; i++) {"
12359 " result1 = snd.x;"
12360 "}"
12361 "fst.x = 239;"
12362 "var result = 0;"
12363 "for (var i = 0; i < 7; i++) {"
12364 " result = snd.x;"
12365 "}"
12366 "result + result1");
12367 CHECK_EQ(239 + 42, value->Int32Value());
12368}
12369
12370
12371// Test the case when we stored callback into
12372// a stub, but interceptor produced value on its own.
12373THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012374 v8::Isolate* isolate = CcTest::isolate();
12375 v8::HandleScope scope(isolate);
12376 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012377 templ_o->SetHandler(
12378 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012379 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12380 templ_p->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000012381
12382 LocalContext context;
12383 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12384 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12385
12386 v8::Handle<Value> value = CompileRun(
12387 "o.__proto__ = p;"
12388 "for (var i = 0; i < 7; i++) {"
12389 " o.x;"
12390 // Now it should be ICed and keep a reference to x defined on p
12391 "}"
12392 "var result = 0;"
12393 "for (var i = 0; i < 7; i++) {"
12394 " result += o.x;"
12395 "}"
12396 "result");
12397 CHECK_EQ(42 * 7, value->Int32Value());
12398}
12399
12400
12401// Test the case when we stored callback into
12402// a stub, but it got invalidated later on.
12403THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012404 v8::Isolate* isolate = CcTest::isolate();
12405 v8::HandleScope scope(isolate);
12406 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012407 templ_o->SetHandler(
12408 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012409 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12410 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
Steve Blocka7e24c12009-10-30 11:49:00 +000012411
12412 LocalContext context;
12413 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12414 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12415
12416 v8::Handle<Value> value = CompileRun(
12417 "inbetween = new Object();"
12418 "o.__proto__ = inbetween;"
12419 "inbetween.__proto__ = p;"
12420 "for (var i = 0; i < 10; i++) {"
12421 " o.y;"
12422 // Now it should be ICed and keep a reference to y defined on p
12423 "}"
12424 "inbetween.y = 42;"
12425 "var result = 0;"
12426 "for (var i = 0; i < 10; i++) {"
12427 " result += o.y;"
12428 "}"
12429 "result");
12430 CHECK_EQ(42 * 10, value->Int32Value());
12431}
12432
12433
12434// Test the case when we stored callback into
12435// a stub, but it got invalidated later on due to override on
12436// global object which is between interceptor and callbacks' holders.
12437THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012438 v8::Isolate* isolate = CcTest::isolate();
12439 v8::HandleScope scope(isolate);
12440 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012441 templ_o->SetHandler(
12442 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012443 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12444 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
Steve Blocka7e24c12009-10-30 11:49:00 +000012445
12446 LocalContext context;
12447 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12448 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12449
12450 v8::Handle<Value> value = CompileRun(
12451 "o.__proto__ = this;"
12452 "this.__proto__ = p;"
12453 "for (var i = 0; i < 10; i++) {"
12454 " if (o.y != 239) throw 'oops: ' + o.y;"
12455 // Now it should be ICed and keep a reference to y defined on p
12456 "}"
12457 "this.y = 42;"
12458 "var result = 0;"
12459 "for (var i = 0; i < 10; i++) {"
12460 " result += o.y;"
12461 "}"
12462 "result");
12463 CHECK_EQ(42 * 10, value->Int32Value());
12464}
12465
12466
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012467static void InterceptorLoadICGetter0(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012468 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012469 ApiTestFuzzer::Fuzz();
12470 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012471 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
Steve Blocka7e24c12009-10-30 11:49:00 +000012472}
12473
12474
12475THREADED_TEST(InterceptorReturningZero) {
12476 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
12477 "o.x == undefined ? 1 : 0",
12478 0);
12479}
12480
12481
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012482static void InterceptorStoreICSetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012483 Local<Name> key, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012484 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012485 CHECK(v8_str("x")->Equals(key));
12486 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012487 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000012488}
12489
12490
12491// This test should hit the store IC for the interceptor case.
12492THREADED_TEST(InterceptorStoreIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012493 v8::Isolate* isolate = CcTest::isolate();
12494 v8::HandleScope scope(isolate);
12495 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012496 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12497 InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
12498 v8_str("data")));
Steve Blocka7e24c12009-10-30 11:49:00 +000012499 LocalContext context;
12500 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012501 CompileRun(
12502 "for (var i = 0; i < 1000; i++) {"
12503 " o.x = 42;"
12504 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +000012505}
12506
12507
12508THREADED_TEST(InterceptorStoreICWithNoSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012509 v8::Isolate* isolate = CcTest::isolate();
12510 v8::HandleScope scope(isolate);
12511 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012512 templ->SetHandler(
12513 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000012514 LocalContext context;
12515 context->Global()->Set(v8_str("o"), templ->NewInstance());
12516 v8::Handle<Value> value = CompileRun(
12517 "for (var i = 0; i < 1000; i++) {"
12518 " o.y = 239;"
12519 "}"
12520 "42 + o.y");
12521 CHECK_EQ(239 + 42, value->Int32Value());
12522}
12523
12524
12525
12526
12527v8::Handle<Value> call_ic_function;
12528v8::Handle<Value> call_ic_function2;
12529v8::Handle<Value> call_ic_function3;
12530
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012531static void InterceptorCallICGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012532 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012533 ApiTestFuzzer::Fuzz();
12534 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012535 info.GetReturnValue().Set(call_ic_function);
Steve Blocka7e24c12009-10-30 11:49:00 +000012536}
12537
12538
12539// This test should hit the call IC for the interceptor case.
12540THREADED_TEST(InterceptorCallIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012541 v8::Isolate* isolate = CcTest::isolate();
12542 v8::HandleScope scope(isolate);
12543 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012544 templ->SetHandler(
12545 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000012546 LocalContext context;
12547 context->Global()->Set(v8_str("o"), templ->NewInstance());
12548 call_ic_function =
12549 v8_compile("function f(x) { return x + 1; }; f")->Run();
12550 v8::Handle<Value> value = CompileRun(
12551 "var result = 0;"
12552 "for (var i = 0; i < 1000; i++) {"
12553 " result = o.x(41);"
12554 "}");
12555 CHECK_EQ(42, value->Int32Value());
12556}
12557
12558
12559// This test checks that if interceptor doesn't provide
12560// a value, we can fetch regular value.
12561THREADED_TEST(InterceptorCallICSeesOthers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012562 v8::Isolate* isolate = CcTest::isolate();
12563 v8::HandleScope scope(isolate);
12564 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012565 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Steve Blocka7e24c12009-10-30 11:49:00 +000012566 LocalContext context;
12567 context->Global()->Set(v8_str("o"), templ->NewInstance());
12568 v8::Handle<Value> value = CompileRun(
12569 "o.x = function f(x) { return x + 1; };"
12570 "var result = 0;"
12571 "for (var i = 0; i < 7; i++) {"
12572 " result = o.x(41);"
12573 "}");
12574 CHECK_EQ(42, value->Int32Value());
12575}
12576
12577
12578static v8::Handle<Value> call_ic_function4;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012579static void InterceptorCallICGetter4(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012580 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012581 ApiTestFuzzer::Fuzz();
12582 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012583 info.GetReturnValue().Set(call_ic_function4);
Steve Blocka7e24c12009-10-30 11:49:00 +000012584}
12585
12586
12587// This test checks that if interceptor provides a function,
12588// even if we cached shadowed variant, interceptor's function
12589// is invoked
12590THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012591 v8::Isolate* isolate = CcTest::isolate();
12592 v8::HandleScope scope(isolate);
12593 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012594 templ->SetHandler(
12595 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
Steve Blocka7e24c12009-10-30 11:49:00 +000012596 LocalContext context;
12597 context->Global()->Set(v8_str("o"), templ->NewInstance());
12598 call_ic_function4 =
12599 v8_compile("function f(x) { return x - 1; }; f")->Run();
12600 v8::Handle<Value> value = CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012601 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
Steve Blocka7e24c12009-10-30 11:49:00 +000012602 "var result = 0;"
12603 "for (var i = 0; i < 1000; i++) {"
12604 " result = o.x(42);"
12605 "}");
12606 CHECK_EQ(41, value->Int32Value());
12607}
12608
12609
12610// Test the case when we stored cacheable lookup into
12611// a stub, but it got invalidated later on
12612THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012613 v8::Isolate* isolate = CcTest::isolate();
12614 v8::HandleScope scope(isolate);
12615 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012616 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Steve Blocka7e24c12009-10-30 11:49:00 +000012617 LocalContext context;
12618 context->Global()->Set(v8_str("o"), templ->NewInstance());
12619 v8::Handle<Value> value = CompileRun(
12620 "proto1 = new Object();"
12621 "proto2 = new Object();"
12622 "o.__proto__ = proto1;"
12623 "proto1.__proto__ = proto2;"
12624 "proto2.y = function(x) { return x + 1; };"
12625 // Invoke it many times to compile a stub
12626 "for (var i = 0; i < 7; i++) {"
12627 " o.y(42);"
12628 "}"
12629 "proto1.y = function(x) { return x - 1; };"
12630 "var result = 0;"
12631 "for (var i = 0; i < 7; i++) {"
12632 " result += o.y(42);"
12633 "}");
12634 CHECK_EQ(41 * 7, value->Int32Value());
12635}
12636
12637
Steve Blocka7e24c12009-10-30 11:49:00 +000012638// This test checks that if interceptor doesn't provide a function,
12639// cached constant function is used
12640THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012641 v8::Isolate* isolate = CcTest::isolate();
12642 v8::HandleScope scope(isolate);
12643 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012644 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Steve Blocka7e24c12009-10-30 11:49:00 +000012645 LocalContext context;
12646 context->Global()->Set(v8_str("o"), templ->NewInstance());
12647 v8::Handle<Value> value = CompileRun(
12648 "function inc(x) { return x + 1; };"
12649 "inc(1);"
12650 "o.x = inc;"
12651 "var result = 0;"
12652 "for (var i = 0; i < 1000; i++) {"
12653 " result = o.x(42);"
12654 "}");
12655 CHECK_EQ(43, value->Int32Value());
12656}
12657
12658
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012659static v8::Handle<Value> call_ic_function5;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012660static void InterceptorCallICGetter5(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012661 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012662 ApiTestFuzzer::Fuzz();
12663 if (v8_str("x")->Equals(name))
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012664 info.GetReturnValue().Set(call_ic_function5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012665}
12666
12667
Steve Blocka7e24c12009-10-30 11:49:00 +000012668// This test checks that if interceptor provides a function,
12669// even if we cached constant function, interceptor's function
12670// is invoked
12671THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012672 v8::Isolate* isolate = CcTest::isolate();
12673 v8::HandleScope scope(isolate);
12674 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012675 templ->SetHandler(
12676 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
Steve Blocka7e24c12009-10-30 11:49:00 +000012677 LocalContext context;
12678 context->Global()->Set(v8_str("o"), templ->NewInstance());
12679 call_ic_function5 =
12680 v8_compile("function f(x) { return x - 1; }; f")->Run();
12681 v8::Handle<Value> value = CompileRun(
12682 "function inc(x) { return x + 1; };"
12683 "inc(1);"
12684 "o.x = inc;"
12685 "var result = 0;"
12686 "for (var i = 0; i < 1000; i++) {"
12687 " result = o.x(42);"
12688 "}");
12689 CHECK_EQ(41, value->Int32Value());
12690}
12691
12692
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012693static v8::Handle<Value> call_ic_function6;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012694static void InterceptorCallICGetter6(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012695 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012696 ApiTestFuzzer::Fuzz();
12697 if (v8_str("x")->Equals(name))
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012698 info.GetReturnValue().Set(call_ic_function6);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012699}
12700
12701
12702// Same test as above, except the code is wrapped in a function
12703// to test the optimized compiler.
12704THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12705 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012706 v8::Isolate* isolate = CcTest::isolate();
12707 v8::HandleScope scope(isolate);
12708 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012709 templ->SetHandler(
12710 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012711 LocalContext context;
12712 context->Global()->Set(v8_str("o"), templ->NewInstance());
12713 call_ic_function6 =
12714 v8_compile("function f(x) { return x - 1; }; f")->Run();
12715 v8::Handle<Value> value = CompileRun(
12716 "function inc(x) { return x + 1; };"
12717 "inc(1);"
12718 "o.x = inc;"
12719 "function test() {"
12720 " var result = 0;"
12721 " for (var i = 0; i < 1000; i++) {"
12722 " result = o.x(42);"
12723 " }"
12724 " return result;"
12725 "};"
12726 "test();"
12727 "test();"
12728 "test();"
12729 "%OptimizeFunctionOnNextCall(test);"
12730 "test()");
12731 CHECK_EQ(41, value->Int32Value());
12732}
12733
12734
Steve Blocka7e24c12009-10-30 11:49:00 +000012735// Test the case when we stored constant function into
12736// a stub, but it got invalidated later on
12737THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012738 v8::Isolate* isolate = CcTest::isolate();
12739 v8::HandleScope scope(isolate);
12740 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012741 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Steve Blocka7e24c12009-10-30 11:49:00 +000012742 LocalContext context;
12743 context->Global()->Set(v8_str("o"), templ->NewInstance());
12744 v8::Handle<Value> value = CompileRun(
12745 "function inc(x) { return x + 1; };"
12746 "inc(1);"
12747 "proto1 = new Object();"
12748 "proto2 = new Object();"
12749 "o.__proto__ = proto1;"
12750 "proto1.__proto__ = proto2;"
12751 "proto2.y = inc;"
12752 // Invoke it many times to compile a stub
12753 "for (var i = 0; i < 7; i++) {"
12754 " o.y(42);"
12755 "}"
12756 "proto1.y = function(x) { return x - 1; };"
12757 "var result = 0;"
12758 "for (var i = 0; i < 7; i++) {"
12759 " result += o.y(42);"
12760 "}");
12761 CHECK_EQ(41 * 7, value->Int32Value());
12762}
12763
12764
12765// Test the case when we stored constant function into
12766// a stub, but it got invalidated later on due to override on
12767// global object which is between interceptor and constant function' holders.
12768THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012769 v8::Isolate* isolate = CcTest::isolate();
12770 v8::HandleScope scope(isolate);
12771 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012772 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Steve Blocka7e24c12009-10-30 11:49:00 +000012773 LocalContext context;
12774 context->Global()->Set(v8_str("o"), templ->NewInstance());
12775 v8::Handle<Value> value = CompileRun(
12776 "function inc(x) { return x + 1; };"
12777 "inc(1);"
12778 "o.__proto__ = this;"
12779 "this.__proto__.y = inc;"
12780 // Invoke it many times to compile a stub
12781 "for (var i = 0; i < 7; i++) {"
12782 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12783 "}"
12784 "this.y = function(x) { return x - 1; };"
12785 "var result = 0;"
12786 "for (var i = 0; i < 7; i++) {"
12787 " result += o.y(42);"
12788 "}");
12789 CHECK_EQ(41 * 7, value->Int32Value());
12790}
12791
12792
Leon Clarke4515c472010-02-03 11:58:03 +000012793// Test the case when actual function to call sits on global object.
12794THREADED_TEST(InterceptorCallICCachedFromGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012795 v8::Isolate* isolate = CcTest::isolate();
12796 v8::HandleScope scope(isolate);
12797 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012798 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Leon Clarke4515c472010-02-03 11:58:03 +000012799
12800 LocalContext context;
12801 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12802
12803 v8::Handle<Value> value = CompileRun(
12804 "try {"
12805 " o.__proto__ = this;"
12806 " for (var i = 0; i < 10; i++) {"
12807 " var v = o.parseFloat('239');"
12808 " if (v != 239) throw v;"
12809 // Now it should be ICed and keep a reference to parseFloat.
12810 " }"
12811 " var result = 0;"
12812 " for (var i = 0; i < 10; i++) {"
12813 " result += o.parseFloat('239');"
12814 " }"
12815 " result"
12816 "} catch(e) {"
12817 " e"
12818 "};");
12819 CHECK_EQ(239 * 10, value->Int32Value());
12820}
12821
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012822static void InterceptorCallICFastApi(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012823 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012824 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012825 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12826 int* call_count =
12827 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
Andrei Popescu402d9372010-02-26 13:31:12 +000012828 ++(*call_count);
12829 if ((*call_count) % 20 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012830 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Andrei Popescu402d9372010-02-26 13:31:12 +000012831 }
Andrei Popescu402d9372010-02-26 13:31:12 +000012832}
12833
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012834static void FastApiCallback_TrivialSignature(
12835 const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012836 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012837 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12838 v8::Isolate* isolate = CcTest::isolate();
12839 CHECK_EQ(isolate, args.GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +000012840 CHECK_EQ(args.This(), args.Holder());
12841 CHECK(args.Data()->Equals(v8_str("method_data")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012842 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +000012843}
12844
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012845static void FastApiCallback_SimpleSignature(
12846 const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012847 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012848 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12849 v8::Isolate* isolate = CcTest::isolate();
12850 CHECK_EQ(isolate, args.GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +000012851 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12852 CHECK(args.Data()->Equals(v8_str("method_data")));
12853 // Note, we're using HasRealNamedProperty instead of Has to avoid
12854 // invoking the interceptor again.
12855 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012856 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +000012857}
12858
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012859
Andrei Popescu402d9372010-02-26 13:31:12 +000012860// Helper to maximize the odds of object moving.
12861static void GenerateSomeGarbage() {
12862 CompileRun(
12863 "var garbage;"
12864 "for (var i = 0; i < 1000; i++) {"
12865 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12866 "}"
12867 "garbage = undefined;");
12868}
12869
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012871void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block1e0659c2011-05-24 12:43:12 +010012872 static int count = 0;
12873 if (count++ % 3 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012874 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12875 // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +010012876 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12877 }
Steve Block1e0659c2011-05-24 12:43:12 +010012878}
12879
12880
12881THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
Steve Block1e0659c2011-05-24 12:43:12 +010012882 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012883 v8::Isolate* isolate = context->GetIsolate();
12884 v8::HandleScope scope(isolate);
12885 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12886 v8::ObjectTemplate::New(isolate);
12887 nativeobject_templ->Set(isolate, "callback",
12888 v8::FunctionTemplate::New(isolate,
12889 DirectApiCallback));
Steve Block1e0659c2011-05-24 12:43:12 +010012890 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12891 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12892 // call the api function multiple times to ensure direct call stub creation.
12893 CompileRun(
12894 "function f() {"
12895 " for (var i = 1; i <= 30; i++) {"
12896 " nativeobject.callback();"
12897 " }"
12898 "}"
12899 "f();");
12900}
12901
12902
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012903void ThrowingDirectApiCallback(
12904 const v8::FunctionCallbackInfo<v8::Value>& args) {
12905 args.GetIsolate()->ThrowException(v8_str("g"));
Steve Block1e0659c2011-05-24 12:43:12 +010012906}
12907
12908
12909THREADED_TEST(CallICFastApi_DirectCall_Throw) {
Steve Block1e0659c2011-05-24 12:43:12 +010012910 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012911 v8::Isolate* isolate = context->GetIsolate();
12912 v8::HandleScope scope(isolate);
12913 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12914 v8::ObjectTemplate::New(isolate);
12915 nativeobject_templ->Set(isolate, "callback",
12916 v8::FunctionTemplate::New(isolate,
12917 ThrowingDirectApiCallback));
Steve Block1e0659c2011-05-24 12:43:12 +010012918 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12919 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12920 // call the api function multiple times to ensure direct call stub creation.
12921 v8::Handle<Value> result = CompileRun(
12922 "var result = '';"
12923 "function f() {"
12924 " for (var i = 1; i <= 5; i++) {"
12925 " try { nativeobject.callback(); } catch (e) { result += e; }"
12926 " }"
12927 "}"
12928 "f(); result;");
12929 CHECK_EQ(v8_str("ggggg"), result);
12930}
12931
12932
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012933static Handle<Value> DoDirectGetter() {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012934 if (++p_getter_count % 3 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012935 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012936 GenerateSomeGarbage();
12937 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012938 return v8_str("Direct Getter Result");
12939}
12940
12941static void DirectGetterCallback(
12942 Local<String> name,
12943 const v8::PropertyCallbackInfo<v8::Value>& info) {
12944 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12945 info.GetReturnValue().Set(DoDirectGetter());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012946}
12947
12948
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012949template<typename Accessor>
12950static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012951 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012952 v8::Isolate* isolate = context->GetIsolate();
12953 v8::HandleScope scope(isolate);
12954 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12955 obj->SetAccessor(v8_str("p1"), accessor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012956 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12957 p_getter_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012958 v8::Handle<v8::Value> result = CompileRun(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012959 "function f() {"
12960 " for (var i = 0; i < 30; i++) o1.p1;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012961 " return o1.p1"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012962 "}"
12963 "f();");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012964 CHECK_EQ(v8_str("Direct Getter Result"), result);
12965 CHECK_EQ(31, p_getter_count);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012966}
12967
12968
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012969THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12970 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12971}
12972
12973
12974void ThrowingDirectGetterCallback(
12975 Local<String> name,
12976 const v8::PropertyCallbackInfo<v8::Value>& info) {
12977 info.GetIsolate()->ThrowException(v8_str("g"));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012978}
12979
12980
12981THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012982 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012983 v8::Isolate* isolate = context->GetIsolate();
12984 v8::HandleScope scope(isolate);
12985 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012986 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12987 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12988 v8::Handle<Value> result = CompileRun(
12989 "var result = '';"
12990 "for (var i = 0; i < 5; i++) {"
12991 " try { o1.p1; } catch (e) { result += e; }"
12992 "}"
12993 "result;");
12994 CHECK_EQ(v8_str("ggggg"), result);
12995}
12996
12997
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012998THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012999 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013000 v8::Isolate* isolate = CcTest::isolate();
13001 v8::HandleScope scope(isolate);
13002 v8::Handle<v8::FunctionTemplate> fun_templ =
13003 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000013004 v8::Handle<v8::FunctionTemplate> method_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013005 v8::FunctionTemplate::New(isolate,
13006 FastApiCallback_TrivialSignature,
Andrei Popescu402d9372010-02-26 13:31:12 +000013007 v8_str("method_data"),
13008 v8::Handle<v8::Signature>());
13009 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13010 proto_templ->Set(v8_str("method"), method_templ);
13011 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013012 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013013 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013014 v8::External::New(isolate, &interceptor_call_count)));
Andrei Popescu402d9372010-02-26 13:31:12 +000013015 LocalContext context;
13016 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13017 GenerateSomeGarbage();
13018 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013019 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013020 "var result = 0;"
13021 "for (var i = 0; i < 100; i++) {"
13022 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013023 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013024 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13025 CHECK_EQ(100, interceptor_call_count);
13026}
13027
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013028
13029THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013030 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013031 v8::Isolate* isolate = CcTest::isolate();
13032 v8::HandleScope scope(isolate);
13033 v8::Handle<v8::FunctionTemplate> fun_templ =
13034 v8::FunctionTemplate::New(isolate);
13035 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13036 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13037 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013038 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13039 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013040 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000013041 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013042 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013043 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013044 v8::External::New(isolate, &interceptor_call_count)));
Andrei Popescu402d9372010-02-26 13:31:12 +000013045 LocalContext context;
13046 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13047 GenerateSomeGarbage();
13048 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013049 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013050 "o.foo = 17;"
13051 "var receiver = {};"
13052 "receiver.__proto__ = o;"
13053 "var result = 0;"
13054 "for (var i = 0; i < 100; i++) {"
13055 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013056 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013057 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13058 CHECK_EQ(100, interceptor_call_count);
13059}
13060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013061
13062THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013063 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013064 v8::Isolate* isolate = CcTest::isolate();
13065 v8::HandleScope scope(isolate);
13066 v8::Handle<v8::FunctionTemplate> fun_templ =
13067 v8::FunctionTemplate::New(isolate);
13068 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13069 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13070 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013071 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13072 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013073 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000013074 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013075 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013076 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013077 v8::External::New(isolate, &interceptor_call_count)));
Andrei Popescu402d9372010-02-26 13:31:12 +000013078 LocalContext context;
13079 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13080 GenerateSomeGarbage();
13081 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013082 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013083 "o.foo = 17;"
13084 "var receiver = {};"
13085 "receiver.__proto__ = o;"
13086 "var result = 0;"
13087 "var saved_result = 0;"
13088 "for (var i = 0; i < 100; i++) {"
13089 " result = receiver.method(41);"
13090 " if (i == 50) {"
13091 " saved_result = result;"
13092 " receiver = {method: function(x) { return x - 1 }};"
13093 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013094 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013095 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13096 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13097 CHECK_GE(interceptor_call_count, 50);
13098}
13099
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013100
13101THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013102 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013103 v8::Isolate* isolate = CcTest::isolate();
13104 v8::HandleScope scope(isolate);
13105 v8::Handle<v8::FunctionTemplate> fun_templ =
13106 v8::FunctionTemplate::New(isolate);
13107 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13108 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13109 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013110 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13111 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013112 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000013113 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013114 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013115 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013116 v8::External::New(isolate, &interceptor_call_count)));
Andrei Popescu402d9372010-02-26 13:31:12 +000013117 LocalContext context;
13118 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13119 GenerateSomeGarbage();
13120 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013121 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013122 "o.foo = 17;"
13123 "var receiver = {};"
13124 "receiver.__proto__ = o;"
13125 "var result = 0;"
13126 "var saved_result = 0;"
13127 "for (var i = 0; i < 100; i++) {"
13128 " result = receiver.method(41);"
13129 " if (i == 50) {"
13130 " saved_result = result;"
13131 " o.method = function(x) { return x - 1 };"
13132 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013133 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013134 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13135 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13136 CHECK_GE(interceptor_call_count, 50);
13137}
13138
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013139
13140THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
Steve Block6ded16b2010-05-10 14:33:55 +010013141 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013142 v8::Isolate* isolate = CcTest::isolate();
13143 v8::HandleScope scope(isolate);
13144 v8::Handle<v8::FunctionTemplate> fun_templ =
13145 v8::FunctionTemplate::New(isolate);
13146 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13147 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13148 v8::Signature::New(isolate, fun_templ));
Steve Block6ded16b2010-05-10 14:33:55 +010013149 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13150 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013151 fun_templ->SetHiddenPrototype(true);
Steve Block6ded16b2010-05-10 14:33:55 +010013152 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013153 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013154 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013155 v8::External::New(isolate, &interceptor_call_count)));
Steve Block6ded16b2010-05-10 14:33:55 +010013156 LocalContext context;
13157 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13158 GenerateSomeGarbage();
13159 context->Global()->Set(v8_str("o"), fun->NewInstance());
13160 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013161 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +010013162 "o.foo = 17;"
13163 "var receiver = {};"
13164 "receiver.__proto__ = o;"
13165 "var result = 0;"
13166 "var saved_result = 0;"
13167 "for (var i = 0; i < 100; i++) {"
13168 " result = receiver.method(41);"
13169 " if (i == 50) {"
13170 " saved_result = result;"
13171 " receiver = 333;"
13172 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013173 "}");
Steve Block6ded16b2010-05-10 14:33:55 +010013174 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013175 // TODO(verwaest): Adjust message.
13176 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013177 try_catch.Exception()->ToString(isolate));
Steve Block6ded16b2010-05-10 14:33:55 +010013178 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13179 CHECK_GE(interceptor_call_count, 50);
13180}
13181
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013182
13183THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
Andrei Popescu402d9372010-02-26 13:31:12 +000013184 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013185 v8::Isolate* isolate = CcTest::isolate();
13186 v8::HandleScope scope(isolate);
13187 v8::Handle<v8::FunctionTemplate> fun_templ =
13188 v8::FunctionTemplate::New(isolate);
13189 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13190 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13191 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013192 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13193 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013194 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000013195 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013196 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013197 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013198 v8::External::New(isolate, &interceptor_call_count)));
Andrei Popescu402d9372010-02-26 13:31:12 +000013199 LocalContext context;
13200 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13201 GenerateSomeGarbage();
13202 context->Global()->Set(v8_str("o"), fun->NewInstance());
13203 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013204 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013205 "o.foo = 17;"
13206 "var receiver = {};"
13207 "receiver.__proto__ = o;"
13208 "var result = 0;"
13209 "var saved_result = 0;"
13210 "for (var i = 0; i < 100; i++) {"
13211 " result = receiver.method(41);"
13212 " if (i == 50) {"
13213 " saved_result = result;"
13214 " receiver = {method: receiver.method};"
13215 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013216 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013217 CHECK(try_catch.HasCaught());
13218 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013219 try_catch.Exception()->ToString(isolate));
Andrei Popescu402d9372010-02-26 13:31:12 +000013220 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13221 CHECK_GE(interceptor_call_count, 50);
13222}
13223
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013224
13225THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
13226 v8::Isolate* isolate = CcTest::isolate();
13227 v8::HandleScope scope(isolate);
13228 v8::Handle<v8::FunctionTemplate> fun_templ =
13229 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000013230 v8::Handle<v8::FunctionTemplate> method_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013231 v8::FunctionTemplate::New(isolate,
13232 FastApiCallback_TrivialSignature,
Andrei Popescu402d9372010-02-26 13:31:12 +000013233 v8_str("method_data"),
13234 v8::Handle<v8::Signature>());
13235 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13236 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013237 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13238 USE(templ);
Andrei Popescu402d9372010-02-26 13:31:12 +000013239 LocalContext context;
13240 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13241 GenerateSomeGarbage();
13242 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013243 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013244 "var result = 0;"
13245 "for (var i = 0; i < 100; i++) {"
13246 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013247 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013248
13249 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13250}
13251
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013252
13253THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
13254 v8::Isolate* isolate = CcTest::isolate();
13255 v8::HandleScope scope(isolate);
13256 v8::Handle<v8::FunctionTemplate> fun_templ =
13257 v8::FunctionTemplate::New(isolate);
13258 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13259 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13260 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013261 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13262 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013263 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013264 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13265 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +000013266 LocalContext context;
13267 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13268 GenerateSomeGarbage();
13269 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013270 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013271 "o.foo = 17;"
13272 "var receiver = {};"
13273 "receiver.__proto__ = o;"
13274 "var result = 0;"
13275 "for (var i = 0; i < 100; i++) {"
13276 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013277 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013278
13279 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13280}
13281
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013282
13283THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
13284 v8::Isolate* isolate = CcTest::isolate();
13285 v8::HandleScope scope(isolate);
13286 v8::Handle<v8::FunctionTemplate> fun_templ =
13287 v8::FunctionTemplate::New(isolate);
13288 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13289 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13290 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000013291 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13292 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013293 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013294 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13295 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +000013296 LocalContext context;
13297 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13298 GenerateSomeGarbage();
13299 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013300 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000013301 "o.foo = 17;"
13302 "var receiver = {};"
13303 "receiver.__proto__ = o;"
13304 "var result = 0;"
13305 "var saved_result = 0;"
13306 "for (var i = 0; i < 100; i++) {"
13307 " result = receiver.method(41);"
13308 " if (i == 50) {"
13309 " saved_result = result;"
13310 " receiver = {method: function(x) { return x - 1 }};"
13311 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013312 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000013313 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13314 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13315}
13316
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013317
13318THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
13319 v8::Isolate* isolate = CcTest::isolate();
13320 v8::HandleScope scope(isolate);
13321 v8::Handle<v8::FunctionTemplate> fun_templ =
13322 v8::FunctionTemplate::New(isolate);
13323 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13324 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13325 v8::Signature::New(isolate, fun_templ));
Steve Block6ded16b2010-05-10 14:33:55 +010013326 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13327 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013328 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013329 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13330 CHECK(!templ.IsEmpty());
Steve Block6ded16b2010-05-10 14:33:55 +010013331 LocalContext context;
13332 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13333 GenerateSomeGarbage();
13334 context->Global()->Set(v8_str("o"), fun->NewInstance());
13335 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013336 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +010013337 "o.foo = 17;"
13338 "var receiver = {};"
13339 "receiver.__proto__ = o;"
13340 "var result = 0;"
13341 "var saved_result = 0;"
13342 "for (var i = 0; i < 100; i++) {"
13343 " result = receiver.method(41);"
13344 " if (i == 50) {"
13345 " saved_result = result;"
13346 " receiver = 333;"
13347 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013348 "}");
Steve Block6ded16b2010-05-10 14:33:55 +010013349 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013350 // TODO(verwaest): Adjust message.
13351 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013352 try_catch.Exception()->ToString(isolate));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013353 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13354}
13355
13356
13357THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
13358 v8::Isolate* isolate = CcTest::isolate();
13359 v8::HandleScope scope(isolate);
13360 v8::Handle<v8::FunctionTemplate> fun_templ =
13361 v8::FunctionTemplate::New(isolate);
13362 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13363 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13364 v8::Signature::New(isolate, fun_templ));
13365 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13366 proto_templ->Set(v8_str("method"), method_templ);
13367 fun_templ->SetHiddenPrototype(true);
13368 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13369 CHECK(!templ.IsEmpty());
13370 LocalContext context;
13371 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13372 GenerateSomeGarbage();
13373 context->Global()->Set(v8_str("o"), fun->NewInstance());
13374 v8::TryCatch try_catch;
13375 CompileRun(
13376 "o.foo = 17;"
13377 "var receiver = {};"
13378 "receiver.__proto__ = o;"
13379 "var result = 0;"
13380 "var saved_result = 0;"
13381 "for (var i = 0; i < 100; i++) {"
13382 " result = receiver.method(41);"
13383 " if (i == 50) {"
13384 " saved_result = result;"
13385 " receiver = Object.create(receiver);"
13386 " }"
13387 "}");
13388 CHECK(try_catch.HasCaught());
13389 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013390 try_catch.Exception()->ToString(isolate));
Steve Block6ded16b2010-05-10 14:33:55 +010013391 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13392}
13393
Leon Clarke4515c472010-02-03 11:58:03 +000013394
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013395v8::Handle<Value> keyed_call_ic_function;
13396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013397static void InterceptorKeyedCallICGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013398 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013399 ApiTestFuzzer::Fuzz();
13400 if (v8_str("x")->Equals(name)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013401 info.GetReturnValue().Set(keyed_call_ic_function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013402 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013403}
13404
13405
13406// Test the case when we stored cacheable lookup into
13407// a stub, but the function name changed (to another cacheable function).
13408THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013409 v8::Isolate* isolate = CcTest::isolate();
13410 v8::HandleScope scope(isolate);
13411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013412 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013413 LocalContext context;
13414 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013415 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013416 "proto = new Object();"
13417 "proto.y = function(x) { return x + 1; };"
13418 "proto.z = function(x) { return x - 1; };"
13419 "o.__proto__ = proto;"
13420 "var result = 0;"
13421 "var method = 'y';"
13422 "for (var i = 0; i < 10; i++) {"
13423 " if (i == 5) { method = 'z'; };"
13424 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013425 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013426 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13427}
13428
13429
13430// Test the case when we stored cacheable lookup into
13431// a stub, but the function name changed (and the new function is present
13432// both before and after the interceptor in the prototype chain).
13433THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013434 v8::Isolate* isolate = CcTest::isolate();
13435 v8::HandleScope scope(isolate);
13436 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013437 templ->SetHandler(
13438 v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013439 LocalContext context;
13440 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
13441 keyed_call_ic_function =
13442 v8_compile("function f(x) { return x - 1; }; f")->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013443 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013444 "o = new Object();"
13445 "proto2 = new Object();"
13446 "o.y = function(x) { return x + 1; };"
13447 "proto2.y = function(x) { return x + 2; };"
13448 "o.__proto__ = proto1;"
13449 "proto1.__proto__ = proto2;"
13450 "var result = 0;"
13451 "var method = 'x';"
13452 "for (var i = 0; i < 10; i++) {"
13453 " if (i == 5) { method = 'y'; };"
13454 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013455 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013456 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13457}
13458
13459
13460// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
13461// on the global object.
13462THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013463 v8::Isolate* isolate = CcTest::isolate();
13464 v8::HandleScope scope(isolate);
13465 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013466 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013467 LocalContext context;
13468 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013469 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013470 "function inc(x) { return x + 1; };"
13471 "inc(1);"
13472 "function dec(x) { return x - 1; };"
13473 "dec(1);"
13474 "o.__proto__ = this;"
13475 "this.__proto__.x = inc;"
13476 "this.__proto__.y = dec;"
13477 "var result = 0;"
13478 "var method = 'x';"
13479 "for (var i = 0; i < 10; i++) {"
13480 " if (i == 5) { method = 'y'; };"
13481 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013482 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013483 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13484}
13485
13486
13487// Test the case when actual function to call sits on global object.
13488THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013489 v8::Isolate* isolate = CcTest::isolate();
13490 v8::HandleScope scope(isolate);
13491 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013492 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013493 LocalContext context;
13494 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13495
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013496 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013497 "function len(x) { return x.length; };"
13498 "o.__proto__ = this;"
13499 "var m = 'parseFloat';"
13500 "var result = 0;"
13501 "for (var i = 0; i < 10; i++) {"
13502 " if (i == 5) {"
13503 " m = 'len';"
13504 " saved_result = result;"
13505 " };"
13506 " result = o[m]('239');"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013507 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013508 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
13509 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13510}
13511
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013512
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013513// Test the map transition before the interceptor.
13514THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013515 v8::Isolate* isolate = CcTest::isolate();
13516 v8::HandleScope scope(isolate);
13517 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013518 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013519 LocalContext context;
13520 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
13521
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013522 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013523 "var o = new Object();"
13524 "o.__proto__ = proto;"
13525 "o.method = function(x) { return x + 1; };"
13526 "var m = 'method';"
13527 "var result = 0;"
13528 "for (var i = 0; i < 10; i++) {"
13529 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
13530 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013531 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013532 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13533}
13534
13535
13536// Test the map transition after the interceptor.
13537THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013538 v8::Isolate* isolate = CcTest::isolate();
13539 v8::HandleScope scope(isolate);
13540 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013541 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013542 LocalContext context;
13543 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13544
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013545 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013546 "var proto = new Object();"
13547 "o.__proto__ = proto;"
13548 "proto.method = function(x) { return x + 1; };"
13549 "var m = 'method';"
13550 "var result = 0;"
13551 "for (var i = 0; i < 10; i++) {"
13552 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
13553 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000013554 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013555 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13556}
13557
13558
Steve Blocka7e24c12009-10-30 11:49:00 +000013559static int interceptor_call_count = 0;
13560
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013561static void InterceptorICRefErrorGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013562 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013563 ApiTestFuzzer::Fuzz();
13564 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013565 info.GetReturnValue().Set(call_ic_function2);
Steve Blocka7e24c12009-10-30 11:49:00 +000013566 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013567}
13568
13569
13570// This test should hit load and call ICs for the interceptor case.
13571// Once in a while, the interceptor will reply that a property was not
13572// found in which case we should get a reference error.
13573THREADED_TEST(InterceptorICReferenceErrors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013574 v8::Isolate* isolate = CcTest::isolate();
13575 v8::HandleScope scope(isolate);
13576 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013577 templ->SetHandler(
13578 v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000013579 LocalContext context(0, templ, v8::Handle<Value>());
13580 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13581 v8::Handle<Value> value = CompileRun(
13582 "function f() {"
13583 " for (var i = 0; i < 1000; i++) {"
13584 " try { x; } catch(e) { return true; }"
13585 " }"
13586 " return false;"
13587 "};"
13588 "f();");
13589 CHECK_EQ(true, value->BooleanValue());
13590 interceptor_call_count = 0;
13591 value = CompileRun(
13592 "function g() {"
13593 " for (var i = 0; i < 1000; i++) {"
13594 " try { x(42); } catch(e) { return true; }"
13595 " }"
13596 " return false;"
13597 "};"
13598 "g();");
13599 CHECK_EQ(true, value->BooleanValue());
13600}
13601
13602
13603static int interceptor_ic_exception_get_count = 0;
13604
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013605static void InterceptorICExceptionGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013606 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013607 ApiTestFuzzer::Fuzz();
13608 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013609 info.GetReturnValue().Set(call_ic_function3);
Steve Blocka7e24c12009-10-30 11:49:00 +000013610 }
13611 if (interceptor_ic_exception_get_count == 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013612 info.GetIsolate()->ThrowException(v8_num(42));
13613 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000013614 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013615}
13616
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013617
Steve Blocka7e24c12009-10-30 11:49:00 +000013618// Test interceptor load/call IC where the interceptor throws an
13619// exception once in a while.
13620THREADED_TEST(InterceptorICGetterExceptions) {
13621 interceptor_ic_exception_get_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013622 v8::Isolate* isolate = CcTest::isolate();
13623 v8::HandleScope scope(isolate);
13624 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013625 templ->SetHandler(
13626 v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000013627 LocalContext context(0, templ, v8::Handle<Value>());
13628 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13629 v8::Handle<Value> value = CompileRun(
13630 "function f() {"
13631 " for (var i = 0; i < 100; i++) {"
13632 " try { x; } catch(e) { return true; }"
13633 " }"
13634 " return false;"
13635 "};"
13636 "f();");
13637 CHECK_EQ(true, value->BooleanValue());
13638 interceptor_ic_exception_get_count = 0;
13639 value = CompileRun(
13640 "function f() {"
13641 " for (var i = 0; i < 100; i++) {"
13642 " try { x(42); } catch(e) { return true; }"
13643 " }"
13644 " return false;"
13645 "};"
13646 "f();");
13647 CHECK_EQ(true, value->BooleanValue());
13648}
13649
13650
13651static int interceptor_ic_exception_set_count = 0;
13652
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013653static void InterceptorICExceptionSetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013654 Local<Name> key, Local<Value> value,
13655 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013656 ApiTestFuzzer::Fuzz();
13657 if (++interceptor_ic_exception_set_count > 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013658 info.GetIsolate()->ThrowException(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013659 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013660}
13661
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013662
Steve Blocka7e24c12009-10-30 11:49:00 +000013663// Test interceptor store IC where the interceptor throws an exception
13664// once in a while.
13665THREADED_TEST(InterceptorICSetterExceptions) {
13666 interceptor_ic_exception_set_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013667 v8::Isolate* isolate = CcTest::isolate();
13668 v8::HandleScope scope(isolate);
13669 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013670 templ->SetHandler(
13671 v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000013672 LocalContext context(0, templ, v8::Handle<Value>());
13673 v8::Handle<Value> value = CompileRun(
13674 "function f() {"
13675 " for (var i = 0; i < 100; i++) {"
13676 " try { x = 42; } catch(e) { return true; }"
13677 " }"
13678 " return false;"
13679 "};"
13680 "f();");
13681 CHECK_EQ(true, value->BooleanValue());
13682}
13683
13684
13685// Test that we ignore null interceptors.
13686THREADED_TEST(NullNamedInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013687 v8::Isolate* isolate = CcTest::isolate();
13688 v8::HandleScope scope(isolate);
13689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013690 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13691 static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
Steve Blocka7e24c12009-10-30 11:49:00 +000013692 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013693 templ->Set(CcTest::isolate(), "x", v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013694 v8::Handle<v8::Object> obj = templ->NewInstance();
13695 context->Global()->Set(v8_str("obj"), obj);
13696 v8::Handle<Value> value = CompileRun("obj.x");
13697 CHECK(value->IsInt32());
13698 CHECK_EQ(42, value->Int32Value());
13699}
13700
13701
13702// Test that we ignore null interceptors.
13703THREADED_TEST(NullIndexedInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013704 v8::Isolate* isolate = CcTest::isolate();
13705 v8::HandleScope scope(isolate);
13706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013707 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
13708 static_cast<v8::IndexedPropertyGetterCallback>(0)));
Steve Blocka7e24c12009-10-30 11:49:00 +000013709 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013710 templ->Set(CcTest::isolate(), "42", v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013711 v8::Handle<v8::Object> obj = templ->NewInstance();
13712 context->Global()->Set(v8_str("obj"), obj);
13713 v8::Handle<Value> value = CompileRun("obj[42]");
13714 CHECK(value->IsInt32());
13715 CHECK_EQ(42, value->Int32Value());
13716}
13717
13718
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013719THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013720 v8::Isolate* isolate = CcTest::isolate();
13721 v8::HandleScope scope(isolate);
13722 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013723 templ->InstanceTemplate()->SetHandler(
13724 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013725 LocalContext env;
13726 env->Global()->Set(v8_str("obj"),
13727 templ->GetFunction()->NewInstance());
13728 ExpectTrue("obj.x === 42");
13729 ExpectTrue("!obj.propertyIsEnumerable('x')");
13730}
13731
13732
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013733static void ThrowingGetter(Local<String> name,
13734 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013735 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013736 info.GetIsolate()->ThrowException(Handle<Value>());
13737 info.GetReturnValue().SetUndefined();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013738}
13739
13740
13741THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013742 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013743 HandleScope scope(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013744
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013745 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013746 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13747 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13748
13749 Local<Object> instance = templ->GetFunction()->NewInstance();
13750
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013751 Local<Object> another = Object::New(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013752 another->SetPrototype(instance);
13753
13754 Local<Object> with_js_getter = CompileRun(
13755 "o = {};\n"
13756 "o.__defineGetter__('f', function() { throw undefined; });\n"
13757 "o\n").As<Object>();
13758 CHECK(!with_js_getter.IsEmpty());
13759
13760 TryCatch try_catch;
13761
13762 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13763 CHECK(try_catch.HasCaught());
13764 try_catch.Reset();
13765 CHECK(result.IsEmpty());
13766
13767 result = another->GetRealNamedProperty(v8_str("f"));
13768 CHECK(try_catch.HasCaught());
13769 try_catch.Reset();
13770 CHECK(result.IsEmpty());
13771
13772 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13773 CHECK(try_catch.HasCaught());
13774 try_catch.Reset();
13775 CHECK(result.IsEmpty());
13776
13777 result = another->Get(v8_str("f"));
13778 CHECK(try_catch.HasCaught());
13779 try_catch.Reset();
13780 CHECK(result.IsEmpty());
13781
13782 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13783 CHECK(try_catch.HasCaught());
13784 try_catch.Reset();
13785 CHECK(result.IsEmpty());
13786
13787 result = with_js_getter->Get(v8_str("f"));
13788 CHECK(try_catch.HasCaught());
13789 try_catch.Reset();
13790 CHECK(result.IsEmpty());
13791}
13792
13793
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013794static void ThrowingCallbackWithTryCatch(
13795 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013796 TryCatch try_catch;
13797 // Verboseness is important: it triggers message delivery which can call into
13798 // external code.
13799 try_catch.SetVerbose(true);
13800 CompileRun("throw 'from JS';");
13801 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013802 CHECK(!CcTest::i_isolate()->has_pending_exception());
13803 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013804}
13805
13806
13807static int call_depth;
13808
13809
13810static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13811 TryCatch try_catch;
13812}
13813
13814
13815static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13816 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13817}
13818
13819
13820static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013821 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
Ben Murdoch8b112d22011-06-08 16:22:53 +010013822}
13823
13824
13825static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13826 Handle<String> errorMessageString = message->Get();
13827 CHECK(!errorMessageString.IsEmpty());
13828 message->GetStackTrace();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013829 message->GetScriptOrigin().ResourceName();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013830}
13831
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013832
Ben Murdoch8b112d22011-06-08 16:22:53 +010013833THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013834 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013835 v8::Isolate* isolate = context->GetIsolate();
13836 HandleScope scope(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010013837
13838 Local<Function> func =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013839 FunctionTemplate::New(isolate,
13840 ThrowingCallbackWithTryCatch)->GetFunction();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013841 context->Global()->Set(v8_str("func"), func);
13842
13843 MessageCallback callbacks[] =
13844 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13845 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13846 MessageCallback callback = callbacks[i];
13847 if (callback != NULL) {
13848 V8::AddMessageListener(callback);
13849 }
Ben Murdoch257744e2011-11-30 15:57:28 +000013850 // Some small number to control number of times message handler should
13851 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013852 call_depth = 5;
13853 ExpectFalse(
13854 "var thrown = false;\n"
13855 "try { func(); } catch(e) { thrown = true; }\n"
13856 "thrown\n");
13857 if (callback != NULL) {
13858 V8::RemoveMessageListeners(callback);
13859 }
13860 }
13861}
13862
13863
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013864static void ParentGetter(Local<String> name,
13865 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013866 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013867 info.GetReturnValue().Set(v8_num(1));
Steve Blocka7e24c12009-10-30 11:49:00 +000013868}
13869
13870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013871static void ChildGetter(Local<String> name,
13872 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013873 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013874 info.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013875}
13876
13877
13878THREADED_TEST(Overriding) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013879 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013880 v8::Isolate* isolate = context->GetIsolate();
13881 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013882
13883 // Parent template.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013884 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013885 Local<ObjectTemplate> parent_instance_templ =
13886 parent_templ->InstanceTemplate();
13887 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13888
13889 // Template that inherits from the parent template.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013890 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013891 Local<ObjectTemplate> child_instance_templ =
13892 child_templ->InstanceTemplate();
13893 child_templ->Inherit(parent_templ);
13894 // Override 'f'. The child version of 'f' should get called for child
13895 // instances.
13896 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13897 // Add 'g' twice. The 'g' added last should get called for instances.
13898 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13899 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13900
13901 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13902 // so 'h' can be shadowed on the instance object.
13903 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13904 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13905 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13906
13907 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13908 // but the attribute does not have effect because it is duplicated with
13909 // NULL setter.
13910 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13911 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13912
13913
13914
13915 // Instantiate the child template.
13916 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13917
13918 // Check that the child function overrides the parent one.
13919 context->Global()->Set(v8_str("o"), instance);
13920 Local<Value> value = v8_compile("o.f")->Run();
13921 // Check that the 'g' that was added last is hit.
13922 CHECK_EQ(42, value->Int32Value());
13923 value = v8_compile("o.g")->Run();
13924 CHECK_EQ(42, value->Int32Value());
13925
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013926 // Check that 'h' cannot be shadowed.
Steve Blocka7e24c12009-10-30 11:49:00 +000013927 value = v8_compile("o.h = 3; o.h")->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013928 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000013929
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013930 // Check that 'i' cannot be shadowed or changed.
Steve Blocka7e24c12009-10-30 11:49:00 +000013931 value = v8_compile("o.i = 3; o.i")->Run();
13932 CHECK_EQ(42, value->Int32Value());
13933}
13934
13935
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013936static void IsConstructHandler(
13937 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013938 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013939 args.GetReturnValue().Set(args.IsConstructCall());
Steve Blocka7e24c12009-10-30 11:49:00 +000013940}
13941
13942
13943THREADED_TEST(IsConstructCall) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013944 v8::Isolate* isolate = CcTest::isolate();
13945 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013946
13947 // Function template with call handler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013948 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013949 templ->SetCallHandler(IsConstructHandler);
13950
13951 LocalContext context;
13952
13953 context->Global()->Set(v8_str("f"), templ->GetFunction());
13954 Local<Value> value = v8_compile("f()")->Run();
13955 CHECK(!value->BooleanValue());
13956 value = v8_compile("new f()")->Run();
13957 CHECK(value->BooleanValue());
13958}
13959
13960
13961THREADED_TEST(ObjectProtoToString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013962 v8::Isolate* isolate = CcTest::isolate();
13963 v8::HandleScope scope(isolate);
13964 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013965 templ->SetClassName(v8_str("MyClass"));
13966
13967 LocalContext context;
13968
13969 Local<String> customized_tostring = v8_str("customized toString");
13970
13971 // Replace Object.prototype.toString
13972 v8_compile("Object.prototype.toString = function() {"
13973 " return 'customized toString';"
13974 "}")->Run();
13975
13976 // Normal ToString call should call replaced Object.prototype.toString
13977 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013978 Local<String> value = instance->ToString(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013979 CHECK(value->IsString() && value->Equals(customized_tostring));
13980
13981 // ObjectProtoToString should not call replace toString function.
13982 value = instance->ObjectProtoToString();
13983 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13984
13985 // Check global
13986 value = context->Global()->ObjectProtoToString();
13987 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13988
13989 // Check ordinary object
13990 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010013991 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +000013992 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13993}
13994
13995
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013996TEST(ObjectProtoToStringES6) {
13997 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
13998 i::FLAG_harmony_tostring = true;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080013999 LocalContext context;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014000 v8::Isolate* isolate = CcTest::isolate();
14001 v8::HandleScope scope(isolate);
14002 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
14003 templ->SetClassName(v8_str("MyClass"));
14004
14005 Local<String> customized_tostring = v8_str("customized toString");
14006
14007 // Replace Object.prototype.toString
14008 CompileRun(
14009 "Object.prototype.toString = function() {"
14010 " return 'customized toString';"
14011 "}");
14012
14013 // Normal ToString call should call replaced Object.prototype.toString
14014 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
14015 Local<String> value = instance->ToString(isolate);
14016 CHECK(value->IsString() && value->Equals(customized_tostring));
14017
14018 // ObjectProtoToString should not call replace toString function.
14019 value = instance->ObjectProtoToString();
14020 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
14021
14022 // Check global
14023 value = context->Global()->ObjectProtoToString();
14024 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
14025
14026 // Check ordinary object
14027 Local<Value> object = CompileRun("new Object()");
14028 value = object.As<v8::Object>()->ObjectProtoToString();
14029 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
14030
14031 // Check that ES6 semantics using @@toStringTag work
14032 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
14033
14034#define TEST_TOSTRINGTAG(type, tag, expected) \
14035 do { \
14036 object = CompileRun("new " #type "()"); \
14037 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
14038 value = object.As<v8::Object>()->ObjectProtoToString(); \
14039 CHECK(value->IsString() && \
14040 value->Equals(v8_str("[object " #expected "]"))); \
14041 } while (0)
14042
14043 TEST_TOSTRINGTAG(Array, Object, Object);
14044 TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
14045 TEST_TOSTRINGTAG(Object, Array, ~Array);
14046 TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
14047 TEST_TOSTRINGTAG(Object, Date, ~Date);
14048 TEST_TOSTRINGTAG(Object, Error, ~Error);
14049 TEST_TOSTRINGTAG(Object, Function, ~Function);
14050 TEST_TOSTRINGTAG(Object, Number, ~Number);
14051 TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
14052 TEST_TOSTRINGTAG(Object, String, ~String);
14053 TEST_TOSTRINGTAG(Object, Foo, Foo);
14054
14055#undef TEST_TOSTRINGTAG
14056
14057 // @@toStringTag getter throws
14058 Local<Value> obj = v8::Object::New(isolate);
14059 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
14060 {
14061 TryCatch try_catch;
14062 value = obj.As<v8::Object>()->ObjectProtoToString();
14063 CHECK(value.IsEmpty());
14064 CHECK(try_catch.HasCaught());
14065 }
14066
14067 // @@toStringTag getter does not throw
14068 obj = v8::Object::New(isolate);
14069 obj.As<v8::Object>()->SetAccessor(
14070 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
14071 {
14072 TryCatch try_catch;
14073 value = obj.As<v8::Object>()->ObjectProtoToString();
14074 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14075 CHECK(!try_catch.HasCaught());
14076 }
14077
14078 // JS @@toStringTag value
14079 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
14080 {
14081 TryCatch try_catch;
14082 value = obj.As<v8::Object>()->ObjectProtoToString();
14083 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14084 CHECK(!try_catch.HasCaught());
14085 }
14086
14087 // JS @@toStringTag getter throws
14088 obj = CompileRun(
14089 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14090 " get: function() { throw 'Test'; }"
14091 "}); obj");
14092 {
14093 TryCatch try_catch;
14094 value = obj.As<v8::Object>()->ObjectProtoToString();
14095 CHECK(value.IsEmpty());
14096 CHECK(try_catch.HasCaught());
14097 }
14098
14099 // JS @@toStringTag getter does not throw
14100 obj = CompileRun(
14101 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14102 " get: function() { return 'Test'; }"
14103 "}); obj");
14104 {
14105 TryCatch try_catch;
14106 value = obj.As<v8::Object>()->ObjectProtoToString();
14107 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14108 CHECK(!try_catch.HasCaught());
14109 }
14110}
14111
14112
14113THREADED_TEST(ObjectGetConstructorName) {
14114 v8::Isolate* isolate = CcTest::isolate();
14115 LocalContext context;
14116 v8::HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080014117 v8_compile("function Parent() {};"
14118 "function Child() {};"
14119 "Child.prototype = new Parent();"
14120 "var outer = { inner: function() { } };"
14121 "var p = new Parent();"
14122 "var c = new Child();"
14123 "var x = new outer.inner();")->Run();
14124
14125 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014126 CHECK(p->IsObject() &&
14127 p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080014128
14129 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014130 CHECK(c->IsObject() &&
14131 c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080014132
14133 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014134 CHECK(x->IsObject() &&
14135 x->ToObject(isolate)->GetConstructorName()->Equals(
14136 v8_str("outer.inner")));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080014137}
14138
14139
Steve Blocka7e24c12009-10-30 11:49:00 +000014140bool ApiTestFuzzer::fuzzing_ = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014141v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014142int ApiTestFuzzer::active_tests_;
14143int ApiTestFuzzer::tests_being_run_;
14144int ApiTestFuzzer::current_;
14145
14146
14147// We are in a callback and want to switch to another thread (if we
14148// are currently running the thread fuzzing test).
14149void ApiTestFuzzer::Fuzz() {
14150 if (!fuzzing_) return;
14151 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
14152 test->ContextSwitch();
14153}
14154
14155
14156// Let the next thread go. Since it is also waiting on the V8 lock it may
14157// not start immediately.
14158bool ApiTestFuzzer::NextThread() {
14159 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +000014160 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000014161 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +000014162 if (kLogThreading)
14163 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000014164 return false;
14165 }
Steve Blockd0582a62009-12-15 09:54:21 +000014166 if (kLogThreading) {
14167 printf("Switch from %s to %s\n",
14168 test_name,
14169 RegisterThreadedTest::nth(test_position)->name());
14170 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014171 current_ = test_position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014172 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +000014173 return true;
14174}
14175
14176
14177void ApiTestFuzzer::Run() {
14178 // When it is our turn...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014179 gate_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000014180 {
14181 // ... get the V8 lock and start running the test.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014182 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014183 CallTest();
14184 }
14185 // This test finished.
14186 active_ = false;
14187 active_tests_--;
14188 // If it was the last then signal that fact.
14189 if (active_tests_ == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014190 all_tests_done_.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +000014191 } else {
14192 // Otherwise select a new test and start that.
14193 NextThread();
14194 }
14195}
14196
14197
14198static unsigned linear_congruential_generator;
14199
14200
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014201void ApiTestFuzzer::SetUp(PartOfTest part) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014202 linear_congruential_generator = i::FLAG_testing_prng_seed;
14203 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +000014204 int count = RegisterThreadedTest::count();
14205 int start = count * part / (LAST_PART + 1);
14206 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
14207 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000014208 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014209 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +000014210 }
14211 for (int i = 0; i < active_tests_; i++) {
14212 RegisterThreadedTest::nth(i)->fuzzer_->Start();
14213 }
14214}
14215
14216
14217static void CallTestNumber(int test_number) {
14218 (RegisterThreadedTest::nth(test_number)->callback())();
14219}
14220
14221
14222void ApiTestFuzzer::RunAllTests() {
14223 // Set off the first test.
14224 current_ = -1;
14225 NextThread();
14226 // Wait till they are all done.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014227 all_tests_done_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000014228}
14229
14230
14231int ApiTestFuzzer::GetNextTestNumber() {
14232 int next_test;
14233 do {
14234 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
14235 linear_congruential_generator *= 1664525u;
14236 linear_congruential_generator += 1013904223u;
14237 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
14238 return next_test;
14239}
14240
14241
14242void ApiTestFuzzer::ContextSwitch() {
14243 // If the new thread is the same as the current thread there is nothing to do.
14244 if (NextThread()) {
14245 // Now it can start.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014246 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014247 // Wait till someone starts us again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014248 gate_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000014249 // And we're off.
14250 }
14251}
14252
14253
14254void ApiTestFuzzer::TearDown() {
14255 fuzzing_ = false;
14256 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
14257 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
14258 if (fuzzer != NULL) fuzzer->Join();
14259 }
14260}
14261
14262
14263// Lets not be needlessly self-referential.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014264TEST(Threading1) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014265 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000014266 ApiTestFuzzer::RunAllTests();
14267 ApiTestFuzzer::TearDown();
14268}
14269
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014270
Steve Blocka7e24c12009-10-30 11:49:00 +000014271TEST(Threading2) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014272 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000014273 ApiTestFuzzer::RunAllTests();
14274 ApiTestFuzzer::TearDown();
14275}
14276
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014277
Ben Murdoch257744e2011-11-30 15:57:28 +000014278TEST(Threading3) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014279 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000014280 ApiTestFuzzer::RunAllTests();
14281 ApiTestFuzzer::TearDown();
14282}
14283
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014284
Ben Murdoch257744e2011-11-30 15:57:28 +000014285TEST(Threading4) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014286 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000014287 ApiTestFuzzer::RunAllTests();
14288 ApiTestFuzzer::TearDown();
14289}
Steve Blocka7e24c12009-10-30 11:49:00 +000014290
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014291
Steve Blocka7e24c12009-10-30 11:49:00 +000014292void ApiTestFuzzer::CallTest() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014293 v8::Isolate::Scope scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +000014294 if (kLogThreading)
14295 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000014296 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +000014297 if (kLogThreading)
14298 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000014299}
14300
14301
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014302static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
14303 v8::Isolate* isolate = args.GetIsolate();
14304 CHECK(v8::Locker::IsLocked(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000014305 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014306 v8::Unlocker unlocker(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014307 const char* code = "throw 7;";
14308 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014309 v8::Locker nested_locker(isolate);
14310 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014311 v8::Handle<Value> exception;
14312 { v8::TryCatch try_catch;
14313 v8::Handle<Value> value = CompileRun(code);
14314 CHECK(value.IsEmpty());
14315 CHECK(try_catch.HasCaught());
14316 // Make sure to wrap the exception in a new handle because
14317 // the handle returned from the TryCatch is destroyed
14318 // when the TryCatch is destroyed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014319 exception = Local<Value>::New(isolate, try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +000014320 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014321 args.GetIsolate()->ThrowException(exception);
Steve Blocka7e24c12009-10-30 11:49:00 +000014322 }
14323}
14324
14325
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014326static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
14327 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000014328 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014329 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014330 const char* code = "throw 7;";
14331 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014332 v8::Locker nested_locker(CcTest::isolate());
14333 v8::HandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014334 v8::Handle<Value> value = CompileRun(code);
14335 CHECK(value.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014336 args.GetReturnValue().Set(v8_str("foo"));
Steve Blocka7e24c12009-10-30 11:49:00 +000014337 }
14338}
14339
14340
14341// These are locking tests that don't need to be run again
14342// as part of the locking aggregation tests.
14343TEST(NestedLockers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014344 v8::Isolate* isolate = CcTest::isolate();
14345 v8::Locker locker(isolate);
14346 CHECK(v8::Locker::IsLocked(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000014347 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014348 v8::HandleScope scope(env->GetIsolate());
14349 Local<v8::FunctionTemplate> fun_templ =
14350 v8::FunctionTemplate::New(isolate, ThrowInJS);
Steve Blocka7e24c12009-10-30 11:49:00 +000014351 Local<Function> fun = fun_templ->GetFunction();
14352 env->Global()->Set(v8_str("throw_in_js"), fun);
14353 Local<Script> script = v8_compile("(function () {"
14354 " try {"
14355 " throw_in_js();"
14356 " return 42;"
14357 " } catch (e) {"
14358 " return e * 13;"
14359 " }"
14360 "})();");
14361 CHECK_EQ(91, script->Run()->Int32Value());
14362}
14363
14364
14365// These are locking tests that don't need to be run again
14366// as part of the locking aggregation tests.
14367TEST(NestedLockersNoTryCatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014368 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014369 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014370 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014371 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014372 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
Steve Blocka7e24c12009-10-30 11:49:00 +000014373 Local<Function> fun = fun_templ->GetFunction();
14374 env->Global()->Set(v8_str("throw_in_js"), fun);
14375 Local<Script> script = v8_compile("(function () {"
14376 " try {"
14377 " throw_in_js();"
14378 " return 42;"
14379 " } catch (e) {"
14380 " return e * 13;"
14381 " }"
14382 "})();");
14383 CHECK_EQ(91, script->Run()->Int32Value());
14384}
14385
14386
14387THREADED_TEST(RecursiveLocking) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014388 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014389 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014390 v8::Locker locker2(CcTest::isolate());
14391 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000014392 }
14393}
14394
14395
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014396static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014397 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014398 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014399}
14400
14401
14402THREADED_TEST(LockUnlockLock) {
14403 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014404 v8::Locker locker(CcTest::isolate());
14405 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014406 LocalContext env;
14407 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014408 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
Steve Blocka7e24c12009-10-30 11:49:00 +000014409 Local<Function> fun = fun_templ->GetFunction();
14410 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14411 Local<Script> script = v8_compile("(function () {"
14412 " unlock_for_a_moment();"
14413 " return 42;"
14414 "})();");
14415 CHECK_EQ(42, script->Run()->Int32Value());
14416 }
14417 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014418 v8::Locker locker(CcTest::isolate());
14419 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014420 LocalContext env;
14421 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014422 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
Steve Blocka7e24c12009-10-30 11:49:00 +000014423 Local<Function> fun = fun_templ->GetFunction();
14424 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14425 Local<Script> script = v8_compile("(function () {"
14426 " unlock_for_a_moment();"
14427 " return 42;"
14428 "})();");
14429 CHECK_EQ(42, script->Run()->Int32Value());
14430 }
14431}
14432
14433
Leon Clarked91b9f72010-01-27 17:25:45 +000014434static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +000014435 int count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014436 i::HeapIterator it(CcTest::heap());
Leon Clarked91b9f72010-01-27 17:25:45 +000014437 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
14438 if (object->IsJSGlobalObject()) count++;
14439 return count;
14440}
14441
14442
Ben Murdochf87a2032010-10-22 12:50:53 +010014443static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014444 // We need to collect all garbage twice to be sure that everything
14445 // has been collected. This is because inline caches are cleared in
14446 // the first garbage collection but some of the maps have already
14447 // been marked at that point. Therefore some of the maps are not
14448 // collected until the second garbage collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014449 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14450 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Leon Clarked91b9f72010-01-27 17:25:45 +000014451 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000014452#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014453 if (count != expected) CcTest::heap()->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +000014454#endif
Ben Murdochf87a2032010-10-22 12:50:53 +010014455 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +000014456}
14457
14458
14459TEST(DontLeakGlobalObjects) {
14460 // Regression test for issues 1139850 and 1174891.
14461
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014462 i::FLAG_expose_gc = true;
Steve Blocka7e24c12009-10-30 11:49:00 +000014463 v8::V8::Initialize();
14464
Steve Blocka7e24c12009-10-30 11:49:00 +000014465 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014466 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014467 LocalContext context;
14468 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014469 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010014470 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014471
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014472 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014473 LocalContext context;
14474 v8_compile("Date")->Run();
14475 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014476 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010014477 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014478
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014479 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014480 LocalContext context;
14481 v8_compile("/aaa/")->Run();
14482 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014483 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010014484 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014485
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014486 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014487 const char* extension_list[] = { "v8/gc" };
14488 v8::ExtensionConfiguration extensions(1, extension_list);
14489 LocalContext context(&extensions);
14490 v8_compile("gc();")->Run();
14491 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014492 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010014493 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014494 }
14495}
14496
14497
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014498TEST(CopyablePersistent) {
14499 LocalContext context;
14500 v8::Isolate* isolate = context->GetIsolate();
14501 i::GlobalHandles* globals =
14502 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14503 int initial_handles = globals->global_handles_count();
14504 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14505 CopyableObject;
14506 {
14507 CopyableObject handle1;
14508 {
14509 v8::HandleScope scope(isolate);
14510 handle1.Reset(isolate, v8::Object::New(isolate));
14511 }
14512 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14513 CopyableObject handle2;
14514 handle2 = handle1;
14515 CHECK(handle1 == handle2);
14516 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14517 CopyableObject handle3(handle2);
14518 CHECK(handle1 == handle3);
14519 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14520 }
14521 // Verify autodispose
14522 CHECK_EQ(initial_handles, globals->global_handles_count());
14523}
14524
14525
14526static void WeakApiCallback(
14527 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
14528 Local<Value> value = data.GetValue()->Get(v8_str("key"));
14529 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
14530 data.GetParameter()->Reset();
14531 delete data.GetParameter();
14532}
14533
14534
14535TEST(WeakCallbackApi) {
14536 LocalContext context;
14537 v8::Isolate* isolate = context->GetIsolate();
14538 i::GlobalHandles* globals =
14539 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14540 int initial_handles = globals->global_handles_count();
14541 {
14542 v8::HandleScope scope(isolate);
14543 v8::Local<v8::Object> obj = v8::Object::New(isolate);
14544 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
14545 v8::Persistent<v8::Object>* handle =
14546 new v8::Persistent<v8::Object>(isolate, obj);
14547 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
14548 WeakApiCallback);
14549 }
14550 reinterpret_cast<i::Isolate*>(isolate)->heap()->
14551 CollectAllGarbage(i::Heap::kNoGCFlags);
14552 // Verify disposed.
14553 CHECK_EQ(initial_handles, globals->global_handles_count());
14554}
14555
14556
Steve Blocka7e24c12009-10-30 11:49:00 +000014557v8::Persistent<v8::Object> some_object;
14558v8::Persistent<v8::Object> bad_handle;
14559
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014560void NewPersistentHandleCallback(
14561 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14562 v8::HandleScope scope(data.GetIsolate());
14563 bad_handle.Reset(data.GetIsolate(), some_object);
14564 data.GetParameter()->Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +000014565}
14566
14567
14568THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14569 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014570 v8::Isolate* isolate = context->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000014571
14572 v8::Persistent<v8::Object> handle1, handle2;
14573 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014574 v8::HandleScope scope(isolate);
14575 some_object.Reset(isolate, v8::Object::New(isolate));
14576 handle1.Reset(isolate, v8::Object::New(isolate));
14577 handle2.Reset(isolate, v8::Object::New(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000014578 }
14579 // Note: order is implementation dependent alas: currently
14580 // global handle nodes are processed by PostGarbageCollectionProcessing
14581 // in reverse allocation order, so if second allocated handle is deleted,
14582 // weak callback of the first handle would be able to 'reallocate' it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014583 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
14584 handle2.Reset();
14585 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blocka7e24c12009-10-30 11:49:00 +000014586}
14587
14588
14589v8::Persistent<v8::Object> to_be_disposed;
14590
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014591void DisposeAndForceGcCallback(
14592 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14593 to_be_disposed.Reset();
14594 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14595 data.GetParameter()->Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +000014596}
14597
14598
14599THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14600 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014601 v8::Isolate* isolate = context->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000014602
14603 v8::Persistent<v8::Object> handle1, handle2;
14604 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014605 v8::HandleScope scope(isolate);
14606 handle1.Reset(isolate, v8::Object::New(isolate));
14607 handle2.Reset(isolate, v8::Object::New(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000014608 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014609 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
14610 to_be_disposed.Reset(isolate, handle2);
14611 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blocka7e24c12009-10-30 11:49:00 +000014612}
14613
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014614void DisposingCallback(
14615 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14616 data.GetParameter()->Reset();
Steve Blockd0582a62009-12-15 09:54:21 +000014617}
14618
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014619void HandleCreatingCallback(
14620 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14621 v8::HandleScope scope(data.GetIsolate());
14622 v8::Persistent<v8::Object>(data.GetIsolate(),
14623 v8::Object::New(data.GetIsolate()));
14624 data.GetParameter()->Reset();
Steve Blockd0582a62009-12-15 09:54:21 +000014625}
14626
14627
14628THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14629 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014630 v8::Isolate* isolate = context->GetIsolate();
Steve Blockd0582a62009-12-15 09:54:21 +000014631
14632 v8::Persistent<v8::Object> handle1, handle2, handle3;
14633 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014634 v8::HandleScope scope(isolate);
14635 handle3.Reset(isolate, v8::Object::New(isolate));
14636 handle2.Reset(isolate, v8::Object::New(isolate));
14637 handle1.Reset(isolate, v8::Object::New(isolate));
Steve Blockd0582a62009-12-15 09:54:21 +000014638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014639 handle2.SetWeak(&handle2, DisposingCallback);
14640 handle3.SetWeak(&handle3, HandleCreatingCallback);
14641 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blockd0582a62009-12-15 09:54:21 +000014642}
14643
Steve Blocka7e24c12009-10-30 11:49:00 +000014644
14645THREADED_TEST(CheckForCrossContextObjectLiterals) {
14646 v8::V8::Initialize();
14647
14648 const int nof = 2;
14649 const char* sources[nof] = {
14650 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14651 "Object()"
14652 };
14653
14654 for (int i = 0; i < nof; i++) {
14655 const char* source = sources[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014656 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014657 LocalContext context;
14658 CompileRun(source);
14659 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014660 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014661 LocalContext context;
14662 CompileRun(source);
14663 }
14664 }
14665}
14666
14667
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014668static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
14669 v8::EscapableHandleScope inner(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014670 env->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014671 v8::Local<Value> three = v8_num(3);
14672 v8::Local<Value> value = inner.Escape(three);
Steve Blocka7e24c12009-10-30 11:49:00 +000014673 env->Exit();
14674 return value;
14675}
14676
14677
14678THREADED_TEST(NestedHandleScopeAndContexts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014679 v8::Isolate* isolate = CcTest::isolate();
14680 v8::HandleScope outer(isolate);
14681 v8::Local<Context> env = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014682 env->Enter();
14683 v8::Handle<Value> value = NestedScope(env);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014684 v8::Handle<String> str(value->ToString(isolate));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014685 CHECK(!str.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000014686 env->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014687}
14688
14689
14690static bool MatchPointers(void* key1, void* key2) {
14691 return key1 == key2;
14692}
14693
14694
14695struct SymbolInfo {
14696 size_t id;
14697 size_t size;
14698 std::string name;
14699};
14700
14701
14702class SetFunctionEntryHookTest {
14703 public:
14704 SetFunctionEntryHookTest() {
14705 CHECK(instance_ == NULL);
14706 instance_ = this;
14707 }
14708 ~SetFunctionEntryHookTest() {
14709 CHECK(instance_ == this);
14710 instance_ = NULL;
14711 }
14712 void Reset() {
14713 symbols_.clear();
14714 symbol_locations_.clear();
14715 invocations_.clear();
14716 }
14717 void RunTest();
14718 void OnJitEvent(const v8::JitCodeEvent* event);
14719 static void JitEvent(const v8::JitCodeEvent* event) {
14720 CHECK(instance_ != NULL);
14721 instance_->OnJitEvent(event);
14722 }
14723
14724 void OnEntryHook(uintptr_t function,
14725 uintptr_t return_addr_location);
14726 static void EntryHook(uintptr_t function,
14727 uintptr_t return_addr_location) {
14728 CHECK(instance_ != NULL);
14729 instance_->OnEntryHook(function, return_addr_location);
14730 }
14731
14732 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14733 CHECK(instance_ != NULL);
14734 args.GetReturnValue().Set(v8_num(42));
14735 }
14736 void RunLoopInNewEnv(v8::Isolate* isolate);
14737
14738 // Records addr as location of symbol.
14739 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14740
14741 // Finds the symbol containing addr
14742 SymbolInfo* FindSymbolForAddr(i::Address addr);
14743 // Returns the number of invocations where the caller name contains
14744 // \p caller_name and the function name contains \p function_name.
14745 int CountInvocations(const char* caller_name,
14746 const char* function_name);
14747
14748 i::Handle<i::JSFunction> foo_func_;
14749 i::Handle<i::JSFunction> bar_func_;
14750
14751 typedef std::map<size_t, SymbolInfo> SymbolMap;
14752 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14753 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14754 SymbolMap symbols_;
14755 SymbolLocationMap symbol_locations_;
14756 InvocationMap invocations_;
14757
14758 static SetFunctionEntryHookTest* instance_;
14759};
14760SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14761
14762
14763// Returns true if addr is in the range [start, start+len).
14764static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14765 if (start <= addr && start + len > addr)
14766 return true;
14767
14768 return false;
14769}
14770
14771void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14772 SymbolInfo* symbol) {
14773 // Insert the symbol at the new location.
14774 SymbolLocationMap::iterator it =
14775 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14776 // Now erase symbols to the left and right that overlap this one.
14777 while (it != symbol_locations_.begin()) {
14778 SymbolLocationMap::iterator left = it;
14779 --left;
14780 if (!Overlaps(left->first, left->second->size, addr))
14781 break;
14782 symbol_locations_.erase(left);
14783 }
14784
14785 // Now erase symbols to the left and right that overlap this one.
14786 while (true) {
14787 SymbolLocationMap::iterator right = it;
14788 ++right;
14789 if (right == symbol_locations_.end())
14790 break;
14791 if (!Overlaps(addr, symbol->size, right->first))
14792 break;
14793 symbol_locations_.erase(right);
14794 }
14795}
14796
14797
14798void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14799 switch (event->type) {
14800 case v8::JitCodeEvent::CODE_ADDED: {
14801 CHECK(event->code_start != NULL);
14802 CHECK_NE(0, static_cast<int>(event->code_len));
14803 CHECK(event->name.str != NULL);
14804 size_t symbol_id = symbols_.size();
14805
14806 // Record the new symbol.
14807 SymbolInfo& info = symbols_[symbol_id];
14808 info.id = symbol_id;
14809 info.size = event->code_len;
14810 info.name.assign(event->name.str, event->name.str + event->name.len);
14811
14812 // And record it's location.
14813 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14814 }
14815 break;
14816
14817 case v8::JitCodeEvent::CODE_MOVED: {
14818 // We would like to never see code move that we haven't seen before,
14819 // but the code creation event does not happen until the line endings
14820 // have been calculated (this is so that we can report the line in the
14821 // script at which the function source is found, see
14822 // Compiler::RecordFunctionCompilation) and the line endings
14823 // calculations can cause a GC, which can move the newly created code
14824 // before its existence can be logged.
14825 SymbolLocationMap::iterator it(
14826 symbol_locations_.find(
14827 reinterpret_cast<i::Address>(event->code_start)));
14828 if (it != symbol_locations_.end()) {
14829 // Found a symbol at this location, move it.
14830 SymbolInfo* info = it->second;
14831 symbol_locations_.erase(it);
14832 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14833 info);
14834 }
14835 }
14836 default:
14837 break;
14838 }
14839}
14840
14841void SetFunctionEntryHookTest::OnEntryHook(
14842 uintptr_t function, uintptr_t return_addr_location) {
14843 // Get the function's code object.
14844 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14845 reinterpret_cast<i::Address>(function));
14846 CHECK(function_code != NULL);
14847
14848 // Then try and look up the caller's code object.
14849 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14850
14851 // Count the invocation.
14852 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14853 SymbolInfo* function_symbol =
14854 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14855 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14856
14857 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14858 // Check that we have a symbol for the "bar" function at the right location.
14859 SymbolLocationMap::iterator it(
14860 symbol_locations_.find(function_code->instruction_start()));
14861 CHECK(it != symbol_locations_.end());
14862 }
14863
14864 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14865 // Check that we have a symbol for "foo" at the right location.
14866 SymbolLocationMap::iterator it(
14867 symbol_locations_.find(function_code->instruction_start()));
14868 CHECK(it != symbol_locations_.end());
14869 }
14870}
14871
14872
14873SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14874 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14875 // Do we have a direct hit on a symbol?
14876 if (it != symbol_locations_.end()) {
14877 if (it->first == addr)
14878 return it->second;
14879 }
14880
14881 // If not a direct hit, it'll have to be the previous symbol.
14882 if (it == symbol_locations_.begin())
14883 return NULL;
14884
14885 --it;
14886 size_t offs = addr - it->first;
14887 if (offs < it->second->size)
14888 return it->second;
14889
14890 return NULL;
14891}
14892
14893
14894int SetFunctionEntryHookTest::CountInvocations(
14895 const char* caller_name, const char* function_name) {
14896 InvocationMap::iterator it(invocations_.begin());
14897 int invocations = 0;
14898 for (; it != invocations_.end(); ++it) {
14899 SymbolInfo* caller = it->first.first;
14900 SymbolInfo* function = it->first.second;
14901
14902 // Filter out non-matching functions.
14903 if (function_name != NULL) {
14904 if (function->name.find(function_name) == std::string::npos)
14905 continue;
14906 }
14907
14908 // Filter out non-matching callers.
14909 if (caller_name != NULL) {
14910 if (caller == NULL)
14911 continue;
14912 if (caller->name.find(caller_name) == std::string::npos)
14913 continue;
14914 }
14915
14916 // It matches add the invocation count to the tally.
14917 invocations += it->second;
14918 }
14919
14920 return invocations;
14921}
14922
14923
14924void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14925 v8::HandleScope outer(isolate);
14926 v8::Local<Context> env = Context::New(isolate);
14927 env->Enter();
14928
14929 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14930 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14931 env->Global()->Set(v8_str("obj"), t->NewInstance());
14932
14933 const char* script =
14934 "function bar() {\n"
14935 " var sum = 0;\n"
14936 " for (i = 0; i < 100; ++i)\n"
14937 " sum = foo(i);\n"
14938 " return sum;\n"
14939 "}\n"
14940 "function foo(i) { return i * i; }\n"
14941 "// Invoke on the runtime function.\n"
14942 "obj.asdf()";
14943 CompileRun(script);
14944 bar_func_ = i::Handle<i::JSFunction>::cast(
14945 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14946 DCHECK(!bar_func_.is_null());
14947
14948 foo_func_ =
14949 i::Handle<i::JSFunction>::cast(
14950 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14951 DCHECK(!foo_func_.is_null());
14952
14953 v8::Handle<v8::Value> value = CompileRun("bar();");
14954 CHECK(value->IsNumber());
14955 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14956
14957 // Test the optimized codegen path.
14958 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14959 "bar();");
14960 CHECK(value->IsNumber());
14961 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14962
14963 env->Exit();
14964}
14965
14966
14967void SetFunctionEntryHookTest::RunTest() {
14968 // Work in a new isolate throughout.
14969 v8::Isolate::CreateParams create_params;
14970 create_params.entry_hook = EntryHook;
14971 create_params.code_event_handler = JitEvent;
14972 v8::Isolate* isolate = v8::Isolate::New(create_params);
14973
14974 {
14975 v8::Isolate::Scope scope(isolate);
14976
14977 RunLoopInNewEnv(isolate);
14978
14979 // Check the exepected invocation counts.
14980 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14981 CHECK_EQ(200, CountInvocations("bar", "foo"));
14982 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14983
14984 // Verify that we have an entry hook on some specific stubs.
14985 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14986 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14987 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14988 }
14989 isolate->Dispose();
14990
14991 Reset();
14992
14993 // Make sure a second isolate is unaffected by the previous entry hook.
14994 isolate = v8::Isolate::New();
14995 {
14996 v8::Isolate::Scope scope(isolate);
14997
14998 // Reset the entry count to zero and set the entry hook.
14999 RunLoopInNewEnv(isolate);
15000
15001 // We should record no invocations in this isolate.
15002 CHECK_EQ(0, static_cast<int>(invocations_.size()));
15003 }
15004
15005 isolate->Dispose();
15006}
15007
15008
15009TEST(SetFunctionEntryHook) {
15010 // FunctionEntryHook does not work well with experimental natives.
15011 // Experimental natives are compiled during snapshot deserialization.
15012 // This test breaks because InstallGetter (function from snapshot that
15013 // only gets called from experimental natives) is compiled with entry hooks.
15014 i::FLAG_allow_natives_syntax = true;
15015 i::FLAG_use_inlining = false;
15016
15017 SetFunctionEntryHookTest test;
15018 test.RunTest();
15019}
15020
15021
15022static i::HashMap* code_map = NULL;
15023static i::HashMap* jitcode_line_info = NULL;
15024static int saw_bar = 0;
15025static int move_events = 0;
15026
15027
15028static bool FunctionNameIs(const char* expected,
15029 const v8::JitCodeEvent* event) {
15030 // Log lines for functions are of the general form:
15031 // "LazyCompile:<type><function_name>", where the type is one of
15032 // "*", "~" or "".
15033 static const char kPreamble[] = "LazyCompile:";
15034 static size_t kPreambleLen = sizeof(kPreamble) - 1;
15035
15036 if (event->name.len < sizeof(kPreamble) - 1 ||
15037 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
15038 return false;
15039 }
15040
15041 const char* tail = event->name.str + kPreambleLen;
15042 size_t tail_len = event->name.len - kPreambleLen;
15043 size_t expected_len = strlen(expected);
15044 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
15045 --tail_len;
15046 ++tail;
15047 }
15048
15049 // Check for tails like 'bar :1'.
15050 if (tail_len > expected_len + 2 &&
15051 tail[expected_len] == ' ' &&
15052 tail[expected_len + 1] == ':' &&
15053 tail[expected_len + 2] &&
15054 !strncmp(tail, expected, expected_len)) {
15055 return true;
15056 }
15057
15058 if (tail_len != expected_len)
15059 return false;
15060
15061 return strncmp(tail, expected, expected_len) == 0;
15062}
15063
15064
15065static void event_handler(const v8::JitCodeEvent* event) {
15066 CHECK(event != NULL);
15067 CHECK(code_map != NULL);
15068 CHECK(jitcode_line_info != NULL);
15069
15070 class DummyJitCodeLineInfo {
15071 };
15072
15073 switch (event->type) {
15074 case v8::JitCodeEvent::CODE_ADDED: {
15075 CHECK(event->code_start != NULL);
15076 CHECK_NE(0, static_cast<int>(event->code_len));
15077 CHECK(event->name.str != NULL);
15078 i::HashMap::Entry* entry =
15079 code_map->Lookup(event->code_start,
15080 i::ComputePointerHash(event->code_start),
15081 true);
15082 entry->value = reinterpret_cast<void*>(event->code_len);
15083
15084 if (FunctionNameIs("bar", event)) {
15085 ++saw_bar;
15086 }
15087 }
15088 break;
15089
15090 case v8::JitCodeEvent::CODE_MOVED: {
15091 uint32_t hash = i::ComputePointerHash(event->code_start);
15092 // We would like to never see code move that we haven't seen before,
15093 // but the code creation event does not happen until the line endings
15094 // have been calculated (this is so that we can report the line in the
15095 // script at which the function source is found, see
15096 // Compiler::RecordFunctionCompilation) and the line endings
15097 // calculations can cause a GC, which can move the newly created code
15098 // before its existence can be logged.
15099 i::HashMap::Entry* entry =
15100 code_map->Lookup(event->code_start, hash, false);
15101 if (entry != NULL) {
15102 ++move_events;
15103
15104 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
15105 code_map->Remove(event->code_start, hash);
15106
15107 entry = code_map->Lookup(event->new_code_start,
15108 i::ComputePointerHash(event->new_code_start),
15109 true);
15110 CHECK(entry != NULL);
15111 entry->value = reinterpret_cast<void*>(event->code_len);
15112 }
15113 }
15114 break;
15115
15116 case v8::JitCodeEvent::CODE_REMOVED:
15117 // Object/code removal events are currently not dispatched from the GC.
15118 CHECK(false);
15119 break;
15120
15121 // For CODE_START_LINE_INFO_RECORDING event, we will create one
15122 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
15123 // record it in jitcode_line_info.
15124 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
15125 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
15126 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
15127 temp_event->user_data = line_info;
15128 i::HashMap::Entry* entry =
15129 jitcode_line_info->Lookup(line_info,
15130 i::ComputePointerHash(line_info),
15131 true);
15132 entry->value = reinterpret_cast<void*>(line_info);
15133 }
15134 break;
15135 // For these two events, we will check whether the event->user_data
15136 // data structure is created before during CODE_START_LINE_INFO_RECORDING
15137 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
15138 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
15139 CHECK(event->user_data != NULL);
15140 uint32_t hash = i::ComputePointerHash(event->user_data);
15141 i::HashMap::Entry* entry =
15142 jitcode_line_info->Lookup(event->user_data, hash, false);
15143 CHECK(entry != NULL);
15144 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
15145 }
15146 break;
15147
15148 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
15149 CHECK(event->user_data != NULL);
15150 uint32_t hash = i::ComputePointerHash(event->user_data);
15151 i::HashMap::Entry* entry =
15152 jitcode_line_info->Lookup(event->user_data, hash, false);
15153 CHECK(entry != NULL);
15154 }
15155 break;
15156
15157 default:
15158 // Impossible event.
15159 CHECK(false);
15160 break;
15161 }
15162}
15163
15164
15165UNINITIALIZED_TEST(SetJitCodeEventHandler) {
15166 i::FLAG_stress_compaction = true;
15167 i::FLAG_incremental_marking = false;
15168 if (i::FLAG_never_compact) return;
15169 const char* script =
15170 "function bar() {"
15171 " var sum = 0;"
15172 " for (i = 0; i < 100; ++i)"
15173 " sum = foo(i);"
15174 " return sum;"
15175 "}"
15176 "function foo(i) { return i * i; };"
15177 "bar();";
15178
15179 // Run this test in a new isolate to make sure we don't
15180 // have remnants of state from other code.
15181 v8::Isolate* isolate = v8::Isolate::New();
15182 isolate->Enter();
15183 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
15184 i::Heap* heap = i_isolate->heap();
15185
15186 {
15187 v8::HandleScope scope(isolate);
15188 i::HashMap code(MatchPointers);
15189 code_map = &code;
15190
15191 i::HashMap lineinfo(MatchPointers);
15192 jitcode_line_info = &lineinfo;
15193
15194 saw_bar = 0;
15195 move_events = 0;
15196
15197 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
15198
15199 // Generate new code objects sparsely distributed across several
15200 // different fragmented code-space pages.
15201 const int kIterations = 10;
15202 for (int i = 0; i < kIterations; ++i) {
15203 LocalContext env(isolate);
15204 i::AlwaysAllocateScope always_allocate(i_isolate);
15205 SimulateFullSpace(heap->code_space());
15206 CompileRun(script);
15207
15208 // Keep a strong reference to the code object in the handle scope.
15209 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
15210 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
15211 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
15212 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
15213
15214 // Clear the compilation cache to get more wastage.
15215 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
15216 }
15217
15218 // Force code movement.
15219 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
15220
15221 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15222
15223 CHECK_LE(kIterations, saw_bar);
15224 CHECK_LT(0, move_events);
15225
15226 code_map = NULL;
15227 jitcode_line_info = NULL;
15228 }
15229
15230 isolate->Exit();
15231 isolate->Dispose();
15232
15233 // Do this in a new isolate.
15234 isolate = v8::Isolate::New();
15235 isolate->Enter();
15236
15237 // Verify that we get callbacks for existing code objects when we
15238 // request enumeration of existing code.
15239 {
15240 v8::HandleScope scope(isolate);
15241 LocalContext env(isolate);
15242 CompileRun(script);
15243
15244 // Now get code through initial iteration.
15245 i::HashMap code(MatchPointers);
15246 code_map = &code;
15247
15248 i::HashMap lineinfo(MatchPointers);
15249 jitcode_line_info = &lineinfo;
15250
15251 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
15252 event_handler);
15253 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15254
15255 jitcode_line_info = NULL;
15256 // We expect that we got some events. Note that if we could get code removal
15257 // notifications, we could compare two collections, one created by listening
15258 // from the time of creation of an isolate, and the other by subscribing
15259 // with EnumExisting.
15260 CHECK_LT(0, code.occupancy());
15261
15262 code_map = NULL;
15263 }
15264
15265 isolate->Exit();
15266 isolate->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000015267}
15268
15269
15270THREADED_TEST(ExternalAllocatedMemory) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015271 v8::Isolate* isolate = CcTest::isolate();
15272 v8::HandleScope outer(isolate);
15273 v8::Local<Context> env(Context::New(isolate));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015274 CHECK(!env.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015275 const int64_t kSize = 1024*1024;
15276 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
15277 CHECK_EQ(baseline + kSize,
15278 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
15279 CHECK_EQ(baseline,
15280 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000015281}
15282
15283
15284// Regression test for issue 54, object templates with internal fields
15285// but no accessors or interceptors did not get their internal field
15286// count set on instances.
15287THREADED_TEST(Regress54) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015288 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015289 v8::Isolate* isolate = context->GetIsolate();
15290 v8::HandleScope outer(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015291 static v8::Persistent<v8::ObjectTemplate> templ;
15292 if (templ.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015293 v8::EscapableHandleScope inner(isolate);
15294 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015295 local->SetInternalFieldCount(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015296 templ.Reset(isolate, inner.Escape(local));
Steve Blocka7e24c12009-10-30 11:49:00 +000015297 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015298 v8::Handle<v8::Object> result =
15299 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
Steve Blocka7e24c12009-10-30 11:49:00 +000015300 CHECK_EQ(1, result->InternalFieldCount());
15301}
15302
15303
15304// If part of the threaded tests, this test makes ThreadingTest fail
15305// on mac.
15306TEST(CatchStackOverflow) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015307 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015308 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015309 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015310 v8::Handle<v8::Value> result = CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +000015311 "function f() {"
15312 " return f();"
15313 "}"
15314 ""
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015315 "f();");
Steve Blocka7e24c12009-10-30 11:49:00 +000015316 CHECK(result.IsEmpty());
15317}
15318
15319
15320static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
15321 const char* resource_name,
15322 int line_offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015323 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015324 v8::TryCatch try_catch;
15325 v8::Handle<v8::Value> result = script->Run();
15326 CHECK(result.IsEmpty());
15327 CHECK(try_catch.HasCaught());
15328 v8::Handle<v8::Message> message = try_catch.Message();
15329 CHECK(!message.IsEmpty());
15330 CHECK_EQ(10 + line_offset, message->GetLineNumber());
15331 CHECK_EQ(91, message->GetStartPosition());
15332 CHECK_EQ(92, message->GetEndPosition());
15333 CHECK_EQ(2, message->GetStartColumn());
15334 CHECK_EQ(3, message->GetEndColumn());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015335 v8::String::Utf8Value line(message->GetSourceLine());
Steve Blocka7e24c12009-10-30 11:49:00 +000015336 CHECK_EQ(" throw 'nirk';", *line);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015337 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +000015338 CHECK_EQ(resource_name, *name);
15339}
15340
15341
15342THREADED_TEST(TryCatchSourceInfo) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015343 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015344 v8::HandleScope scope(context->GetIsolate());
15345 v8::Local<v8::String> source = v8_str(
Steve Blocka7e24c12009-10-30 11:49:00 +000015346 "function Foo() {\n"
15347 " return Bar();\n"
15348 "}\n"
15349 "\n"
15350 "function Bar() {\n"
15351 " return Baz();\n"
15352 "}\n"
15353 "\n"
15354 "function Baz() {\n"
15355 " throw 'nirk';\n"
15356 "}\n"
15357 "\n"
15358 "Foo();\n");
15359
15360 const char* resource_name;
15361 v8::Handle<v8::Script> script;
15362 resource_name = "test.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015363 script = CompileWithOrigin(source, resource_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000015364 CheckTryCatchSourceInfo(script, resource_name, 0);
15365
15366 resource_name = "test1.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015367 v8::ScriptOrigin origin1(
15368 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
Steve Blocka7e24c12009-10-30 11:49:00 +000015369 script = v8::Script::Compile(source, &origin1);
15370 CheckTryCatchSourceInfo(script, resource_name, 0);
15371
15372 resource_name = "test2.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015373 v8::ScriptOrigin origin2(
15374 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
15375 v8::Integer::New(context->GetIsolate(), 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000015376 script = v8::Script::Compile(source, &origin2);
15377 CheckTryCatchSourceInfo(script, resource_name, 7);
15378}
15379
15380
15381THREADED_TEST(CompilationCache) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015382 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015383 v8::HandleScope scope(context->GetIsolate());
15384 v8::Handle<v8::String> source0 =
15385 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15386 v8::Handle<v8::String> source1 =
15387 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15388 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15389 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
Steve Blocka7e24c12009-10-30 11:49:00 +000015390 v8::Handle<v8::Script> script2 =
15391 v8::Script::Compile(source0); // different origin
15392 CHECK_EQ(1234, script0->Run()->Int32Value());
15393 CHECK_EQ(1234, script1->Run()->Int32Value());
15394 CHECK_EQ(1234, script2->Run()->Int32Value());
15395}
15396
15397
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015398static void FunctionNameCallback(
15399 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015400 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015401 args.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000015402}
15403
15404
15405THREADED_TEST(CallbackFunctionName) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015406 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015407 v8::Isolate* isolate = context->GetIsolate();
15408 v8::HandleScope scope(isolate);
15409 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15410 t->Set(v8_str("asdf"),
15411 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000015412 context->Global()->Set(v8_str("obj"), t->NewInstance());
15413 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
15414 CHECK(value->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015415 v8::String::Utf8Value name(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000015416 CHECK_EQ("asdf", *name);
15417}
15418
15419
15420THREADED_TEST(DateAccess) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015421 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015422 v8::HandleScope scope(context->GetIsolate());
15423 v8::Handle<v8::Value> date =
15424 v8::Date::New(context->GetIsolate(), 1224744689038.0);
Steve Blocka7e24c12009-10-30 11:49:00 +000015425 CHECK(date->IsDate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015426 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
Steve Blocka7e24c12009-10-30 11:49:00 +000015427}
15428
15429
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015430void CheckProperties(v8::Isolate* isolate,
15431 v8::Handle<v8::Value> val,
15432 int elmc,
15433 const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010015434 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015435 v8::Handle<v8::Array> props = obj->GetPropertyNames();
15436 CHECK_EQ(elmc, props->Length());
15437 for (int i = 0; i < elmc; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015438 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015439 CHECK_EQ(elmv[i], *elm);
15440 }
15441}
15442
15443
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015444void CheckOwnProperties(v8::Isolate* isolate,
15445 v8::Handle<v8::Value> val,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015446 int elmc,
15447 const char* elmv[]) {
15448 v8::Handle<v8::Object> obj = val.As<v8::Object>();
15449 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
15450 CHECK_EQ(elmc, props->Length());
15451 for (int i = 0; i < elmc; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015452 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015453 CHECK_EQ(elmv[i], *elm);
15454 }
15455}
15456
15457
Steve Blocka7e24c12009-10-30 11:49:00 +000015458THREADED_TEST(PropertyEnumeration) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015459 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015460 v8::Isolate* isolate = context->GetIsolate();
15461 v8::HandleScope scope(isolate);
15462 v8::Handle<v8::Value> obj = CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +000015463 "var result = [];"
15464 "result[0] = {};"
15465 "result[1] = {a: 1, b: 2};"
15466 "result[2] = [1, 2, 3];"
15467 "var proto = {x: 1, y: 2, z: 3};"
15468 "var x = { __proto__: proto, w: 0, z: 1 };"
15469 "result[3] = x;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015470 "result;");
Steve Block6ded16b2010-05-10 14:33:55 +010015471 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015472 CHECK_EQ(4, elms->Length());
15473 int elmc0 = 0;
15474 const char** elmv0 = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015475 CheckProperties(
15476 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15477 CheckOwnProperties(
15478 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000015479 int elmc1 = 2;
15480 const char* elmv1[] = {"a", "b"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015481 CheckProperties(
15482 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15483 CheckOwnProperties(
15484 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015485 int elmc2 = 3;
15486 const char* elmv2[] = {"0", "1", "2"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015487 CheckProperties(
15488 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15489 CheckOwnProperties(
15490 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000015491 int elmc3 = 4;
15492 const char* elmv3[] = {"w", "z", "x", "y"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015493 CheckProperties(
15494 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015495 int elmc4 = 2;
15496 const char* elmv4[] = {"w", "z"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015497 CheckOwnProperties(
15498 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000015499}
15500
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015501
Steve Block44f0eee2011-05-26 01:26:41 +010015502THREADED_TEST(PropertyEnumeration2) {
Steve Block44f0eee2011-05-26 01:26:41 +010015503 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015504 v8::Isolate* isolate = context->GetIsolate();
15505 v8::HandleScope scope(isolate);
15506 v8::Handle<v8::Value> obj = CompileRun(
Steve Block44f0eee2011-05-26 01:26:41 +010015507 "var result = [];"
15508 "result[0] = {};"
15509 "result[1] = {a: 1, b: 2};"
15510 "result[2] = [1, 2, 3];"
15511 "var proto = {x: 1, y: 2, z: 3};"
15512 "var x = { __proto__: proto, w: 0, z: 1 };"
15513 "result[3] = x;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015514 "result;");
Steve Block44f0eee2011-05-26 01:26:41 +010015515 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15516 CHECK_EQ(4, elms->Length());
15517 int elmc0 = 0;
15518 const char** elmv0 = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015519 CheckProperties(isolate,
15520 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
Steve Block44f0eee2011-05-26 01:26:41 +010015521
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015522 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
Steve Block44f0eee2011-05-26 01:26:41 +010015523 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
15524 CHECK_EQ(0, props->Length());
15525 for (uint32_t i = 0; i < props->Length(); i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015526 printf("p[%u]\n", i);
Steve Block44f0eee2011-05-26 01:26:41 +010015527 }
15528}
Steve Blocka7e24c12009-10-30 11:49:00 +000015529
Steve Blocka7e24c12009-10-30 11:49:00 +000015530static bool NamedSetAccessBlocker(Local<v8::Object> obj,
15531 Local<Value> name,
15532 v8::AccessType type,
15533 Local<Value> data) {
15534 return type != v8::ACCESS_SET;
15535}
15536
15537
15538static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
15539 uint32_t key,
15540 v8::AccessType type,
15541 Local<Value> data) {
15542 return type != v8::ACCESS_SET;
15543}
15544
15545
15546THREADED_TEST(DisableAccessChecksWhileConfiguring) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015547 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015548 v8::Isolate* isolate = context->GetIsolate();
15549 v8::HandleScope scope(isolate);
15550 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015551 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15552 IndexedSetAccessBlocker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015553 templ->Set(v8_str("x"), v8::True(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000015554 Local<v8::Object> instance = templ->NewInstance();
15555 context->Global()->Set(v8_str("obj"), instance);
15556 Local<Value> value = CompileRun("obj.x");
15557 CHECK(value->BooleanValue());
15558}
15559
15560
15561static bool NamedGetAccessBlocker(Local<v8::Object> obj,
15562 Local<Value> name,
15563 v8::AccessType type,
15564 Local<Value> data) {
15565 return false;
15566}
15567
15568
15569static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
15570 uint32_t key,
15571 v8::AccessType type,
15572 Local<Value> data) {
15573 return false;
15574}
15575
15576
15577
15578THREADED_TEST(AccessChecksReenabledCorrectly) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015579 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015580 v8::Isolate* isolate = context->GetIsolate();
15581 v8::HandleScope scope(isolate);
15582 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015583 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15584 IndexedGetAccessBlocker);
15585 templ->Set(v8_str("a"), v8_str("a"));
15586 // Add more than 8 (see kMaxFastProperties) properties
15587 // so that the constructor will force copying map.
15588 // Cannot sprintf, gcc complains unsafety.
15589 char buf[4];
15590 for (char i = '0'; i <= '9' ; i++) {
15591 buf[0] = i;
15592 for (char j = '0'; j <= '9'; j++) {
15593 buf[1] = j;
15594 for (char k = '0'; k <= '9'; k++) {
15595 buf[2] = k;
15596 buf[3] = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015597 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
Steve Blocka7e24c12009-10-30 11:49:00 +000015598 }
15599 }
15600 }
15601
15602 Local<v8::Object> instance_1 = templ->NewInstance();
15603 context->Global()->Set(v8_str("obj_1"), instance_1);
15604
15605 Local<Value> value_1 = CompileRun("obj_1.a");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015606 CHECK(value_1.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000015607
15608 Local<v8::Object> instance_2 = templ->NewInstance();
15609 context->Global()->Set(v8_str("obj_2"), instance_2);
15610
15611 Local<Value> value_2 = CompileRun("obj_2.a");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015612 CHECK(value_2.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000015613}
15614
15615
15616// This tests that access check information remains on the global
15617// object template when creating contexts.
15618THREADED_TEST(AccessControlRepeatedContextCreation) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015619 v8::Isolate* isolate = CcTest::isolate();
15620 v8::HandleScope handle_scope(isolate);
15621 v8::Handle<v8::ObjectTemplate> global_template =
15622 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015623 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15624 IndexedSetAccessBlocker);
15625 i::Handle<i::ObjectTemplateInfo> internal_template =
15626 v8::Utils::OpenHandle(*global_template);
15627 CHECK(!internal_template->constructor()->IsUndefined());
15628 i::Handle<i::FunctionTemplateInfo> constructor(
15629 i::FunctionTemplateInfo::cast(internal_template->constructor()));
15630 CHECK(!constructor->access_check_info()->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015631 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015632 CHECK(!context0.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000015633 CHECK(!constructor->access_check_info()->IsUndefined());
15634}
15635
15636
15637THREADED_TEST(TurnOnAccessCheck) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015638 v8::Isolate* isolate = CcTest::isolate();
15639 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015640
15641 // Create an environment with access check to the global object disabled by
15642 // default.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015643 v8::Handle<v8::ObjectTemplate> global_template =
15644 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015645 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15646 IndexedGetAccessBlocker,
15647 v8::Handle<v8::Value>(),
15648 false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015649 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +000015650 Context::Scope context_scope(context);
15651
15652 // Set up a property and a number of functions.
15653 context->Global()->Set(v8_str("a"), v8_num(1));
15654 CompileRun("function f1() {return a;}"
15655 "function f2() {return a;}"
15656 "function g1() {return h();}"
15657 "function g2() {return h();}"
15658 "function h() {return 1;}");
15659 Local<Function> f1 =
15660 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15661 Local<Function> f2 =
15662 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15663 Local<Function> g1 =
15664 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15665 Local<Function> g2 =
15666 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15667 Local<Function> h =
15668 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15669
15670 // Get the global object.
15671 v8::Handle<v8::Object> global = context->Global();
15672
15673 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15674 // uses the runtime system to retreive property a whereas f2 uses global load
15675 // inline cache.
15676 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15677 for (int i = 0; i < 4; i++) {
15678 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15679 }
15680
15681 // Same for g1 and g2.
15682 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15683 for (int i = 0; i < 4; i++) {
15684 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15685 }
15686
15687 // Detach the global and turn on access check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015688 Local<Object> hidden_global = Local<Object>::Cast(
15689 context->Global()->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +000015690 context->DetachGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015691 hidden_global->TurnOnAccessCheck();
Steve Blocka7e24c12009-10-30 11:49:00 +000015692
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015693 // Failing access check results in exception.
15694 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15695 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000015696 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15697 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15698
15699 // No failing access check when just returning a constant.
15700 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15701}
15702
15703
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015704static const char* kPropertyA = "a";
15705static const char* kPropertyH = "h";
Ben Murdochb0fe1622011-05-05 13:52:32 +010015706
15707static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15708 Local<Value> name,
15709 v8::AccessType type,
15710 Local<Value> data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015711 if (!name->IsString()) return false;
15712 i::Handle<i::String> name_handle =
15713 v8::Utils::OpenHandle(String::Cast(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015714 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15715 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
Ben Murdochb0fe1622011-05-05 13:52:32 +010015716}
15717
15718
15719THREADED_TEST(TurnOnAccessCheckAndRecompile) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015720 v8::Isolate* isolate = CcTest::isolate();
15721 v8::HandleScope handle_scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010015722
15723 // Create an environment with access check to the global object disabled by
15724 // default. When the registered access checker will block access to properties
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015725 // a and h.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015726 v8::Handle<v8::ObjectTemplate> global_template =
15727 v8::ObjectTemplate::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010015728 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15729 IndexedGetAccessBlocker,
15730 v8::Handle<v8::Value>(),
15731 false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015732 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
Ben Murdochb0fe1622011-05-05 13:52:32 +010015733 Context::Scope context_scope(context);
15734
15735 // Set up a property and a number of functions.
15736 context->Global()->Set(v8_str("a"), v8_num(1));
15737 static const char* source = "function f1() {return a;}"
15738 "function f2() {return a;}"
15739 "function g1() {return h();}"
15740 "function g2() {return h();}"
15741 "function h() {return 1;}";
15742
15743 CompileRun(source);
15744 Local<Function> f1;
15745 Local<Function> f2;
15746 Local<Function> g1;
15747 Local<Function> g2;
15748 Local<Function> h;
15749 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15750 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15751 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15752 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15753 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15754
15755 // Get the global object.
15756 v8::Handle<v8::Object> global = context->Global();
15757
15758 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15759 // uses the runtime system to retreive property a whereas f2 uses global load
15760 // inline cache.
15761 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15762 for (int i = 0; i < 4; i++) {
15763 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15764 }
15765
15766 // Same for g1 and g2.
15767 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15768 for (int i = 0; i < 4; i++) {
15769 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15770 }
15771
15772 // Detach the global and turn on access check now blocking access to property
15773 // a and function h.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015774 Local<Object> hidden_global = Local<Object>::Cast(
15775 context->Global()->GetPrototype());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015776 context->DetachGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015777 hidden_global->TurnOnAccessCheck();
Ben Murdochb0fe1622011-05-05 13:52:32 +010015778
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015779 // Failing access check results in exception.
15780 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15781 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015782 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15783 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15784
15785 // No failing access check when just returning a constant.
15786 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15787
15788 // Now compile the source again. And get the newly compiled functions, except
15789 // for h for which access is blocked.
15790 CompileRun(source);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015791 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15792 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15793 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15794 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15795 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015796
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015797 // Failing access check results in exception.
15798 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15799 CHECK(result.IsEmpty());
15800 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15801 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015802 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15803 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15804}
15805
15806
Leon Clarkef7060e22010-06-03 12:02:55 +010015807// Tests that ScriptData can be serialized and deserialized.
15808TEST(PreCompileSerialization) {
15809 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015810 LocalContext env;
15811 v8::Isolate* isolate = env->GetIsolate();
15812 HandleScope handle_scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010015813
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015814 i::FLAG_min_preparse_length = 0;
15815 const char* script = "function foo(a) { return a+1; }";
15816 v8::ScriptCompiler::Source source(v8_str(script));
15817 v8::ScriptCompiler::Compile(isolate, &source,
15818 v8::ScriptCompiler::kProduceParserCache);
Leon Clarkef7060e22010-06-03 12:02:55 +010015819 // Serialize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015820 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15821 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15822 i::MemCopy(serialized_data, cd->data, cd->length);
Leon Clarkef7060e22010-06-03 12:02:55 +010015823
15824 // Deserialize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015825 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
Leon Clarkef7060e22010-06-03 12:02:55 +010015826
15827 // Verify that the original is the same as the deserialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015828 CHECK_EQ(cd->length, deserialized->length());
15829 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
Leon Clarkef7060e22010-06-03 12:02:55 +010015830
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015831 delete deserialized;
15832 i::DeleteArray(serialized_data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010015833}
15834
15835
Steve Blocka7e24c12009-10-30 11:49:00 +000015836// This tests that we do not allow dictionary load/call inline caches
15837// to use functions that have not yet been compiled. The potential
15838// problem of loading a function that has not yet been compiled can
15839// arise because we share code between contexts via the compilation
15840// cache.
15841THREADED_TEST(DictionaryICLoadedFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015842 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015843 // Test LoadIC.
15844 for (int i = 0; i < 2; i++) {
15845 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015846 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015847 context->Global()->Delete(v8_str("tmp"));
15848 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15849 }
15850 // Test CallIC.
15851 for (int i = 0; i < 2; i++) {
15852 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015853 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015854 context->Global()->Delete(v8_str("tmp"));
15855 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15856 }
15857}
15858
15859
15860// Test that cross-context new calls use the context of the callee to
15861// create the new JavaScript object.
15862THREADED_TEST(CrossContextNew) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015863 v8::Isolate* isolate = CcTest::isolate();
15864 v8::HandleScope scope(isolate);
15865 v8::Local<Context> context0 = Context::New(isolate);
15866 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015867
15868 // Allow cross-domain access.
15869 Local<String> token = v8_str("<security token>");
15870 context0->SetSecurityToken(token);
15871 context1->SetSecurityToken(token);
15872
15873 // Set an 'x' property on the Object prototype and define a
15874 // constructor function in context0.
15875 context0->Enter();
15876 CompileRun("Object.prototype.x = 42; function C() {};");
15877 context0->Exit();
15878
15879 // Call the constructor function from context0 and check that the
15880 // result has the 'x' property.
15881 context1->Enter();
15882 context1->Global()->Set(v8_str("other"), context0->Global());
15883 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15884 CHECK(value->IsInt32());
15885 CHECK_EQ(42, value->Int32Value());
15886 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000015887}
15888
15889
15890// Verify that we can clone an object
15891TEST(ObjectClone) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015892 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015893 v8::Isolate* isolate = env->GetIsolate();
15894 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015895
15896 const char* sample =
15897 "var rv = {};" \
15898 "rv.alpha = 'hello';" \
15899 "rv.beta = 123;" \
15900 "rv;";
15901
15902 // Create an object, verify basics.
15903 Local<Value> val = CompileRun(sample);
15904 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010015905 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015906 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15907
15908 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015909 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015910 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15911
15912 // Clone it.
15913 Local<v8::Object> clone = obj->Clone();
15914 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015915 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015916 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15917
15918 // Set a property on the clone, verify each object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015919 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15920 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15921 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015922}
15923
15924
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015925class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
Steve Blocka7e24c12009-10-30 11:49:00 +000015926 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015927 explicit OneByteVectorResource(i::Vector<const char> vector)
Steve Blocka7e24c12009-10-30 11:49:00 +000015928 : data_(vector) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015929 virtual ~OneByteVectorResource() {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015930 virtual size_t length() const { return data_.length(); }
15931 virtual const char* data() const { return data_.start(); }
15932 private:
15933 i::Vector<const char> data_;
15934};
15935
15936
15937class UC16VectorResource : public v8::String::ExternalStringResource {
15938 public:
15939 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15940 : data_(vector) {}
15941 virtual ~UC16VectorResource() {}
15942 virtual size_t length() const { return data_.length(); }
15943 virtual const i::uc16* data() const { return data_.start(); }
15944 private:
15945 i::Vector<const i::uc16> data_;
15946};
15947
15948
15949static void MorphAString(i::String* string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015950 OneByteVectorResource* one_byte_resource,
Steve Blocka7e24c12009-10-30 11:49:00 +000015951 UC16VectorResource* uc16_resource) {
15952 CHECK(i::StringShape(string).IsExternal());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015953 if (string->IsOneByteRepresentation()) {
15954 // Check old map is not internalized or long.
15955 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000015956 // Morph external string to be TwoByte string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015957 string->set_map(CcTest::heap()->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000015958 i::ExternalTwoByteString* morphed =
15959 i::ExternalTwoByteString::cast(string);
15960 morphed->set_resource(uc16_resource);
15961 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015962 // Check old map is not internalized or long.
15963 CHECK(string->map() == CcTest::heap()->external_string_map());
15964 // Morph external string to be one-byte string.
15965 string->set_map(CcTest::heap()->external_one_byte_string_map());
15966 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15967 morphed->set_resource(one_byte_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000015968 }
15969}
15970
15971
15972// Test that we can still flatten a string if the components it is built up
15973// from have been turned into 16 bit strings in the mean time.
15974THREADED_TEST(MorphCompositeStringTest) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015975 char utf_buffer[129];
Steve Blocka7e24c12009-10-30 11:49:00 +000015976 const char* c_string = "Now is the time for all good men"
15977 " to come to the aid of the party";
15978 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15979 {
Steve Blocka7e24c12009-10-30 11:49:00 +000015980 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015981 i::Factory* factory = CcTest::i_isolate()->factory();
15982 v8::HandleScope scope(env->GetIsolate());
15983 OneByteVectorResource one_byte_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000015984 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015985 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000015986 i::Vector<const uint16_t>(two_byte_string,
15987 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015988
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015989 Local<String> lhs(
15990 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15991 &one_byte_resource).ToHandleChecked()));
15992 Local<String> rhs(
15993 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15994 &one_byte_resource).ToHandleChecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015995
15996 env->Global()->Set(v8_str("lhs"), lhs);
15997 env->Global()->Set(v8_str("rhs"), rhs);
15998
15999 CompileRun(
16000 "var cons = lhs + rhs;"
16001 "var slice = lhs.substring(1, lhs.length - 1);"
16002 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
16003
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016004 CHECK(lhs->IsOneByte());
16005 CHECK(rhs->IsOneByte());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016006
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016007 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
16008 &uc16_resource);
16009 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
16010 &uc16_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000016011
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016012 // This should UTF-8 without flattening, since everything is ASCII.
16013 Handle<String> cons = v8_compile("cons")->Run().As<String>();
16014 CHECK_EQ(128, cons->Utf8Length());
16015 int nchars = -1;
16016 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
16017 CHECK_EQ(128, nchars);
16018 CHECK_EQ(0, strcmp(
16019 utf_buffer,
16020 "Now is the time for all good men to come to the aid of the party"
16021 "Now is the time for all good men to come to the aid of the party"));
16022
Steve Blocka7e24c12009-10-30 11:49:00 +000016023 // Now do some stuff to make sure the strings are flattened, etc.
16024 CompileRun(
16025 "/[^a-z]/.test(cons);"
16026 "/[^a-z]/.test(slice);"
16027 "/[^a-z]/.test(slice_on_cons);");
16028 const char* expected_cons =
16029 "Now is the time for all good men to come to the aid of the party"
16030 "Now is the time for all good men to come to the aid of the party";
16031 const char* expected_slice =
16032 "ow is the time for all good men to come to the aid of the part";
16033 const char* expected_slice_on_cons =
16034 "ow is the time for all good men to come to the aid of the party"
16035 "Now is the time for all good men to come to the aid of the part";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016036 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
Steve Blocka7e24c12009-10-30 11:49:00 +000016037 env->Global()->Get(v8_str("cons")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016038 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
Steve Blocka7e24c12009-10-30 11:49:00 +000016039 env->Global()->Get(v8_str("slice")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016040 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
Steve Blocka7e24c12009-10-30 11:49:00 +000016041 env->Global()->Get(v8_str("slice_on_cons")));
16042 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010016043 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000016044}
16045
16046
16047TEST(CompileExternalTwoByteSource) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016048 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016049 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000016050
16051 // This is a very short list of sources, which currently is to check for a
16052 // regression caused by r2703.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016053 const char* one_byte_sources[] = {
16054 "0.5",
16055 "-0.5", // This mainly testes PushBack in the Scanner.
16056 "--0.5", // This mainly testes PushBack in the Scanner.
16057 NULL};
Steve Blocka7e24c12009-10-30 11:49:00 +000016058
16059 // Compile the sources as external two byte strings.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016060 for (int i = 0; one_byte_sources[i] != NULL; i++) {
16061 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
16062 TestResource* uc16_resource = new TestResource(two_byte_string);
16063 v8::Local<v8::String> source =
16064 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000016065 v8::Script::Compile(source);
16066 }
16067}
16068
16069
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016070#ifndef V8_INTERPRETED_REGEXP
16071
16072struct RegExpInterruptionData {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016073 v8::base::Atomic32 loop_count;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016074 UC16VectorResource* string_resource;
16075 v8::Persistent<v8::String> string;
16076} regexp_interruption_data;
16077
16078
16079class RegExpInterruptionThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +000016080 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016081 explicit RegExpInterruptionThread(v8::Isolate* isolate)
16082 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000016083
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016084 virtual void Run() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016085 for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
16086 v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
16087 v8::base::NoBarrier_AtomicIncrement(
16088 &regexp_interruption_data.loop_count, 1)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016089 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
16090 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
Steve Blocka7e24c12009-10-30 11:49:00 +000016091 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016092 v8::base::OS::Sleep(50); // Wait a bit before terminating.
16093 v8::V8::TerminateExecution(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +000016094 }
Steve Blocka7e24c12009-10-30 11:49:00 +000016095
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016096 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016097 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +000016098};
16099
16100
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016101void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016102 if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
16103 return;
16104 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016105 v8::HandleScope scope(CcTest::isolate());
16106 v8::Local<v8::String> string = v8::Local<v8::String>::New(
16107 CcTest::isolate(), regexp_interruption_data.string);
16108 string->MakeExternal(regexp_interruption_data.string_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000016109}
16110
16111
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016112// Test that RegExp execution can be interrupted. Specifically, we test
16113// * interrupting with GC
16114// * turn the subject string from one-byte internal to two-byte external string
16115// * force termination
16116TEST(RegExpInterruption) {
16117 v8::HandleScope scope(CcTest::isolate());
16118 LocalContext env;
16119
16120 RegExpInterruptionThread timeout_thread(CcTest::isolate());
16121
16122 v8::V8::AddGCPrologueCallback(RunBeforeGC);
16123 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
16124 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
16125 v8::Local<v8::String> string = v8_str(one_byte_content);
16126
16127 CcTest::global()->Set(v8_str("a"), string);
16128 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
16129 regexp_interruption_data.string_resource = new UC16VectorResource(
16130 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
16131
16132 v8::TryCatch try_catch;
16133 timeout_thread.Start();
16134
16135 CompileRun("/((a*)*)*b/.exec(a)");
16136 CHECK(try_catch.HasTerminated());
16137
16138 timeout_thread.Join();
16139
16140 regexp_interruption_data.string.Reset();
16141 i::DeleteArray(uc16_content);
16142}
16143
16144#endif // V8_INTERPRETED_REGEXP
16145
16146
16147// Test that we cannot set a property on the global object if there
Steve Blocka7e24c12009-10-30 11:49:00 +000016148// is a read-only property in the prototype chain.
16149TEST(ReadOnlyPropertyInGlobalProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016150 v8::Isolate* isolate = CcTest::isolate();
16151 v8::HandleScope scope(isolate);
16152 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016153 LocalContext context(0, templ);
16154 v8::Handle<v8::Object> global = context->Global();
16155 v8::Handle<v8::Object> global_proto =
16156 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016157 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
16158 v8::ReadOnly);
16159 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
16160 v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +000016161 // Check without 'eval' or 'with'.
16162 v8::Handle<v8::Value> res =
16163 CompileRun("function f() { x = 42; return x; }; f()");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016164 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000016165 // Check with 'eval'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016166 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
16167 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000016168 // Check with 'with'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016169 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
16170 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000016171}
16172
16173static int force_set_set_count = 0;
16174static int force_set_get_count = 0;
16175bool pass_on_get = false;
16176
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016177static void ForceSetGetter(v8::Local<v8::String> name,
16178 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016179 force_set_get_count++;
16180 if (pass_on_get) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016181 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000016182 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016183 info.GetReturnValue().Set(3);
Steve Blocka7e24c12009-10-30 11:49:00 +000016184}
16185
16186static void ForceSetSetter(v8::Local<v8::String> name,
16187 v8::Local<v8::Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016188 const v8::PropertyCallbackInfo<void>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016189 force_set_set_count++;
16190}
16191
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016192static void ForceSetInterceptGetter(
16193 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16194 CHECK(name->IsString());
16195 ForceSetGetter(Local<String>::Cast(name), info);
16196}
16197
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016198static void ForceSetInterceptSetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016199 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016200 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016201 force_set_set_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016202 info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000016203}
16204
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016205
Steve Blocka7e24c12009-10-30 11:49:00 +000016206TEST(ForceSet) {
16207 force_set_get_count = 0;
16208 force_set_set_count = 0;
16209 pass_on_get = false;
16210
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016211 v8::Isolate* isolate = CcTest::isolate();
16212 v8::HandleScope scope(isolate);
16213 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16214 v8::Handle<v8::String> access_property =
16215 v8::String::NewFromUtf8(isolate, "a");
Steve Blocka7e24c12009-10-30 11:49:00 +000016216 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
16217 LocalContext context(NULL, templ);
16218 v8::Handle<v8::Object> global = context->Global();
16219
16220 // Ordinary properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016221 v8::Handle<v8::String> simple_property =
16222 v8::String::NewFromUtf8(isolate, "p");
16223 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +000016224 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16225 // This should fail because the property is read-only
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016226 global->Set(simple_property, v8::Int32::New(isolate, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +000016227 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16228 // This should succeed even though the property is read-only
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016229 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +000016230 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
16231
16232 // Accessors
16233 CHECK_EQ(0, force_set_set_count);
16234 CHECK_EQ(0, force_set_get_count);
16235 CHECK_EQ(3, global->Get(access_property)->Int32Value());
16236 // CHECK_EQ the property shouldn't override it, just call the setter
16237 // which in this case does nothing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016238 global->Set(access_property, v8::Int32::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000016239 CHECK_EQ(3, global->Get(access_property)->Int32Value());
16240 CHECK_EQ(1, force_set_set_count);
16241 CHECK_EQ(2, force_set_get_count);
16242 // Forcing the property to be set should override the accessor without
16243 // calling it
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016244 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000016245 CHECK_EQ(8, global->Get(access_property)->Int32Value());
16246 CHECK_EQ(1, force_set_set_count);
16247 CHECK_EQ(2, force_set_get_count);
16248}
16249
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016250
Steve Blocka7e24c12009-10-30 11:49:00 +000016251TEST(ForceSetWithInterceptor) {
16252 force_set_get_count = 0;
16253 force_set_set_count = 0;
16254 pass_on_get = false;
16255
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016256 v8::Isolate* isolate = CcTest::isolate();
16257 v8::HandleScope scope(isolate);
16258 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016259 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16260 ForceSetInterceptGetter, ForceSetInterceptSetter));
Steve Blocka7e24c12009-10-30 11:49:00 +000016261 LocalContext context(NULL, templ);
16262 v8::Handle<v8::Object> global = context->Global();
16263
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016264 v8::Handle<v8::String> some_property =
16265 v8::String::NewFromUtf8(isolate, "a");
Steve Blocka7e24c12009-10-30 11:49:00 +000016266 CHECK_EQ(0, force_set_set_count);
16267 CHECK_EQ(0, force_set_get_count);
16268 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16269 // Setting the property shouldn't override it, just call the setter
16270 // which in this case does nothing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016271 global->Set(some_property, v8::Int32::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000016272 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16273 CHECK_EQ(1, force_set_set_count);
16274 CHECK_EQ(2, force_set_get_count);
16275 // Getting the property when the interceptor returns an empty handle
16276 // should yield undefined, since the property isn't present on the
16277 // object itself yet.
16278 pass_on_get = true;
16279 CHECK(global->Get(some_property)->IsUndefined());
16280 CHECK_EQ(1, force_set_set_count);
16281 CHECK_EQ(3, force_set_get_count);
16282 // Forcing the property to be set should cause the value to be
16283 // set locally without calling the interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016284 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000016285 CHECK_EQ(8, global->Get(some_property)->Int32Value());
16286 CHECK_EQ(1, force_set_set_count);
16287 CHECK_EQ(4, force_set_get_count);
16288 // Reenabling the interceptor should cause it to take precedence over
16289 // the property
16290 pass_on_get = false;
16291 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16292 CHECK_EQ(1, force_set_set_count);
16293 CHECK_EQ(5, force_set_get_count);
16294 // The interceptor should also work for other properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016295 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
16296 ->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016297 CHECK_EQ(1, force_set_set_count);
16298 CHECK_EQ(6, force_set_get_count);
16299}
16300
16301
16302THREADED_TEST(ForceDelete) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016303 v8::Isolate* isolate = CcTest::isolate();
16304 v8::HandleScope scope(isolate);
16305 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016306 LocalContext context(NULL, templ);
16307 v8::Handle<v8::Object> global = context->Global();
16308
16309 // Ordinary properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016310 v8::Handle<v8::String> simple_property =
16311 v8::String::NewFromUtf8(isolate, "p");
16312 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +000016313 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16314 // This should fail because the property is dont-delete.
16315 CHECK(!global->Delete(simple_property));
16316 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16317 // This should succeed even though the property is dont-delete.
16318 CHECK(global->ForceDelete(simple_property));
16319 CHECK(global->Get(simple_property)->IsUndefined());
16320}
16321
16322
16323static int force_delete_interceptor_count = 0;
16324static bool pass_on_delete = false;
16325
16326
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016327static void ForceDeleteDeleter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016328 v8::Local<v8::Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016329 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016330 force_delete_interceptor_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016331 if (pass_on_delete) return;
16332 info.GetReturnValue().Set(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000016333}
16334
16335
16336THREADED_TEST(ForceDeleteWithInterceptor) {
16337 force_delete_interceptor_count = 0;
16338 pass_on_delete = false;
16339
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016340 v8::Isolate* isolate = CcTest::isolate();
16341 v8::HandleScope scope(isolate);
16342 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016343 templ->SetHandler(
16344 v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
Steve Blocka7e24c12009-10-30 11:49:00 +000016345 LocalContext context(NULL, templ);
16346 v8::Handle<v8::Object> global = context->Global();
16347
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016348 v8::Handle<v8::String> some_property =
16349 v8::String::NewFromUtf8(isolate, "a");
16350 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
16351 v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +000016352
16353 // Deleting a property should get intercepted and nothing should
16354 // happen.
16355 CHECK_EQ(0, force_delete_interceptor_count);
16356 CHECK(global->Delete(some_property));
16357 CHECK_EQ(1, force_delete_interceptor_count);
16358 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16359 // Deleting the property when the interceptor returns an empty
16360 // handle should not delete the property since it is DontDelete.
16361 pass_on_delete = true;
16362 CHECK(!global->Delete(some_property));
16363 CHECK_EQ(2, force_delete_interceptor_count);
16364 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16365 // Forcing the property to be deleted should delete the value
16366 // without calling the interceptor.
16367 CHECK(global->ForceDelete(some_property));
16368 CHECK(global->Get(some_property)->IsUndefined());
16369 CHECK_EQ(2, force_delete_interceptor_count);
16370}
16371
16372
16373// Make sure that forcing a delete invalidates any IC stubs, so we
16374// don't read the hole value.
16375THREADED_TEST(ForceDeleteIC) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016376 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016377 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000016378 // Create a DontDelete variable on the global object.
16379 CompileRun("this.__proto__ = { foo: 'horse' };"
16380 "var foo = 'fish';"
16381 "function f() { return foo.length; }");
16382 // Initialize the IC for foo in f.
16383 CompileRun("for (var i = 0; i < 4; i++) f();");
16384 // Make sure the value of foo is correct before the deletion.
16385 CHECK_EQ(4, CompileRun("f()")->Int32Value());
16386 // Force the deletion of foo.
16387 CHECK(context->Global()->ForceDelete(v8_str("foo")));
16388 // Make sure the value for foo is read from the prototype, and that
16389 // we don't get in trouble with reading the deleted cell value
16390 // sentinel.
16391 CHECK_EQ(5, CompileRun("f()")->Int32Value());
16392}
16393
16394
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016395TEST(InlinedFunctionAcrossContexts) {
16396 i::FLAG_allow_natives_syntax = true;
16397 v8::Isolate* isolate = CcTest::isolate();
16398 v8::HandleScope outer_scope(isolate);
16399 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
16400 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
16401 ctx1->Enter();
16402
16403 {
16404 v8::HandleScope inner_scope(CcTest::isolate());
16405 CompileRun("var G = 42; function foo() { return G; }");
16406 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
16407 ctx2->Enter();
16408 ctx2->Global()->Set(v8_str("o"), foo);
16409 v8::Local<v8::Value> res = CompileRun(
16410 "function f() { return o(); }"
16411 "for (var i = 0; i < 10; ++i) f();"
16412 "%OptimizeFunctionOnNextCall(f);"
16413 "f();");
16414 CHECK_EQ(42, res->Int32Value());
16415 ctx2->Exit();
16416 v8::Handle<v8::String> G_property =
16417 v8::String::NewFromUtf8(CcTest::isolate(), "G");
16418 CHECK(ctx1->Global()->ForceDelete(G_property));
16419 ctx2->Enter();
16420 ExpectString(
16421 "(function() {"
16422 " try {"
16423 " return f();"
16424 " } catch(e) {"
16425 " return e.toString();"
16426 " }"
16427 " })()",
16428 "ReferenceError: G is not defined");
16429 ctx2->Exit();
16430 ctx1->Exit();
16431 }
16432}
16433
16434
16435static v8::Local<Context> calling_context0;
16436static v8::Local<Context> calling_context1;
16437static v8::Local<Context> calling_context2;
Steve Blocka7e24c12009-10-30 11:49:00 +000016438
16439
16440// Check that the call to the callback is initiated in
16441// calling_context2, the directly calling context is calling_context1
16442// and the callback itself is in calling_context0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016443static void GetCallingContextCallback(
16444 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016445 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016446 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
16447 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
16448 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
16449 args.GetReturnValue().Set(42);
16450}
16451
16452
16453THREADED_TEST(GetCurrentContextWhenNotInContext) {
16454 i::Isolate* isolate = CcTest::i_isolate();
16455 CHECK(isolate != NULL);
16456 CHECK(isolate->context() == NULL);
16457 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16458 v8::HandleScope scope(v8_isolate);
16459 // The following should not crash, but return an empty handle.
16460 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16461 CHECK(current.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000016462}
16463
16464
16465THREADED_TEST(GetCallingContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016466 v8::Isolate* isolate = CcTest::isolate();
16467 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016468
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016469 Local<Context> calling_context0(Context::New(isolate));
16470 Local<Context> calling_context1(Context::New(isolate));
16471 Local<Context> calling_context2(Context::New(isolate));
16472 ::calling_context0 = calling_context0;
16473 ::calling_context1 = calling_context1;
16474 ::calling_context2 = calling_context2;
Steve Blocka7e24c12009-10-30 11:49:00 +000016475
16476 // Allow cross-domain access.
16477 Local<String> token = v8_str("<security token>");
16478 calling_context0->SetSecurityToken(token);
16479 calling_context1->SetSecurityToken(token);
16480 calling_context2->SetSecurityToken(token);
16481
16482 // Create an object with a C++ callback in context0.
16483 calling_context0->Enter();
16484 Local<v8::FunctionTemplate> callback_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016485 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000016486 calling_context0->Global()->Set(v8_str("callback"),
16487 callback_templ->GetFunction());
16488 calling_context0->Exit();
16489
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016490 // Expose context0 in context1 and set up a function that calls the
Steve Blocka7e24c12009-10-30 11:49:00 +000016491 // callback function.
16492 calling_context1->Enter();
16493 calling_context1->Global()->Set(v8_str("context0"),
16494 calling_context0->Global());
16495 CompileRun("function f() { context0.callback() }");
16496 calling_context1->Exit();
16497
16498 // Expose context1 in context2 and call the callback function in
16499 // context0 indirectly through f in context1.
16500 calling_context2->Enter();
16501 calling_context2->Global()->Set(v8_str("context1"),
16502 calling_context1->Global());
16503 CompileRun("context1.f()");
16504 calling_context2->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016505 ::calling_context0.Clear();
16506 ::calling_context1.Clear();
16507 ::calling_context2.Clear();
Steve Blocka7e24c12009-10-30 11:49:00 +000016508}
16509
16510
16511// Check that a variable declaration with no explicit initialization
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016512// value does shadow an existing property in the prototype chain.
Steve Blocka7e24c12009-10-30 11:49:00 +000016513THREADED_TEST(InitGlobalVarInProtoChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016514 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016515 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000016516 // Introduce a variable in the prototype chain.
16517 CompileRun("__proto__.x = 42");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016518 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
Steve Blocka7e24c12009-10-30 11:49:00 +000016519 CHECK(!result->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016520 CHECK_EQ(43, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016521}
16522
16523
16524// Regression test for issue 398.
16525// If a function is added to an object, creating a constant function
16526// field, and the result is cloned, replacing the constant function on the
16527// original should not affect the clone.
16528// See http://code.google.com/p/v8/issues/detail?id=398
16529THREADED_TEST(ReplaceConstantFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016530 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016531 v8::Isolate* isolate = context->GetIsolate();
16532 v8::HandleScope scope(isolate);
16533 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16534 v8::Handle<v8::FunctionTemplate> func_templ =
16535 v8::FunctionTemplate::New(isolate);
16536 v8::Handle<v8::String> foo_string =
16537 v8::String::NewFromUtf8(isolate, "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +000016538 obj->Set(foo_string, func_templ->GetFunction());
16539 v8::Handle<v8::Object> obj_clone = obj->Clone();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016540 obj_clone->Set(foo_string,
16541 v8::String::NewFromUtf8(isolate, "Hello"));
Steve Blocka7e24c12009-10-30 11:49:00 +000016542 CHECK(!obj->Get(foo_string)->IsUndefined());
16543}
16544
16545
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016546static void CheckElementValue(i::Isolate* isolate,
16547 int expected,
16548 i::Handle<i::Object> obj,
16549 int offset) {
16550 i::Object* element =
16551 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16552 CHECK_EQ(expected, i::Smi::cast(element)->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016553}
16554
16555
16556THREADED_TEST(PixelArray) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016557 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016558 i::Isolate* isolate = CcTest::i_isolate();
16559 i::Factory* factory = isolate->factory();
16560 v8::HandleScope scope(context->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000016561 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000016562 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016563 i::Handle<i::ExternalUint8ClampedArray> pixels =
16564 i::Handle<i::ExternalUint8ClampedArray>::cast(
16565 factory->NewExternalArray(kElementCount,
16566 v8::kExternalUint8ClampedArray,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016567 pixel_data));
16568 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016569 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000016570 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000016571 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000016572 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016573 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000016575 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016576 CHECK_EQ(i % 256, pixels->get_scalar(i));
Steve Blockd0582a62009-12-15 09:54:21 +000016577 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000016578 }
16579
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016580 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000016581 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16582 // Set the elements to be the pixels.
16583 // jsobj->set_elements(*pixels);
16584 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016585 CheckElementValue(isolate, 1, jsobj, 1);
16586 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
Steve Blocka7e24c12009-10-30 11:49:00 +000016587 context->Global()->Set(v8_str("pixels"), obj);
16588 v8::Handle<v8::Value> result = CompileRun("pixels.field");
16589 CHECK_EQ(1503, result->Int32Value());
16590 result = CompileRun("pixels[1]");
16591 CHECK_EQ(1, result->Int32Value());
16592
16593 result = CompileRun("var sum = 0;"
16594 "for (var i = 0; i < 8; i++) {"
16595 " sum += pixels[i] = pixels[i] = -i;"
16596 "}"
16597 "sum;");
16598 CHECK_EQ(-28, result->Int32Value());
16599
16600 result = CompileRun("var sum = 0;"
16601 "for (var i = 0; i < 8; i++) {"
16602 " sum += pixels[i] = pixels[i] = 0;"
16603 "}"
16604 "sum;");
16605 CHECK_EQ(0, result->Int32Value());
16606
16607 result = CompileRun("var sum = 0;"
16608 "for (var i = 0; i < 8; i++) {"
16609 " sum += pixels[i] = pixels[i] = 255;"
16610 "}"
16611 "sum;");
16612 CHECK_EQ(8 * 255, result->Int32Value());
16613
16614 result = CompileRun("var sum = 0;"
16615 "for (var i = 0; i < 8; i++) {"
16616 " sum += pixels[i] = pixels[i] = 256 + i;"
16617 "}"
16618 "sum;");
16619 CHECK_EQ(2076, result->Int32Value());
16620
16621 result = CompileRun("var sum = 0;"
16622 "for (var i = 0; i < 8; i++) {"
16623 " sum += pixels[i] = pixels[i] = i;"
16624 "}"
16625 "sum;");
16626 CHECK_EQ(28, result->Int32Value());
16627
16628 result = CompileRun("var sum = 0;"
16629 "for (var i = 0; i < 8; i++) {"
16630 " sum += pixels[i];"
16631 "}"
16632 "sum;");
16633 CHECK_EQ(28, result->Int32Value());
16634
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016635 i::Handle<i::Smi> value(i::Smi::FromInt(2),
16636 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
Ben Murdoch589d6972011-11-30 16:04:58 +000016637 i::Handle<i::Object> no_failure;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016638 no_failure = i::JSObject::SetElement(
16639 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16640 DCHECK(!no_failure.is_null());
16641 USE(no_failure);
16642 CheckElementValue(isolate, 2, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016643 *value.location() = i::Smi::FromInt(256);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016644 no_failure = i::JSObject::SetElement(
16645 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16646 DCHECK(!no_failure.is_null());
16647 USE(no_failure);
16648 CheckElementValue(isolate, 255, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016649 *value.location() = i::Smi::FromInt(-1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016650 no_failure = i::JSObject::SetElement(
16651 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16652 DCHECK(!no_failure.is_null());
16653 USE(no_failure);
16654 CheckElementValue(isolate, 0, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016655
16656 result = CompileRun("for (var i = 0; i < 8; i++) {"
16657 " pixels[i] = (i * 65) - 109;"
16658 "}"
16659 "pixels[1] + pixels[6];");
16660 CHECK_EQ(255, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016661 CheckElementValue(isolate, 0, jsobj, 0);
16662 CheckElementValue(isolate, 0, jsobj, 1);
16663 CheckElementValue(isolate, 21, jsobj, 2);
16664 CheckElementValue(isolate, 86, jsobj, 3);
16665 CheckElementValue(isolate, 151, jsobj, 4);
16666 CheckElementValue(isolate, 216, jsobj, 5);
16667 CheckElementValue(isolate, 255, jsobj, 6);
16668 CheckElementValue(isolate, 255, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000016669 result = CompileRun("var sum = 0;"
16670 "for (var i = 0; i < 8; i++) {"
16671 " sum += pixels[i];"
16672 "}"
16673 "sum;");
16674 CHECK_EQ(984, result->Int32Value());
16675
16676 result = CompileRun("for (var i = 0; i < 8; i++) {"
16677 " pixels[i] = (i * 1.1);"
16678 "}"
16679 "pixels[1] + pixels[6];");
16680 CHECK_EQ(8, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016681 CheckElementValue(isolate, 0, jsobj, 0);
16682 CheckElementValue(isolate, 1, jsobj, 1);
16683 CheckElementValue(isolate, 2, jsobj, 2);
16684 CheckElementValue(isolate, 3, jsobj, 3);
16685 CheckElementValue(isolate, 4, jsobj, 4);
16686 CheckElementValue(isolate, 6, jsobj, 5);
16687 CheckElementValue(isolate, 7, jsobj, 6);
16688 CheckElementValue(isolate, 8, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000016689
16690 result = CompileRun("for (var i = 0; i < 8; i++) {"
16691 " pixels[7] = undefined;"
16692 "}"
16693 "pixels[7];");
16694 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016695 CheckElementValue(isolate, 0, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000016696
16697 result = CompileRun("for (var i = 0; i < 8; i++) {"
16698 " pixels[6] = '2.3';"
16699 "}"
16700 "pixels[6];");
16701 CHECK_EQ(2, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016702 CheckElementValue(isolate, 2, jsobj, 6);
Steve Blocka7e24c12009-10-30 11:49:00 +000016703
16704 result = CompileRun("for (var i = 0; i < 8; i++) {"
16705 " pixels[5] = NaN;"
16706 "}"
16707 "pixels[5];");
16708 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016709 CheckElementValue(isolate, 0, jsobj, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +000016710
16711 result = CompileRun("for (var i = 0; i < 8; i++) {"
16712 " pixels[8] = Infinity;"
16713 "}"
16714 "pixels[8];");
16715 CHECK_EQ(255, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016716 CheckElementValue(isolate, 255, jsobj, 8);
Steve Blocka7e24c12009-10-30 11:49:00 +000016717
16718 result = CompileRun("for (var i = 0; i < 8; i++) {"
16719 " pixels[9] = -Infinity;"
16720 "}"
16721 "pixels[9];");
16722 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016723 CheckElementValue(isolate, 0, jsobj, 9);
Steve Blocka7e24c12009-10-30 11:49:00 +000016724
16725 result = CompileRun("pixels[3] = 33;"
16726 "delete pixels[3];"
16727 "pixels[3];");
16728 CHECK_EQ(33, result->Int32Value());
16729
16730 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16731 "pixels[2] = 12; pixels[3] = 13;"
16732 "pixels.__defineGetter__('2',"
16733 "function() { return 120; });"
16734 "pixels[2];");
16735 CHECK_EQ(12, result->Int32Value());
16736
16737 result = CompileRun("var js_array = new Array(40);"
16738 "js_array[0] = 77;"
16739 "js_array;");
16740 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16741
16742 result = CompileRun("pixels[1] = 23;"
16743 "pixels.__proto__ = [];"
16744 "js_array.__proto__ = pixels;"
16745 "js_array.concat(pixels);");
16746 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16747 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16748
16749 result = CompileRun("pixels[1] = 23;");
16750 CHECK_EQ(23, result->Int32Value());
16751
Steve Blockd0582a62009-12-15 09:54:21 +000016752 // Test for index greater than 255. Regression test for:
16753 // http://code.google.com/p/chromium/issues/detail?id=26337.
16754 result = CompileRun("pixels[256] = 255;");
16755 CHECK_EQ(255, result->Int32Value());
16756 result = CompileRun("var i = 0;"
16757 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16758 "i");
16759 CHECK_EQ(255, result->Int32Value());
16760
Steve Block1e0659c2011-05-24 12:43:12 +010016761 // Make sure that pixel array ICs recognize when a non-pixel array
16762 // is passed to it.
16763 result = CompileRun("function pa_load(p) {"
16764 " var sum = 0;"
16765 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16766 " return sum;"
16767 "}"
16768 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16769 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16770 "just_ints = new Object();"
16771 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16772 "for (var i = 0; i < 10; ++i) {"
16773 " result = pa_load(just_ints);"
16774 "}"
16775 "result");
16776 CHECK_EQ(32640, result->Int32Value());
16777
16778 // Make sure that pixel array ICs recognize out-of-bound accesses.
16779 result = CompileRun("function pa_load(p, start) {"
16780 " var sum = 0;"
16781 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16782 " return sum;"
16783 "}"
16784 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16785 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16786 "for (var i = 0; i < 10; ++i) {"
16787 " result = pa_load(pixels,-10);"
16788 "}"
16789 "result");
16790 CHECK_EQ(0, result->Int32Value());
16791
16792 // Make sure that generic ICs properly handles a pixel array.
16793 result = CompileRun("function pa_load(p) {"
16794 " var sum = 0;"
16795 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16796 " return sum;"
16797 "}"
16798 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16799 "just_ints = new Object();"
16800 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16801 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16802 "for (var i = 0; i < 10; ++i) {"
16803 " result = pa_load(pixels);"
16804 "}"
16805 "result");
16806 CHECK_EQ(32640, result->Int32Value());
16807
16808 // Make sure that generic load ICs recognize out-of-bound accesses in
16809 // pixel arrays.
16810 result = CompileRun("function pa_load(p, start) {"
16811 " var sum = 0;"
16812 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16813 " return sum;"
16814 "}"
16815 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16816 "just_ints = new Object();"
16817 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16818 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16819 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16820 "for (var i = 0; i < 10; ++i) {"
16821 " result = pa_load(pixels,-10);"
16822 "}"
16823 "result");
16824 CHECK_EQ(0, result->Int32Value());
16825
16826 // Make sure that generic ICs properly handles other types than pixel
16827 // arrays (that the inlined fast pixel array test leaves the right information
16828 // in the right registers).
16829 result = CompileRun("function pa_load(p) {"
16830 " var sum = 0;"
16831 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16832 " return sum;"
16833 "}"
16834 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16835 "just_ints = new Object();"
16836 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16837 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16838 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16839 "sparse_array = new Object();"
16840 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16841 "sparse_array[1000000] = 3;"
16842 "for (var i = 0; i < 10; ++i) {"
16843 " result = pa_load(sparse_array);"
16844 "}"
16845 "result");
16846 CHECK_EQ(32640, result->Int32Value());
16847
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016848 // Make sure that pixel array store ICs clamp values correctly.
16849 result = CompileRun("function pa_store(p) {"
16850 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16851 "}"
16852 "pa_store(pixels);"
16853 "var sum = 0;"
16854 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16855 "sum");
16856 CHECK_EQ(48896, result->Int32Value());
16857
16858 // Make sure that pixel array stores correctly handle accesses outside
16859 // of the pixel array..
16860 result = CompileRun("function pa_store(p,start) {"
16861 " for (var j = 0; j < 256; j++) {"
16862 " p[j+start] = j * 2;"
16863 " }"
16864 "}"
16865 "pa_store(pixels,0);"
16866 "pa_store(pixels,-128);"
16867 "var sum = 0;"
16868 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16869 "sum");
16870 CHECK_EQ(65280, result->Int32Value());
16871
16872 // Make sure that the generic store stub correctly handle accesses outside
16873 // of the pixel array..
16874 result = CompileRun("function pa_store(p,start) {"
16875 " for (var j = 0; j < 256; j++) {"
16876 " p[j+start] = j * 2;"
16877 " }"
16878 "}"
16879 "pa_store(pixels,0);"
16880 "just_ints = new Object();"
16881 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16882 "pa_store(just_ints, 0);"
16883 "pa_store(pixels,-128);"
16884 "var sum = 0;"
16885 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16886 "sum");
16887 CHECK_EQ(65280, result->Int32Value());
16888
16889 // Make sure that the generic keyed store stub clamps pixel array values
16890 // correctly.
16891 result = CompileRun("function pa_store(p) {"
16892 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16893 "}"
16894 "pa_store(pixels);"
16895 "just_ints = new Object();"
16896 "pa_store(just_ints);"
16897 "pa_store(pixels);"
16898 "var sum = 0;"
16899 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16900 "sum");
16901 CHECK_EQ(48896, result->Int32Value());
16902
16903 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010016904 result = CompileRun("function pa_load(p) {"
16905 " var sum = 0;"
16906 " for (var i=0; i<256; ++i) {"
16907 " sum += p[i];"
16908 " }"
16909 " return sum; "
16910 "}"
16911 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010016912 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010016913 " result = pa_load(pixels);"
16914 "}"
16915 "result");
16916 CHECK_EQ(32640, result->Int32Value());
16917
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016918 // Make sure that pixel array stores are optimized by crankshaft.
16919 result = CompileRun("function pa_init(p) {"
16920 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16921 "}"
16922 "function pa_load(p) {"
16923 " var sum = 0;"
16924 " for (var i=0; i<256; ++i) {"
16925 " sum += p[i];"
16926 " }"
16927 " return sum; "
16928 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010016929 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016930 " pa_init(pixels);"
16931 "}"
16932 "result = pa_load(pixels);"
16933 "result");
16934 CHECK_EQ(32640, result->Int32Value());
16935
Steve Blocka7e24c12009-10-30 11:49:00 +000016936 free(pixel_data);
16937}
16938
16939
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016940THREADED_TEST(PixelArrayInfo) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016941 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016942 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016943 for (int size = 0; size < 100; size += 10) {
16944 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016945 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016946 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16947 CHECK(obj->HasIndexedPropertiesInPixelData());
16948 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16949 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16950 free(pixel_data);
16951 }
16952}
16953
16954
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016955static void NotHandledIndexedPropertyGetter(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016956 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016957 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016958 ApiTestFuzzer::Fuzz();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016959}
16960
16961
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016962static void NotHandledIndexedPropertySetter(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016963 uint32_t index,
16964 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016965 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016966 ApiTestFuzzer::Fuzz();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016967}
16968
16969
16970THREADED_TEST(PixelArrayWithInterceptor) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016971 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016972 i::Factory* factory = CcTest::i_isolate()->factory();
16973 v8::Isolate* isolate = context->GetIsolate();
16974 v8::HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016975 const int kElementCount = 260;
16976 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016977 i::Handle<i::ExternalUint8ClampedArray> pixels =
16978 i::Handle<i::ExternalUint8ClampedArray>::cast(
16979 factory->NewExternalArray(kElementCount,
16980 v8::kExternalUint8ClampedArray,
Steve Block44f0eee2011-05-26 01:26:41 +010016981 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016982 for (int i = 0; i < kElementCount; i++) {
16983 pixels->set(i, i % 256);
16984 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016985 v8::Handle<v8::ObjectTemplate> templ =
16986 v8::ObjectTemplate::New(context->GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016987 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
16988 NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016989 v8::Handle<v8::Object> obj = templ->NewInstance();
16990 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16991 context->Global()->Set(v8_str("pixels"), obj);
16992 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16993 CHECK_EQ(1, result->Int32Value());
16994 result = CompileRun("var sum = 0;"
16995 "for (var i = 0; i < 8; i++) {"
16996 " sum += pixels[i] = pixels[i] = -i;"
16997 "}"
16998 "sum;");
16999 CHECK_EQ(-28, result->Int32Value());
17000 result = CompileRun("pixels.hasOwnProperty('1')");
17001 CHECK(result->BooleanValue());
17002 free(pixel_data);
17003}
17004
17005
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017006static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
17007 switch (array_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017008 case v8::kExternalInt8Array:
17009 case v8::kExternalUint8Array:
17010 case v8::kExternalUint8ClampedArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017011 return 1;
17012 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017013 case v8::kExternalInt16Array:
17014 case v8::kExternalUint16Array:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017015 return 2;
17016 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017017 case v8::kExternalInt32Array:
17018 case v8::kExternalUint32Array:
17019 case v8::kExternalFloat32Array:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017020 return 4;
17021 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017022 case v8::kExternalFloat64Array:
Ben Murdoch257744e2011-11-30 15:57:28 +000017023 return 8;
17024 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017025 default:
17026 UNREACHABLE();
17027 return -1;
17028 }
17029 UNREACHABLE();
17030 return -1;
17031}
17032
17033
Steve Block3ce2e202009-11-05 08:53:23 +000017034template <class ExternalArrayClass, class ElementType>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017035static void ObjectWithExternalArrayTestHelper(
17036 Handle<Context> context,
17037 v8::Handle<Object> obj,
17038 int element_count,
17039 v8::ExternalArrayType array_type,
17040 int64_t low, int64_t high) {
Steve Block3ce2e202009-11-05 08:53:23 +000017041 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017042 i::Isolate* isolate = jsobj->GetIsolate();
17043 obj->Set(v8_str("field"),
17044 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
Steve Block3ce2e202009-11-05 08:53:23 +000017045 context->Global()->Set(v8_str("ext_array"), obj);
17046 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
17047 CHECK_EQ(1503, result->Int32Value());
17048 result = CompileRun("ext_array[1]");
17049 CHECK_EQ(1, result->Int32Value());
17050
Steve Block3ce2e202009-11-05 08:53:23 +000017051 // Check assigned smis
17052 result = CompileRun("for (var i = 0; i < 8; i++) {"
17053 " ext_array[i] = i;"
17054 "}"
17055 "var sum = 0;"
17056 "for (var i = 0; i < 8; i++) {"
17057 " sum += ext_array[i];"
17058 "}"
17059 "sum;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017060
Steve Block3ce2e202009-11-05 08:53:23 +000017061 CHECK_EQ(28, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017062 // Check pass through of assigned smis
17063 result = CompileRun("var sum = 0;"
17064 "for (var i = 0; i < 8; i++) {"
17065 " sum += ext_array[i] = ext_array[i] = -i;"
17066 "}"
17067 "sum;");
17068 CHECK_EQ(-28, result->Int32Value());
17069
Steve Block3ce2e202009-11-05 08:53:23 +000017070
17071 // Check assigned smis in reverse order
17072 result = CompileRun("for (var i = 8; --i >= 0; ) {"
17073 " ext_array[i] = i;"
17074 "}"
17075 "var sum = 0;"
17076 "for (var i = 0; i < 8; i++) {"
17077 " sum += ext_array[i];"
17078 "}"
17079 "sum;");
17080 CHECK_EQ(28, result->Int32Value());
17081
17082 // Check pass through of assigned HeapNumbers
17083 result = CompileRun("var sum = 0;"
17084 "for (var i = 0; i < 16; i+=2) {"
17085 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
17086 "}"
17087 "sum;");
17088 CHECK_EQ(-28, result->Int32Value());
17089
17090 // Check assigned HeapNumbers
17091 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
17092 " ext_array[i] = (i * 0.5);"
17093 "}"
17094 "var sum = 0;"
17095 "for (var i = 0; i < 16; i+=2) {"
17096 " sum += ext_array[i];"
17097 "}"
17098 "sum;");
17099 CHECK_EQ(28, result->Int32Value());
17100
17101 // Check assigned HeapNumbers in reverse order
17102 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
17103 " ext_array[i] = (i * 0.5);"
17104 "}"
17105 "var sum = 0;"
17106 "for (var i = 0; i < 16; i+=2) {"
17107 " sum += ext_array[i];"
17108 "}"
17109 "sum;");
17110 CHECK_EQ(28, result->Int32Value());
17111
17112 i::ScopedVector<char> test_buf(1024);
17113
17114 // Check legal boundary conditions.
17115 // The repeated loads and stores ensure the ICs are exercised.
17116 const char* boundary_program =
17117 "var res = 0;"
17118 "for (var i = 0; i < 16; i++) {"
17119 " ext_array[i] = %lld;"
17120 " if (i > 8) {"
17121 " res = ext_array[i];"
17122 " }"
17123 "}"
17124 "res;";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017125 i::SNPrintF(test_buf,
17126 boundary_program,
17127 low);
Steve Block3ce2e202009-11-05 08:53:23 +000017128 result = CompileRun(test_buf.start());
17129 CHECK_EQ(low, result->IntegerValue());
17130
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017131 i::SNPrintF(test_buf,
17132 boundary_program,
17133 high);
Steve Block3ce2e202009-11-05 08:53:23 +000017134 result = CompileRun(test_buf.start());
17135 CHECK_EQ(high, result->IntegerValue());
17136
17137 // Check misprediction of type in IC.
17138 result = CompileRun("var tmp_array = ext_array;"
17139 "var sum = 0;"
17140 "for (var i = 0; i < 8; i++) {"
17141 " tmp_array[i] = i;"
17142 " sum += tmp_array[i];"
17143 " if (i == 4) {"
17144 " tmp_array = {};"
17145 " }"
17146 "}"
17147 "sum;");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017148 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017149 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000017150 CHECK_EQ(28, result->Int32Value());
17151
17152 // Make sure out-of-range loads do not throw.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017153 i::SNPrintF(test_buf,
17154 "var caught_exception = false;"
17155 "try {"
17156 " ext_array[%d];"
17157 "} catch (e) {"
17158 " caught_exception = true;"
17159 "}"
17160 "caught_exception;",
17161 element_count);
Steve Block3ce2e202009-11-05 08:53:23 +000017162 result = CompileRun(test_buf.start());
17163 CHECK_EQ(false, result->BooleanValue());
17164
17165 // Make sure out-of-range stores do not throw.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017166 i::SNPrintF(test_buf,
17167 "var caught_exception = false;"
17168 "try {"
17169 " ext_array[%d] = 1;"
17170 "} catch (e) {"
17171 " caught_exception = true;"
17172 "}"
17173 "caught_exception;",
17174 element_count);
Steve Block3ce2e202009-11-05 08:53:23 +000017175 result = CompileRun(test_buf.start());
17176 CHECK_EQ(false, result->BooleanValue());
17177
17178 // Check other boundary conditions, values and operations.
17179 result = CompileRun("for (var i = 0; i < 8; i++) {"
17180 " ext_array[7] = undefined;"
17181 "}"
17182 "ext_array[7];");
17183 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017184 if (array_type == v8::kExternalFloat64Array ||
17185 array_type == v8::kExternalFloat32Array) {
17186 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
17187 static_cast<int>(
17188 i::Object::GetElement(
17189 isolate, jsobj, 7).ToHandleChecked()->Number()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017190 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017191 CheckElementValue(isolate, 0, jsobj, 7);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017192 }
Steve Block3ce2e202009-11-05 08:53:23 +000017193
17194 result = CompileRun("for (var i = 0; i < 8; i++) {"
17195 " ext_array[6] = '2.3';"
17196 "}"
17197 "ext_array[6];");
17198 CHECK_EQ(2, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017199 CHECK_EQ(2,
17200 static_cast<int>(
17201 i::Object::GetElement(
17202 isolate, jsobj, 6).ToHandleChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000017203
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017204 if (array_type != v8::kExternalFloat32Array &&
17205 array_type != v8::kExternalFloat64Array) {
Steve Block3ce2e202009-11-05 08:53:23 +000017206 // Though the specification doesn't state it, be explicit about
17207 // converting NaNs and +/-Infinity to zero.
17208 result = CompileRun("for (var i = 0; i < 8; i++) {"
17209 " ext_array[i] = 5;"
17210 "}"
17211 "for (var i = 0; i < 8; i++) {"
17212 " ext_array[i] = NaN;"
17213 "}"
17214 "ext_array[5];");
17215 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017216 CheckElementValue(isolate, 0, jsobj, 5);
Steve Block3ce2e202009-11-05 08:53:23 +000017217
17218 result = CompileRun("for (var i = 0; i < 8; i++) {"
17219 " ext_array[i] = 5;"
17220 "}"
17221 "for (var i = 0; i < 8; i++) {"
17222 " ext_array[i] = Infinity;"
17223 "}"
17224 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010017225 int expected_value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017226 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
Steve Block44f0eee2011-05-26 01:26:41 +010017227 CHECK_EQ(expected_value, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017228 CheckElementValue(isolate, expected_value, jsobj, 5);
Steve Block3ce2e202009-11-05 08:53:23 +000017229
17230 result = CompileRun("for (var i = 0; i < 8; i++) {"
17231 " ext_array[i] = 5;"
17232 "}"
17233 "for (var i = 0; i < 8; i++) {"
17234 " ext_array[i] = -Infinity;"
17235 "}"
17236 "ext_array[5];");
17237 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017238 CheckElementValue(isolate, 0, jsobj, 5);
Steve Block1e0659c2011-05-24 12:43:12 +010017239
17240 // Check truncation behavior of integral arrays.
17241 const char* unsigned_data =
17242 "var source_data = [0.6, 10.6];"
17243 "var expected_results = [0, 10];";
17244 const char* signed_data =
17245 "var source_data = [0.6, 10.6, -0.6, -10.6];"
17246 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010017247 const char* pixel_data =
17248 "var source_data = [0.6, 10.6];"
17249 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010017250 bool is_unsigned =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017251 (array_type == v8::kExternalUint8Array ||
17252 array_type == v8::kExternalUint16Array ||
17253 array_type == v8::kExternalUint32Array);
17254 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
Steve Block1e0659c2011-05-24 12:43:12 +010017255
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017256 i::SNPrintF(test_buf,
17257 "%s"
17258 "var all_passed = true;"
17259 "for (var i = 0; i < source_data.length; i++) {"
17260 " for (var j = 0; j < 8; j++) {"
17261 " ext_array[j] = source_data[i];"
17262 " }"
17263 " all_passed = all_passed &&"
17264 " (ext_array[5] == expected_results[i]);"
17265 "}"
17266 "all_passed;",
17267 (is_unsigned ?
17268 unsigned_data :
17269 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010017270 result = CompileRun(test_buf.start());
17271 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000017272 }
17273
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017274 i::Handle<ExternalArrayClass> array(
17275 ExternalArrayClass::cast(jsobj->elements()));
17276 for (int i = 0; i < element_count; i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010017277 array->set(i, static_cast<ElementType>(i));
17278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017279
Ben Murdoch8b112d22011-06-08 16:22:53 +010017280 // Test complex assignments
17281 result = CompileRun("function ee_op_test_complex_func(sum) {"
17282 " for (var i = 0; i < 40; ++i) {"
17283 " sum += (ext_array[i] += 1);"
17284 " sum += (ext_array[i] -= 1);"
17285 " } "
17286 " return sum;"
17287 "}"
17288 "sum=0;"
17289 "for (var i=0;i<10000;++i) {"
17290 " sum=ee_op_test_complex_func(sum);"
17291 "}"
17292 "sum;");
17293 CHECK_EQ(16000000, result->Int32Value());
17294
17295 // Test count operations
17296 result = CompileRun("function ee_op_test_count_func(sum) {"
17297 " for (var i = 0; i < 40; ++i) {"
17298 " sum += (++ext_array[i]);"
17299 " sum += (--ext_array[i]);"
17300 " } "
17301 " return sum;"
17302 "}"
17303 "sum=0;"
17304 "for (var i=0;i<10000;++i) {"
17305 " sum=ee_op_test_count_func(sum);"
17306 "}"
17307 "sum;");
17308 CHECK_EQ(16000000, result->Int32Value());
17309
Steve Block3ce2e202009-11-05 08:53:23 +000017310 result = CompileRun("ext_array[3] = 33;"
17311 "delete ext_array[3];"
17312 "ext_array[3];");
17313 CHECK_EQ(33, result->Int32Value());
17314
17315 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
17316 "ext_array[2] = 12; ext_array[3] = 13;"
17317 "ext_array.__defineGetter__('2',"
17318 "function() { return 120; });"
17319 "ext_array[2];");
17320 CHECK_EQ(12, result->Int32Value());
17321
17322 result = CompileRun("var js_array = new Array(40);"
17323 "js_array[0] = 77;"
17324 "js_array;");
17325 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17326
17327 result = CompileRun("ext_array[1] = 23;"
17328 "ext_array.__proto__ = [];"
17329 "js_array.__proto__ = ext_array;"
17330 "js_array.concat(ext_array);");
17331 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17332 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
17333
17334 result = CompileRun("ext_array[1] = 23;");
17335 CHECK_EQ(23, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017336}
17337
17338
17339template <class FixedTypedArrayClass,
17340 i::ElementsKind elements_kind,
17341 class ElementType>
17342static void FixedTypedArrayTestHelper(
17343 v8::ExternalArrayType array_type,
17344 ElementType low,
17345 ElementType high) {
17346 i::FLAG_allow_natives_syntax = true;
17347 LocalContext context;
17348 i::Isolate* isolate = CcTest::i_isolate();
17349 i::Factory* factory = isolate->factory();
17350 v8::HandleScope scope(context->GetIsolate());
17351 const int kElementCount = 260;
17352 i::Handle<FixedTypedArrayClass> fixed_array =
17353 i::Handle<FixedTypedArrayClass>::cast(
17354 factory->NewFixedTypedArray(kElementCount, array_type));
17355 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
17356 fixed_array->map()->instance_type());
17357 CHECK_EQ(kElementCount, fixed_array->length());
17358 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17359 for (int i = 0; i < kElementCount; i++) {
17360 fixed_array->set(i, static_cast<ElementType>(i));
17361 }
17362 // Force GC to trigger verification.
17363 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17364 for (int i = 0; i < kElementCount; i++) {
17365 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
17366 static_cast<int64_t>(fixed_array->get_scalar(i)));
17367 }
17368 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
17369 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17370 i::Handle<i::Map> fixed_array_map =
17371 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
17372 jsobj->set_map(*fixed_array_map);
17373 jsobj->set_elements(*fixed_array);
17374
17375 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
17376 context.local(), obj, kElementCount, array_type,
17377 static_cast<int64_t>(low),
17378 static_cast<int64_t>(high));
17379}
17380
17381
17382THREADED_TEST(FixedUint8Array) {
17383 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
17384 v8::kExternalUint8Array,
17385 0x0, 0xFF);
17386}
17387
17388
17389THREADED_TEST(FixedUint8ClampedArray) {
17390 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
17391 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
17392 v8::kExternalUint8ClampedArray,
17393 0x0, 0xFF);
17394}
17395
17396
17397THREADED_TEST(FixedInt8Array) {
17398 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
17399 v8::kExternalInt8Array,
17400 -0x80, 0x7F);
17401}
17402
17403
17404THREADED_TEST(FixedUint16Array) {
17405 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
17406 v8::kExternalUint16Array,
17407 0x0, 0xFFFF);
17408}
17409
17410
17411THREADED_TEST(FixedInt16Array) {
17412 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
17413 v8::kExternalInt16Array,
17414 -0x8000, 0x7FFF);
17415}
17416
17417
17418THREADED_TEST(FixedUint32Array) {
17419 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
17420 v8::kExternalUint32Array,
17421 0x0, UINT_MAX);
17422}
17423
17424
17425THREADED_TEST(FixedInt32Array) {
17426 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
17427 v8::kExternalInt32Array,
17428 INT_MIN, INT_MAX);
17429}
17430
17431
17432THREADED_TEST(FixedFloat32Array) {
17433 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
17434 v8::kExternalFloat32Array,
17435 -500, 500);
17436}
17437
17438
17439THREADED_TEST(FixedFloat64Array) {
17440 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
17441 v8::kExternalFloat64Array,
17442 -500, 500);
17443}
17444
17445
17446template <class ExternalArrayClass, class ElementType>
17447static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
17448 int64_t low,
17449 int64_t high) {
17450 LocalContext context;
17451 i::Isolate* isolate = CcTest::i_isolate();
17452 i::Factory* factory = isolate->factory();
17453 v8::HandleScope scope(context->GetIsolate());
17454 const int kElementCount = 40;
17455 int element_size = ExternalArrayElementSize(array_type);
17456 ElementType* array_data =
17457 static_cast<ElementType*>(malloc(kElementCount * element_size));
17458 i::Handle<ExternalArrayClass> array =
17459 i::Handle<ExternalArrayClass>::cast(
17460 factory->NewExternalArray(kElementCount, array_type, array_data));
17461 // Force GC to trigger verification.
17462 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17463 for (int i = 0; i < kElementCount; i++) {
17464 array->set(i, static_cast<ElementType>(i));
17465 }
17466 // Force GC to trigger verification.
17467 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17468 for (int i = 0; i < kElementCount; i++) {
17469 CHECK_EQ(static_cast<int64_t>(i),
17470 static_cast<int64_t>(array->get_scalar(i)));
17471 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
17472 }
17473
17474 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17475 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17476 // Set the elements to be the external array.
17477 obj->SetIndexedPropertiesToExternalArrayData(array_data,
17478 array_type,
17479 kElementCount);
17480 CHECK_EQ(1,
17481 static_cast<int>(
17482 i::Object::GetElement(
17483 isolate, jsobj, 1).ToHandleChecked()->Number()));
17484
17485 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17486 context.local(), obj, kElementCount, array_type, low, high);
17487
17488 v8::Handle<v8::Value> result;
Steve Block3ce2e202009-11-05 08:53:23 +000017489
Steve Blockd0582a62009-12-15 09:54:21 +000017490 // Test more complex manipulations which cause eax to contain values
17491 // that won't be completely overwritten by loads from the arrays.
17492 // This catches bugs in the instructions used for the KeyedLoadIC
17493 // for byte and word types.
17494 {
17495 const int kXSize = 300;
17496 const int kYSize = 300;
17497 const int kLargeElementCount = kXSize * kYSize * 4;
17498 ElementType* large_array_data =
17499 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017500 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000017501 // Set the elements to be the external array.
17502 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
17503 array_type,
17504 kLargeElementCount);
17505 context->Global()->Set(v8_str("large_array"), large_obj);
17506 // Initialize contents of a few rows.
17507 for (int x = 0; x < 300; x++) {
17508 int row = 0;
17509 int offset = row * 300 * 4;
17510 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17511 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17512 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17513 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17514 row = 150;
17515 offset = row * 300 * 4;
17516 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17517 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17518 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17519 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17520 row = 298;
17521 offset = row * 300 * 4;
17522 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17523 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17524 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17525 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17526 }
17527 // The goal of the code below is to make "offset" large enough
17528 // that the computation of the index (which goes into eax) has
17529 // high bits set which will not be overwritten by a byte or short
17530 // load.
17531 result = CompileRun("var failed = false;"
17532 "var offset = 0;"
17533 "for (var i = 0; i < 300; i++) {"
17534 " if (large_array[4 * i] != 127 ||"
17535 " large_array[4 * i + 1] != 0 ||"
17536 " large_array[4 * i + 2] != 0 ||"
17537 " large_array[4 * i + 3] != 127) {"
17538 " failed = true;"
17539 " }"
17540 "}"
17541 "offset = 150 * 300 * 4;"
17542 "for (var i = 0; i < 300; i++) {"
17543 " if (large_array[offset + 4 * i] != 127 ||"
17544 " large_array[offset + 4 * i + 1] != 0 ||"
17545 " large_array[offset + 4 * i + 2] != 0 ||"
17546 " large_array[offset + 4 * i + 3] != 127) {"
17547 " failed = true;"
17548 " }"
17549 "}"
17550 "offset = 298 * 300 * 4;"
17551 "for (var i = 0; i < 300; i++) {"
17552 " if (large_array[offset + 4 * i] != 127 ||"
17553 " large_array[offset + 4 * i + 1] != 0 ||"
17554 " large_array[offset + 4 * i + 2] != 0 ||"
17555 " large_array[offset + 4 * i + 3] != 127) {"
17556 " failed = true;"
17557 " }"
17558 "}"
17559 "!failed;");
17560 CHECK_EQ(true, result->BooleanValue());
17561 free(large_array_data);
17562 }
17563
Steve Block44f0eee2011-05-26 01:26:41 +010017564 // The "" property descriptor is overloaded to store information about
17565 // the external array. Ensure that setting and accessing the "" property
17566 // works (it should overwrite the information cached about the external
17567 // array in the DescriptorArray) in various situations.
17568 result = CompileRun("ext_array[''] = 23; ext_array['']");
17569 CHECK_EQ(23, result->Int32Value());
17570
17571 // Property "" set after the external array is associated with the object.
17572 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017573 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17574 obj2->Set(v8_str("ee_test_field"),
17575 v8::Int32::New(context->GetIsolate(), 256));
17576 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
Steve Block44f0eee2011-05-26 01:26:41 +010017577 // Set the elements to be the external array.
17578 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17579 array_type,
17580 kElementCount);
17581 context->Global()->Set(v8_str("ext_array"), obj2);
17582 result = CompileRun("ext_array['']");
17583 CHECK_EQ(1503, result->Int32Value());
17584 }
17585
17586 // Property "" set after the external array is associated with the object.
17587 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017588 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17589 obj2->Set(v8_str("ee_test_field_2"),
17590 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017591 // Set the elements to be the external array.
17592 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17593 array_type,
17594 kElementCount);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017595 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
Steve Block44f0eee2011-05-26 01:26:41 +010017596 context->Global()->Set(v8_str("ext_array"), obj2);
17597 result = CompileRun("ext_array['']");
17598 CHECK_EQ(1503, result->Int32Value());
17599 }
17600
17601 // Should reuse the map from previous test.
17602 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017603 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17604 obj2->Set(v8_str("ee_test_field_2"),
17605 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017606 // Set the elements to be the external array. Should re-use the map
17607 // from previous test.
17608 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17609 array_type,
17610 kElementCount);
17611 context->Global()->Set(v8_str("ext_array"), obj2);
17612 result = CompileRun("ext_array['']");
17613 }
17614
17615 // Property "" is a constant function that shouldn't not be interfered with
17616 // when an external array is set.
17617 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017618 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
Steve Block44f0eee2011-05-26 01:26:41 +010017619 // Start
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017620 obj2->Set(v8_str("ee_test_field3"),
17621 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017622
17623 // Add a constant function to an object.
17624 context->Global()->Set(v8_str("ext_array"), obj2);
17625 result = CompileRun("ext_array[''] = function() {return 1503;};"
17626 "ext_array['']();");
17627
17628 // Add an external array transition to the same map that
17629 // has the constant transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017630 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17631 obj3->Set(v8_str("ee_test_field3"),
17632 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017633 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17634 array_type,
17635 kElementCount);
17636 context->Global()->Set(v8_str("ext_array"), obj3);
17637 }
17638
17639 // If a external array transition is in the map, it should get clobbered
17640 // by a constant function.
17641 {
17642 // Add an external array transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017643 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17644 obj3->Set(v8_str("ee_test_field4"),
17645 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017646 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17647 array_type,
17648 kElementCount);
17649
17650 // Add a constant function to the same map that just got an external array
17651 // transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017652 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17653 obj2->Set(v8_str("ee_test_field4"),
17654 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010017655 context->Global()->Set(v8_str("ext_array"), obj2);
17656 result = CompileRun("ext_array[''] = function() {return 1503;};"
17657 "ext_array['']();");
17658 }
17659
Steve Block3ce2e202009-11-05 08:53:23 +000017660 free(array_data);
17661}
17662
17663
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017664THREADED_TEST(ExternalInt8Array) {
17665 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
17666 v8::kExternalInt8Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017667 -128,
17668 127);
17669}
17670
17671
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017672THREADED_TEST(ExternalUint8Array) {
17673 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
17674 v8::kExternalUint8Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017675 0,
17676 255);
17677}
17678
17679
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017680THREADED_TEST(ExternalUint8ClampedArray) {
17681 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
17682 v8::kExternalUint8ClampedArray,
Steve Block44f0eee2011-05-26 01:26:41 +010017683 0,
17684 255);
17685}
17686
17687
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017688THREADED_TEST(ExternalInt16Array) {
17689 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17690 v8::kExternalInt16Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017691 -32768,
17692 32767);
17693}
17694
17695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017696THREADED_TEST(ExternalUint16Array) {
17697 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17698 v8::kExternalUint16Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017699 0,
17700 65535);
17701}
17702
17703
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017704THREADED_TEST(ExternalInt32Array) {
17705 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17706 v8::kExternalInt32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017707 INT_MIN, // -2147483648
17708 INT_MAX); // 2147483647
17709}
17710
17711
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017712THREADED_TEST(ExternalUint32Array) {
17713 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17714 v8::kExternalUint32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017715 0,
17716 UINT_MAX); // 4294967295
17717}
17718
17719
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017720THREADED_TEST(ExternalFloat32Array) {
17721 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17722 v8::kExternalFloat32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000017723 -500,
17724 500);
17725}
17726
17727
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017728THREADED_TEST(ExternalFloat64Array) {
17729 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17730 v8::kExternalFloat64Array,
Ben Murdoch257744e2011-11-30 15:57:28 +000017731 -500,
17732 500);
17733}
17734
17735
Steve Block3ce2e202009-11-05 08:53:23 +000017736THREADED_TEST(ExternalArrays) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017737 TestExternalInt8Array();
17738 TestExternalUint8Array();
17739 TestExternalInt16Array();
17740 TestExternalUint16Array();
17741 TestExternalInt32Array();
17742 TestExternalUint32Array();
17743 TestExternalFloat32Array();
Steve Block3ce2e202009-11-05 08:53:23 +000017744}
17745
17746
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017747void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017748 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017749 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017750 for (int size = 0; size < 100; size += 10) {
17751 int element_size = ExternalArrayElementSize(array_type);
17752 void* external_data = malloc(size * element_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017753 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017754 obj->SetIndexedPropertiesToExternalArrayData(
17755 external_data, array_type, size);
17756 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17757 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17758 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17759 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17760 free(external_data);
17761 }
17762}
17763
17764
17765THREADED_TEST(ExternalArrayInfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017766 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17767 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17768 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17769 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17770 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17771 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17772 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17773 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17774 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017775}
17776
17777
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017778void ExtArrayLimitsHelper(v8::Isolate* isolate,
17779 v8::ExternalArrayType array_type,
17780 int size) {
17781 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17782 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17783 last_location = last_message = NULL;
17784 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17785 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17786 CHECK_NE(NULL, last_location);
17787 CHECK_NE(NULL, last_message);
17788}
17789
17790
17791TEST(ExternalArrayLimits) {
17792 LocalContext context;
17793 v8::Isolate* isolate = context->GetIsolate();
17794 v8::HandleScope scope(isolate);
17795 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17796 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17797 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17798 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17799 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17800 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17801 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17802 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17803 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17804 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17805 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17806 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17807 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17808 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17809 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17810 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17811 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17812 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17813}
17814
17815
17816template <typename ElementType, typename TypedArray,
17817 class ExternalArrayClass>
17818void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17819 int64_t low, int64_t high) {
17820 const int kElementCount = 50;
17821
17822 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17823
17824 LocalContext env;
17825 v8::Isolate* isolate = env->GetIsolate();
17826 v8::HandleScope handle_scope(isolate);
17827
17828 Local<v8::ArrayBuffer> ab =
17829 v8::ArrayBuffer::New(isolate, backing_store.start(),
17830 (kElementCount + 2) * sizeof(ElementType));
17831 Local<TypedArray> ta =
17832 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17833 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17834 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17835 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17836 CHECK_EQ(kElementCount*sizeof(ElementType),
17837 static_cast<int>(ta->ByteLength()));
17838 CHECK_EQ(ab, ta->Buffer());
17839
17840 ElementType* data = backing_store.start() + 2;
17841 for (int i = 0; i < kElementCount; i++) {
17842 data[i] = static_cast<ElementType>(i);
17843 }
17844
17845 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17846 env.local(), ta, kElementCount, array_type, low, high);
17847}
17848
17849
17850THREADED_TEST(Uint8Array) {
17851 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17852 v8::kExternalUint8Array, 0, 0xFF);
17853}
17854
17855
17856THREADED_TEST(Int8Array) {
17857 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17858 v8::kExternalInt8Array, -0x80, 0x7F);
17859}
17860
17861
17862THREADED_TEST(Uint16Array) {
17863 TypedArrayTestHelper<uint16_t,
17864 v8::Uint16Array,
17865 i::ExternalUint16Array>(
17866 v8::kExternalUint16Array, 0, 0xFFFF);
17867}
17868
17869
17870THREADED_TEST(Int16Array) {
17871 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17872 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17873}
17874
17875
17876THREADED_TEST(Uint32Array) {
17877 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17878 v8::kExternalUint32Array, 0, UINT_MAX);
17879}
17880
17881
17882THREADED_TEST(Int32Array) {
17883 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17884 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17885}
17886
17887
17888THREADED_TEST(Float32Array) {
17889 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17890 v8::kExternalFloat32Array, -500, 500);
17891}
17892
17893
17894THREADED_TEST(Float64Array) {
17895 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17896 v8::kExternalFloat64Array, -500, 500);
17897}
17898
17899
17900THREADED_TEST(Uint8ClampedArray) {
17901 TypedArrayTestHelper<uint8_t,
17902 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17903 v8::kExternalUint8ClampedArray, 0, 0xFF);
17904}
17905
17906
17907THREADED_TEST(DataView) {
17908 const int kSize = 50;
17909
17910 i::ScopedVector<uint8_t> backing_store(kSize+2);
17911
17912 LocalContext env;
17913 v8::Isolate* isolate = env->GetIsolate();
17914 v8::HandleScope handle_scope(isolate);
17915
17916 Local<v8::ArrayBuffer> ab =
17917 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17918 Local<v8::DataView> dv =
17919 v8::DataView::New(ab, 2, kSize);
17920 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17921 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17922 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17923 CHECK_EQ(ab, dv->Buffer());
17924}
17925
17926
17927#define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17928 THREADED_TEST(Is##View) { \
17929 LocalContext env; \
17930 v8::Isolate* isolate = env->GetIsolate(); \
17931 v8::HandleScope handle_scope(isolate); \
17932 \
17933 Handle<Value> result = CompileRun( \
17934 "var ab = new ArrayBuffer(128);" \
17935 "new " #View "(ab)"); \
17936 CHECK(result->IsArrayBufferView()); \
17937 CHECK(result->Is##View()); \
17938 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17939 }
17940
17941IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17942IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17943IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17944IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17945IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17946IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17947IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17948IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17949IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17950IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17951
17952#undef IS_ARRAY_BUFFER_VIEW_TEST
17953
17954
17955
Steve Blocka7e24c12009-10-30 11:49:00 +000017956THREADED_TEST(ScriptContextDependence) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017957 LocalContext c1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017958 v8::HandleScope scope(c1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017959 const char *source = "foo";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017960 v8::Handle<v8::Script> dep = v8_compile(source);
17961 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17962 c1->GetIsolate(), source));
17963 v8::Handle<v8::UnboundScript> indep =
17964 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17965 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17966 v8::Integer::New(c1->GetIsolate(), 100));
Steve Blocka7e24c12009-10-30 11:49:00 +000017967 CHECK_EQ(dep->Run()->Int32Value(), 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017968 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
Steve Blocka7e24c12009-10-30 11:49:00 +000017969 LocalContext c2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017970 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17971 v8::Integer::New(c2->GetIsolate(), 101));
Steve Blocka7e24c12009-10-30 11:49:00 +000017972 CHECK_EQ(dep->Run()->Int32Value(), 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017973 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
Steve Blocka7e24c12009-10-30 11:49:00 +000017974}
17975
17976
17977THREADED_TEST(StackTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017978 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017979 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017980 v8::TryCatch try_catch;
17981 const char *source = "function foo() { FAIL.FAIL; }; foo();";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017982 v8::Handle<v8::String> src =
17983 v8::String::NewFromUtf8(context->GetIsolate(), source);
17984 v8::Handle<v8::String> origin =
17985 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17986 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17987 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17988 ->BindToCurrentContext()
17989 ->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +000017990 CHECK(try_catch.HasCaught());
17991 v8::String::Utf8Value stack(try_catch.StackTrace());
17992 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17993}
17994
17995
Kristian Monsen25f61362010-05-21 11:50:48 +010017996// Checks that a StackFrame has certain expected values.
17997void checkStackFrame(const char* expected_script_name,
17998 const char* expected_func_name, int expected_line_number,
17999 int expected_column, bool is_eval, bool is_constructor,
18000 v8::Handle<v8::StackFrame> frame) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018001 v8::HandleScope scope(CcTest::isolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010018002 v8::String::Utf8Value func_name(frame->GetFunctionName());
18003 v8::String::Utf8Value script_name(frame->GetScriptName());
18004 if (*script_name == NULL) {
18005 // The situation where there is no associated script, like for evals.
18006 CHECK(expected_script_name == NULL);
18007 } else {
18008 CHECK(strstr(*script_name, expected_script_name) != NULL);
18009 }
18010 CHECK(strstr(*func_name, expected_func_name) != NULL);
18011 CHECK_EQ(expected_line_number, frame->GetLineNumber());
18012 CHECK_EQ(expected_column, frame->GetColumn());
18013 CHECK_EQ(is_eval, frame->IsEval());
18014 CHECK_EQ(is_constructor, frame->IsConstructor());
18015}
18016
18017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018018void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
18019 v8::HandleScope scope(args.GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010018020 const char* origin = "capture-stack-trace-test";
18021 const int kOverviewTest = 1;
18022 const int kDetailedTest = 2;
18023
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018024 DCHECK(args.Length() == 1);
Kristian Monsen25f61362010-05-21 11:50:48 +010018025
18026 int testGroup = args[0]->Int32Value();
18027 if (testGroup == kOverviewTest) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018028 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18029 args.GetIsolate(), 10, v8::StackTrace::kOverview);
Kristian Monsen25f61362010-05-21 11:50:48 +010018030 CHECK_EQ(4, stackTrace->GetFrameCount());
18031 checkStackFrame(origin, "bar", 2, 10, false, false,
18032 stackTrace->GetFrame(0));
18033 checkStackFrame(origin, "foo", 6, 3, false, false,
18034 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018035 // This is the source string inside the eval which has the call to foo.
18036 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010018037 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018038 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010018039 checkStackFrame(origin, "", 8, 7, false, false,
18040 stackTrace->GetFrame(3));
18041
18042 CHECK(stackTrace->AsArray()->IsArray());
18043 } else if (testGroup == kDetailedTest) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018044 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18045 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
Kristian Monsen25f61362010-05-21 11:50:48 +010018046 CHECK_EQ(4, stackTrace->GetFrameCount());
18047 checkStackFrame(origin, "bat", 4, 22, false, false,
18048 stackTrace->GetFrame(0));
18049 checkStackFrame(origin, "baz", 8, 3, false, true,
18050 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010018051 bool is_eval = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018052 // This is the source string inside the eval which has the call to baz.
18053 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010018054 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000018055 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010018056 checkStackFrame(origin, "", 10, 1, false, false,
18057 stackTrace->GetFrame(3));
18058
18059 CHECK(stackTrace->AsArray()->IsArray());
18060 }
Kristian Monsen25f61362010-05-21 11:50:48 +010018061}
18062
18063
18064// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010018065// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
18066// THREADED_TEST(CaptureStackTrace) {
18067TEST(CaptureStackTrace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018068 v8::Isolate* isolate = CcTest::isolate();
18069 v8::HandleScope scope(isolate);
18070 v8::Handle<v8::String> origin =
18071 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
18072 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Kristian Monsen25f61362010-05-21 11:50:48 +010018073 templ->Set(v8_str("AnalyzeStackInNativeCode"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018074 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
Kristian Monsen25f61362010-05-21 11:50:48 +010018075 LocalContext context(0, templ);
18076
18077 // Test getting OVERVIEW information. Should ignore information that is not
18078 // script name, function name, line number, and column offset.
18079 const char *overview_source =
18080 "function bar() {\n"
18081 " var y; AnalyzeStackInNativeCode(1);\n"
18082 "}\n"
18083 "function foo() {\n"
18084 "\n"
18085 " bar();\n"
18086 "}\n"
18087 "var x;eval('new foo();');";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018088 v8::Handle<v8::String> overview_src =
18089 v8::String::NewFromUtf8(isolate, overview_source);
18090 v8::ScriptCompiler::Source script_source(overview_src,
18091 v8::ScriptOrigin(origin));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018092 v8::Handle<Value> overview_result(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018093 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
18094 ->BindToCurrentContext()
18095 ->Run());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018096 CHECK(!overview_result.IsEmpty());
18097 CHECK(overview_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010018098
18099 // Test getting DETAILED information.
18100 const char *detailed_source =
18101 "function bat() {AnalyzeStackInNativeCode(2);\n"
18102 "}\n"
18103 "\n"
18104 "function baz() {\n"
18105 " bat();\n"
18106 "}\n"
18107 "eval('new baz();');";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018108 v8::Handle<v8::String> detailed_src =
18109 v8::String::NewFromUtf8(isolate, detailed_source);
Kristian Monsen25f61362010-05-21 11:50:48 +010018110 // Make the script using a non-zero line and column offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018111 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
18112 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
Kristian Monsen25f61362010-05-21 11:50:48 +010018113 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018114 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
18115 v8::Handle<v8::UnboundScript> detailed_script(
18116 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
18117 v8::Handle<Value> detailed_result(
18118 detailed_script->BindToCurrentContext()->Run());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018119 CHECK(!detailed_result.IsEmpty());
18120 CHECK(detailed_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010018121}
18122
18123
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018124static void StackTraceForUncaughtExceptionListener(
18125 v8::Handle<v8::Message> message,
18126 v8::Handle<Value>) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018127 report_count++;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018128 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18129 CHECK_EQ(2, stack_trace->GetFrameCount());
18130 checkStackFrame("origin", "foo", 2, 3, false, false,
18131 stack_trace->GetFrame(0));
18132 checkStackFrame("origin", "bar", 5, 3, false, false,
18133 stack_trace->GetFrame(1));
18134}
18135
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018136
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018137TEST(CaptureStackTraceForUncaughtException) {
18138 report_count = 0;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018139 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018140 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018141 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18142 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18143
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018144 CompileRunWithOrigin(
18145 "function foo() {\n"
18146 " throw 1;\n"
18147 "};\n"
18148 "function bar() {\n"
18149 " foo();\n"
18150 "};",
18151 "origin");
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018152 v8::Local<v8::Object> global = env->Global();
18153 Local<Value> trouble = global->Get(v8_str("bar"));
18154 CHECK(trouble->IsFunction());
18155 Function::Cast(*trouble)->Call(global, 0, NULL);
18156 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18157 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018158 CHECK_EQ(1, report_count);
18159}
18160
18161
18162TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
18163 report_count = 0;
18164 LocalContext env;
18165 v8::HandleScope scope(env->GetIsolate());
18166
18167 // Create an Error object first.
18168 CompileRunWithOrigin(
18169 "function foo() {\n"
18170 "e=new Error('err');\n"
18171 "};\n"
18172 "function bar() {\n"
18173 " foo();\n"
18174 "};\n"
18175 "var e;",
18176 "origin");
18177 v8::Local<v8::Object> global = env->Global();
18178 Local<Value> trouble = global->Get(v8_str("bar"));
18179 CHECK(trouble->IsFunction());
18180 Function::Cast(*trouble)->Call(global, 0, NULL);
18181
18182 // Enable capturing detailed stack trace late, and throw the exception.
18183 // The detailed stack trace should be extracted from the simple stack.
18184 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18185 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18186 CompileRunWithOrigin("throw e", "origin");
18187 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18188 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
18189 CHECK_EQ(1, report_count);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010018190}
18191
18192
Steve Block1e0659c2011-05-24 12:43:12 +010018193TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
Steve Block1e0659c2011-05-24 12:43:12 +010018194 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018195 v8::HandleScope scope(env->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010018196 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
18197 1024,
18198 v8::StackTrace::kDetailed);
18199
18200 CompileRun(
18201 "var setters = ['column', 'lineNumber', 'scriptName',\n"
18202 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
18203 " 'isConstructor'];\n"
18204 "for (var i = 0; i < setters.length; i++) {\n"
18205 " var prop = setters[i];\n"
18206 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
18207 "}\n");
18208 CompileRun("throw 'exception';");
18209 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18210}
18211
18212
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018213static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
18214 v8::Handle<v8::Value> data) {
18215 // Use the frame where JavaScript is called from.
18216 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18217 CHECK(!stack_trace.IsEmpty());
18218 int frame_count = stack_trace->GetFrameCount();
18219 CHECK_EQ(3, frame_count);
18220 int line_number[] = {1, 2, 5};
18221 for (int i = 0; i < frame_count; i++) {
18222 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18223 }
18224}
18225
18226
18227// Test that we only return the stack trace at the site where the exception
18228// is first thrown (not where it is rethrown).
18229TEST(RethrowStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018230 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018231 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018232 // We make sure that
18233 // - the stack trace of the ReferenceError in g() is reported.
18234 // - the stack trace is not overwritten when e1 is rethrown by t().
18235 // - the stack trace of e2 does not overwrite that of e1.
18236 const char* source =
18237 "function g() { error; } \n"
18238 "function f() { g(); } \n"
18239 "function t(e) { throw e; } \n"
18240 "try { \n"
18241 " f(); \n"
18242 "} catch (e1) { \n"
18243 " try { \n"
18244 " error; \n"
18245 " } catch (e2) { \n"
18246 " t(e1); \n"
18247 " } \n"
18248 "} \n";
18249 v8::V8::AddMessageListener(RethrowStackTraceHandler);
18250 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18251 CompileRun(source);
18252 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18253 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
18254}
18255
18256
18257static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
18258 v8::Handle<v8::Value> data) {
18259 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18260 CHECK(!stack_trace.IsEmpty());
18261 int frame_count = stack_trace->GetFrameCount();
18262 CHECK_EQ(2, frame_count);
18263 int line_number[] = {3, 7};
18264 for (int i = 0; i < frame_count; i++) {
18265 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18266 }
18267}
18268
18269
18270// Test that we do not recognize identity for primitive exceptions.
18271TEST(RethrowPrimitiveStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018272 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018273 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018274 // We do not capture stack trace for non Error objects on creation time.
18275 // Instead, we capture the stack trace on last throw.
18276 const char* source =
18277 "function g() { throw 404; } \n"
18278 "function f() { g(); } \n"
18279 "function t(e) { throw e; } \n"
18280 "try { \n"
18281 " f(); \n"
18282 "} catch (e1) { \n"
18283 " t(e1) \n"
18284 "} \n";
18285 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
18286 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18287 CompileRun(source);
18288 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18289 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
18290}
18291
18292
18293static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
18294 v8::Handle<v8::Value> data) {
18295 // Use the frame where JavaScript is called from.
18296 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18297 CHECK(!stack_trace.IsEmpty());
18298 CHECK_EQ(1, stack_trace->GetFrameCount());
18299 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
18300}
18301
18302
18303// Test that the stack trace is captured when the error object is created and
18304// not where it is thrown.
18305TEST(RethrowExistingStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018306 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018307 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018308 const char* source =
18309 "var e = new Error(); \n"
18310 "throw e; \n";
18311 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
18312 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18313 CompileRun(source);
18314 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18315 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
18316}
18317
18318
18319static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
18320 v8::Handle<v8::Value> data) {
18321 // Use the frame where JavaScript is called from.
18322 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18323 CHECK(!stack_trace.IsEmpty());
18324 CHECK_EQ(1, stack_trace->GetFrameCount());
18325 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
18326}
18327
18328
18329// Test that the stack trace is captured where the bogus Error object is thrown.
18330TEST(RethrowBogusErrorStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018331 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018332 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018333 const char* source =
18334 "var e = {__proto__: new Error()} \n"
18335 "throw e; \n";
18336 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
18337 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18338 CompileRun(source);
18339 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18340 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
18341}
18342
18343
Emily Bernierd0a1eb72015-03-24 16:35:39 -040018344v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
18345int promise_reject_counter = 0;
18346int promise_revoke_counter = 0;
18347int promise_reject_line_number = -1;
18348int promise_reject_frame_count = -1;
18349
18350void PromiseRejectCallback(v8::PromiseRejectMessage message) {
18351 if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
18352 promise_reject_counter++;
18353 CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
18354 CcTest::global()->Set(v8_str("value"), message.GetValue());
18355 v8::Handle<v8::StackTrace> stack_trace =
18356 v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
18357 if (!stack_trace.IsEmpty()) {
18358 promise_reject_frame_count = stack_trace->GetFrameCount();
18359 if (promise_reject_frame_count > 0) {
18360 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
18361 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
18362 } else {
18363 promise_reject_line_number = -1;
18364 }
18365 }
18366 } else {
18367 promise_revoke_counter++;
18368 CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
18369 CHECK(message.GetValue().IsEmpty());
18370 }
18371}
18372
18373
18374v8::Handle<v8::Promise> GetPromise(const char* name) {
18375 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
18376}
18377
18378
18379v8::Handle<v8::Value> RejectValue() {
18380 return CcTest::global()->Get(v8_str("value"));
18381}
18382
18383
18384void ResetPromiseStates() {
18385 promise_reject_counter = 0;
18386 promise_revoke_counter = 0;
18387 promise_reject_line_number = -1;
18388 promise_reject_frame_count = -1;
18389 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
18390 CcTest::global()->Set(v8_str("value"), v8_str(""));
18391 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
18392}
18393
18394
18395TEST(PromiseRejectCallback) {
18396 LocalContext env;
18397 v8::Isolate* isolate = env->GetIsolate();
18398 v8::HandleScope scope(isolate);
18399
18400 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18401
18402 ResetPromiseStates();
18403
18404 // Create promise p0.
18405 CompileRun(
18406 "var reject; \n"
18407 "var p0 = new Promise( \n"
18408 " function(res, rej) { \n"
18409 " reject = rej; \n"
18410 " } \n"
18411 "); \n");
18412 CHECK(!GetPromise("p0")->HasHandler());
18413 CHECK_EQ(0, promise_reject_counter);
18414 CHECK_EQ(0, promise_revoke_counter);
18415
18416 // Add resolve handler (and default reject handler) to p0.
18417 CompileRun("var p1 = p0.then(function(){});");
18418 CHECK(GetPromise("p0")->HasHandler());
18419 CHECK(!GetPromise("p1")->HasHandler());
18420 CHECK_EQ(0, promise_reject_counter);
18421 CHECK_EQ(0, promise_revoke_counter);
18422
18423 // Reject p0.
18424 CompileRun("reject('ppp');");
18425 CHECK(GetPromise("p0")->HasHandler());
18426 CHECK(!GetPromise("p1")->HasHandler());
18427 CHECK_EQ(1, promise_reject_counter);
18428 CHECK_EQ(0, promise_revoke_counter);
18429 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
18430 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
18431 CHECK(RejectValue()->Equals(v8_str("ppp")));
18432
18433 // Reject p0 again. Callback is not triggered again.
18434 CompileRun("reject();");
18435 CHECK(GetPromise("p0")->HasHandler());
18436 CHECK(!GetPromise("p1")->HasHandler());
18437 CHECK_EQ(1, promise_reject_counter);
18438 CHECK_EQ(0, promise_revoke_counter);
18439
18440 // Add resolve handler to p1.
18441 CompileRun("var p2 = p1.then(function(){});");
18442 CHECK(GetPromise("p0")->HasHandler());
18443 CHECK(GetPromise("p1")->HasHandler());
18444 CHECK(!GetPromise("p2")->HasHandler());
18445 CHECK_EQ(2, promise_reject_counter);
18446 CHECK_EQ(1, promise_revoke_counter);
18447 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
18448 CHECK(RejectValue()->Equals(v8_str("ppp")));
18449 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
18450
18451 ResetPromiseStates();
18452
18453 // Create promise q0.
18454 CompileRun(
18455 "var q0 = new Promise( \n"
18456 " function(res, rej) { \n"
18457 " reject = rej; \n"
18458 " } \n"
18459 "); \n");
18460 CHECK(!GetPromise("q0")->HasHandler());
18461 CHECK_EQ(0, promise_reject_counter);
18462 CHECK_EQ(0, promise_revoke_counter);
18463
18464 // Add reject handler to q0.
18465 CompileRun("var q1 = q0.catch(function() {});");
18466 CHECK(GetPromise("q0")->HasHandler());
18467 CHECK(!GetPromise("q1")->HasHandler());
18468 CHECK_EQ(0, promise_reject_counter);
18469 CHECK_EQ(0, promise_revoke_counter);
18470
18471 // Reject q0.
18472 CompileRun("reject('qq')");
18473 CHECK(GetPromise("q0")->HasHandler());
18474 CHECK(!GetPromise("q1")->HasHandler());
18475 CHECK_EQ(0, promise_reject_counter);
18476 CHECK_EQ(0, promise_revoke_counter);
18477
18478 // Add a new reject handler, which rejects by returning Promise.reject().
18479 // The returned promise q_ triggers a reject callback at first, only to
18480 // revoke it when returning it causes q2 to be rejected.
18481 CompileRun(
18482 "var q_;"
18483 "var q2 = q0.catch( \n"
18484 " function() { \n"
18485 " q_ = Promise.reject('qqq'); \n"
18486 " return q_; \n"
18487 " } \n"
18488 "); \n");
18489 CHECK(GetPromise("q0")->HasHandler());
18490 CHECK(!GetPromise("q1")->HasHandler());
18491 CHECK(!GetPromise("q2")->HasHandler());
18492 CHECK(GetPromise("q_")->HasHandler());
18493 CHECK_EQ(2, promise_reject_counter);
18494 CHECK_EQ(1, promise_revoke_counter);
18495 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
18496 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
18497 CHECK(RejectValue()->Equals(v8_str("qqq")));
18498
18499 // Add a reject handler to the resolved q1, which rejects by throwing.
18500 CompileRun(
18501 "var q3 = q1.then( \n"
18502 " function() { \n"
18503 " throw 'qqqq'; \n"
18504 " } \n"
18505 "); \n");
18506 CHECK(GetPromise("q0")->HasHandler());
18507 CHECK(GetPromise("q1")->HasHandler());
18508 CHECK(!GetPromise("q2")->HasHandler());
18509 CHECK(!GetPromise("q3")->HasHandler());
18510 CHECK_EQ(3, promise_reject_counter);
18511 CHECK_EQ(1, promise_revoke_counter);
18512 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
18513 CHECK(RejectValue()->Equals(v8_str("qqqq")));
18514
18515 ResetPromiseStates();
18516
18517 // Create promise r0, which has three handlers, two of which handle rejects.
18518 CompileRun(
18519 "var r0 = new Promise( \n"
18520 " function(res, rej) { \n"
18521 " reject = rej; \n"
18522 " } \n"
18523 "); \n"
18524 "var r1 = r0.catch(function() {}); \n"
18525 "var r2 = r0.then(function() {}); \n"
18526 "var r3 = r0.then(function() {}, \n"
18527 " function() {}); \n");
18528 CHECK(GetPromise("r0")->HasHandler());
18529 CHECK(!GetPromise("r1")->HasHandler());
18530 CHECK(!GetPromise("r2")->HasHandler());
18531 CHECK(!GetPromise("r3")->HasHandler());
18532 CHECK_EQ(0, promise_reject_counter);
18533 CHECK_EQ(0, promise_revoke_counter);
18534
18535 // Reject r0.
18536 CompileRun("reject('rrr')");
18537 CHECK(GetPromise("r0")->HasHandler());
18538 CHECK(!GetPromise("r1")->HasHandler());
18539 CHECK(!GetPromise("r2")->HasHandler());
18540 CHECK(!GetPromise("r3")->HasHandler());
18541 CHECK_EQ(1, promise_reject_counter);
18542 CHECK_EQ(0, promise_revoke_counter);
18543 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
18544 CHECK(RejectValue()->Equals(v8_str("rrr")));
18545
18546 // Add reject handler to r2.
18547 CompileRun("var r4 = r2.catch(function() {});");
18548 CHECK(GetPromise("r0")->HasHandler());
18549 CHECK(!GetPromise("r1")->HasHandler());
18550 CHECK(GetPromise("r2")->HasHandler());
18551 CHECK(!GetPromise("r3")->HasHandler());
18552 CHECK(!GetPromise("r4")->HasHandler());
18553 CHECK_EQ(1, promise_reject_counter);
18554 CHECK_EQ(1, promise_revoke_counter);
18555 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
18556 CHECK(RejectValue()->Equals(v8_str("rrr")));
18557
18558 // Add reject handlers to r4.
18559 CompileRun("var r5 = r4.then(function() {}, function() {});");
18560 CHECK(GetPromise("r0")->HasHandler());
18561 CHECK(!GetPromise("r1")->HasHandler());
18562 CHECK(GetPromise("r2")->HasHandler());
18563 CHECK(!GetPromise("r3")->HasHandler());
18564 CHECK(GetPromise("r4")->HasHandler());
18565 CHECK(!GetPromise("r5")->HasHandler());
18566 CHECK_EQ(1, promise_reject_counter);
18567 CHECK_EQ(1, promise_revoke_counter);
18568
18569 ResetPromiseStates();
18570
18571 // Create promise s0, which has three handlers, none of which handle rejects.
18572 CompileRun(
18573 "var s0 = new Promise( \n"
18574 " function(res, rej) { \n"
18575 " reject = rej; \n"
18576 " } \n"
18577 "); \n"
18578 "var s1 = s0.then(function() {}); \n"
18579 "var s2 = s0.then(function() {}); \n"
18580 "var s3 = s0.then(function() {}); \n");
18581 CHECK(GetPromise("s0")->HasHandler());
18582 CHECK(!GetPromise("s1")->HasHandler());
18583 CHECK(!GetPromise("s2")->HasHandler());
18584 CHECK(!GetPromise("s3")->HasHandler());
18585 CHECK_EQ(0, promise_reject_counter);
18586 CHECK_EQ(0, promise_revoke_counter);
18587
18588 // Reject s0.
18589 CompileRun("reject('sss')");
18590 CHECK(GetPromise("s0")->HasHandler());
18591 CHECK(!GetPromise("s1")->HasHandler());
18592 CHECK(!GetPromise("s2")->HasHandler());
18593 CHECK(!GetPromise("s3")->HasHandler());
18594 CHECK_EQ(3, promise_reject_counter);
18595 CHECK_EQ(0, promise_revoke_counter);
18596 CHECK(RejectValue()->Equals(v8_str("sss")));
18597
18598 // Test stack frames.
18599 V8::SetCaptureStackTraceForUncaughtExceptions(true);
18600
18601 ResetPromiseStates();
18602
18603 // Create promise t0, which is rejected in the constructor with an error.
18604 CompileRunWithOrigin(
18605 "var t0 = new Promise( \n"
18606 " function(res, rej) { \n"
18607 " reference_error; \n"
18608 " } \n"
18609 "); \n",
18610 "pro", 0, 0);
18611 CHECK(!GetPromise("t0")->HasHandler());
18612 CHECK_EQ(1, promise_reject_counter);
18613 CHECK_EQ(0, promise_revoke_counter);
18614 CHECK_EQ(2, promise_reject_frame_count);
18615 CHECK_EQ(3, promise_reject_line_number);
18616
18617 ResetPromiseStates();
18618
18619 // Create promise u0 and chain u1 to it, which is rejected via throw.
18620 CompileRunWithOrigin(
18621 "var u0 = Promise.resolve(); \n"
18622 "var u1 = u0.then( \n"
18623 " function() { \n"
18624 " (function() { \n"
18625 " throw new Error(); \n"
18626 " })(); \n"
18627 " } \n"
18628 " ); \n",
18629 "pro", 0, 0);
18630 CHECK(GetPromise("u0")->HasHandler());
18631 CHECK(!GetPromise("u1")->HasHandler());
18632 CHECK_EQ(1, promise_reject_counter);
18633 CHECK_EQ(0, promise_revoke_counter);
18634 CHECK_EQ(2, promise_reject_frame_count);
18635 CHECK_EQ(5, promise_reject_line_number);
18636
18637 // Throw in u3, which handles u1's rejection.
18638 CompileRunWithOrigin(
18639 "function f() { \n"
18640 " return (function() { \n"
18641 " return new Error(); \n"
18642 " })(); \n"
18643 "} \n"
18644 "var u2 = Promise.reject(f()); \n"
18645 "var u3 = u1.catch( \n"
18646 " function() { \n"
18647 " return u2; \n"
18648 " } \n"
18649 " ); \n",
18650 "pro", 0, 0);
18651 CHECK(GetPromise("u0")->HasHandler());
18652 CHECK(GetPromise("u1")->HasHandler());
18653 CHECK(GetPromise("u2")->HasHandler());
18654 CHECK(!GetPromise("u3")->HasHandler());
18655 CHECK_EQ(3, promise_reject_counter);
18656 CHECK_EQ(2, promise_revoke_counter);
18657 CHECK_EQ(3, promise_reject_frame_count);
18658 CHECK_EQ(3, promise_reject_line_number);
18659
18660 ResetPromiseStates();
18661
18662 // Create promise rejected promise v0, which is incorrectly handled by v1
18663 // via chaining cycle.
18664 CompileRunWithOrigin(
18665 "var v0 = Promise.reject(); \n"
18666 "var v1 = v0.catch( \n"
18667 " function() { \n"
18668 " return v1; \n"
18669 " } \n"
18670 " ); \n",
18671 "pro", 0, 0);
18672 CHECK(GetPromise("v0")->HasHandler());
18673 CHECK(!GetPromise("v1")->HasHandler());
18674 CHECK_EQ(2, promise_reject_counter);
18675 CHECK_EQ(1, promise_revoke_counter);
18676 CHECK_EQ(0, promise_reject_frame_count);
18677 CHECK_EQ(-1, promise_reject_line_number);
18678}
18679
18680
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018681void AnalyzeStackOfEvalWithSourceURL(
18682 const v8::FunctionCallbackInfo<v8::Value>& args) {
18683 v8::HandleScope scope(args.GetIsolate());
18684 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18685 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
Ben Murdochf87a2032010-10-22 12:50:53 +010018686 CHECK_EQ(5, stackTrace->GetFrameCount());
18687 v8::Handle<v8::String> url = v8_str("eval_url");
18688 for (int i = 0; i < 3; i++) {
18689 v8::Handle<v8::String> name =
18690 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18691 CHECK(!name.IsEmpty());
18692 CHECK_EQ(url, name);
18693 }
Ben Murdochf87a2032010-10-22 12:50:53 +010018694}
18695
18696
18697TEST(SourceURLInStackTrace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018698 v8::Isolate* isolate = CcTest::isolate();
18699 v8::HandleScope scope(isolate);
18700 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +010018701 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018702 v8::FunctionTemplate::New(isolate,
18703 AnalyzeStackOfEvalWithSourceURL));
Ben Murdochf87a2032010-10-22 12:50:53 +010018704 LocalContext context(0, templ);
18705
18706 const char *source =
18707 "function outer() {\n"
18708 "function bar() {\n"
18709 " AnalyzeStackOfEvalWithSourceURL();\n"
18710 "}\n"
18711 "function foo() {\n"
18712 "\n"
18713 " bar();\n"
18714 "}\n"
18715 "foo();\n"
18716 "}\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018717 "eval('(' + outer +')()%s');";
18718
18719 i::ScopedVector<char> code(1024);
18720 i::SNPrintF(code, source, "//# sourceURL=eval_url");
18721 CHECK(CompileRun(code.start())->IsUndefined());
18722 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18723 CHECK(CompileRun(code.start())->IsUndefined());
18724}
18725
18726
18727static int scriptIdInStack[2];
18728
18729void AnalyzeScriptIdInStack(
18730 const v8::FunctionCallbackInfo<v8::Value>& args) {
18731 v8::HandleScope scope(args.GetIsolate());
18732 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18733 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18734 CHECK_EQ(2, stackTrace->GetFrameCount());
18735 for (int i = 0; i < 2; i++) {
18736 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18737 }
18738}
18739
18740
18741TEST(ScriptIdInStackTrace) {
18742 v8::Isolate* isolate = CcTest::isolate();
18743 v8::HandleScope scope(isolate);
18744 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18745 templ->Set(v8_str("AnalyzeScriptIdInStack"),
18746 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18747 LocalContext context(0, templ);
18748
18749 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18750 isolate,
18751 "function foo() {\n"
18752 " AnalyzeScriptIdInStack();"
18753 "}\n"
18754 "foo();\n");
18755 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18756 script->Run();
18757 for (int i = 0; i < 2; i++) {
18758 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
18759 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18760 }
18761}
18762
18763
18764void AnalyzeStackOfInlineScriptWithSourceURL(
18765 const v8::FunctionCallbackInfo<v8::Value>& args) {
18766 v8::HandleScope scope(args.GetIsolate());
18767 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18768 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18769 CHECK_EQ(4, stackTrace->GetFrameCount());
18770 v8::Handle<v8::String> url = v8_str("url");
18771 for (int i = 0; i < 3; i++) {
18772 v8::Handle<v8::String> name =
18773 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18774 CHECK(!name.IsEmpty());
18775 CHECK_EQ(url, name);
18776 }
18777}
18778
18779
18780TEST(InlineScriptWithSourceURLInStackTrace) {
18781 v8::Isolate* isolate = CcTest::isolate();
18782 v8::HandleScope scope(isolate);
18783 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18784 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18785 v8::FunctionTemplate::New(
18786 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18787 LocalContext context(0, templ);
18788
18789 const char *source =
18790 "function outer() {\n"
18791 "function bar() {\n"
18792 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
18793 "}\n"
18794 "function foo() {\n"
18795 "\n"
18796 " bar();\n"
18797 "}\n"
18798 "foo();\n"
18799 "}\n"
18800 "outer()\n%s";
18801
18802 i::ScopedVector<char> code(1024);
18803 i::SNPrintF(code, source, "//# sourceURL=source_url");
18804 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18805 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18806 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18807}
18808
18809
18810void AnalyzeStackOfDynamicScriptWithSourceURL(
18811 const v8::FunctionCallbackInfo<v8::Value>& args) {
18812 v8::HandleScope scope(args.GetIsolate());
18813 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18814 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18815 CHECK_EQ(4, stackTrace->GetFrameCount());
18816 v8::Handle<v8::String> url = v8_str("source_url");
18817 for (int i = 0; i < 3; i++) {
18818 v8::Handle<v8::String> name =
18819 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18820 CHECK(!name.IsEmpty());
18821 CHECK_EQ(url, name);
18822 }
18823}
18824
18825
18826TEST(DynamicWithSourceURLInStackTrace) {
18827 v8::Isolate* isolate = CcTest::isolate();
18828 v8::HandleScope scope(isolate);
18829 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18830 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18831 v8::FunctionTemplate::New(
18832 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18833 LocalContext context(0, templ);
18834
18835 const char *source =
18836 "function outer() {\n"
18837 "function bar() {\n"
18838 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18839 "}\n"
18840 "function foo() {\n"
18841 "\n"
18842 " bar();\n"
18843 "}\n"
18844 "foo();\n"
18845 "}\n"
18846 "outer()\n%s";
18847
18848 i::ScopedVector<char> code(1024);
18849 i::SNPrintF(code, source, "//# sourceURL=source_url");
18850 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18851 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18852 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18853}
18854
18855
18856TEST(DynamicWithSourceURLInStackTraceString) {
18857 LocalContext context;
18858 v8::HandleScope scope(context->GetIsolate());
18859
18860 const char *source =
18861 "function outer() {\n"
18862 " function foo() {\n"
18863 " FAIL.FAIL;\n"
18864 " }\n"
18865 " foo();\n"
18866 "}\n"
18867 "outer()\n%s";
18868
18869 i::ScopedVector<char> code(1024);
18870 i::SNPrintF(code, source, "//# sourceURL=source_url");
18871 v8::TryCatch try_catch;
18872 CompileRunWithOrigin(code.start(), "", 0, 0);
18873 CHECK(try_catch.HasCaught());
18874 v8::String::Utf8Value stack(try_catch.StackTrace());
18875 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
18876}
18877
18878
18879TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18880 LocalContext context;
18881 v8::HandleScope scope(context->GetIsolate());
18882
18883 const char *source =
18884 "function outer() {\n"
18885 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18886 " //# sourceURL=source_url\";\n"
18887 " eval(scriptContents);\n"
18888 " foo(); }\n"
18889 "outer();\n"
18890 "//# sourceURL=outer_url";
18891
18892 v8::TryCatch try_catch;
18893 CompileRun(source);
18894 CHECK(try_catch.HasCaught());
18895
18896 Local<v8::Message> message = try_catch.Message();
18897 Handle<Value> sourceURL =
18898 message->GetScriptOrigin().ResourceName();
18899 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18900}
18901
18902
18903TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18904 LocalContext context;
18905 v8::HandleScope scope(context->GetIsolate());
18906
18907 const char *source =
18908 "function outer() {\n"
18909 " var scriptContents = \"function boo(){ boo(); }\\\n"
18910 " //# sourceURL=source_url\";\n"
18911 " eval(scriptContents);\n"
18912 " boo(); }\n"
18913 "outer();\n"
18914 "//# sourceURL=outer_url";
18915
18916 v8::TryCatch try_catch;
18917 CompileRun(source);
18918 CHECK(try_catch.HasCaught());
18919
18920 Local<v8::Message> message = try_catch.Message();
18921 Handle<Value> sourceURL =
18922 message->GetScriptOrigin().ResourceName();
18923 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18924}
18925
18926
18927static void CreateGarbageInOldSpace() {
18928 i::Factory* factory = CcTest::i_isolate()->factory();
18929 v8::HandleScope scope(CcTest::isolate());
18930 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18931 for (int i = 0; i < 1000; i++) {
18932 factory->NewFixedArray(1000, i::TENURED);
18933 }
Ben Murdochf87a2032010-10-22 12:50:53 +010018934}
18935
18936
Steve Block3ce2e202009-11-05 08:53:23 +000018937// Test that idle notification can be handled and eventually returns true.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018938TEST(IdleNotification) {
18939 const intptr_t MB = 1024 * 1024;
18940 const int IdlePauseInMs = 1000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018941 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018942 v8::HandleScope scope(env->GetIsolate());
18943 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18944 CreateGarbageInOldSpace();
18945 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18946 CHECK_GT(size_with_garbage, initial_size + MB);
18947 bool finished = false;
18948 for (int i = 0; i < 200 && !finished; i++) {
18949 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Steve Block3ce2e202009-11-05 08:53:23 +000018950 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018951 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18952 CHECK(finished);
18953 CHECK_LT(final_size, initial_size + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018954}
18955
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018956
18957// Test that idle notification can be handled and eventually collects garbage.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018958TEST(IdleNotificationWithSmallHint) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018959 const intptr_t MB = 1024 * 1024;
18960 const int IdlePauseInMs = 900;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018961 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018962 v8::HandleScope scope(env->GetIsolate());
18963 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18964 CreateGarbageInOldSpace();
18965 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18966 CHECK_GT(size_with_garbage, initial_size + MB);
18967 bool finished = false;
18968 for (int i = 0; i < 200 && !finished; i++) {
18969 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018970 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018971 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18972 CHECK(finished);
18973 CHECK_LT(final_size, initial_size + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018974}
18975
18976
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018977// Test that idle notification can be handled and eventually collects garbage.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018978TEST(IdleNotificationWithLargeHint) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018979 const intptr_t MB = 1024 * 1024;
18980 const int IdlePauseInMs = 900;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018981 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018982 v8::HandleScope scope(env->GetIsolate());
18983 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18984 CreateGarbageInOldSpace();
18985 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18986 CHECK_GT(size_with_garbage, initial_size + MB);
18987 bool finished = false;
18988 for (int i = 0; i < 200 && !finished; i++) {
18989 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018990 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018991 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18992 CHECK(finished);
18993 CHECK_LT(final_size, initial_size + 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +000018994}
18995
Steve Blocka7e24c12009-10-30 11:49:00 +000018996
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018997TEST(Regress2333) {
18998 LocalContext env;
18999 for (int i = 0; i < 3; i++) {
19000 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
19001 }
19002}
19003
Steve Blocka7e24c12009-10-30 11:49:00 +000019004static uint32_t* stack_limit;
19005
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019006static void GetStackLimitCallback(
19007 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010019008 stack_limit = reinterpret_cast<uint32_t*>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019009 CcTest::i_isolate()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000019010}
19011
19012
19013// Uses the address of a local variable to determine the stack top now.
19014// Given a size, returns an address that is that far from the current
19015// top of stack.
19016static uint32_t* ComputeStackLimit(uint32_t size) {
19017 uint32_t* answer = &size - (size / sizeof(size));
19018 // If the size is very large and the stack is very near the bottom of
19019 // memory then the calculation above may wrap around and give an address
19020 // that is above the (downwards-growing) stack. In that case we return
19021 // a very low address.
19022 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
19023 return answer;
19024}
19025
19026
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019027// We need at least 165kB for an x64 debug build with clang and ASAN.
19028static const int stack_breathing_room = 256 * i::KB;
19029
19030
19031TEST(SetStackLimit) {
19032 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
Steve Blocka7e24c12009-10-30 11:49:00 +000019033
19034 // Set stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019035 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +000019036
19037 // Execute a script.
Steve Blocka7e24c12009-10-30 11:49:00 +000019038 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019039 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019040 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019041 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000019042 Local<Function> fun = fun_templ->GetFunction();
19043 env->Global()->Set(v8_str("get_stack_limit"), fun);
19044 CompileRun("get_stack_limit();");
19045
19046 CHECK(stack_limit == set_limit);
19047}
19048
19049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019050TEST(SetStackLimitInThread) {
Steve Blocka7e24c12009-10-30 11:49:00 +000019051 uint32_t* set_limit;
19052 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019053 v8::Locker locker(CcTest::isolate());
19054 set_limit = ComputeStackLimit(stack_breathing_room);
Steve Blocka7e24c12009-10-30 11:49:00 +000019055
19056 // Set stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019057 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +000019058
19059 // Execute a script.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019060 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019061 LocalContext env;
19062 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019063 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000019064 Local<Function> fun = fun_templ->GetFunction();
19065 env->Global()->Set(v8_str("get_stack_limit"), fun);
19066 CompileRun("get_stack_limit();");
19067
19068 CHECK(stack_limit == set_limit);
19069 }
19070 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019071 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000019072 CHECK(stack_limit == set_limit);
19073 }
19074}
Steve Block3ce2e202009-11-05 08:53:23 +000019075
19076
19077THREADED_TEST(GetHeapStatistics) {
Steve Block3ce2e202009-11-05 08:53:23 +000019078 LocalContext c1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019079 v8::HandleScope scope(c1->GetIsolate());
Steve Block3ce2e202009-11-05 08:53:23 +000019080 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000019081 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
19082 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019083 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000019084 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
19085 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
19086}
19087
19088
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019089class VisitorImpl : public v8::ExternalResourceVisitor {
19090 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019091 explicit VisitorImpl(TestResource** resource) {
19092 for (int i = 0; i < 4; i++) {
19093 resource_[i] = resource[i];
19094 found_resource_[i] = false;
19095 }
19096 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019097 virtual ~VisitorImpl() {}
19098 virtual void VisitExternalString(v8::Handle<v8::String> string) {
19099 if (!string->IsExternal()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019100 CHECK(string->IsExternalOneByte());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019101 return;
19102 }
19103 v8::String::ExternalStringResource* resource =
19104 string->GetExternalStringResource();
19105 CHECK(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019106 for (int i = 0; i < 4; i++) {
19107 if (resource_[i] == resource) {
19108 CHECK(!found_resource_[i]);
19109 found_resource_[i] = true;
19110 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019111 }
19112 }
19113 void CheckVisitedResources() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019114 for (int i = 0; i < 4; i++) {
19115 CHECK(found_resource_[i]);
19116 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019117 }
19118
19119 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019120 v8::String::ExternalStringResource* resource_[4];
19121 bool found_resource_[4];
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019122};
19123
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019124
19125TEST(ExternalizeOldSpaceTwoByteCons) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019126 v8::Isolate* isolate = CcTest::isolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019127 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019128 v8::HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019129 v8::Local<v8::String> cons =
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019130 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019131 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19132 CcTest::heap()->CollectAllAvailableGarbage();
19133 CHECK(CcTest::heap()->old_pointer_space()->Contains(
19134 *v8::Utils::OpenHandle(*cons)));
19135
19136 TestResource* resource = new TestResource(
19137 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
19138 cons->MakeExternal(resource);
19139
19140 CHECK(cons->IsExternal());
19141 CHECK_EQ(resource, cons->GetExternalStringResource());
19142 String::Encoding encoding;
19143 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19144 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
19145}
19146
19147
19148TEST(ExternalizeOldSpaceOneByteCons) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019149 v8::Isolate* isolate = CcTest::isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019150 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019151 v8::HandleScope scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019152 v8::Local<v8::String> cons =
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019153 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019154 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19155 CcTest::heap()->CollectAllAvailableGarbage();
19156 CHECK(CcTest::heap()->old_pointer_space()->Contains(
19157 *v8::Utils::OpenHandle(*cons)));
19158
19159 TestOneByteResource* resource =
19160 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
19161 cons->MakeExternal(resource);
19162
19163 CHECK(cons->IsExternalOneByte());
19164 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
19165 String::Encoding encoding;
19166 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19167 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
19168}
19169
19170
19171TEST(VisitExternalStrings) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019172 v8::Isolate* isolate = CcTest::isolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019173 LocalContext env;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019174 v8::HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019175 const char* string = "Some string";
19176 uint16_t* two_byte_string = AsciiToTwoByteString(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019177 TestResource* resource[4];
19178 resource[0] = new TestResource(two_byte_string);
19179 v8::Local<v8::String> string0 =
19180 v8::String::NewExternal(env->GetIsolate(), resource[0]);
19181 resource[1] = new TestResource(two_byte_string, NULL, false);
19182 v8::Local<v8::String> string1 =
19183 v8::String::NewExternal(env->GetIsolate(), resource[1]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019184
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019185 // Externalized symbol.
19186 resource[2] = new TestResource(two_byte_string, NULL, false);
19187 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
19188 env->GetIsolate(), string, v8::String::kInternalizedString);
19189 CHECK(string2->MakeExternal(resource[2]));
19190
19191 // Symbolized External.
19192 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
19193 v8::Local<v8::String> string3 =
19194 v8::String::NewExternal(env->GetIsolate(), resource[3]);
19195 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
19196 // Turn into a symbol.
19197 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
19198 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
19199 string3_i).is_null());
19200 CHECK(string3_i->IsInternalizedString());
19201
19202 // We need to add usages for string* to avoid warnings in GCC 4.7
19203 CHECK(string0->IsExternal());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019204 CHECK(string1->IsExternal());
19205 CHECK(string2->IsExternal());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019206 CHECK(string3->IsExternal());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019207
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019208 VisitorImpl visitor(resource);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019209 v8::V8::VisitExternalResources(&visitor);
19210 visitor.CheckVisitedResources();
19211}
19212
19213
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019214TEST(ExternalStringCollectedAtTearDown) {
19215 int destroyed = 0;
19216 v8::Isolate* isolate = v8::Isolate::New();
19217 { v8::Isolate::Scope isolate_scope(isolate);
19218 v8::HandleScope handle_scope(isolate);
19219 const char* s = "One string to test them all, one string to find them.";
19220 TestOneByteResource* inscription =
19221 new TestOneByteResource(i::StrDup(s), &destroyed);
19222 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
19223 // Ring is still alive. Orcs are roaming freely across our lands.
19224 CHECK_EQ(0, destroyed);
19225 USE(ring);
19226 }
19227
19228 isolate->Dispose();
19229 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19230 CHECK_EQ(1, destroyed);
19231}
19232
19233
19234TEST(ExternalInternalizedStringCollectedAtTearDown) {
19235 int destroyed = 0;
19236 v8::Isolate* isolate = v8::Isolate::New();
19237 { v8::Isolate::Scope isolate_scope(isolate);
19238 LocalContext env(isolate);
19239 v8::HandleScope handle_scope(isolate);
19240 CompileRun("var ring = 'One string to test them all';");
19241 const char* s = "One string to test them all";
19242 TestOneByteResource* inscription =
19243 new TestOneByteResource(i::StrDup(s), &destroyed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019244 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019245 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19246 ring->MakeExternal(inscription);
19247 // Ring is still alive. Orcs are roaming freely across our lands.
19248 CHECK_EQ(0, destroyed);
19249 USE(ring);
19250 }
19251
19252 isolate->Dispose();
19253 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19254 CHECK_EQ(1, destroyed);
19255}
19256
19257
19258TEST(ExternalInternalizedStringCollectedAtGC) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019259 // TODO(mvstanton): vector ics need weak support.
19260 if (i::FLAG_vector_ics) return;
19261
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019262 int destroyed = 0;
19263 { LocalContext env;
19264 v8::HandleScope handle_scope(env->GetIsolate());
19265 CompileRun("var ring = 'One string to test them all';");
19266 const char* s = "One string to test them all";
19267 TestOneByteResource* inscription =
19268 new TestOneByteResource(i::StrDup(s), &destroyed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019269 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019270 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19271 ring->MakeExternal(inscription);
19272 // Ring is still alive. Orcs are roaming freely across our lands.
19273 CHECK_EQ(0, destroyed);
19274 USE(ring);
19275 }
19276
19277 // Garbage collector deals swift blows to evil.
19278 CcTest::i_isolate()->compilation_cache()->Clear();
19279 CcTest::heap()->CollectAllAvailableGarbage();
19280
19281 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19282 CHECK_EQ(1, destroyed);
19283}
19284
19285
Steve Blockd0582a62009-12-15 09:54:21 +000019286static double DoubleFromBits(uint64_t value) {
19287 double target;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019288 i::MemCopy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000019289 return target;
19290}
19291
19292
19293static uint64_t DoubleToBits(double value) {
19294 uint64_t target;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019295 i::MemCopy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000019296 return target;
19297}
19298
19299
19300static double DoubleToDateTime(double input) {
19301 double date_limit = 864e13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019302 if (std::isnan(input) || input < -date_limit || input > date_limit) {
19303 return v8::base::OS::nan_value();
Steve Blockd0582a62009-12-15 09:54:21 +000019304 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019305 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
Steve Blockd0582a62009-12-15 09:54:21 +000019306}
19307
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019308
Steve Blockd0582a62009-12-15 09:54:21 +000019309// We don't have a consistent way to write 64-bit constants syntactically, so we
19310// split them into two 32-bit constants and combine them programmatically.
19311static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
19312 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
19313}
19314
19315
19316THREADED_TEST(QuietSignalingNaNs) {
Steve Blockd0582a62009-12-15 09:54:21 +000019317 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019318 v8::Isolate* isolate = context->GetIsolate();
19319 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019320 v8::TryCatch try_catch;
19321
19322 // Special double values.
19323 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
19324 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
19325 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
19326 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
19327 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
19328 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
19329 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
19330
19331 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
19332 // on either side of the epoch.
19333 double date_limit = 864e13;
19334
19335 double test_values[] = {
19336 snan,
19337 qnan,
19338 infinity,
19339 max_normal,
19340 date_limit + 1,
19341 date_limit,
19342 min_normal,
19343 max_denormal,
19344 min_denormal,
19345 0,
19346 -0,
19347 -min_denormal,
19348 -max_denormal,
19349 -min_normal,
19350 -date_limit,
19351 -date_limit - 1,
19352 -max_normal,
19353 -infinity,
19354 -qnan,
19355 -snan
19356 };
19357 int num_test_values = 20;
19358
19359 for (int i = 0; i < num_test_values; i++) {
19360 double test_value = test_values[i];
19361
19362 // Check that Number::New preserves non-NaNs and quiets SNaNs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019363 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
Steve Blockd0582a62009-12-15 09:54:21 +000019364 double stored_number = number->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019365 if (!std::isnan(test_value)) {
Steve Blockd0582a62009-12-15 09:54:21 +000019366 CHECK_EQ(test_value, stored_number);
19367 } else {
19368 uint64_t stored_bits = DoubleToBits(stored_number);
19369 // Check if quiet nan (bits 51..62 all set).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019370#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19371 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019372 // Most significant fraction bit for quiet nan is set to 0
19373 // on MIPS architecture. Allowed by IEEE-754.
19374 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19375#else
Steve Blockd0582a62009-12-15 09:54:21 +000019376 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019377#endif
Steve Blockd0582a62009-12-15 09:54:21 +000019378 }
19379
19380 // Check that Date::New preserves non-NaNs in the date range and
19381 // quiets SNaNs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019382 v8::Handle<v8::Value> date =
19383 v8::Date::New(isolate, test_value);
Steve Blockd0582a62009-12-15 09:54:21 +000019384 double expected_stored_date = DoubleToDateTime(test_value);
19385 double stored_date = date->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019386 if (!std::isnan(expected_stored_date)) {
Steve Blockd0582a62009-12-15 09:54:21 +000019387 CHECK_EQ(expected_stored_date, stored_date);
19388 } else {
19389 uint64_t stored_bits = DoubleToBits(stored_date);
19390 // Check if quiet nan (bits 51..62 all set).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019391#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19392 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019393 // Most significant fraction bit for quiet nan is set to 0
19394 // on MIPS architecture. Allowed by IEEE-754.
19395 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19396#else
Steve Blockd0582a62009-12-15 09:54:21 +000019397 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019398#endif
Steve Blockd0582a62009-12-15 09:54:21 +000019399 }
19400 }
19401}
19402
19403
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019404static void SpaghettiIncident(
19405 const v8::FunctionCallbackInfo<v8::Value>& args) {
19406 v8::HandleScope scope(args.GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000019407 v8::TryCatch tc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019408 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019409 USE(str);
Steve Blockd0582a62009-12-15 09:54:21 +000019410 if (tc.HasCaught())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019411 tc.ReThrow();
Steve Blockd0582a62009-12-15 09:54:21 +000019412}
19413
19414
19415// Test that an exception can be propagated down through a spaghetti
19416// stack using ReThrow.
19417THREADED_TEST(SpaghettiStackReThrow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019418 v8::Isolate* isolate = CcTest::isolate();
19419 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019420 LocalContext context;
19421 context->Global()->Set(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019422 v8::String::NewFromUtf8(isolate, "s"),
19423 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
Steve Blockd0582a62009-12-15 09:54:21 +000019424 v8::TryCatch try_catch;
19425 CompileRun(
19426 "var i = 0;"
19427 "var o = {"
19428 " toString: function () {"
19429 " if (i == 10) {"
19430 " throw 'Hey!';"
19431 " } else {"
19432 " i++;"
19433 " return s(o);"
19434 " }"
19435 " }"
19436 "};"
19437 "s(o);");
19438 CHECK(try_catch.HasCaught());
19439 v8::String::Utf8Value value(try_catch.Exception());
19440 CHECK_EQ(0, strcmp(*value, "Hey!"));
19441}
19442
19443
Steve Blockd0582a62009-12-15 09:54:21 +000019444TEST(Regress528) {
19445 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019446 v8::Isolate* isolate = CcTest::isolate();
19447 v8::HandleScope scope(isolate);
19448 v8::Local<Context> other_context;
Steve Blockd0582a62009-12-15 09:54:21 +000019449 int gc_count;
19450
19451 // Create a context used to keep the code from aging in the compilation
19452 // cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019453 other_context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019454
19455 // Context-dependent context data creates reference from the compilation
19456 // cache to the global object.
19457 const char* source_simple = "1";
Steve Blockd0582a62009-12-15 09:54:21 +000019458 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019459 v8::HandleScope scope(isolate);
19460 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019461
19462 context->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019463 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
19464 context->SetEmbedderData(0, obj);
Steve Blockd0582a62009-12-15 09:54:21 +000019465 CompileRun(source_simple);
19466 context->Exit();
19467 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019468 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000019469 for (gc_count = 1; gc_count < 10; gc_count++) {
19470 other_context->Enter();
19471 CompileRun(source_simple);
19472 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019473 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000019474 if (GetGlobalObjectsCount() == 1) break;
19475 }
19476 CHECK_GE(2, gc_count);
19477 CHECK_EQ(1, GetGlobalObjectsCount());
19478
19479 // Eval in a function creates reference from the compilation cache to the
19480 // global object.
19481 const char* source_eval = "function f(){eval('1')}; f()";
Steve Blockd0582a62009-12-15 09:54:21 +000019482 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019483 v8::HandleScope scope(isolate);
19484 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019485
19486 context->Enter();
19487 CompileRun(source_eval);
19488 context->Exit();
19489 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019490 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000019491 for (gc_count = 1; gc_count < 10; gc_count++) {
19492 other_context->Enter();
19493 CompileRun(source_eval);
19494 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019495 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000019496 if (GetGlobalObjectsCount() == 1) break;
19497 }
19498 CHECK_GE(2, gc_count);
19499 CHECK_EQ(1, GetGlobalObjectsCount());
19500
19501 // Looking up the line number for an exception creates reference from the
19502 // compilation cache to the global object.
19503 const char* source_exception = "function f(){throw 1;} f()";
Steve Blockd0582a62009-12-15 09:54:21 +000019504 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019505 v8::HandleScope scope(isolate);
19506 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000019507
19508 context->Enter();
19509 v8::TryCatch try_catch;
19510 CompileRun(source_exception);
19511 CHECK(try_catch.HasCaught());
19512 v8::Handle<v8::Message> message = try_catch.Message();
19513 CHECK(!message.IsEmpty());
19514 CHECK_EQ(1, message->GetLineNumber());
19515 context->Exit();
19516 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019517 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000019518 for (gc_count = 1; gc_count < 10; gc_count++) {
19519 other_context->Enter();
19520 CompileRun(source_exception);
19521 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019522 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000019523 if (GetGlobalObjectsCount() == 1) break;
19524 }
19525 CHECK_GE(2, gc_count);
19526 CHECK_EQ(1, GetGlobalObjectsCount());
19527
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019528 isolate->ContextDisposedNotification();
Steve Block3ce2e202009-11-05 08:53:23 +000019529}
Andrei Popescu402d9372010-02-26 13:31:12 +000019530
19531
19532THREADED_TEST(ScriptOrigin) {
Andrei Popescu402d9372010-02-26 13:31:12 +000019533 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019534 v8::HandleScope scope(env->GetIsolate());
19535 v8::ScriptOrigin origin =
19536 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19537 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19538 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
Andrei Popescu402d9372010-02-26 13:31:12 +000019539 v8::Script::Compile(script, &origin)->Run();
19540 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019541 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
Andrei Popescu402d9372010-02-26 13:31:12 +000019542 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019543 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
Andrei Popescu402d9372010-02-26 13:31:12 +000019544
19545 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019546 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
Andrei Popescu402d9372010-02-26 13:31:12 +000019547 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
19548
19549 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019550 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
Andrei Popescu402d9372010-02-26 13:31:12 +000019551 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
19552}
19553
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019554
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019555THREADED_TEST(FunctionGetInferredName) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019556 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019557 v8::HandleScope scope(env->GetIsolate());
19558 v8::ScriptOrigin origin =
19559 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19560 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19561 env->GetIsolate(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019562 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19563 v8::Script::Compile(script, &origin)->Run();
19564 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019565 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19566 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019567}
Andrei Popescu402d9372010-02-26 13:31:12 +000019568
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019569
19570THREADED_TEST(FunctionGetDisplayName) {
Andrei Popescu402d9372010-02-26 13:31:12 +000019571 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019572 v8::HandleScope scope(env->GetIsolate());
19573 const char* code = "var error = false;"
19574 "function a() { this.x = 1; };"
19575 "a.displayName = 'display_a';"
19576 "var b = (function() {"
19577 " var f = function() { this.x = 2; };"
19578 " f.displayName = 'display_b';"
19579 " return f;"
19580 "})();"
19581 "var c = function() {};"
19582 "c.__defineGetter__('displayName', function() {"
19583 " error = true;"
19584 " throw new Error();"
19585 "});"
19586 "function d() {};"
19587 "d.__defineGetter__('displayName', function() {"
19588 " error = true;"
19589 " return 'wrong_display_name';"
19590 "});"
19591 "function e() {};"
19592 "e.displayName = 'wrong_display_name';"
19593 "e.__defineSetter__('displayName', function() {"
19594 " error = true;"
19595 " throw new Error();"
19596 "});"
19597 "function f() {};"
19598 "f.displayName = { 'foo': 6, toString: function() {"
19599 " error = true;"
19600 " return 'wrong_display_name';"
19601 "}};"
19602 "var g = function() {"
19603 " arguments.callee.displayName = 'set_in_runtime';"
19604 "}; g();"
19605 ;
19606 v8::ScriptOrigin origin =
19607 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19608 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
19609 ->Run();
19610 v8::Local<v8::Value> error =
19611 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
19612 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19613 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
19614 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19615 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
19616 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19617 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
19618 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19619 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
19620 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19621 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
19622 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19623 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19624 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19625 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19626 CHECK_EQ(false, error->BooleanValue());
19627 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
19628 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
19629 CHECK(c->GetDisplayName()->IsUndefined());
19630 CHECK(d->GetDisplayName()->IsUndefined());
19631 CHECK(e->GetDisplayName()->IsUndefined());
19632 CHECK(f->GetDisplayName()->IsUndefined());
19633 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
19634}
19635
19636
19637THREADED_TEST(ScriptLineNumber) {
19638 LocalContext env;
19639 v8::HandleScope scope(env->GetIsolate());
19640 v8::ScriptOrigin origin =
19641 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19642 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19643 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
Andrei Popescu402d9372010-02-26 13:31:12 +000019644 v8::Script::Compile(script, &origin)->Run();
19645 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019646 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
Andrei Popescu402d9372010-02-26 13:31:12 +000019647 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019648 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
Andrei Popescu402d9372010-02-26 13:31:12 +000019649 CHECK_EQ(0, f->GetScriptLineNumber());
19650 CHECK_EQ(2, g->GetScriptLineNumber());
19651}
19652
19653
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019654THREADED_TEST(ScriptColumnNumber) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019655 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019656 v8::Isolate* isolate = env->GetIsolate();
19657 v8::HandleScope scope(isolate);
19658 v8::ScriptOrigin origin =
19659 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19660 v8::Integer::New(isolate, 3),
19661 v8::Integer::New(isolate, 2));
19662 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19663 isolate, "function foo() {}\n\n function bar() {}");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019664 v8::Script::Compile(script, &origin)->Run();
19665 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019666 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019667 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019668 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019669 CHECK_EQ(14, foo->GetScriptColumnNumber());
19670 CHECK_EQ(17, bar->GetScriptColumnNumber());
19671}
19672
19673
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019674THREADED_TEST(FunctionIsBuiltin) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019675 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019676 v8::Isolate* isolate = env->GetIsolate();
19677 v8::HandleScope scope(isolate);
19678 v8::Local<v8::Function> f;
19679 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
19680 CHECK(f->IsBuiltin());
19681 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
19682 CHECK(f->IsBuiltin());
19683 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
19684 CHECK(f->IsBuiltin());
19685 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
19686 CHECK(f->IsBuiltin());
19687 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
19688 CHECK(!f->IsBuiltin());
19689}
19690
19691
19692THREADED_TEST(FunctionGetScriptId) {
19693 LocalContext env;
19694 v8::Isolate* isolate = env->GetIsolate();
19695 v8::HandleScope scope(isolate);
19696 v8::ScriptOrigin origin =
19697 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19698 v8::Integer::New(isolate, 3),
19699 v8::Integer::New(isolate, 2));
19700 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
19701 isolate, "function foo() {}\n\n function bar() {}");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019702 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
19703 script->Run();
19704 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019705 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019706 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019707 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19708 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19709 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019710}
19711
19712
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019713THREADED_TEST(FunctionGetBoundFunction) {
19714 LocalContext env;
19715 v8::HandleScope scope(env->GetIsolate());
19716 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
19717 env->GetIsolate(), "test"));
19718 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19719 env->GetIsolate(),
19720 "var a = new Object();\n"
19721 "a.x = 1;\n"
19722 "function f () { return this.x };\n"
19723 "var g = f.bind(a);\n"
19724 "var b = g();");
19725 v8::Script::Compile(script, &origin)->Run();
19726 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19727 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19728 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19729 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19730 CHECK(g->GetBoundFunction()->IsFunction());
19731 Local<v8::Function> original_function = Local<v8::Function>::Cast(
19732 g->GetBoundFunction());
19733 CHECK_EQ(f->GetName(), original_function->GetName());
19734 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19735 CHECK_EQ(f->GetScriptColumnNumber(),
19736 original_function->GetScriptColumnNumber());
Andrei Popescu402d9372010-02-26 13:31:12 +000019737}
19738
19739
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019740static void GetterWhichReturns42(
19741 Local<String> name,
19742 const v8::PropertyCallbackInfo<v8::Value>& info) {
19743 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19744 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19745 info.GetReturnValue().Set(v8_num(42));
19746}
19747
19748
19749static void SetterWhichSetsYOnThisTo23(
19750 Local<String> name,
19751 Local<Value> value,
19752 const v8::PropertyCallbackInfo<void>& info) {
19753 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19754 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19755 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19756}
19757
19758
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019759void FooGetInterceptor(Local<Name> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019760 const v8::PropertyCallbackInfo<v8::Value>& info) {
19761 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19762 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19763 if (!name->Equals(v8_str("foo"))) return;
19764 info.GetReturnValue().Set(v8_num(42));
19765}
19766
19767
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019768void FooSetInterceptor(Local<Name> name, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019769 const v8::PropertyCallbackInfo<v8::Value>& info) {
19770 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19771 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19772 if (!name->Equals(v8_str("foo"))) return;
19773 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19774 info.GetReturnValue().Set(v8_num(23));
Andrei Popescu402d9372010-02-26 13:31:12 +000019775}
19776
19777
Steve Block6ded16b2010-05-10 14:33:55 +010019778TEST(SetterOnConstructorPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019779 v8::Isolate* isolate = CcTest::isolate();
19780 v8::HandleScope scope(isolate);
19781 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19782 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
Andrei Popescu402d9372010-02-26 13:31:12 +000019783 SetterWhichSetsYOnThisTo23);
19784 LocalContext context;
19785 context->Global()->Set(v8_str("P"), templ->NewInstance());
19786 CompileRun("function C1() {"
19787 " this.x = 23;"
19788 "};"
19789 "C1.prototype = P;"
19790 "function C2() {"
19791 " this.x = 23"
19792 "};"
19793 "C2.prototype = { };"
19794 "C2.prototype.__proto__ = P;");
19795
19796 v8::Local<v8::Script> script;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019797 script = v8_compile("new C1();");
Andrei Popescu402d9372010-02-26 13:31:12 +000019798 for (int i = 0; i < 10; i++) {
19799 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19800 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19801 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19802 }
19803
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019804script = v8_compile("new C2();");
Andrei Popescu402d9372010-02-26 13:31:12 +000019805 for (int i = 0; i < 10; i++) {
19806 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19807 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
19808 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
19809 }
19810}
19811
19812
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019813static void NamedPropertyGetterWhichReturns42(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019814 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019815 info.GetReturnValue().Set(v8_num(42));
Andrei Popescu402d9372010-02-26 13:31:12 +000019816}
19817
19818
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019819static void NamedPropertySetterWhichSetsYOnThisTo23(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019820 Local<Name> name, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019821 const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +000019822 if (name->Equals(v8_str("x"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019823 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
Andrei Popescu402d9372010-02-26 13:31:12 +000019824 }
Andrei Popescu402d9372010-02-26 13:31:12 +000019825}
19826
19827
19828THREADED_TEST(InterceptorOnConstructorPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019829 v8::Isolate* isolate = CcTest::isolate();
19830 v8::HandleScope scope(isolate);
19831 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040019832 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19833 NamedPropertyGetterWhichReturns42,
19834 NamedPropertySetterWhichSetsYOnThisTo23));
Andrei Popescu402d9372010-02-26 13:31:12 +000019835 LocalContext context;
19836 context->Global()->Set(v8_str("P"), templ->NewInstance());
19837 CompileRun("function C1() {"
19838 " this.x = 23;"
19839 "};"
19840 "C1.prototype = P;"
19841 "function C2() {"
19842 " this.x = 23"
19843 "};"
19844 "C2.prototype = { };"
19845 "C2.prototype.__proto__ = P;");
19846
19847 v8::Local<v8::Script> script;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019848 script = v8_compile("new C1();");
Andrei Popescu402d9372010-02-26 13:31:12 +000019849 for (int i = 0; i < 10; i++) {
19850 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19851 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19852 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19853 }
19854
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019855 script = v8_compile("new C2();");
Andrei Popescu402d9372010-02-26 13:31:12 +000019856 for (int i = 0; i < 10; i++) {
19857 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19858 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
19859 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
19860 }
19861}
Steve Block6ded16b2010-05-10 14:33:55 +010019862
19863
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019864TEST(Regress618) {
Steve Block6ded16b2010-05-10 14:33:55 +010019865 const char* source = "function C1() {"
19866 " this.x = 23;"
19867 "};"
19868 "C1.prototype = P;";
19869
Steve Block6ded16b2010-05-10 14:33:55 +010019870 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019871 v8::Isolate* isolate = context->GetIsolate();
19872 v8::HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010019873 v8::Local<v8::Script> script;
19874
19875 // Use a simple object as prototype.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019876 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010019877 prototype->Set(v8_str("y"), v8_num(42));
19878 context->Global()->Set(v8_str("P"), prototype);
19879
19880 // This compile will add the code to the compilation cache.
19881 CompileRun(source);
19882
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019883 script = v8_compile("new C1();");
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019884 // Allow enough iterations for the inobject slack tracking logic
19885 // to finalize instance size and install the fast construct stub.
19886 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010019887 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19888 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19889 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19890 }
19891
19892 // Use an API object with accessors as prototype.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019893 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19894 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
Steve Block6ded16b2010-05-10 14:33:55 +010019895 SetterWhichSetsYOnThisTo23);
19896 context->Global()->Set(v8_str("P"), templ->NewInstance());
19897
19898 // This compile will get the code from the compilation cache.
19899 CompileRun(source);
19900
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019901 script = v8_compile("new C1();");
Steve Block6ded16b2010-05-10 14:33:55 +010019902 for (int i = 0; i < 10; i++) {
19903 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19904 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19905 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19906 }
19907}
19908
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019909v8::Isolate* gc_callbacks_isolate = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +010019910int prologue_call_count = 0;
19911int epilogue_call_count = 0;
19912int prologue_call_count_second = 0;
19913int epilogue_call_count_second = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019914int prologue_call_count_alloc = 0;
19915int epilogue_call_count_alloc = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010019916
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019917void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19918 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010019919 ++prologue_call_count;
19920}
19921
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019922
19923void PrologueCallback(v8::Isolate* isolate,
19924 v8::GCType,
19925 v8::GCCallbackFlags flags) {
19926 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19927 CHECK_EQ(gc_callbacks_isolate, isolate);
19928 ++prologue_call_count;
19929}
19930
19931
19932void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19933 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010019934 ++epilogue_call_count;
19935}
19936
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019937
19938void EpilogueCallback(v8::Isolate* isolate,
19939 v8::GCType,
19940 v8::GCCallbackFlags flags) {
19941 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19942 CHECK_EQ(gc_callbacks_isolate, isolate);
19943 ++epilogue_call_count;
19944}
19945
19946
19947void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19948 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010019949 ++prologue_call_count_second;
19950}
19951
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019952
19953void PrologueCallbackSecond(v8::Isolate* isolate,
19954 v8::GCType,
19955 v8::GCCallbackFlags flags) {
19956 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19957 CHECK_EQ(gc_callbacks_isolate, isolate);
19958 ++prologue_call_count_second;
19959}
19960
19961
19962void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19963 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010019964 ++epilogue_call_count_second;
19965}
19966
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019967
19968void EpilogueCallbackSecond(v8::Isolate* isolate,
19969 v8::GCType,
19970 v8::GCCallbackFlags flags) {
19971 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19972 CHECK_EQ(gc_callbacks_isolate, isolate);
19973 ++epilogue_call_count_second;
19974}
19975
19976
19977void PrologueCallbackAlloc(v8::Isolate* isolate,
19978 v8::GCType,
19979 v8::GCCallbackFlags flags) {
19980 v8::HandleScope scope(isolate);
19981
19982 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19983 CHECK_EQ(gc_callbacks_isolate, isolate);
19984 ++prologue_call_count_alloc;
19985
19986 // Simulate full heap to see if we will reenter this callback
19987 SimulateFullSpace(CcTest::heap()->new_space());
19988
19989 Local<Object> obj = Object::New(isolate);
19990 CHECK(!obj.IsEmpty());
19991
19992 CcTest::heap()->CollectAllGarbage(
19993 i::Heap::kAbortIncrementalMarkingMask);
19994}
19995
19996
19997void EpilogueCallbackAlloc(v8::Isolate* isolate,
19998 v8::GCType,
19999 v8::GCCallbackFlags flags) {
20000 v8::HandleScope scope(isolate);
20001
20002 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20003 CHECK_EQ(gc_callbacks_isolate, isolate);
20004 ++epilogue_call_count_alloc;
20005
20006 // Simulate full heap to see if we will reenter this callback
20007 SimulateFullSpace(CcTest::heap()->new_space());
20008
20009 Local<Object> obj = Object::New(isolate);
20010 CHECK(!obj.IsEmpty());
20011
20012 CcTest::heap()->CollectAllGarbage(
20013 i::Heap::kAbortIncrementalMarkingMask);
20014}
20015
20016
20017TEST(GCCallbacksOld) {
Steve Block6ded16b2010-05-10 14:33:55 +010020018 LocalContext context;
20019
20020 v8::V8::AddGCPrologueCallback(PrologueCallback);
20021 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
20022 CHECK_EQ(0, prologue_call_count);
20023 CHECK_EQ(0, epilogue_call_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020024 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010020025 CHECK_EQ(1, prologue_call_count);
20026 CHECK_EQ(1, epilogue_call_count);
20027 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
20028 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020029 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010020030 CHECK_EQ(2, prologue_call_count);
20031 CHECK_EQ(2, epilogue_call_count);
20032 CHECK_EQ(1, prologue_call_count_second);
20033 CHECK_EQ(1, epilogue_call_count_second);
20034 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
20035 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020036 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010020037 CHECK_EQ(2, prologue_call_count);
20038 CHECK_EQ(2, epilogue_call_count);
20039 CHECK_EQ(2, prologue_call_count_second);
20040 CHECK_EQ(2, epilogue_call_count_second);
20041 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
20042 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020043 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010020044 CHECK_EQ(2, prologue_call_count);
20045 CHECK_EQ(2, epilogue_call_count);
20046 CHECK_EQ(2, prologue_call_count_second);
20047 CHECK_EQ(2, epilogue_call_count_second);
20048}
Kristian Monsen25f61362010-05-21 11:50:48 +010020049
20050
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020051TEST(GCCallbacks) {
20052 LocalContext context;
20053 v8::Isolate* isolate = context->GetIsolate();
20054 gc_callbacks_isolate = isolate;
20055 isolate->AddGCPrologueCallback(PrologueCallback);
20056 isolate->AddGCEpilogueCallback(EpilogueCallback);
20057 CHECK_EQ(0, prologue_call_count);
20058 CHECK_EQ(0, epilogue_call_count);
20059 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20060 CHECK_EQ(1, prologue_call_count);
20061 CHECK_EQ(1, epilogue_call_count);
20062 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
20063 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
20064 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20065 CHECK_EQ(2, prologue_call_count);
20066 CHECK_EQ(2, epilogue_call_count);
20067 CHECK_EQ(1, prologue_call_count_second);
20068 CHECK_EQ(1, epilogue_call_count_second);
20069 isolate->RemoveGCPrologueCallback(PrologueCallback);
20070 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
20071 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20072 CHECK_EQ(2, prologue_call_count);
20073 CHECK_EQ(2, epilogue_call_count);
20074 CHECK_EQ(2, prologue_call_count_second);
20075 CHECK_EQ(2, epilogue_call_count_second);
20076 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
20077 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20078 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20079 CHECK_EQ(2, prologue_call_count);
20080 CHECK_EQ(2, epilogue_call_count);
20081 CHECK_EQ(2, prologue_call_count_second);
20082 CHECK_EQ(2, epilogue_call_count_second);
20083
20084 CHECK_EQ(0, prologue_call_count_alloc);
20085 CHECK_EQ(0, epilogue_call_count_alloc);
20086 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
20087 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
20088 CcTest::heap()->CollectAllGarbage(
20089 i::Heap::kAbortIncrementalMarkingMask);
20090 CHECK_EQ(1, prologue_call_count_alloc);
20091 CHECK_EQ(1, epilogue_call_count_alloc);
20092 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
20093 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
20094}
20095
20096
Kristian Monsen25f61362010-05-21 11:50:48 +010020097THREADED_TEST(AddToJSFunctionResultCache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020098 i::FLAG_stress_compaction = false;
Kristian Monsen25f61362010-05-21 11:50:48 +010020099 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020100 v8::HandleScope scope(CcTest::isolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010020101
20102 LocalContext context;
20103
20104 const char* code =
20105 "(function() {"
20106 " var key0 = 'a';"
20107 " var key1 = 'b';"
20108 " var r0 = %_GetFromCache(0, key0);"
20109 " var r1 = %_GetFromCache(0, key1);"
20110 " var r0_ = %_GetFromCache(0, key0);"
20111 " if (r0 !== r0_)"
20112 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
20113 " var r1_ = %_GetFromCache(0, key1);"
20114 " if (r1 !== r1_)"
20115 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
20116 " return 'PASSED';"
20117 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020118 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010020119 ExpectString(code, "PASSED");
20120}
20121
20122
Kristian Monsen25f61362010-05-21 11:50:48 +010020123THREADED_TEST(FillJSFunctionResultCache) {
20124 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010020125 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020126 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010020127
20128 const char* code =
20129 "(function() {"
20130 " var k = 'a';"
20131 " var r = %_GetFromCache(0, k);"
20132 " for (var i = 0; i < 16; i++) {"
20133 " %_GetFromCache(0, 'a' + i);"
20134 " };"
20135 " if (r === %_GetFromCache(0, k))"
20136 " return 'FAILED: k0CacheSize is too small';"
20137 " return 'PASSED';"
20138 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020139 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010020140 ExpectString(code, "PASSED");
20141}
20142
20143
20144THREADED_TEST(RoundRobinGetFromCache) {
20145 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010020146 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020147 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010020148
20149 const char* code =
20150 "(function() {"
20151 " var keys = [];"
20152 " for (var i = 0; i < 16; i++) keys.push(i);"
20153 " var values = [];"
20154 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20155 " for (var i = 0; i < 16; i++) {"
20156 " var v = %_GetFromCache(0, keys[i]);"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020157 " if (v.toString() !== values[i].toString())"
Kristian Monsen25f61362010-05-21 11:50:48 +010020158 " return 'Wrong value for ' + "
20159 " keys[i] + ': ' + v + ' vs. ' + values[i];"
20160 " };"
20161 " return 'PASSED';"
20162 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020163 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010020164 ExpectString(code, "PASSED");
20165}
20166
20167
20168THREADED_TEST(ReverseGetFromCache) {
20169 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010020170 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020171 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010020172
20173 const char* code =
20174 "(function() {"
20175 " var keys = [];"
20176 " for (var i = 0; i < 16; i++) keys.push(i);"
20177 " var values = [];"
20178 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20179 " for (var i = 15; i >= 16; i--) {"
20180 " var v = %_GetFromCache(0, keys[i]);"
20181 " if (v !== values[i])"
20182 " return 'Wrong value for ' + "
20183 " keys[i] + ': ' + v + ' vs. ' + values[i];"
20184 " };"
20185 " return 'PASSED';"
20186 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020187 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010020188 ExpectString(code, "PASSED");
20189}
20190
20191
20192THREADED_TEST(TestEviction) {
20193 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010020194 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020195 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010020196
20197 const char* code =
20198 "(function() {"
20199 " for (var i = 0; i < 2*16; i++) {"
20200 " %_GetFromCache(0, 'a' + i);"
20201 " };"
20202 " return 'PASSED';"
20203 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020204 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010020205 ExpectString(code, "PASSED");
20206}
Steve Block8defd9f2010-07-08 12:39:36 +010020207
20208
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020209THREADED_TEST(TwoByteStringInOneByteCons) {
Steve Block8defd9f2010-07-08 12:39:36 +010020210 // See Chromium issue 47824.
Steve Block8defd9f2010-07-08 12:39:36 +010020211 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020212 v8::HandleScope scope(context->GetIsolate());
20213
Steve Block8defd9f2010-07-08 12:39:36 +010020214 const char* init_code =
20215 "var str1 = 'abelspendabel';"
20216 "var str2 = str1 + str1 + str1;"
20217 "str2;";
20218 Local<Value> result = CompileRun(init_code);
20219
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020220 Local<Value> indexof = CompileRun("str2.indexOf('els')");
20221 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
20222
Steve Block8defd9f2010-07-08 12:39:36 +010020223 CHECK(result->IsString());
20224 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
20225 int length = string->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020226 CHECK(string->IsOneByteRepresentation());
Steve Block8defd9f2010-07-08 12:39:36 +010020227
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020228 i::Handle<i::String> flat_string = i::String::Flatten(string);
Steve Block8defd9f2010-07-08 12:39:36 +010020229
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020230 CHECK(string->IsOneByteRepresentation());
20231 CHECK(flat_string->IsOneByteRepresentation());
Steve Block8defd9f2010-07-08 12:39:36 +010020232
20233 // Create external resource.
20234 uint16_t* uc16_buffer = new uint16_t[length + 1];
20235
20236 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
20237 uc16_buffer[length] = 0;
20238
20239 TestResource resource(uc16_buffer);
20240
20241 flat_string->MakeExternal(&resource);
20242
20243 CHECK(flat_string->IsTwoByteRepresentation());
20244
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020245 // If the cons string has been short-circuited, skip the following checks.
20246 if (!string.is_identical_to(flat_string)) {
20247 // At this point, we should have a Cons string which is flat and one-byte,
20248 // with a first half that is a two-byte string (although it only contains
20249 // one-byte characters). This is a valid sequence of steps, and it can
20250 // happen in real pages.
20251 CHECK(string->IsOneByteRepresentation());
20252 i::ConsString* cons = i::ConsString::cast(*string);
20253 CHECK_EQ(0, cons->second()->length());
20254 CHECK(cons->first()->IsTwoByteRepresentation());
20255 }
Steve Block8defd9f2010-07-08 12:39:36 +010020256
20257 // Check that some string operations work.
20258
20259 // Atom RegExp.
20260 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
20261 CHECK_EQ(6, reresult->Int32Value());
20262
20263 // Nonatom RegExp.
20264 reresult = CompileRun("str2.match(/abe./g).length;");
20265 CHECK_EQ(6, reresult->Int32Value());
20266
20267 reresult = CompileRun("str2.search(/bel/g);");
20268 CHECK_EQ(1, reresult->Int32Value());
20269
20270 reresult = CompileRun("str2.search(/be./g);");
20271 CHECK_EQ(1, reresult->Int32Value());
20272
20273 ExpectTrue("/bel/g.test(str2);");
20274
20275 ExpectTrue("/be./g.test(str2);");
20276
20277 reresult = CompileRun("/bel/g.exec(str2);");
20278 CHECK(!reresult->IsNull());
20279
20280 reresult = CompileRun("/be./g.exec(str2);");
20281 CHECK(!reresult->IsNull());
20282
20283 ExpectString("str2.substring(2, 10);", "elspenda");
20284
20285 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
20286
20287 ExpectString("str2.charAt(2);", "e");
20288
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020289 ExpectObject("str2.indexOf('els');", indexof);
20290
20291 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
20292
Steve Block8defd9f2010-07-08 12:39:36 +010020293 reresult = CompileRun("str2.charCodeAt(2);");
20294 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
20295}
Iain Merrick75681382010-08-19 15:07:18 +010020296
20297
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020298TEST(ContainsOnlyOneByte) {
20299 v8::V8::Initialize();
20300 v8::Isolate* isolate = CcTest::isolate();
20301 v8::HandleScope scope(isolate);
20302 // Make a buffer long enough that it won't automatically be converted.
20303 const int length = 512;
20304 // Ensure word aligned assignment.
20305 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
20306 i::SmartArrayPointer<uintptr_t>
20307 aligned_contents(new uintptr_t[aligned_length]);
20308 uint16_t* string_contents =
20309 reinterpret_cast<uint16_t*>(aligned_contents.get());
20310 // Set to contain only one byte.
20311 for (int i = 0; i < length-1; i++) {
20312 string_contents[i] = 0x41;
20313 }
20314 string_contents[length-1] = 0;
20315 // Simple case.
20316 Handle<String> string =
20317 String::NewExternal(isolate,
20318 new TestResource(string_contents, NULL, false));
20319 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20320 // Counter example.
20321 string = String::NewFromTwoByte(isolate, string_contents);
20322 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20323 // Test left right and balanced cons strings.
20324 Handle<String> base = String::NewFromUtf8(isolate, "a");
20325 Handle<String> left = base;
20326 Handle<String> right = base;
20327 for (int i = 0; i < 1000; i++) {
20328 left = String::Concat(base, left);
20329 right = String::Concat(right, base);
20330 }
20331 Handle<String> balanced = String::Concat(left, base);
20332 balanced = String::Concat(balanced, right);
20333 Handle<String> cons_strings[] = {left, balanced, right};
20334 Handle<String> two_byte =
20335 String::NewExternal(isolate,
20336 new TestResource(string_contents, NULL, false));
20337 USE(two_byte); USE(cons_strings);
20338 for (size_t i = 0; i < arraysize(cons_strings); i++) {
20339 // Base assumptions.
20340 string = cons_strings[i];
20341 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20342 // Test left and right concatentation.
20343 string = String::Concat(two_byte, cons_strings[i]);
20344 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20345 string = String::Concat(cons_strings[i], two_byte);
20346 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20347 }
20348 // Set bits in different positions
20349 // for strings of different lengths and alignments.
20350 for (int alignment = 0; alignment < 7; alignment++) {
20351 for (int size = 2; alignment + size < length; size *= 2) {
20352 int zero_offset = size + alignment;
20353 string_contents[zero_offset] = 0;
20354 for (int i = 0; i < size; i++) {
20355 int shift = 8 + (i % 7);
20356 string_contents[alignment + i] = 1 << shift;
20357 string = String::NewExternal(
20358 isolate,
20359 new TestResource(string_contents + alignment, NULL, false));
20360 CHECK_EQ(size, string->Length());
20361 CHECK(!string->ContainsOnlyOneByte());
20362 string_contents[alignment + i] = 0x41;
20363 }
20364 string_contents[zero_offset] = 0x41;
20365 }
20366 }
20367}
20368
20369
Iain Merrick75681382010-08-19 15:07:18 +010020370// Failed access check callback that performs a GC on each invocation.
20371void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20372 v8::AccessType type,
20373 Local<v8::Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020374 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Iain Merrick75681382010-08-19 15:07:18 +010020375}
20376
20377
20378TEST(GCInFailedAccessCheckCallback) {
20379 // Install a failed access check callback that performs a GC on each
20380 // invocation. Then force the callback to be called from va
20381
20382 v8::V8::Initialize();
20383 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20384
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020385 v8::Isolate* isolate = CcTest::isolate();
20386 v8::HandleScope scope(isolate);
Iain Merrick75681382010-08-19 15:07:18 +010020387
20388 // Create an ObjectTemplate for global objects and install access
20389 // check callbacks that will block access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020390 v8::Handle<v8::ObjectTemplate> global_template =
20391 v8::ObjectTemplate::New(isolate);
Iain Merrick75681382010-08-19 15:07:18 +010020392 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
20393 IndexedGetAccessBlocker,
20394 v8::Handle<v8::Value>(),
20395 false);
20396
20397 // Create a context and set an x property on it's global object.
20398 LocalContext context0(NULL, global_template);
20399 context0->Global()->Set(v8_str("x"), v8_num(42));
20400 v8::Handle<v8::Object> global0 = context0->Global();
20401
20402 // Create a context with a different security token so that the
20403 // failed access check callback will be called on each access.
20404 LocalContext context1(NULL, global_template);
20405 context1->Global()->Set(v8_str("other"), global0);
20406
20407 // Get property with failed access check.
20408 ExpectUndefined("other.x");
20409
20410 // Get element with failed access check.
20411 ExpectUndefined("other[0]");
20412
20413 // Set property with failed access check.
20414 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
20415 CHECK(result->IsObject());
20416
20417 // Set element with failed access check.
20418 result = CompileRun("other[0] = new Object()");
20419 CHECK(result->IsObject());
20420
20421 // Get property attribute with failed access check.
20422 ExpectFalse("\'x\' in other");
20423
20424 // Get property attribute for element with failed access check.
20425 ExpectFalse("0 in other");
20426
20427 // Delete property.
20428 ExpectFalse("delete other.x");
20429
20430 // Delete element.
20431 CHECK_EQ(false, global0->Delete(0));
20432
20433 // DefineAccessor.
20434 CHECK_EQ(false,
20435 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
20436
20437 // Define JavaScript accessor.
20438 ExpectUndefined("Object.prototype.__defineGetter__.call("
20439 " other, \'x\', function() { return 42; })");
20440
20441 // LookupAccessor.
20442 ExpectUndefined("Object.prototype.__lookupGetter__.call("
20443 " other, \'x\')");
20444
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020445 // HasOwnElement.
Iain Merrick75681382010-08-19 15:07:18 +010020446 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
20447
20448 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
20449 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
20450 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
20451
20452 // Reset the failed access check callback so it does not influence
20453 // the other tests.
20454 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20455}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020456
Steve Block44f0eee2011-05-26 01:26:41 +010020457
20458TEST(IsolateNewDispose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020459 v8::Isolate* current_isolate = CcTest::isolate();
Steve Block44f0eee2011-05-26 01:26:41 +010020460 v8::Isolate* isolate = v8::Isolate::New();
20461 CHECK(isolate != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010020462 CHECK(current_isolate != isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020463 CHECK(current_isolate == CcTest::isolate());
Steve Block44f0eee2011-05-26 01:26:41 +010020464
20465 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20466 last_location = last_message = NULL;
20467 isolate->Dispose();
20468 CHECK_EQ(last_location, NULL);
20469 CHECK_EQ(last_message, NULL);
20470}
20471
Steve Block44f0eee2011-05-26 01:26:41 +010020472
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020473UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
Steve Block44f0eee2011-05-26 01:26:41 +010020474 v8::Isolate* isolate = v8::Isolate::New();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020475 {
20476 v8::Isolate::Scope i_scope(isolate);
20477 v8::HandleScope scope(isolate);
20478 LocalContext context(isolate);
20479 // Run something in this isolate.
20480 ExpectTrue("true");
20481 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20482 last_location = last_message = NULL;
20483 // Still entered, should fail.
20484 isolate->Dispose();
20485 CHECK_NE(last_location, NULL);
20486 CHECK_NE(last_message, NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010020487 }
Steve Block44f0eee2011-05-26 01:26:41 +010020488 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010020489}
20490
Steve Block44f0eee2011-05-26 01:26:41 +010020491
20492TEST(RunTwoIsolatesOnSingleThread) {
20493 // Run isolate 1.
20494 v8::Isolate* isolate1 = v8::Isolate::New();
20495 isolate1->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020496 v8::Persistent<v8::Context> context1;
20497 {
20498 v8::HandleScope scope(isolate1);
20499 context1.Reset(isolate1, Context::New(isolate1));
20500 }
Steve Block44f0eee2011-05-26 01:26:41 +010020501
20502 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020503 v8::HandleScope scope(isolate1);
20504 v8::Local<v8::Context> context =
20505 v8::Local<v8::Context>::New(isolate1, context1);
20506 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020507 // Run something in new isolate.
20508 CompileRun("var foo = 'isolate 1';");
20509 ExpectString("function f() { return foo; }; f()", "isolate 1");
20510 }
20511
20512 // Run isolate 2.
20513 v8::Isolate* isolate2 = v8::Isolate::New();
20514 v8::Persistent<v8::Context> context2;
20515
20516 {
20517 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020518 v8::HandleScope scope(isolate2);
20519 context2.Reset(isolate2, Context::New(isolate2));
20520 v8::Local<v8::Context> context =
20521 v8::Local<v8::Context>::New(isolate2, context2);
20522 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020523
20524 // Run something in new isolate.
20525 CompileRun("var foo = 'isolate 2';");
20526 ExpectString("function f() { return foo; }; f()", "isolate 2");
20527 }
20528
20529 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020530 v8::HandleScope scope(isolate1);
20531 v8::Local<v8::Context> context =
20532 v8::Local<v8::Context>::New(isolate1, context1);
20533 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020534 // Now again in isolate 1
20535 ExpectString("function f() { return foo; }; f()", "isolate 1");
20536 }
20537
20538 isolate1->Exit();
20539
20540 // Run some stuff in default isolate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020541 v8::Persistent<v8::Context> context_default;
20542 {
20543 v8::Isolate* isolate = CcTest::isolate();
20544 v8::Isolate::Scope iscope(isolate);
20545 v8::HandleScope scope(isolate);
20546 context_default.Reset(isolate, Context::New(isolate));
20547 }
Steve Block44f0eee2011-05-26 01:26:41 +010020548
20549 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020550 v8::HandleScope scope(CcTest::isolate());
20551 v8::Local<v8::Context> context =
20552 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20553 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020554 // Variables in other isolates should be not available, verify there
20555 // is an exception.
20556 ExpectTrue("function f() {"
20557 " try {"
20558 " foo;"
20559 " return false;"
20560 " } catch(e) {"
20561 " return true;"
20562 " }"
20563 "};"
20564 "var isDefaultIsolate = true;"
20565 "f()");
20566 }
20567
20568 isolate1->Enter();
20569
20570 {
20571 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020572 v8::HandleScope scope(isolate2);
20573 v8::Local<v8::Context> context =
20574 v8::Local<v8::Context>::New(isolate2, context2);
20575 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020576 ExpectString("function f() { return foo; }; f()", "isolate 2");
20577 }
20578
20579 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020580 v8::HandleScope scope(v8::Isolate::GetCurrent());
20581 v8::Local<v8::Context> context =
20582 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20583 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020584 ExpectString("function f() { return foo; }; f()", "isolate 1");
20585 }
20586
20587 {
20588 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020589 context2.Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010020590 }
20591
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020592 context1.Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010020593 isolate1->Exit();
20594
20595 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20596 last_location = last_message = NULL;
20597
20598 isolate1->Dispose();
20599 CHECK_EQ(last_location, NULL);
20600 CHECK_EQ(last_message, NULL);
20601
20602 isolate2->Dispose();
20603 CHECK_EQ(last_location, NULL);
20604 CHECK_EQ(last_message, NULL);
20605
20606 // Check that default isolate still runs.
20607 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020608 v8::HandleScope scope(CcTest::isolate());
20609 v8::Local<v8::Context> context =
20610 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20611 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010020612 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20613 }
20614}
20615
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020616
Steve Block44f0eee2011-05-26 01:26:41 +010020617static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20618 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020619 v8::HandleScope scope(isolate);
20620 LocalContext context(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +010020621 i::ScopedVector<char> code(1024);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020622 i::SNPrintF(code, "function fib(n) {"
20623 " if (n <= 2) return 1;"
20624 " return fib(n-1) + fib(n-2);"
20625 "}"
20626 "fib(%d)", limit);
Steve Block44f0eee2011-05-26 01:26:41 +010020627 Local<Value> value = CompileRun(code.start());
20628 CHECK(value->IsNumber());
20629 return static_cast<int>(value->NumberValue());
20630}
20631
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020632class IsolateThread : public v8::base::Thread {
Steve Block44f0eee2011-05-26 01:26:41 +010020633 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020634 explicit IsolateThread(int fib_limit)
20635 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
Steve Block44f0eee2011-05-26 01:26:41 +010020636
20637 void Run() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020638 v8::Isolate* isolate = v8::Isolate::New();
20639 result_ = CalcFibonacci(isolate, fib_limit_);
20640 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010020641 }
20642
20643 int result() { return result_; }
20644
20645 private:
Steve Block44f0eee2011-05-26 01:26:41 +010020646 int fib_limit_;
20647 int result_;
20648};
20649
Steve Block44f0eee2011-05-26 01:26:41 +010020650
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020651TEST(MultipleIsolatesOnIndividualThreads) {
20652 IsolateThread thread1(21);
20653 IsolateThread thread2(12);
Steve Block44f0eee2011-05-26 01:26:41 +010020654
20655 // Compute some fibonacci numbers on 3 threads in 3 isolates.
20656 thread1.Start();
20657 thread2.Start();
20658
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020659 int result1 = CalcFibonacci(CcTest::isolate(), 21);
20660 int result2 = CalcFibonacci(CcTest::isolate(), 12);
Steve Block44f0eee2011-05-26 01:26:41 +010020661
20662 thread1.Join();
20663 thread2.Join();
20664
20665 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20666 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20667 CHECK_EQ(result1, 10946);
20668 CHECK_EQ(result2, 144);
20669 CHECK_EQ(result1, thread1.result());
20670 CHECK_EQ(result2, thread2.result());
Steve Block44f0eee2011-05-26 01:26:41 +010020671}
20672
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020673
Ben Murdoch257744e2011-11-30 15:57:28 +000020674TEST(IsolateDifferentContexts) {
20675 v8::Isolate* isolate = v8::Isolate::New();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020676 Local<v8::Context> context;
Ben Murdoch257744e2011-11-30 15:57:28 +000020677 {
20678 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020679 v8::HandleScope handle_scope(isolate);
20680 context = v8::Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020681 v8::Context::Scope context_scope(context);
20682 Local<Value> v = CompileRun("2");
20683 CHECK(v->IsNumber());
20684 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
20685 }
20686 {
20687 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020688 v8::HandleScope handle_scope(isolate);
20689 context = v8::Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020690 v8::Context::Scope context_scope(context);
20691 Local<Value> v = CompileRun("22");
20692 CHECK(v->IsNumber());
20693 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
20694 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020695 isolate->Dispose();
Ben Murdoch257744e2011-11-30 15:57:28 +000020696}
Steve Block44f0eee2011-05-26 01:26:41 +010020697
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020698class InitDefaultIsolateThread : public v8::base::Thread {
Steve Block44f0eee2011-05-26 01:26:41 +010020699 public:
20700 enum TestCase {
Steve Block44f0eee2011-05-26 01:26:41 +010020701 SetResourceConstraints,
20702 SetFatalHandler,
20703 SetCounterFunction,
20704 SetCreateHistogramFunction,
20705 SetAddHistogramSampleFunction
20706 };
20707
20708 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020709 : Thread(Options("InitDefaultIsolateThread")),
Steve Block44f0eee2011-05-26 01:26:41 +010020710 testCase_(testCase),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020711 result_(false) {}
Steve Block44f0eee2011-05-26 01:26:41 +010020712
20713 void Run() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020714 v8::Isolate::CreateParams create_params;
Steve Block44f0eee2011-05-26 01:26:41 +010020715 switch (testCase_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020716 case SetResourceConstraints: {
20717 create_params.constraints.set_max_semi_space_size(1);
20718 create_params.constraints.set_max_old_space_size(4);
20719 break;
20720 }
20721 default:
20722 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020724 v8::Isolate* isolate = v8::Isolate::New(create_params);
20725 isolate->Enter();
20726 switch (testCase_) {
20727 case SetResourceConstraints:
20728 // Already handled in pre-Isolate-creation block.
20729 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020730
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020731 case SetFatalHandler:
20732 v8::V8::SetFatalErrorHandler(NULL);
20733 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020734
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020735 case SetCounterFunction:
20736 CcTest::isolate()->SetCounterFunction(NULL);
20737 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020738
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020739 case SetCreateHistogramFunction:
20740 CcTest::isolate()->SetCreateHistogramFunction(NULL);
20741 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020742
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020743 case SetAddHistogramSampleFunction:
20744 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
20745 break;
Steve Block44f0eee2011-05-26 01:26:41 +010020746 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020747 isolate->Exit();
20748 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010020749 result_ = true;
20750 }
20751
20752 bool result() { return result_; }
20753
20754 private:
20755 TestCase testCase_;
20756 bool result_;
20757};
20758
20759
20760static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20761 InitDefaultIsolateThread thread(testCase);
20762 thread.Start();
20763 thread.Join();
20764 CHECK_EQ(thread.result(), true);
20765}
20766
Steve Block44f0eee2011-05-26 01:26:41 +010020767
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020768TEST(InitializeDefaultIsolateOnSecondaryThread1) {
Steve Block44f0eee2011-05-26 01:26:41 +010020769 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20770}
20771
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020772
20773TEST(InitializeDefaultIsolateOnSecondaryThread2) {
Steve Block44f0eee2011-05-26 01:26:41 +010020774 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20775}
20776
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020777
20778TEST(InitializeDefaultIsolateOnSecondaryThread3) {
Steve Block44f0eee2011-05-26 01:26:41 +010020779 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20780}
20781
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020782
20783TEST(InitializeDefaultIsolateOnSecondaryThread4) {
Steve Block44f0eee2011-05-26 01:26:41 +010020784 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20785}
20786
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020787
20788TEST(InitializeDefaultIsolateOnSecondaryThread5) {
Steve Block44f0eee2011-05-26 01:26:41 +010020789 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20790}
20791
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020792
20793TEST(StringCheckMultipleContexts) {
20794 const char* code =
20795 "(function() { return \"a\".charAt(0); })()";
20796
20797 {
20798 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020799 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020800 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020801 ExpectString(code, "a");
20802 ExpectString(code, "a");
20803 }
20804
20805 {
20806 // Change the String.prototype in the second context and check
20807 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020808 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020809 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020810 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20811 ExpectString(code, "not a");
20812 }
20813}
20814
20815
20816TEST(NumberCheckMultipleContexts) {
20817 const char* code =
20818 "(function() { return (42).toString(); })()";
20819
20820 {
20821 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020822 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020823 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020824 ExpectString(code, "42");
20825 ExpectString(code, "42");
20826 }
20827
20828 {
20829 // Change the Number.prototype in the second context and check
20830 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020831 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020832 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020833 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20834 ExpectString(code, "not 42");
20835 }
20836}
20837
20838
20839TEST(BooleanCheckMultipleContexts) {
20840 const char* code =
20841 "(function() { return true.toString(); })()";
20842
20843 {
20844 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020845 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020846 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020847 ExpectString(code, "true");
20848 ExpectString(code, "true");
20849 }
20850
20851 {
20852 // Change the Boolean.prototype in the second context and check
20853 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020854 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020855 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010020856 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20857 ExpectString(code, "");
20858 }
20859}
Ben Murdochf87a2032010-10-22 12:50:53 +010020860
20861
20862TEST(DontDeleteCellLoadIC) {
20863 const char* function_code =
20864 "function readCell() { while (true) { return cell; } }";
20865
20866 {
20867 // Run the code twice in the first context to initialize the load
20868 // IC for a don't delete cell.
Ben Murdochf87a2032010-10-22 12:50:53 +010020869 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020870 v8::HandleScope scope(context1->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010020871 CompileRun("var cell = \"first\";");
20872 ExpectBoolean("delete cell", false);
20873 CompileRun(function_code);
20874 ExpectString("readCell()", "first");
20875 ExpectString("readCell()", "first");
20876 }
20877
20878 {
20879 // Use a deletable cell in the second context.
Ben Murdochf87a2032010-10-22 12:50:53 +010020880 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020881 v8::HandleScope scope(context2->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010020882 CompileRun("cell = \"second\";");
20883 CompileRun(function_code);
20884 ExpectString("readCell()", "second");
20885 ExpectBoolean("delete cell", true);
20886 ExpectString("(function() {"
20887 " try {"
20888 " return readCell();"
20889 " } catch(e) {"
20890 " return e.toString();"
20891 " }"
20892 "})()",
20893 "ReferenceError: cell is not defined");
20894 CompileRun("cell = \"new_second\";");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020895 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdochf87a2032010-10-22 12:50:53 +010020896 ExpectString("readCell()", "new_second");
20897 ExpectString("readCell()", "new_second");
20898 }
20899}
20900
20901
20902TEST(DontDeleteCellLoadICForceDelete) {
20903 const char* function_code =
20904 "function readCell() { while (true) { return cell; } }";
20905
20906 // Run the code twice to initialize the load IC for a don't delete
20907 // cell.
Ben Murdochf87a2032010-10-22 12:50:53 +010020908 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020909 v8::HandleScope scope(context->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010020910 CompileRun("var cell = \"value\";");
20911 ExpectBoolean("delete cell", false);
20912 CompileRun(function_code);
20913 ExpectString("readCell()", "value");
20914 ExpectString("readCell()", "value");
20915
20916 // Delete the cell using the API and check the inlined code works
20917 // correctly.
20918 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20919 ExpectString("(function() {"
20920 " try {"
20921 " return readCell();"
20922 " } catch(e) {"
20923 " return e.toString();"
20924 " }"
20925 "})()",
20926 "ReferenceError: cell is not defined");
20927}
20928
20929
20930TEST(DontDeleteCellLoadICAPI) {
20931 const char* function_code =
20932 "function readCell() { while (true) { return cell; } }";
20933
20934 // Run the code twice to initialize the load IC for a don't delete
20935 // cell created using the API.
Ben Murdochf87a2032010-10-22 12:50:53 +010020936 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020937 v8::HandleScope scope(context->GetIsolate());
20938 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
Ben Murdochf87a2032010-10-22 12:50:53 +010020939 ExpectBoolean("delete cell", false);
20940 CompileRun(function_code);
20941 ExpectString("readCell()", "value");
20942 ExpectString("readCell()", "value");
20943
20944 // Delete the cell using the API and check the inlined code works
20945 // correctly.
20946 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20947 ExpectString("(function() {"
20948 " try {"
20949 " return readCell();"
20950 " } catch(e) {"
20951 " return e.toString();"
20952 " }"
20953 "})()",
20954 "ReferenceError: cell is not defined");
20955}
20956
20957
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020958class Visitor42 : public v8::PersistentHandleVisitor {
20959 public:
20960 explicit Visitor42(v8::Persistent<v8::Object>* object)
20961 : counter_(0), object_(object) { }
20962
20963 virtual void VisitPersistentHandle(Persistent<Value>* value,
20964 uint16_t class_id) {
20965 if (class_id != 42) return;
20966 CHECK_EQ(42, value->WrapperClassId());
20967 v8::Isolate* isolate = CcTest::isolate();
20968 v8::HandleScope handle_scope(isolate);
20969 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20970 v8::Handle<v8::Value> object =
20971 v8::Local<v8::Object>::New(isolate, *object_);
20972 CHECK(handle->IsObject());
20973 CHECK_EQ(Handle<Object>::Cast(handle), object);
20974 ++counter_;
20975 }
20976
20977 int counter_;
20978 v8::Persistent<v8::Object>* object_;
20979};
20980
20981
20982TEST(PersistentHandleVisitor) {
Ben Murdochf87a2032010-10-22 12:50:53 +010020983 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020984 v8::Isolate* isolate = context->GetIsolate();
20985 v8::HandleScope scope(isolate);
20986 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20987 CHECK_EQ(0, object.WrapperClassId());
20988 object.SetWrapperClassId(42);
20989 CHECK_EQ(42, object.WrapperClassId());
20990
20991 Visitor42 visitor(&object);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020992 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020993 CHECK_EQ(1, visitor.counter_);
20994
20995 object.Reset();
20996}
20997
20998
20999TEST(WrapperClassId) {
21000 LocalContext context;
21001 v8::Isolate* isolate = context->GetIsolate();
21002 v8::HandleScope scope(isolate);
21003 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
21004 CHECK_EQ(0, object.WrapperClassId());
21005 object.SetWrapperClassId(65535);
21006 CHECK_EQ(65535, object.WrapperClassId());
21007 object.Reset();
21008}
21009
21010
21011TEST(PersistentHandleInNewSpaceVisitor) {
21012 LocalContext context;
21013 v8::Isolate* isolate = context->GetIsolate();
21014 v8::HandleScope scope(isolate);
21015 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
21016 CHECK_EQ(0, object1.WrapperClassId());
21017 object1.SetWrapperClassId(42);
21018 CHECK_EQ(42, object1.WrapperClassId());
21019
21020 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21021 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21022
21023 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
21024 CHECK_EQ(0, object2.WrapperClassId());
21025 object2.SetWrapperClassId(42);
21026 CHECK_EQ(42, object2.WrapperClassId());
21027
21028 Visitor42 visitor(&object2);
21029 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
21030 CHECK_EQ(1, visitor.counter_);
21031
21032 object1.Reset();
21033 object2.Reset();
21034}
21035
21036
21037TEST(RegExp) {
21038 LocalContext context;
21039 v8::HandleScope scope(context->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010021040
21041 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
21042 CHECK(re->IsRegExp());
21043 CHECK(re->GetSource()->Equals(v8_str("foo")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021044 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010021045
21046 re = v8::RegExp::New(v8_str("bar"),
21047 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21048 v8::RegExp::kGlobal));
21049 CHECK(re->IsRegExp());
21050 CHECK(re->GetSource()->Equals(v8_str("bar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021051 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
21052 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010021053
21054 re = v8::RegExp::New(v8_str("baz"),
21055 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21056 v8::RegExp::kMultiline));
21057 CHECK(re->IsRegExp());
21058 CHECK(re->GetSource()->Equals(v8_str("baz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021059 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21060 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010021061
21062 re = CompileRun("/quux/").As<v8::RegExp>();
21063 CHECK(re->IsRegExp());
21064 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021065 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010021066
21067 re = CompileRun("/quux/gm").As<v8::RegExp>();
21068 CHECK(re->IsRegExp());
21069 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021070 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
21071 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010021072
21073 // Override the RegExp constructor and check the API constructor
21074 // still works.
21075 CompileRun("RegExp = function() {}");
21076
21077 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
21078 CHECK(re->IsRegExp());
21079 CHECK(re->GetSource()->Equals(v8_str("foobar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021080 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010021081
21082 re = v8::RegExp::New(v8_str("foobarbaz"),
21083 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21084 v8::RegExp::kMultiline));
21085 CHECK(re->IsRegExp());
21086 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021087 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21088 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010021089
21090 context->Global()->Set(v8_str("re"), re);
21091 ExpectTrue("re.test('FoobarbaZ')");
21092
Ben Murdoch257744e2011-11-30 15:57:28 +000021093 // RegExps are objects on which you can set properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021094 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021095 v8::Handle<v8::Value> value(CompileRun("re.property"));
21096 CHECK_EQ(32, value->Int32Value());
Ben Murdoch257744e2011-11-30 15:57:28 +000021097
Ben Murdochf87a2032010-10-22 12:50:53 +010021098 v8::TryCatch try_catch;
21099 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
21100 CHECK(re.IsEmpty());
21101 CHECK(try_catch.HasCaught());
21102 context->Global()->Set(v8_str("ex"), try_catch.Exception());
21103 ExpectTrue("ex instanceof SyntaxError");
21104}
21105
21106
Steve Block1e0659c2011-05-24 12:43:12 +010021107THREADED_TEST(Equals) {
Steve Block1e0659c2011-05-24 12:43:12 +010021108 LocalContext localContext;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021109 v8::HandleScope handleScope(localContext->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010021110
21111 v8::Handle<v8::Object> globalProxy = localContext->Global();
21112 v8::Handle<Value> global = globalProxy->GetPrototype();
21113
21114 CHECK(global->StrictEquals(global));
21115 CHECK(!global->StrictEquals(globalProxy));
21116 CHECK(!globalProxy->StrictEquals(global));
21117 CHECK(globalProxy->StrictEquals(globalProxy));
21118
21119 CHECK(global->Equals(global));
21120 CHECK(!global->Equals(globalProxy));
21121 CHECK(!globalProxy->Equals(global));
21122 CHECK(globalProxy->Equals(globalProxy));
21123}
21124
21125
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021126static void Getter(v8::Local<v8::Name> property,
21127 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021128 info.GetReturnValue().Set(v8_str("42!"));
Ben Murdochf87a2032010-10-22 12:50:53 +010021129}
21130
21131
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021132static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
21133 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010021134 result->Set(0, v8_str("universalAnswer"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021135 info.GetReturnValue().Set(result);
Ben Murdochf87a2032010-10-22 12:50:53 +010021136}
21137
21138
21139TEST(NamedEnumeratorAndForIn) {
Ben Murdochf87a2032010-10-22 12:50:53 +010021140 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021141 v8::Isolate* isolate = context->GetIsolate();
21142 v8::HandleScope handle_scope(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +010021143 v8::Context::Scope context_scope(context.local());
21144
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021145 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021146 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
21147 NULL, Enumerator));
Ben Murdochf87a2032010-10-22 12:50:53 +010021148 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
21149 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
21150 "var result = []; for (var k in o) result.push(k); result"));
21151 CHECK_EQ(1, result->Length());
21152 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
21153}
Steve Block1e0659c2011-05-24 12:43:12 +010021154
21155
21156TEST(DefinePropertyPostDetach) {
Steve Block1e0659c2011-05-24 12:43:12 +010021157 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021158 v8::HandleScope scope(context->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010021159 v8::Handle<v8::Object> proxy = context->Global();
21160 v8::Handle<v8::Function> define_property =
21161 CompileRun("(function() {"
21162 " Object.defineProperty("
21163 " this,"
21164 " 1,"
21165 " { configurable: true, enumerable: true, value: 3 });"
21166 "})").As<Function>();
21167 context->DetachGlobal();
21168 define_property->Call(proxy, 0, NULL);
21169}
Ben Murdoch8b112d22011-06-08 16:22:53 +010021170
21171
21172static void InstallContextId(v8::Handle<Context> context, int id) {
21173 Context::Scope scope(context);
21174 CompileRun("Object.prototype").As<Object>()->
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021175 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
Ben Murdoch8b112d22011-06-08 16:22:53 +010021176}
21177
21178
21179static void CheckContextId(v8::Handle<Object> object, int expected) {
21180 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
21181}
21182
21183
21184THREADED_TEST(CreationContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021185 v8::Isolate* isolate = CcTest::isolate();
21186 HandleScope handle_scope(isolate);
21187 Handle<Context> context1 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021188 InstallContextId(context1, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021189 Handle<Context> context2 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021190 InstallContextId(context2, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021191 Handle<Context> context3 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021192 InstallContextId(context3, 3);
21193
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021194 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021195
21196 Local<Object> object1;
21197 Local<Function> func1;
21198 {
21199 Context::Scope scope(context1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021200 object1 = Object::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021201 func1 = tmpl->GetFunction();
21202 }
21203
21204 Local<Object> object2;
21205 Local<Function> func2;
21206 {
21207 Context::Scope scope(context2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021208 object2 = Object::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010021209 func2 = tmpl->GetFunction();
21210 }
21211
21212 Local<Object> instance1;
21213 Local<Object> instance2;
21214
21215 {
21216 Context::Scope scope(context3);
21217 instance1 = func1->NewInstance();
21218 instance2 = func2->NewInstance();
21219 }
21220
21221 CHECK(object1->CreationContext() == context1);
21222 CheckContextId(object1, 1);
21223 CHECK(func1->CreationContext() == context1);
21224 CheckContextId(func1, 1);
21225 CHECK(instance1->CreationContext() == context1);
21226 CheckContextId(instance1, 1);
21227 CHECK(object2->CreationContext() == context2);
21228 CheckContextId(object2, 2);
21229 CHECK(func2->CreationContext() == context2);
21230 CheckContextId(func2, 2);
21231 CHECK(instance2->CreationContext() == context2);
21232 CheckContextId(instance2, 2);
21233
21234 {
21235 Context::Scope scope(context1);
21236 CHECK(object1->CreationContext() == context1);
21237 CheckContextId(object1, 1);
21238 CHECK(func1->CreationContext() == context1);
21239 CheckContextId(func1, 1);
21240 CHECK(instance1->CreationContext() == context1);
21241 CheckContextId(instance1, 1);
21242 CHECK(object2->CreationContext() == context2);
21243 CheckContextId(object2, 2);
21244 CHECK(func2->CreationContext() == context2);
21245 CheckContextId(func2, 2);
21246 CHECK(instance2->CreationContext() == context2);
21247 CheckContextId(instance2, 2);
21248 }
21249
21250 {
21251 Context::Scope scope(context2);
21252 CHECK(object1->CreationContext() == context1);
21253 CheckContextId(object1, 1);
21254 CHECK(func1->CreationContext() == context1);
21255 CheckContextId(func1, 1);
21256 CHECK(instance1->CreationContext() == context1);
21257 CheckContextId(instance1, 1);
21258 CHECK(object2->CreationContext() == context2);
21259 CheckContextId(object2, 2);
21260 CHECK(func2->CreationContext() == context2);
21261 CheckContextId(func2, 2);
21262 CHECK(instance2->CreationContext() == context2);
21263 CheckContextId(instance2, 2);
21264 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010021265}
Ben Murdoch257744e2011-11-30 15:57:28 +000021266
21267
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021268THREADED_TEST(CreationContextOfJsFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021269 HandleScope handle_scope(CcTest::isolate());
21270 Handle<Context> context = Context::New(CcTest::isolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021271 InstallContextId(context, 1);
21272
21273 Local<Object> function;
21274 {
21275 Context::Scope scope(context);
21276 function = CompileRun("function foo() {}; foo").As<Object>();
21277 }
21278
21279 CHECK(function->CreationContext() == context);
21280 CheckContextId(function, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021281}
21282
21283
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021284void HasOwnPropertyIndexedPropertyGetter(
21285 uint32_t index,
21286 const v8::PropertyCallbackInfo<v8::Value>& info) {
21287 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000021288}
21289
21290
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021291void HasOwnPropertyNamedPropertyGetter(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021292 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021293 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000021294}
21295
21296
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021297void HasOwnPropertyIndexedPropertyQuery(
21298 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21299 if (index == 42) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000021300}
21301
21302
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021303void HasOwnPropertyNamedPropertyQuery(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021304 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021305 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000021306}
21307
21308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021309void HasOwnPropertyNamedPropertyQuery2(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021310 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021311 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000021312}
21313
21314
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021315void HasOwnPropertyAccessorGetter(
21316 Local<String> property,
21317 const v8::PropertyCallbackInfo<v8::Value>& info) {
21318 info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000021319}
21320
21321
21322TEST(HasOwnProperty) {
Ben Murdoch257744e2011-11-30 15:57:28 +000021323 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021324 v8::Isolate* isolate = env->GetIsolate();
21325 v8::HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000021326 { // Check normal properties and defined getters.
21327 Handle<Value> value = CompileRun(
21328 "function Foo() {"
21329 " this.foo = 11;"
21330 " this.__defineGetter__('baz', function() { return 1; });"
21331 "};"
21332 "function Bar() { "
21333 " this.bar = 13;"
21334 " this.__defineGetter__('bla', function() { return 2; });"
21335 "};"
21336 "Bar.prototype = new Foo();"
21337 "new Bar();");
21338 CHECK(value->IsObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021339 Handle<Object> object = value->ToObject(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000021340 CHECK(object->Has(v8_str("foo")));
21341 CHECK(!object->HasOwnProperty(v8_str("foo")));
21342 CHECK(object->HasOwnProperty(v8_str("bar")));
21343 CHECK(object->Has(v8_str("baz")));
21344 CHECK(!object->HasOwnProperty(v8_str("baz")));
21345 CHECK(object->HasOwnProperty(v8_str("bla")));
21346 }
21347 { // Check named getter interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021348 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021349 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21350 HasOwnPropertyNamedPropertyGetter));
Ben Murdoch257744e2011-11-30 15:57:28 +000021351 Handle<Object> instance = templ->NewInstance();
21352 CHECK(!instance->HasOwnProperty(v8_str("42")));
21353 CHECK(instance->HasOwnProperty(v8_str("foo")));
21354 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21355 }
21356 { // Check indexed getter interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021357 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021358 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21359 HasOwnPropertyIndexedPropertyGetter));
Ben Murdoch257744e2011-11-30 15:57:28 +000021360 Handle<Object> instance = templ->NewInstance();
21361 CHECK(instance->HasOwnProperty(v8_str("42")));
21362 CHECK(!instance->HasOwnProperty(v8_str("43")));
21363 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21364 }
21365 { // Check named query interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021366 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021367 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21368 0, 0, HasOwnPropertyNamedPropertyQuery));
Ben Murdoch257744e2011-11-30 15:57:28 +000021369 Handle<Object> instance = templ->NewInstance();
21370 CHECK(instance->HasOwnProperty(v8_str("foo")));
21371 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21372 }
21373 { // Check indexed query interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021374 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021375 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21376 0, 0, HasOwnPropertyIndexedPropertyQuery));
Ben Murdoch257744e2011-11-30 15:57:28 +000021377 Handle<Object> instance = templ->NewInstance();
21378 CHECK(instance->HasOwnProperty(v8_str("42")));
21379 CHECK(!instance->HasOwnProperty(v8_str("41")));
21380 }
21381 { // Check callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021382 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000021383 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21384 Handle<Object> instance = templ->NewInstance();
21385 CHECK(instance->HasOwnProperty(v8_str("foo")));
21386 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21387 }
21388 { // Check that query wins on disagreement.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021389 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021390 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21391 HasOwnPropertyNamedPropertyGetter, 0,
21392 HasOwnPropertyNamedPropertyQuery2));
Ben Murdoch257744e2011-11-30 15:57:28 +000021393 Handle<Object> instance = templ->NewInstance();
21394 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21395 CHECK(instance->HasOwnProperty(v8_str("bar")));
21396 }
21397}
21398
21399
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021400TEST(IndexedInterceptorWithStringProto) {
21401 v8::Isolate* isolate = CcTest::isolate();
21402 v8::HandleScope scope(isolate);
21403 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021404 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21405 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021406 LocalContext context;
21407 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21408 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21409 // These should be intercepted.
21410 CHECK(CompileRun("42 in obj")->BooleanValue());
21411 CHECK(CompileRun("'42' in obj")->BooleanValue());
21412 // These should fall through to the String prototype.
21413 CHECK(CompileRun("0 in obj")->BooleanValue());
21414 CHECK(CompileRun("'0' in obj")->BooleanValue());
21415 // And these should both fail.
21416 CHECK(!CompileRun("32 in obj")->BooleanValue());
21417 CHECK(!CompileRun("'32' in obj")->BooleanValue());
21418}
21419
21420
Ben Murdoch257744e2011-11-30 15:57:28 +000021421void CheckCodeGenerationAllowed() {
21422 Handle<Value> result = CompileRun("eval('42')");
21423 CHECK_EQ(42, result->Int32Value());
21424 result = CompileRun("(function(e) { return e('42'); })(eval)");
21425 CHECK_EQ(42, result->Int32Value());
21426 result = CompileRun("var f = new Function('return 42'); f()");
21427 CHECK_EQ(42, result->Int32Value());
21428}
21429
21430
21431void CheckCodeGenerationDisallowed() {
21432 TryCatch try_catch;
21433
21434 Handle<Value> result = CompileRun("eval('42')");
21435 CHECK(result.IsEmpty());
21436 CHECK(try_catch.HasCaught());
21437 try_catch.Reset();
21438
21439 result = CompileRun("(function(e) { return e('42'); })(eval)");
21440 CHECK(result.IsEmpty());
21441 CHECK(try_catch.HasCaught());
21442 try_catch.Reset();
21443
21444 result = CompileRun("var f = new Function('return 42'); f()");
21445 CHECK(result.IsEmpty());
21446 CHECK(try_catch.HasCaught());
21447}
21448
21449
21450bool CodeGenerationAllowed(Local<Context> context) {
21451 ApiTestFuzzer::Fuzz();
21452 return true;
21453}
21454
21455
21456bool CodeGenerationDisallowed(Local<Context> context) {
21457 ApiTestFuzzer::Fuzz();
21458 return false;
21459}
21460
21461
21462THREADED_TEST(AllowCodeGenFromStrings) {
Ben Murdoch257744e2011-11-30 15:57:28 +000021463 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021464 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +000021465
21466 // eval and the Function constructor allowed by default.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021467 CHECK(context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000021468 CheckCodeGenerationAllowed();
21469
21470 // Disallow eval and the Function constructor.
21471 context->AllowCodeGenerationFromStrings(false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021472 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000021473 CheckCodeGenerationDisallowed();
21474
21475 // Allow again.
21476 context->AllowCodeGenerationFromStrings(true);
21477 CheckCodeGenerationAllowed();
21478
21479 // Disallow but setting a global callback that will allow the calls.
21480 context->AllowCodeGenerationFromStrings(false);
21481 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021482 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000021483 CheckCodeGenerationAllowed();
21484
21485 // Set a callback that disallows the code generation.
21486 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021487 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000021488 CheckCodeGenerationDisallowed();
21489}
21490
21491
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021492TEST(SetErrorMessageForCodeGenFromStrings) {
21493 LocalContext context;
21494 v8::HandleScope scope(context->GetIsolate());
21495 TryCatch try_catch;
21496
21497 Handle<String> message = v8_str("Message") ;
21498 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
21499 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21500 context->AllowCodeGenerationFromStrings(false);
21501 context->SetErrorMessageForCodeGenerationFromStrings(message);
21502 Handle<Value> result = CompileRun("eval('42')");
21503 CHECK(result.IsEmpty());
21504 CHECK(try_catch.HasCaught());
21505 Handle<String> actual_message = try_catch.Message()->Get();
21506 CHECK(expected_message->Equals(actual_message));
21507}
21508
21509
21510static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000021511}
21512
21513
21514THREADED_TEST(CallAPIFunctionOnNonObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000021515 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021516 v8::Isolate* isolate = context->GetIsolate();
21517 v8::HandleScope scope(isolate);
21518 Handle<FunctionTemplate> templ =
21519 v8::FunctionTemplate::New(isolate, NonObjectThis);
Ben Murdoch257744e2011-11-30 15:57:28 +000021520 Handle<Function> function = templ->GetFunction();
21521 context->Global()->Set(v8_str("f"), function);
21522 TryCatch try_catch;
21523 CompileRun("f.call(2)");
21524}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021525
21526
21527// Regression test for issue 1470.
21528THREADED_TEST(ReadOnlyIndexedProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021529 v8::Isolate* isolate = CcTest::isolate();
21530 v8::HandleScope scope(isolate);
21531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021532
21533 LocalContext context;
21534 Local<v8::Object> obj = templ->NewInstance();
21535 context->Global()->Set(v8_str("obj"), obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021536 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021537 obj->Set(v8_str("1"), v8_str("foobar"));
21538 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021539 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021540 obj->Set(v8_num(2), v8_str("foobar"));
21541 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
21542
21543 // Test non-smi case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021544 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021545 obj->Set(v8_str("2000000000"), v8_str("foobar"));
21546 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
21547}
21548
21549
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021550static int CountLiveMapsInMapCache(i::Context* context) {
21551 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
21552 int length = map_cache->length();
21553 int count = 0;
21554 for (int i = 0; i < length; i++) {
21555 i::Object* value = map_cache->get(i);
21556 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
21557 }
21558 return count;
21559}
21560
21561
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021562THREADED_TEST(Regress1516) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021563 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021564 v8::HandleScope scope(context->GetIsolate());
21565
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021566 // Object with 20 properties is not a common case, so it should be removed
21567 // from the cache after GC.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021568 { v8::HandleScope temp_scope(context->GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021569 CompileRun(
21570 "({"
21571 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21572 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21573 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21574 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21575 "})");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021576 }
21577
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021578 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21579 CHECK_LE(1, elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021580
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
21582
21583 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021584}
21585
21586
21587static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
21588 Local<Value> name,
21589 v8::AccessType type,
21590 Local<Value> data) {
21591 // Only block read access to __proto__.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021592 if (type == v8::ACCESS_GET && name->IsString() &&
21593 name.As<v8::String>()->Length() == 9 &&
21594 name.As<v8::String>()->Utf8Length() == 9) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021595 char buffer[10];
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021596 CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021597 return strncmp(buffer, "__proto__", 9) != 0;
21598 }
21599
21600 return true;
21601}
21602
21603
21604THREADED_TEST(Regress93759) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021605 v8::Isolate* isolate = CcTest::isolate();
21606 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021607
21608 // Template for object with security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021609 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021610 // We don't do indexing, so any callback can be used for that.
21611 no_proto_template->SetAccessCheckCallbacks(
21612 BlockProtoNamedSecurityTestCallback,
21613 IndexedSecurityTestCallback);
21614
21615 // Templates for objects with hidden prototypes and possibly security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021616 Local<FunctionTemplate> hidden_proto_template =
21617 v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021618 hidden_proto_template->SetHiddenPrototype(true);
21619
21620 Local<FunctionTemplate> protected_hidden_proto_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021621 v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021622 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
21623 BlockProtoNamedSecurityTestCallback,
21624 IndexedSecurityTestCallback);
21625 protected_hidden_proto_template->SetHiddenPrototype(true);
21626
21627 // Context for "foreign" objects used in test.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021628 Local<Context> context = v8::Context::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021629 context->Enter();
21630
21631 // Plain object, no security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021632 Local<Object> simple_object = Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021633
21634 // Object with explicit security check.
21635 Local<Object> protected_object =
21636 no_proto_template->NewInstance();
21637
21638 // JSGlobalProxy object, always have security check.
21639 Local<Object> proxy_object =
21640 context->Global();
21641
21642 // Global object, the prototype of proxy_object. No security checks.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021643 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021644
21645 // Hidden prototype without security check.
21646 Local<Object> hidden_prototype =
21647 hidden_proto_template->GetFunction()->NewInstance();
21648 Local<Object> object_with_hidden =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021649 Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021650 object_with_hidden->SetPrototype(hidden_prototype);
21651
21652 // Hidden prototype with security check on the hidden prototype.
21653 Local<Object> protected_hidden_prototype =
21654 protected_hidden_proto_template->GetFunction()->NewInstance();
21655 Local<Object> object_with_protected_hidden =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021656 Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021657 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
21658
21659 context->Exit();
21660
21661 // Template for object for second context. Values to test are put on it as
21662 // properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021663 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021664 global_template->Set(v8_str("simple"), simple_object);
21665 global_template->Set(v8_str("protected"), protected_object);
21666 global_template->Set(v8_str("global"), global_object);
21667 global_template->Set(v8_str("proxy"), proxy_object);
21668 global_template->Set(v8_str("hidden"), object_with_hidden);
21669 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
21670
21671 LocalContext context2(NULL, global_template);
21672
21673 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21674 CHECK(result1->Equals(simple_object->GetPrototype()));
21675
21676 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021677 CHECK(result2.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021678
21679 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21680 CHECK(result3->Equals(global_object->GetPrototype()));
21681
21682 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021683 CHECK(result4.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021684
21685 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21686 CHECK(result5->Equals(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021687 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021688
21689 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021690 CHECK(result6.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000021691}
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021692
21693
Ben Murdoch5710cea2012-05-21 14:52:42 +010021694THREADED_TEST(Regress125988) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021695 v8::HandleScope scope(CcTest::isolate());
21696 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch5710cea2012-05-21 14:52:42 +010021697 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
21698 LocalContext env;
21699 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
21700 CompileRun("var a = new Object();"
21701 "var b = new Intercept();"
21702 "var c = new Object();"
21703 "c.__proto__ = b;"
21704 "b.__proto__ = a;"
21705 "a.x = 23;"
21706 "for (var i = 0; i < 3; i++) c.x;");
21707 ExpectBoolean("c.hasOwnProperty('x')", false);
21708 ExpectInt32("c.x", 23);
21709 CompileRun("a.y = 42;"
21710 "for (var i = 0; i < 3; i++) c.x;");
21711 ExpectBoolean("c.hasOwnProperty('x')", false);
21712 ExpectInt32("c.x", 23);
21713 ExpectBoolean("c.hasOwnProperty('y')", false);
21714 ExpectInt32("c.y", 42);
21715}
21716
21717
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021718static void TestReceiver(Local<Value> expected_result,
21719 Local<Value> expected_receiver,
21720 const char* code) {
21721 Local<Value> result = CompileRun(code);
21722 CHECK(result->IsObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040021723 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
21724 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021725}
21726
21727
21728THREADED_TEST(ForeignFunctionReceiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021729 v8::Isolate* isolate = CcTest::isolate();
21730 HandleScope scope(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021731
21732 // Create two contexts with different "id" properties ('i' and 'o').
21733 // Call a function both from its own context and from a the foreign
21734 // context, and see what "this" is bound to (returning both "this"
21735 // and "this.id" for comparison).
21736
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021737 Local<Context> foreign_context = v8::Context::New(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021738 foreign_context->Enter();
21739 Local<Value> foreign_function =
21740 CompileRun("function func() { return { 0: this.id, "
21741 " 1: this, "
21742 " toString: function() { "
21743 " return this[0];"
21744 " }"
21745 " };"
21746 "}"
21747 "var id = 'i';"
21748 "func;");
21749 CHECK(foreign_function->IsFunction());
21750 foreign_context->Exit();
21751
21752 LocalContext context;
21753
21754 Local<String> password = v8_str("Password");
21755 // Don't get hit by security checks when accessing foreign_context's
21756 // global receiver (aka. global proxy).
21757 context->SetSecurityToken(password);
21758 foreign_context->SetSecurityToken(password);
21759
21760 Local<String> i = v8_str("i");
21761 Local<String> o = v8_str("o");
21762 Local<String> id = v8_str("id");
21763
21764 CompileRun("function ownfunc() { return { 0: this.id, "
21765 " 1: this, "
21766 " toString: function() { "
21767 " return this[0];"
21768 " }"
21769 " };"
21770 "}"
21771 "var id = 'o';"
21772 "ownfunc");
21773 context->Global()->Set(v8_str("func"), foreign_function);
21774
21775 // Sanity check the contexts.
21776 CHECK(i->Equals(foreign_context->Global()->Get(id)));
21777 CHECK(o->Equals(context->Global()->Get(id)));
21778
21779 // Checking local function's receiver.
21780 // Calling function using its call/apply methods.
21781 TestReceiver(o, context->Global(), "ownfunc.call()");
21782 TestReceiver(o, context->Global(), "ownfunc.apply()");
21783 // Making calls through built-in functions.
21784 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21785 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
21786 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
21787 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
21788 // Calling with environment record as base.
21789 TestReceiver(o, context->Global(), "ownfunc()");
21790 // Calling with no base.
21791 TestReceiver(o, context->Global(), "(1,ownfunc)()");
21792
21793 // Checking foreign function return value.
21794 // Calling function using its call/apply methods.
21795 TestReceiver(i, foreign_context->Global(), "func.call()");
21796 TestReceiver(i, foreign_context->Global(), "func.apply()");
21797 // Calling function using another context's call/apply methods.
21798 TestReceiver(i, foreign_context->Global(),
21799 "Function.prototype.call.call(func)");
21800 TestReceiver(i, foreign_context->Global(),
21801 "Function.prototype.call.apply(func)");
21802 TestReceiver(i, foreign_context->Global(),
21803 "Function.prototype.apply.call(func)");
21804 TestReceiver(i, foreign_context->Global(),
21805 "Function.prototype.apply.apply(func)");
21806 // Making calls through built-in functions.
21807 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21808 // ToString(func()) is func()[0], i.e., the returned this.id.
21809 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
21810 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
21811 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
21812
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021813 // Calling with environment record as base.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021814 TestReceiver(i, foreign_context->Global(), "func()");
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021815 // Calling with no base.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021816 TestReceiver(i, foreign_context->Global(), "(1,func)()");
Ben Murdoch69a99ed2011-11-30 16:03:39 +000021817}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021818
21819
21820uint8_t callback_fired = 0;
21821
21822
21823void CallCompletedCallback1() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021824 v8::base::OS::Print("Firing callback 1.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021825 callback_fired ^= 1; // Toggle first bit.
21826}
21827
21828
21829void CallCompletedCallback2() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021830 v8::base::OS::Print("Firing callback 2.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021831 callback_fired ^= 2; // Toggle second bit.
21832}
21833
21834
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021835void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021836 int32_t level = args[0]->Int32Value();
21837 if (level < 3) {
21838 level++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021839 v8::base::OS::Print("Entering recursion level %d.\n", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021840 char script[64];
21841 i::Vector<char> script_vector(script, sizeof(script));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021842 i::SNPrintF(script_vector, "recursion(%d)", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021843 CompileRun(script_vector.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021844 v8::base::OS::Print("Leaving recursion level %d.\n", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021845 CHECK_EQ(0, callback_fired);
21846 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021847 v8::base::OS::Print("Recursion ends.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021848 CHECK_EQ(0, callback_fired);
21849 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021850}
21851
21852
21853TEST(CallCompletedCallback) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021854 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021855 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021856 v8::Handle<v8::FunctionTemplate> recursive_runtime =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021857 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021858 env->Global()->Set(v8_str("recursion"),
21859 recursive_runtime->GetFunction());
21860 // Adding the same callback a second time has no effect.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021861 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21862 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21863 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21864 v8::base::OS::Print("--- Script (1) ---\n");
21865 Local<Script> script = v8::Script::Compile(
21866 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021867 script->Run();
21868 CHECK_EQ(3, callback_fired);
21869
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021870 v8::base::OS::Print("\n--- Script (2) ---\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021871 callback_fired = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021872 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021873 script->Run();
21874 CHECK_EQ(2, callback_fired);
21875
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021876 v8::base::OS::Print("\n--- Function ---\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021877 callback_fired = 0;
21878 Local<Function> recursive_function =
21879 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
21880 v8::Handle<Value> args[] = { v8_num(0) };
21881 recursive_function->Call(env->Global(), 1, args);
21882 CHECK_EQ(2, callback_fired);
21883}
21884
21885
21886void CallCompletedCallbackNoException() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021887 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021888 CompileRun("1+1;");
21889}
21890
21891
21892void CallCompletedCallbackException() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021893 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021894 CompileRun("throw 'second exception';");
21895}
21896
21897
21898TEST(CallCompletedCallbackOneException) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021899 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021900 v8::HandleScope scope(env->GetIsolate());
21901 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021902 CompileRun("throw 'exception';");
21903}
21904
21905
21906TEST(CallCompletedCallbackTwoExceptions) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021907 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021908 v8::HandleScope scope(env->GetIsolate());
21909 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021910 CompileRun("throw 'first exception';");
21911}
21912
21913
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021914static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21915 v8::HandleScope scope(info.GetIsolate());
21916 CompileRun("ext1Calls++;");
21917}
21918
21919
21920static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21921 v8::HandleScope scope(info.GetIsolate());
21922 CompileRun("ext2Calls++;");
21923}
21924
21925
21926void* g_passed_to_three = NULL;
21927
21928
21929static void MicrotaskThree(void* data) {
21930 g_passed_to_three = data;
21931}
21932
21933
21934TEST(EnqueueMicrotask) {
21935 LocalContext env;
21936 v8::HandleScope scope(env->GetIsolate());
21937 CompileRun(
21938 "var ext1Calls = 0;"
21939 "var ext2Calls = 0;");
21940 CompileRun("1+1;");
21941 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21942 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21943
21944 env->GetIsolate()->EnqueueMicrotask(
21945 Function::New(env->GetIsolate(), MicrotaskOne));
21946 CompileRun("1+1;");
21947 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21948 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21949
21950 env->GetIsolate()->EnqueueMicrotask(
21951 Function::New(env->GetIsolate(), MicrotaskOne));
21952 env->GetIsolate()->EnqueueMicrotask(
21953 Function::New(env->GetIsolate(), MicrotaskTwo));
21954 CompileRun("1+1;");
21955 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21956 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21957
21958 env->GetIsolate()->EnqueueMicrotask(
21959 Function::New(env->GetIsolate(), MicrotaskTwo));
21960 CompileRun("1+1;");
21961 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21962 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21963
21964 CompileRun("1+1;");
21965 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21966 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21967
21968 g_passed_to_three = NULL;
21969 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21970 CompileRun("1+1;");
21971 CHECK_EQ(NULL, g_passed_to_three);
21972 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21973 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21974
21975 int dummy;
21976 env->GetIsolate()->EnqueueMicrotask(
21977 Function::New(env->GetIsolate(), MicrotaskOne));
21978 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21979 env->GetIsolate()->EnqueueMicrotask(
21980 Function::New(env->GetIsolate(), MicrotaskTwo));
21981 CompileRun("1+1;");
21982 CHECK_EQ(&dummy, g_passed_to_three);
21983 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
21984 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21985 g_passed_to_three = NULL;
21986}
21987
21988
21989static void MicrotaskExceptionOne(
21990 const v8::FunctionCallbackInfo<Value>& info) {
21991 v8::HandleScope scope(info.GetIsolate());
21992 CompileRun("exception1Calls++;");
21993 info.GetIsolate()->ThrowException(
21994 v8::Exception::Error(v8_str("first")));
21995}
21996
21997
21998static void MicrotaskExceptionTwo(
21999 const v8::FunctionCallbackInfo<Value>& info) {
22000 v8::HandleScope scope(info.GetIsolate());
22001 CompileRun("exception2Calls++;");
22002 info.GetIsolate()->ThrowException(
22003 v8::Exception::Error(v8_str("second")));
22004}
22005
22006
22007TEST(RunMicrotasksIgnoresThrownExceptions) {
22008 LocalContext env;
22009 v8::Isolate* isolate = env->GetIsolate();
22010 v8::HandleScope scope(isolate);
22011 CompileRun(
22012 "var exception1Calls = 0;"
22013 "var exception2Calls = 0;");
22014 isolate->EnqueueMicrotask(
22015 Function::New(isolate, MicrotaskExceptionOne));
22016 isolate->EnqueueMicrotask(
22017 Function::New(isolate, MicrotaskExceptionTwo));
22018 TryCatch try_catch;
22019 CompileRun("1+1;");
22020 CHECK(!try_catch.HasCaught());
22021 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
22022 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
22023}
22024
22025
22026TEST(SetAutorunMicrotasks) {
22027 LocalContext env;
22028 v8::HandleScope scope(env->GetIsolate());
22029 CompileRun(
22030 "var ext1Calls = 0;"
22031 "var ext2Calls = 0;");
22032 CompileRun("1+1;");
22033 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
22034 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22035
22036 env->GetIsolate()->EnqueueMicrotask(
22037 Function::New(env->GetIsolate(), MicrotaskOne));
22038 CompileRun("1+1;");
22039 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22040 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22041
22042 env->GetIsolate()->SetAutorunMicrotasks(false);
22043 env->GetIsolate()->EnqueueMicrotask(
22044 Function::New(env->GetIsolate(), MicrotaskOne));
22045 env->GetIsolate()->EnqueueMicrotask(
22046 Function::New(env->GetIsolate(), MicrotaskTwo));
22047 CompileRun("1+1;");
22048 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22049 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22050
22051 env->GetIsolate()->RunMicrotasks();
22052 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22053 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22054
22055 env->GetIsolate()->EnqueueMicrotask(
22056 Function::New(env->GetIsolate(), MicrotaskTwo));
22057 CompileRun("1+1;");
22058 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22059 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22060
22061 env->GetIsolate()->RunMicrotasks();
22062 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22063 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
22064
22065 env->GetIsolate()->SetAutorunMicrotasks(true);
22066 env->GetIsolate()->EnqueueMicrotask(
22067 Function::New(env->GetIsolate(), MicrotaskTwo));
22068 CompileRun("1+1;");
22069 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22070 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22071
22072 env->GetIsolate()->EnqueueMicrotask(
22073 Function::New(env->GetIsolate(), MicrotaskTwo));
22074 {
22075 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
22076 CompileRun("1+1;");
22077 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22078 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22079 }
22080
22081 CompileRun("1+1;");
22082 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22083 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
22084}
22085
22086
22087TEST(RunMicrotasksWithoutEnteringContext) {
22088 v8::Isolate* isolate = CcTest::isolate();
22089 HandleScope handle_scope(isolate);
22090 isolate->SetAutorunMicrotasks(false);
22091 Handle<Context> context = Context::New(isolate);
22092 {
22093 Context::Scope context_scope(context);
22094 CompileRun("var ext1Calls = 0;");
22095 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
22096 }
22097 isolate->RunMicrotasks();
22098 {
22099 Context::Scope context_scope(context);
22100 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22101 }
22102 isolate->SetAutorunMicrotasks(true);
22103}
22104
22105
22106static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
22107 v8::DebugEvent event = event_details.GetEvent();
22108 if (event != v8::Break) return;
22109 Handle<Object> exec_state = event_details.GetExecutionState();
22110 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
22111 CompileRun("function f(id) { new FrameDetails(id, 0); }");
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022112 Handle<Function> fun =
22113 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022114 fun->Call(CcTest::global(), 1, &break_id);
22115}
22116
22117
22118TEST(Regress385349) {
22119 i::FLAG_allow_natives_syntax = true;
22120 v8::Isolate* isolate = CcTest::isolate();
22121 HandleScope handle_scope(isolate);
22122 isolate->SetAutorunMicrotasks(false);
22123 Handle<Context> context = Context::New(isolate);
22124 v8::Debug::SetDebugEventListener(DebugEventInObserver);
22125 {
22126 Context::Scope context_scope(context);
22127 CompileRun("var obj = {};"
22128 "Object.observe(obj, function(changes) { debugger; });"
22129 "obj.a = 0;");
22130 }
22131 isolate->RunMicrotasks();
22132 isolate->SetAutorunMicrotasks(true);
22133 v8::Debug::SetDebugEventListener(NULL);
22134}
22135
22136
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022137#ifdef ENABLE_DISASSEMBLER
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022138static int probes_counter = 0;
22139static int misses_counter = 0;
22140static int updates_counter = 0;
22141
22142
22143static int* LookupCounter(const char* name) {
22144 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
22145 return &probes_counter;
22146 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
22147 return &misses_counter;
22148 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
22149 return &updates_counter;
22150 }
22151 return NULL;
22152}
22153
22154
22155static const char* kMegamorphicTestProgram =
22156 "function ClassA() { };"
22157 "function ClassB() { };"
22158 "ClassA.prototype.foo = function() { };"
22159 "ClassB.prototype.foo = function() { };"
22160 "function fooify(obj) { obj.foo(); };"
22161 "var a = new ClassA();"
22162 "var b = new ClassB();"
22163 "for (var i = 0; i < 10000; i++) {"
22164 " fooify(a);"
22165 " fooify(b);"
22166 "}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022167#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022168
22169
22170static void StubCacheHelper(bool primary) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022171#ifdef ENABLE_DISASSEMBLER
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022172 i::FLAG_native_code_counters = true;
22173 if (primary) {
22174 i::FLAG_test_primary_stub_cache = true;
22175 } else {
22176 i::FLAG_test_secondary_stub_cache = true;
22177 }
22178 i::FLAG_crankshaft = false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022179 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022180 env->GetIsolate()->SetCounterFunction(LookupCounter);
22181 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022182 int initial_probes = probes_counter;
22183 int initial_misses = misses_counter;
22184 int initial_updates = updates_counter;
22185 CompileRun(kMegamorphicTestProgram);
22186 int probes = probes_counter - initial_probes;
22187 int misses = misses_counter - initial_misses;
22188 int updates = updates_counter - initial_updates;
22189 CHECK_LT(updates, 10);
22190 CHECK_LT(misses, 10);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022191 // TODO(verwaest): Update this test to overflow the degree of polymorphism
22192 // before megamorphism. The number of probes will only work once we teach the
22193 // serializer to embed references to counters in the stubs, given that the
22194 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
22195 CHECK_GE(probes, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010022196#endif
22197}
22198
22199
22200TEST(SecondaryStubCache) {
22201 StubCacheHelper(true);
22202}
22203
22204
22205TEST(PrimaryStubCache) {
22206 StubCacheHelper(false);
22207}
22208
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022209
22210#ifdef DEBUG
22211static int cow_arrays_created_runtime = 0;
22212
22213
22214static int* LookupCounterCOWArrays(const char* name) {
22215 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
22216 return &cow_arrays_created_runtime;
22217 }
22218 return NULL;
22219}
22220#endif
22221
22222
22223TEST(CheckCOWArraysCreatedRuntimeCounter) {
22224#ifdef DEBUG
22225 i::FLAG_native_code_counters = true;
22226 LocalContext env;
22227 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
22228 v8::HandleScope scope(env->GetIsolate());
22229 int initial_cow_arrays = cow_arrays_created_runtime;
22230 CompileRun("var o = [1, 2, 3];");
22231 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
22232 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
22233 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
22234 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
22235 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
22236#endif
22237}
22238
22239
22240TEST(StaticGetters) {
22241 LocalContext context;
22242 i::Factory* factory = CcTest::i_isolate()->factory();
22243 v8::Isolate* isolate = CcTest::isolate();
22244 v8::HandleScope scope(isolate);
22245 i::Handle<i::Object> undefined_value = factory->undefined_value();
22246 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
22247 i::Handle<i::Object> null_value = factory->null_value();
22248 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
22249 i::Handle<i::Object> true_value = factory->true_value();
22250 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
22251 i::Handle<i::Object> false_value = factory->false_value();
22252 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
22253}
22254
22255
22256UNINITIALIZED_TEST(IsolateEmbedderData) {
22257 CcTest::DisableAutomaticDispose();
22258 v8::Isolate* isolate = v8::Isolate::New();
22259 isolate->Enter();
22260 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22261 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22262 CHECK_EQ(NULL, isolate->GetData(slot));
22263 CHECK_EQ(NULL, i_isolate->GetData(slot));
22264 }
22265 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22266 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22267 isolate->SetData(slot, data);
22268 }
22269 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22270 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22271 CHECK_EQ(data, isolate->GetData(slot));
22272 CHECK_EQ(data, i_isolate->GetData(slot));
22273 }
22274 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22275 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22276 isolate->SetData(slot, data);
22277 }
22278 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22279 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22280 CHECK_EQ(data, isolate->GetData(slot));
22281 CHECK_EQ(data, i_isolate->GetData(slot));
22282 }
22283 isolate->Exit();
22284 isolate->Dispose();
22285}
22286
22287
22288TEST(StringEmpty) {
22289 LocalContext context;
22290 i::Factory* factory = CcTest::i_isolate()->factory();
22291 v8::Isolate* isolate = CcTest::isolate();
22292 v8::HandleScope scope(isolate);
22293 i::Handle<i::Object> empty_string = factory->empty_string();
22294 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22295}
22296
22297
22298static int instance_checked_getter_count = 0;
22299static void InstanceCheckedGetter(
22300 Local<String> name,
22301 const v8::PropertyCallbackInfo<v8::Value>& info) {
22302 CHECK_EQ(name, v8_str("foo"));
22303 instance_checked_getter_count++;
22304 info.GetReturnValue().Set(v8_num(11));
22305}
22306
22307
22308static int instance_checked_setter_count = 0;
22309static void InstanceCheckedSetter(Local<String> name,
22310 Local<Value> value,
22311 const v8::PropertyCallbackInfo<void>& info) {
22312 CHECK_EQ(name, v8_str("foo"));
22313 CHECK_EQ(value, v8_num(23));
22314 instance_checked_setter_count++;
22315}
22316
22317
22318static void CheckInstanceCheckedResult(int getters, int setters,
22319 bool expects_callbacks,
22320 TryCatch* try_catch) {
22321 if (expects_callbacks) {
22322 CHECK(!try_catch->HasCaught());
22323 CHECK_EQ(getters, instance_checked_getter_count);
22324 CHECK_EQ(setters, instance_checked_setter_count);
22325 } else {
22326 CHECK(try_catch->HasCaught());
22327 CHECK_EQ(0, instance_checked_getter_count);
22328 CHECK_EQ(0, instance_checked_setter_count);
22329 }
22330 try_catch->Reset();
22331}
22332
22333
22334static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22335 instance_checked_getter_count = 0;
22336 instance_checked_setter_count = 0;
22337 TryCatch try_catch;
22338
22339 // Test path through generic runtime code.
22340 CompileRun("obj.foo");
22341 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22342 CompileRun("obj.foo = 23");
22343 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22344
22345 // Test path through generated LoadIC and StoredIC.
22346 CompileRun("function test_get(o) { o.foo; }"
22347 "test_get(obj);");
22348 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22349 CompileRun("test_get(obj);");
22350 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22351 CompileRun("test_get(obj);");
22352 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22353 CompileRun("function test_set(o) { o.foo = 23; }"
22354 "test_set(obj);");
22355 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22356 CompileRun("test_set(obj);");
22357 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22358 CompileRun("test_set(obj);");
22359 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22360
22361 // Test path through optimized code.
22362 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22363 "test_get(obj);");
22364 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22365 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22366 "test_set(obj);");
22367 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22368
22369 // Cleanup so that closures start out fresh in next check.
22370 CompileRun("%DeoptimizeFunction(test_get);"
22371 "%ClearFunctionTypeFeedback(test_get);"
22372 "%DeoptimizeFunction(test_set);"
22373 "%ClearFunctionTypeFeedback(test_set);");
22374}
22375
22376
22377THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22378 v8::internal::FLAG_allow_natives_syntax = true;
22379 LocalContext context;
22380 v8::HandleScope scope(context->GetIsolate());
22381
22382 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22383 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22384 inst->SetAccessor(v8_str("foo"),
22385 InstanceCheckedGetter, InstanceCheckedSetter,
22386 Handle<Value>(),
22387 v8::DEFAULT,
22388 v8::None,
22389 v8::AccessorSignature::New(context->GetIsolate(), templ));
22390 context->Global()->Set(v8_str("f"), templ->GetFunction());
22391
22392 printf("Testing positive ...\n");
22393 CompileRun("var obj = new f();");
22394 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22395 CheckInstanceCheckedAccessors(true);
22396
22397 printf("Testing negative ...\n");
22398 CompileRun("var obj = {};"
22399 "obj.__proto__ = new f();");
22400 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22401 CheckInstanceCheckedAccessors(false);
22402}
22403
22404
22405THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22406 v8::internal::FLAG_allow_natives_syntax = true;
22407 LocalContext context;
22408 v8::HandleScope scope(context->GetIsolate());
22409
22410 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22411 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22412 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22413 inst->SetAccessor(v8_str("foo"),
22414 InstanceCheckedGetter, InstanceCheckedSetter,
22415 Handle<Value>(),
22416 v8::DEFAULT,
22417 v8::None,
22418 v8::AccessorSignature::New(context->GetIsolate(), templ));
22419 context->Global()->Set(v8_str("f"), templ->GetFunction());
22420
22421 printf("Testing positive ...\n");
22422 CompileRun("var obj = new f();");
22423 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22424 CheckInstanceCheckedAccessors(true);
22425
22426 printf("Testing negative ...\n");
22427 CompileRun("var obj = {};"
22428 "obj.__proto__ = new f();");
22429 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22430 CheckInstanceCheckedAccessors(false);
22431}
22432
22433
22434THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22435 v8::internal::FLAG_allow_natives_syntax = true;
22436 LocalContext context;
22437 v8::HandleScope scope(context->GetIsolate());
22438
22439 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22440 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22441 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22442 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
22443 v8::None,
22444 v8::AccessorSignature::New(context->GetIsolate(), templ));
22445 context->Global()->Set(v8_str("f"), templ->GetFunction());
22446
22447 printf("Testing positive ...\n");
22448 CompileRun("var obj = new f();");
22449 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22450 CheckInstanceCheckedAccessors(true);
22451
22452 printf("Testing negative ...\n");
22453 CompileRun("var obj = {};"
22454 "obj.__proto__ = new f();");
22455 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22456 CheckInstanceCheckedAccessors(false);
22457
22458 printf("Testing positive with modified prototype chain ...\n");
22459 CompileRun("var obj = new f();"
22460 "var pro = {};"
22461 "pro.__proto__ = obj.__proto__;"
22462 "obj.__proto__ = pro;");
22463 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22464 CheckInstanceCheckedAccessors(true);
22465}
22466
22467
22468TEST(TryFinallyMessage) {
22469 LocalContext context;
22470 v8::HandleScope scope(context->GetIsolate());
22471 {
22472 // Test that the original error message is not lost if there is a
22473 // recursive call into Javascript is done in the finally block, e.g. to
22474 // initialize an IC. (crbug.com/129171)
22475 TryCatch try_catch;
22476 const char* trigger_ic =
22477 "try { \n"
22478 " throw new Error('test'); \n"
22479 "} finally { \n"
22480 " var x = 0; \n"
22481 " x++; \n" // Trigger an IC initialization here.
22482 "} \n";
22483 CompileRun(trigger_ic);
22484 CHECK(try_catch.HasCaught());
22485 Local<Message> message = try_catch.Message();
22486 CHECK(!message.IsEmpty());
22487 CHECK_EQ(2, message->GetLineNumber());
22488 }
22489
22490 {
22491 // Test that the original exception message is indeed overwritten if
22492 // a new error is thrown in the finally block.
22493 TryCatch try_catch;
22494 const char* throw_again =
22495 "try { \n"
22496 " throw new Error('test'); \n"
22497 "} finally { \n"
22498 " var x = 0; \n"
22499 " x++; \n"
22500 " throw new Error('again'); \n" // This is the new uncaught error.
22501 "} \n";
22502 CompileRun(throw_again);
22503 CHECK(try_catch.HasCaught());
22504 Local<Message> message = try_catch.Message();
22505 CHECK(!message.IsEmpty());
22506 CHECK_EQ(6, message->GetLineNumber());
22507 }
22508}
22509
22510
22511static void Helper137002(bool do_store,
22512 bool polymorphic,
22513 bool remove_accessor,
22514 bool interceptor) {
22515 LocalContext context;
22516 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22517 if (interceptor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022518 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22519 FooSetInterceptor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022520 } else {
22521 templ->SetAccessor(v8_str("foo"),
22522 GetterWhichReturns42,
22523 SetterWhichSetsYOnThisTo23);
22524 }
22525 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22526
22527 // Turn monomorphic on slow object with native accessor, then turn
22528 // polymorphic, finally optimize to create negative lookup and fail.
22529 CompileRun(do_store ?
22530 "function f(x) { x.foo = void 0; }" :
22531 "function f(x) { return x.foo; }");
22532 CompileRun("obj.y = void 0;");
22533 if (!interceptor) {
22534 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22535 }
22536 CompileRun("obj.__proto__ = null;"
22537 "f(obj); f(obj); f(obj);");
22538 if (polymorphic) {
22539 CompileRun("f({});");
22540 }
22541 CompileRun("obj.y = void 0;"
22542 "%OptimizeFunctionOnNextCall(f);");
22543 if (remove_accessor) {
22544 CompileRun("delete obj.foo;");
22545 }
22546 CompileRun("var result = f(obj);");
22547 if (do_store) {
22548 CompileRun("result = obj.y;");
22549 }
22550 if (remove_accessor && !interceptor) {
22551 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
22552 } else {
22553 CHECK_EQ(do_store ? 23 : 42,
22554 context->Global()->Get(v8_str("result"))->Int32Value());
22555 }
22556}
22557
22558
22559THREADED_TEST(Regress137002a) {
22560 i::FLAG_allow_natives_syntax = true;
22561 i::FLAG_compilation_cache = false;
22562 v8::HandleScope scope(CcTest::isolate());
22563 for (int i = 0; i < 16; i++) {
22564 Helper137002(i & 8, i & 4, i & 2, i & 1);
22565 }
22566}
22567
22568
22569THREADED_TEST(Regress137002b) {
22570 i::FLAG_allow_natives_syntax = true;
22571 LocalContext context;
22572 v8::Isolate* isolate = context->GetIsolate();
22573 v8::HandleScope scope(isolate);
22574 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22575 templ->SetAccessor(v8_str("foo"),
22576 GetterWhichReturns42,
22577 SetterWhichSetsYOnThisTo23);
22578 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22579
22580 // Turn monomorphic on slow object with native accessor, then just
22581 // delete the property and fail.
22582 CompileRun("function load(x) { return x.foo; }"
22583 "function store(x) { x.foo = void 0; }"
22584 "function keyed_load(x, key) { return x[key]; }"
22585 // Second version of function has a different source (add void 0)
22586 // so that it does not share code with the first version. This
22587 // ensures that the ICs are monomorphic.
22588 "function load2(x) { void 0; return x.foo; }"
22589 "function store2(x) { void 0; x.foo = void 0; }"
22590 "function keyed_load2(x, key) { void 0; return x[key]; }"
22591
22592 "obj.y = void 0;"
22593 "obj.__proto__ = null;"
22594 "var subobj = {};"
22595 "subobj.y = void 0;"
22596 "subobj.__proto__ = obj;"
22597 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22598
22599 // Make the ICs monomorphic.
22600 "load(obj); load(obj);"
22601 "load2(subobj); load2(subobj);"
22602 "store(obj); store(obj);"
22603 "store2(subobj); store2(subobj);"
22604 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22605 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22606
22607 // Actually test the shiny new ICs and better not crash. This
22608 // serves as a regression test for issue 142088 as well.
22609 "load(obj);"
22610 "load2(subobj);"
22611 "store(obj);"
22612 "store2(subobj);"
22613 "keyed_load(obj, 'foo');"
22614 "keyed_load2(subobj, 'foo');"
22615
22616 // Delete the accessor. It better not be called any more now.
22617 "delete obj.foo;"
22618 "obj.y = void 0;"
22619 "subobj.y = void 0;"
22620
22621 "var load_result = load(obj);"
22622 "var load_result2 = load2(subobj);"
22623 "var keyed_load_result = keyed_load(obj, 'foo');"
22624 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22625 "store(obj);"
22626 "store2(subobj);"
22627 "var y_from_obj = obj.y;"
22628 "var y_from_subobj = subobj.y;");
22629 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
22630 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
22631 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
22632 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
22633 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
22634 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
22635}
22636
22637
22638THREADED_TEST(Regress142088) {
22639 i::FLAG_allow_natives_syntax = true;
22640 LocalContext context;
22641 v8::Isolate* isolate = context->GetIsolate();
22642 v8::HandleScope scope(isolate);
22643 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22644 templ->SetAccessor(v8_str("foo"),
22645 GetterWhichReturns42,
22646 SetterWhichSetsYOnThisTo23);
22647 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22648
22649 CompileRun("function load(x) { return x.foo; }"
22650 "var o = Object.create(obj);"
22651 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22652 "load(o); load(o); load(o); load(o);");
22653}
22654
22655
22656THREADED_TEST(Regress3337) {
22657 LocalContext context;
22658 v8::Isolate* isolate = context->GetIsolate();
22659 v8::HandleScope scope(isolate);
22660 Local<v8::Object> o1 = Object::New(isolate);
22661 Local<v8::Object> o2 = Object::New(isolate);
22662 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
22663 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
22664 CHECK(io1->map() == io2->map());
22665 o1->SetIndexedPropertiesToExternalArrayData(
22666 NULL, v8::kExternalUint32Array, 0);
22667 o2->SetIndexedPropertiesToExternalArrayData(
22668 NULL, v8::kExternalUint32Array, 0);
22669 CHECK(io1->map() == io2->map());
22670}
22671
22672
22673THREADED_TEST(Regress137496) {
22674 i::FLAG_expose_gc = true;
22675 LocalContext context;
22676 v8::HandleScope scope(context->GetIsolate());
22677
22678 // Compile a try-finally clause where the finally block causes a GC
22679 // while there still is a message pending for external reporting.
22680 TryCatch try_catch;
22681 try_catch.SetVerbose(true);
22682 CompileRun("try { throw new Error(); } finally { gc(); }");
22683 CHECK(try_catch.HasCaught());
22684}
22685
22686
22687THREADED_TEST(Regress149912) {
22688 LocalContext context;
22689 v8::HandleScope scope(context->GetIsolate());
22690 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22691 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22692 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22693 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
22694}
22695
22696
22697THREADED_TEST(Regress157124) {
22698 LocalContext context;
22699 v8::Isolate* isolate = context->GetIsolate();
22700 v8::HandleScope scope(isolate);
22701 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22702 Local<Object> obj = templ->NewInstance();
22703 obj->GetIdentityHash();
22704 obj->DeleteHiddenValue(v8_str("Bug"));
22705}
22706
22707
22708THREADED_TEST(Regress2535) {
22709 LocalContext context;
22710 v8::HandleScope scope(context->GetIsolate());
22711 Local<Value> set_value = CompileRun("new Set();");
22712 Local<Object> set_object(Local<Object>::Cast(set_value));
22713 CHECK_EQ(0, set_object->InternalFieldCount());
22714 Local<Value> map_value = CompileRun("new Map();");
22715 Local<Object> map_object(Local<Object>::Cast(map_value));
22716 CHECK_EQ(0, map_object->InternalFieldCount());
22717}
22718
22719
22720THREADED_TEST(Regress2746) {
22721 LocalContext context;
22722 v8::Isolate* isolate = context->GetIsolate();
22723 v8::HandleScope scope(isolate);
22724 Local<Object> obj = Object::New(isolate);
22725 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
22726 obj->SetHiddenValue(key, v8::Undefined(isolate));
22727 Local<Value> value = obj->GetHiddenValue(key);
22728 CHECK(!value.IsEmpty());
22729 CHECK(value->IsUndefined());
22730}
22731
22732
22733THREADED_TEST(Regress260106) {
22734 LocalContext context;
22735 v8::Isolate* isolate = context->GetIsolate();
22736 v8::HandleScope scope(isolate);
22737 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22738 DummyCallHandler);
22739 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22740 Local<Function> function = templ->GetFunction();
22741 CHECK(!function.IsEmpty());
22742 CHECK(function->IsFunction());
22743}
22744
22745
22746THREADED_TEST(JSONParseObject) {
22747 LocalContext context;
22748 HandleScope scope(context->GetIsolate());
22749 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
22750 Handle<Object> global = context->Global();
22751 global->Set(v8_str("obj"), obj);
22752 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22753}
22754
22755
22756THREADED_TEST(JSONParseNumber) {
22757 LocalContext context;
22758 HandleScope scope(context->GetIsolate());
22759 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
22760 Handle<Object> global = context->Global();
22761 global->Set(v8_str("obj"), obj);
22762 ExpectString("JSON.stringify(obj)", "42");
22763}
22764
22765
22766#if V8_OS_POSIX && !V8_OS_NACL
22767class ThreadInterruptTest {
22768 public:
22769 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22770 ~ThreadInterruptTest() {}
22771
22772 void RunTest() {
22773 InterruptThread i_thread(this);
22774 i_thread.Start();
22775
22776 sem_.Wait();
22777 CHECK_EQ(kExpectedValue, sem_value_);
22778 }
22779
22780 private:
22781 static const int kExpectedValue = 1;
22782
22783 class InterruptThread : public v8::base::Thread {
22784 public:
22785 explicit InterruptThread(ThreadInterruptTest* test)
22786 : Thread(Options("InterruptThread")), test_(test) {}
22787
22788 virtual void Run() {
22789 struct sigaction action;
22790
22791 // Ensure that we'll enter waiting condition
22792 v8::base::OS::Sleep(100);
22793
22794 // Setup signal handler
22795 memset(&action, 0, sizeof(action));
22796 action.sa_handler = SignalHandler;
22797 sigaction(SIGCHLD, &action, NULL);
22798
22799 // Send signal
22800 kill(getpid(), SIGCHLD);
22801
22802 // Ensure that if wait has returned because of error
22803 v8::base::OS::Sleep(100);
22804
22805 // Set value and signal semaphore
22806 test_->sem_value_ = 1;
22807 test_->sem_.Signal();
22808 }
22809
22810 static void SignalHandler(int signal) {
22811 }
22812
22813 private:
22814 ThreadInterruptTest* test_;
22815 };
22816
22817 v8::base::Semaphore sem_;
22818 volatile int sem_value_;
22819};
22820
22821
22822THREADED_TEST(SemaphoreInterruption) {
22823 ThreadInterruptTest().RunTest();
22824}
22825
22826
22827#endif // V8_OS_POSIX
22828
22829
22830static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
22831 Local<Value> name,
22832 v8::AccessType type,
22833 Local<Value> data) {
22834 i::PrintF("Named access blocked.\n");
22835 return false;
22836}
22837
22838
22839static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
22840 uint32_t key,
22841 v8::AccessType type,
22842 Local<Value> data) {
22843 i::PrintF("Indexed access blocked.\n");
22844 return false;
22845}
22846
22847
22848void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22849 CHECK(false);
22850}
22851
22852
22853TEST(JSONStringifyAccessCheck) {
22854 v8::V8::Initialize();
22855 v8::Isolate* isolate = CcTest::isolate();
22856 v8::HandleScope scope(isolate);
22857
22858 // Create an ObjectTemplate for global objects and install access
22859 // check callbacks that will block access.
22860 v8::Handle<v8::ObjectTemplate> global_template =
22861 v8::ObjectTemplate::New(isolate);
22862 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22863 IndexAccessAlwaysBlocked);
22864
22865 // Create a context and set an x property on it's global object.
22866 LocalContext context0(NULL, global_template);
22867 v8::Handle<v8::Object> global0 = context0->Global();
22868 global0->Set(v8_str("x"), v8_num(42));
22869 ExpectString("JSON.stringify(this)", "{\"x\":42}");
22870
22871 for (int i = 0; i < 2; i++) {
22872 if (i == 1) {
22873 // Install a toJSON function on the second run.
22874 v8::Handle<v8::FunctionTemplate> toJSON =
22875 v8::FunctionTemplate::New(isolate, UnreachableCallback);
22876
22877 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
22878 }
22879 // Create a context with a different security token so that the
22880 // failed access check callback will be called on each access.
22881 LocalContext context1(NULL, global_template);
22882 context1->Global()->Set(v8_str("other"), global0);
22883
22884 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22885 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22886 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22887
22888 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
22889 array->Set(0, v8_str("a"));
22890 array->Set(1, v8_str("b"));
22891 context1->Global()->Set(v8_str("array"), array);
22892 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
22893 array->TurnOnAccessCheck();
22894 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
22895 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
22896 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
22897 }
22898}
22899
22900
22901bool access_check_fail_thrown = false;
22902bool catch_callback_called = false;
22903
22904
22905// Failed access check callback that performs a GC on each invocation.
22906void FailedAccessCheckThrows(Local<v8::Object> target,
22907 v8::AccessType type,
22908 Local<v8::Value> data) {
22909 access_check_fail_thrown = true;
22910 i::PrintF("Access check failed. Error thrown.\n");
22911 CcTest::isolate()->ThrowException(
22912 v8::Exception::Error(v8_str("cross context")));
22913}
22914
22915
22916void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22917 for (int i = 0; i < args.Length(); i++) {
22918 i::PrintF("%s\n", *String::Utf8Value(args[i]));
22919 }
22920 catch_callback_called = true;
22921}
22922
22923
22924void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040022925 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
22926 args[1]->ToString(args.GetIsolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022927}
22928
22929
22930void CheckCorrectThrow(const char* script) {
22931 // Test that the script, when wrapped into a try-catch, triggers the catch
22932 // clause due to failed access check throwing an exception.
22933 // The subsequent try-catch should run without any exception.
22934 access_check_fail_thrown = false;
22935 catch_callback_called = false;
22936 i::ScopedVector<char> source(1024);
22937 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22938 CompileRun(source.start());
22939 CHECK(access_check_fail_thrown);
22940 CHECK(catch_callback_called);
22941
22942 access_check_fail_thrown = false;
22943 catch_callback_called = false;
22944 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22945 CHECK(!access_check_fail_thrown);
22946 CHECK(!catch_callback_called);
22947}
22948
22949
22950TEST(AccessCheckThrows) {
22951 i::FLAG_allow_natives_syntax = true;
22952 v8::V8::Initialize();
22953 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22954 v8::Isolate* isolate = CcTest::isolate();
22955 v8::HandleScope scope(isolate);
22956
22957 // Create an ObjectTemplate for global objects and install access
22958 // check callbacks that will block access.
22959 v8::Handle<v8::ObjectTemplate> global_template =
22960 v8::ObjectTemplate::New(isolate);
22961 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22962 IndexAccessAlwaysBlocked);
22963
22964 // Create a context and set an x property on it's global object.
22965 LocalContext context0(NULL, global_template);
22966 v8::Handle<v8::Object> global0 = context0->Global();
22967
22968 // Create a context with a different security token so that the
22969 // failed access check callback will be called on each access.
22970 LocalContext context1(NULL, global_template);
22971 context1->Global()->Set(v8_str("other"), global0);
22972
22973 v8::Handle<v8::FunctionTemplate> catcher_fun =
22974 v8::FunctionTemplate::New(isolate, CatcherCallback);
22975 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
22976
22977 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
22978 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22979 context1->Global()->Set(v8_str("has_own_property"),
22980 has_own_property_fun->GetFunction());
22981
22982 { v8::TryCatch try_catch;
22983 access_check_fail_thrown = false;
22984 CompileRun("other.x;");
22985 CHECK(access_check_fail_thrown);
22986 CHECK(try_catch.HasCaught());
22987 }
22988
22989 CheckCorrectThrow("other.x");
22990 CheckCorrectThrow("other[1]");
22991 CheckCorrectThrow("JSON.stringify(other)");
22992 CheckCorrectThrow("has_own_property(other, 'x')");
22993 CheckCorrectThrow("%GetProperty(other, 'x')");
22994 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22995 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22996 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
22997 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22998 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
22999 CheckCorrectThrow("%HasProperty(other, 'x')");
23000 CheckCorrectThrow("%HasElement(other, 1)");
23001 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
23002 CheckCorrectThrow("%GetPropertyNames(other)");
23003 // PROPERTY_ATTRIBUTES_NONE = 0
23004 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
23005 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
23006 "other, 'x', null, null, 1)");
23007
23008 // Reset the failed access check callback so it does not influence
23009 // the other tests.
23010 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
23011}
23012
23013
23014THREADED_TEST(Regress256330) {
23015 i::FLAG_allow_natives_syntax = true;
23016 LocalContext context;
23017 v8::HandleScope scope(context->GetIsolate());
23018 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
23019 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
23020 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
23021 CompileRun("\"use strict\"; var o = new Bug;"
23022 "function f(o) { o.x = 10; };"
23023 "f(o); f(o); f(o);"
23024 "%OptimizeFunctionOnNextCall(f);"
23025 "f(o);");
23026 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
23027}
23028
23029
23030THREADED_TEST(CrankshaftInterceptorSetter) {
23031 i::FLAG_allow_natives_syntax = true;
23032 v8::HandleScope scope(CcTest::isolate());
23033 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23034 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23035 LocalContext env;
23036 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23037 CompileRun("var obj = new Obj;"
23038 // Initialize fields to avoid transitions later.
23039 "obj.age = 0;"
23040 "obj.accessor_age = 42;"
23041 "function setter(i) { this.accessor_age = i; };"
23042 "function getter() { return this.accessor_age; };"
23043 "function setAge(i) { obj.age = i; };"
23044 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
23045 "setAge(1);"
23046 "setAge(2);"
23047 "setAge(3);"
23048 "%OptimizeFunctionOnNextCall(setAge);"
23049 "setAge(4);");
23050 // All stores went through the interceptor.
23051 ExpectInt32("obj.interceptor_age", 4);
23052 ExpectInt32("obj.accessor_age", 42);
23053}
23054
23055
23056THREADED_TEST(CrankshaftInterceptorGetter) {
23057 i::FLAG_allow_natives_syntax = true;
23058 v8::HandleScope scope(CcTest::isolate());
23059 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23060 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23061 LocalContext env;
23062 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23063 CompileRun("var obj = new Obj;"
23064 // Initialize fields to avoid transitions later.
23065 "obj.age = 1;"
23066 "obj.accessor_age = 42;"
23067 "function getter() { return this.accessor_age; };"
23068 "function getAge() { return obj.interceptor_age; };"
23069 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
23070 "getAge();"
23071 "getAge();"
23072 "getAge();"
23073 "%OptimizeFunctionOnNextCall(getAge);");
23074 // Access through interceptor.
23075 ExpectInt32("getAge()", 1);
23076}
23077
23078
23079THREADED_TEST(CrankshaftInterceptorFieldRead) {
23080 i::FLAG_allow_natives_syntax = true;
23081 v8::HandleScope scope(CcTest::isolate());
23082 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23083 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23084 LocalContext env;
23085 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23086 CompileRun("var obj = new Obj;"
23087 "obj.__proto__.interceptor_age = 42;"
23088 "obj.age = 100;"
23089 "function getAge() { return obj.interceptor_age; };");
23090 ExpectInt32("getAge();", 100);
23091 ExpectInt32("getAge();", 100);
23092 ExpectInt32("getAge();", 100);
23093 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
23094 // Access through interceptor.
23095 ExpectInt32("getAge();", 100);
23096}
23097
23098
23099THREADED_TEST(CrankshaftInterceptorFieldWrite) {
23100 i::FLAG_allow_natives_syntax = true;
23101 v8::HandleScope scope(CcTest::isolate());
23102 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23103 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23104 LocalContext env;
23105 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23106 CompileRun("var obj = new Obj;"
23107 "obj.age = 100000;"
23108 "function setAge(i) { obj.age = i };"
23109 "setAge(100);"
23110 "setAge(101);"
23111 "setAge(102);"
23112 "%OptimizeFunctionOnNextCall(setAge);"
23113 "setAge(103);");
23114 ExpectInt32("obj.age", 100000);
23115 ExpectInt32("obj.interceptor_age", 103);
23116}
23117
23118
23119class RequestInterruptTestBase {
23120 public:
23121 RequestInterruptTestBase()
23122 : env_(),
23123 isolate_(env_->GetIsolate()),
23124 sem_(0),
23125 warmup_(20000),
23126 should_continue_(true) {
23127 }
23128
23129 virtual ~RequestInterruptTestBase() { }
23130
23131 virtual void StartInterruptThread() = 0;
23132
23133 virtual void TestBody() = 0;
23134
23135 void RunTest() {
23136 StartInterruptThread();
23137
23138 v8::HandleScope handle_scope(isolate_);
23139
23140 TestBody();
23141
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023142 // Verify we arrived here because interruptor was called
23143 // not due to a bug causing us to exit the loop too early.
23144 CHECK(!should_continue());
23145 }
23146
23147 void WakeUpInterruptor() {
23148 sem_.Signal();
23149 }
23150
23151 bool should_continue() const { return should_continue_; }
23152
23153 bool ShouldContinue() {
23154 if (warmup_ > 0) {
23155 if (--warmup_ == 0) {
23156 WakeUpInterruptor();
23157 }
23158 }
23159
23160 return should_continue_;
23161 }
23162
23163 static void ShouldContinueCallback(
23164 const v8::FunctionCallbackInfo<Value>& info) {
23165 RequestInterruptTestBase* test =
23166 reinterpret_cast<RequestInterruptTestBase*>(
23167 info.Data().As<v8::External>()->Value());
23168 info.GetReturnValue().Set(test->ShouldContinue());
23169 }
23170
23171 LocalContext env_;
23172 v8::Isolate* isolate_;
23173 v8::base::Semaphore sem_;
23174 int warmup_;
23175 bool should_continue_;
23176};
23177
23178
23179class RequestInterruptTestBaseWithSimpleInterrupt
23180 : public RequestInterruptTestBase {
23181 public:
23182 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
23183
23184 virtual void StartInterruptThread() {
23185 i_thread.Start();
23186 }
23187
23188 private:
23189 class InterruptThread : public v8::base::Thread {
23190 public:
23191 explicit InterruptThread(RequestInterruptTestBase* test)
23192 : Thread(Options("RequestInterruptTest")), test_(test) {}
23193
23194 virtual void Run() {
23195 test_->sem_.Wait();
23196 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23197 }
23198
23199 static void OnInterrupt(v8::Isolate* isolate, void* data) {
23200 reinterpret_cast<RequestInterruptTestBase*>(data)->
23201 should_continue_ = false;
23202 }
23203
23204 private:
23205 RequestInterruptTestBase* test_;
23206 };
23207
23208 InterruptThread i_thread;
23209};
23210
23211
23212class RequestInterruptTestWithFunctionCall
23213 : public RequestInterruptTestBaseWithSimpleInterrupt {
23214 public:
23215 virtual void TestBody() {
23216 Local<Function> func = Function::New(
23217 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23218 env_->Global()->Set(v8_str("ShouldContinue"), func);
23219
23220 CompileRun("while (ShouldContinue()) { }");
23221 }
23222};
23223
23224
23225class RequestInterruptTestWithMethodCall
23226 : public RequestInterruptTestBaseWithSimpleInterrupt {
23227 public:
23228 virtual void TestBody() {
23229 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23230 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23231 proto->Set(v8_str("shouldContinue"), Function::New(
23232 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23233 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23234
23235 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23236 }
23237};
23238
23239
23240class RequestInterruptTestWithAccessor
23241 : public RequestInterruptTestBaseWithSimpleInterrupt {
23242 public:
23243 virtual void TestBody() {
23244 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23245 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23246 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23247 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23248 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23249
23250 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23251 }
23252};
23253
23254
23255class RequestInterruptTestWithNativeAccessor
23256 : public RequestInterruptTestBaseWithSimpleInterrupt {
23257 public:
23258 virtual void TestBody() {
23259 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23260 t->InstanceTemplate()->SetNativeDataProperty(
23261 v8_str("shouldContinue"),
23262 &ShouldContinueNativeGetter,
23263 NULL,
23264 v8::External::New(isolate_, this));
23265 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23266
23267 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23268 }
23269
23270 private:
23271 static void ShouldContinueNativeGetter(
23272 Local<String> property,
23273 const v8::PropertyCallbackInfo<v8::Value>& info) {
23274 RequestInterruptTestBase* test =
23275 reinterpret_cast<RequestInterruptTestBase*>(
23276 info.Data().As<v8::External>()->Value());
23277 info.GetReturnValue().Set(test->ShouldContinue());
23278 }
23279};
23280
23281
23282class RequestInterruptTestWithMethodCallAndInterceptor
23283 : public RequestInterruptTestBaseWithSimpleInterrupt {
23284 public:
23285 virtual void TestBody() {
23286 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23287 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23288 proto->Set(v8_str("shouldContinue"), Function::New(
23289 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23290 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023291 instance_template->SetHandler(
23292 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023293
23294 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23295
23296 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23297 }
23298
23299 private:
23300 static void EmptyInterceptor(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023301 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023302};
23303
23304
23305class RequestInterruptTestWithMathAbs
23306 : public RequestInterruptTestBaseWithSimpleInterrupt {
23307 public:
23308 virtual void TestBody() {
23309 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
23310 isolate_,
23311 WakeUpInterruptorCallback,
23312 v8::External::New(isolate_, this)));
23313
23314 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
23315 isolate_,
23316 ShouldContinueCallback,
23317 v8::External::New(isolate_, this)));
23318
23319 i::FLAG_allow_natives_syntax = true;
23320 CompileRun("function loopish(o) {"
23321 " var pre = 10;"
23322 " while (o.abs(1) > 0) {"
23323 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23324 " if (pre > 0) {"
23325 " if (--pre === 0) WakeUpInterruptor(o === Math);"
23326 " }"
23327 " }"
23328 "}"
23329 "var i = 50;"
23330 "var obj = {abs: function () { return i-- }, x: null};"
23331 "delete obj.x;"
23332 "loopish(obj);"
23333 "%OptimizeFunctionOnNextCall(loopish);"
23334 "loopish(Math);");
23335
23336 i::FLAG_allow_natives_syntax = false;
23337 }
23338
23339 private:
23340 static void WakeUpInterruptorCallback(
23341 const v8::FunctionCallbackInfo<Value>& info) {
23342 if (!info[0]->BooleanValue()) return;
23343
23344 RequestInterruptTestBase* test =
23345 reinterpret_cast<RequestInterruptTestBase*>(
23346 info.Data().As<v8::External>()->Value());
23347 test->WakeUpInterruptor();
23348 }
23349
23350 static void ShouldContinueCallback(
23351 const v8::FunctionCallbackInfo<Value>& info) {
23352 RequestInterruptTestBase* test =
23353 reinterpret_cast<RequestInterruptTestBase*>(
23354 info.Data().As<v8::External>()->Value());
23355 info.GetReturnValue().Set(test->should_continue());
23356 }
23357};
23358
23359
23360TEST(RequestInterruptTestWithFunctionCall) {
23361 RequestInterruptTestWithFunctionCall().RunTest();
23362}
23363
23364
23365TEST(RequestInterruptTestWithMethodCall) {
23366 RequestInterruptTestWithMethodCall().RunTest();
23367}
23368
23369
23370TEST(RequestInterruptTestWithAccessor) {
23371 RequestInterruptTestWithAccessor().RunTest();
23372}
23373
23374
23375TEST(RequestInterruptTestWithNativeAccessor) {
23376 RequestInterruptTestWithNativeAccessor().RunTest();
23377}
23378
23379
23380TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23381 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23382}
23383
23384
23385TEST(RequestInterruptTestWithMathAbs) {
23386 RequestInterruptTestWithMathAbs().RunTest();
23387}
23388
23389
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023390class RequestMultipleInterrupts : public RequestInterruptTestBase {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023391 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023392 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023393
23394 virtual void StartInterruptThread() {
23395 i_thread.Start();
23396 }
23397
23398 virtual void TestBody() {
23399 Local<Function> func = Function::New(
23400 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23401 env_->Global()->Set(v8_str("ShouldContinue"), func);
23402
23403 CompileRun("while (ShouldContinue()) { }");
23404 }
23405
23406 private:
23407 class InterruptThread : public v8::base::Thread {
23408 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023409 enum { NUM_INTERRUPTS = 10 };
23410 explicit InterruptThread(RequestMultipleInterrupts* test)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023411 : Thread(Options("RequestInterruptTest")), test_(test) {}
23412
23413 virtual void Run() {
23414 test_->sem_.Wait();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023415 for (int i = 0; i < NUM_INTERRUPTS; i++) {
23416 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23417 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023418 }
23419
23420 static void OnInterrupt(v8::Isolate* isolate, void* data) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023421 RequestMultipleInterrupts* test =
23422 reinterpret_cast<RequestMultipleInterrupts*>(data);
23423 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023424 }
23425
23426 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023427 RequestMultipleInterrupts* test_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023428 };
23429
23430 InterruptThread i_thread;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023431 int counter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023432};
23433
23434
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023435TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023436
23437
23438static Local<Value> function_new_expected_env;
23439static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23440 CHECK_EQ(function_new_expected_env, info.Data());
23441 info.GetReturnValue().Set(17);
23442}
23443
23444
23445THREADED_TEST(FunctionNew) {
23446 LocalContext env;
23447 v8::Isolate* isolate = env->GetIsolate();
23448 v8::HandleScope scope(isolate);
23449 Local<Object> data = v8::Object::New(isolate);
23450 function_new_expected_env = data;
23451 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
23452 env->Global()->Set(v8_str("func"), func);
23453 Local<Value> result = CompileRun("func();");
23454 CHECK_EQ(v8::Integer::New(isolate, 17), result);
23455 // Verify function not cached
23456 int serial_number =
23457 i::Smi::cast(v8::Utils::OpenHandle(*func)
23458 ->shared()->get_api_func_data()->serial_number())->value();
23459 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23460 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
23461 i::Handle<i::Object> elm =
23462 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
23463 CHECK(elm->IsUndefined());
23464 // Verify that each Function::New creates a new function instance
23465 Local<Object> data2 = v8::Object::New(isolate);
23466 function_new_expected_env = data2;
23467 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
23468 CHECK(!func2->IsNull());
23469 CHECK_NE(func, func2);
23470 env->Global()->Set(v8_str("func2"), func2);
23471 Local<Value> result2 = CompileRun("func2();");
23472 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
23473}
23474
23475
23476TEST(EscapeableHandleScope) {
23477 HandleScope outer_scope(CcTest::isolate());
23478 LocalContext context;
23479 const int runs = 10;
23480 Local<String> values[runs];
23481 for (int i = 0; i < runs; i++) {
23482 v8::EscapableHandleScope inner_scope(CcTest::isolate());
23483 Local<String> value;
23484 if (i != 0) value = v8_str("escape value");
23485 values[i] = inner_scope.Escape(value);
23486 }
23487 for (int i = 0; i < runs; i++) {
23488 Local<String> expected;
23489 if (i != 0) {
23490 CHECK_EQ(v8_str("escape value"), values[i]);
23491 } else {
23492 CHECK(values[i].IsEmpty());
23493 }
23494 }
23495}
23496
23497
23498static void SetterWhichExpectsThisAndHolderToDiffer(
23499 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23500 CHECK(info.Holder() != info.This());
23501}
23502
23503
23504TEST(Regress239669) {
23505 LocalContext context;
23506 v8::Isolate* isolate = context->GetIsolate();
23507 v8::HandleScope scope(isolate);
23508 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23509 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23510 context->Global()->Set(v8_str("P"), templ->NewInstance());
23511 CompileRun(
23512 "function C1() {"
23513 " this.x = 23;"
23514 "};"
23515 "C1.prototype = P;"
23516 "for (var i = 0; i < 4; i++ ) {"
23517 " new C1();"
23518 "}");
23519}
23520
23521
23522class ApiCallOptimizationChecker {
23523 private:
23524 static Local<Object> data;
23525 static Local<Object> receiver;
23526 static Local<Object> holder;
23527 static Local<Object> callee;
23528 static int count;
23529
23530 static void OptimizationCallback(
23531 const v8::FunctionCallbackInfo<v8::Value>& info) {
23532 CHECK(callee == info.Callee());
23533 CHECK(data == info.Data());
23534 CHECK(receiver == info.This());
23535 if (info.Length() == 1) {
23536 CHECK_EQ(v8_num(1), info[0]);
23537 }
23538 CHECK(holder == info.Holder());
23539 count++;
23540 info.GetReturnValue().Set(v8_str("returned"));
23541 }
23542
23543 public:
23544 enum SignatureType {
23545 kNoSignature,
23546 kSignatureOnReceiver,
23547 kSignatureOnPrototype
23548 };
23549
23550 void RunAll() {
23551 SignatureType signature_types[] =
23552 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23553 for (unsigned i = 0; i < arraysize(signature_types); i++) {
23554 SignatureType signature_type = signature_types[i];
23555 for (int j = 0; j < 2; j++) {
23556 bool global = j == 0;
23557 int key = signature_type +
23558 arraysize(signature_types) * (global ? 1 : 0);
23559 Run(signature_type, global, key);
23560 }
23561 }
23562 }
23563
23564 void Run(SignatureType signature_type, bool global, int key) {
23565 v8::Isolate* isolate = CcTest::isolate();
23566 v8::HandleScope scope(isolate);
23567 // Build a template for signature checks.
23568 Local<v8::ObjectTemplate> signature_template;
23569 Local<v8::Signature> signature;
23570 {
23571 Local<v8::FunctionTemplate> parent_template =
23572 FunctionTemplate::New(isolate);
23573 parent_template->SetHiddenPrototype(true);
23574 Local<v8::FunctionTemplate> function_template
23575 = FunctionTemplate::New(isolate);
23576 function_template->Inherit(parent_template);
23577 switch (signature_type) {
23578 case kNoSignature:
23579 break;
23580 case kSignatureOnReceiver:
23581 signature = v8::Signature::New(isolate, function_template);
23582 break;
23583 case kSignatureOnPrototype:
23584 signature = v8::Signature::New(isolate, parent_template);
23585 break;
23586 }
23587 signature_template = function_template->InstanceTemplate();
23588 }
23589 // Global object must pass checks.
23590 Local<v8::Context> context =
23591 v8::Context::New(isolate, NULL, signature_template);
23592 v8::Context::Scope context_scope(context);
23593 // Install regular object that can pass signature checks.
23594 Local<Object> function_receiver = signature_template->NewInstance();
23595 context->Global()->Set(v8_str("function_receiver"), function_receiver);
23596 // Get the holder objects.
23597 Local<Object> inner_global =
23598 Local<Object>::Cast(context->Global()->GetPrototype());
23599 // Install functions on hidden prototype object if there is one.
23600 data = Object::New(isolate);
23601 Local<FunctionTemplate> function_template = FunctionTemplate::New(
23602 isolate, OptimizationCallback, data, signature);
23603 Local<Function> function = function_template->GetFunction();
23604 Local<Object> global_holder = inner_global;
23605 Local<Object> function_holder = function_receiver;
23606 if (signature_type == kSignatureOnPrototype) {
23607 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23608 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23609 }
23610 global_holder->Set(v8_str("g_f"), function);
23611 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23612 function_holder->Set(v8_str("f"), function);
23613 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23614 // Initialize expected values.
23615 callee = function;
23616 count = 0;
23617 if (global) {
23618 receiver = context->Global();
23619 holder = inner_global;
23620 } else {
23621 holder = function_receiver;
23622 // If not using a signature, add something else to the prototype chain
23623 // to test the case that holder != receiver
23624 if (signature_type == kNoSignature) {
23625 receiver = Local<Object>::Cast(CompileRun(
23626 "var receiver_subclass = {};\n"
23627 "receiver_subclass.__proto__ = function_receiver;\n"
23628 "receiver_subclass"));
23629 } else {
23630 receiver = Local<Object>::Cast(CompileRun(
23631 "var receiver_subclass = function_receiver;\n"
23632 "receiver_subclass"));
23633 }
23634 }
23635 // With no signature, the holder is not set.
23636 if (signature_type == kNoSignature) holder = receiver;
23637 // build wrap_function
23638 i::ScopedVector<char> wrap_function(200);
23639 if (global) {
23640 i::SNPrintF(
23641 wrap_function,
23642 "function wrap_f_%d() { var f = g_f; return f(); }\n"
23643 "function wrap_get_%d() { return this.g_acc; }\n"
23644 "function wrap_set_%d() { return this.g_acc = 1; }\n",
23645 key, key, key);
23646 } else {
23647 i::SNPrintF(
23648 wrap_function,
23649 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23650 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23651 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23652 key, key, key);
23653 }
23654 // build source string
23655 i::ScopedVector<char> source(1000);
23656 i::SNPrintF(
23657 source,
23658 "%s\n" // wrap functions
23659 "function wrap_f() { return wrap_f_%d(); }\n"
23660 "function wrap_get() { return wrap_get_%d(); }\n"
23661 "function wrap_set() { return wrap_set_%d(); }\n"
23662 "check = function(returned) {\n"
23663 " if (returned !== 'returned') { throw returned; }\n"
23664 "}\n"
23665 "\n"
23666 "check(wrap_f());\n"
23667 "check(wrap_f());\n"
23668 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23669 "check(wrap_f());\n"
23670 "\n"
23671 "check(wrap_get());\n"
23672 "check(wrap_get());\n"
23673 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23674 "check(wrap_get());\n"
23675 "\n"
23676 "check = function(returned) {\n"
23677 " if (returned !== 1) { throw returned; }\n"
23678 "}\n"
23679 "check(wrap_set());\n"
23680 "check(wrap_set());\n"
23681 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23682 "check(wrap_set());\n",
23683 wrap_function.start(), key, key, key, key, key, key);
23684 v8::TryCatch try_catch;
23685 CompileRun(source.start());
23686 DCHECK(!try_catch.HasCaught());
23687 CHECK_EQ(9, count);
23688 }
23689};
23690
23691
23692Local<Object> ApiCallOptimizationChecker::data;
23693Local<Object> ApiCallOptimizationChecker::receiver;
23694Local<Object> ApiCallOptimizationChecker::holder;
23695Local<Object> ApiCallOptimizationChecker::callee;
23696int ApiCallOptimizationChecker::count = 0;
23697
23698
23699TEST(TestFunctionCallOptimization) {
23700 i::FLAG_allow_natives_syntax = true;
23701 ApiCallOptimizationChecker checker;
23702 checker.RunAll();
23703}
23704
23705
23706static const char* last_event_message;
23707static int last_event_status;
23708void StoringEventLoggerCallback(const char* message, int status) {
23709 last_event_message = message;
23710 last_event_status = status;
23711}
23712
23713
23714TEST(EventLogging) {
23715 v8::Isolate* isolate = CcTest::isolate();
23716 isolate->SetEventLogger(StoringEventLoggerCallback);
23717 v8::internal::HistogramTimer histogramTimer(
23718 "V8.Test", 0, 10000, 50,
23719 reinterpret_cast<v8::internal::Isolate*>(isolate));
23720 histogramTimer.Start();
23721 CHECK_EQ("V8.Test", last_event_message);
23722 CHECK_EQ(0, last_event_status);
23723 histogramTimer.Stop();
23724 CHECK_EQ("V8.Test", last_event_message);
23725 CHECK_EQ(1, last_event_status);
23726}
23727
23728
23729TEST(Promises) {
23730 LocalContext context;
23731 v8::Isolate* isolate = context->GetIsolate();
23732 v8::HandleScope scope(isolate);
23733 Handle<Object> global = context->Global();
23734
23735 // Creation.
23736 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23737 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
23738 Handle<v8::Promise> p = pr->GetPromise();
23739 Handle<v8::Promise> r = rr->GetPromise();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023740 CHECK_EQ(isolate, p->GetIsolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023741
23742 // IsPromise predicate.
23743 CHECK(p->IsPromise());
23744 CHECK(r->IsPromise());
23745 Handle<Value> o = v8::Object::New(isolate);
23746 CHECK(!o->IsPromise());
23747
23748 // Resolution and rejection.
23749 pr->Resolve(v8::Integer::New(isolate, 1));
23750 CHECK(p->IsPromise());
23751 rr->Reject(v8::Integer::New(isolate, 2));
23752 CHECK(r->IsPromise());
23753
23754 // Chaining non-pending promises.
23755 CompileRun(
23756 "var x1 = 0;\n"
23757 "var x2 = 0;\n"
23758 "function f1(x) { x1 = x; return x+1 };\n"
23759 "function f2(x) { x2 = x; return x+1 };\n");
23760 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23761 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23762
23763 p->Chain(f1);
23764 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23765 isolate->RunMicrotasks();
23766 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23767
23768 p->Catch(f2);
23769 isolate->RunMicrotasks();
23770 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23771
23772 r->Catch(f2);
23773 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23774 isolate->RunMicrotasks();
23775 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23776
23777 r->Chain(f1);
23778 isolate->RunMicrotasks();
23779 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23780
23781 // Chaining pending promises.
23782 CompileRun("x1 = x2 = 0;");
23783 pr = v8::Promise::Resolver::New(isolate);
23784 rr = v8::Promise::Resolver::New(isolate);
23785
23786 pr->GetPromise()->Chain(f1);
23787 rr->GetPromise()->Catch(f2);
23788 isolate->RunMicrotasks();
23789 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23790 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23791
23792 pr->Resolve(v8::Integer::New(isolate, 1));
23793 rr->Reject(v8::Integer::New(isolate, 2));
23794 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23795 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23796
23797 isolate->RunMicrotasks();
23798 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23799 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23800
23801 // Multi-chaining.
23802 CompileRun("x1 = x2 = 0;");
23803 pr = v8::Promise::Resolver::New(isolate);
23804 pr->GetPromise()->Chain(f1)->Chain(f2);
23805 pr->Resolve(v8::Integer::New(isolate, 3));
23806 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23807 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23808 isolate->RunMicrotasks();
23809 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23810 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23811
23812 CompileRun("x1 = x2 = 0;");
23813 rr = v8::Promise::Resolver::New(isolate);
23814 rr->GetPromise()->Catch(f1)->Chain(f2);
23815 rr->Reject(v8::Integer::New(isolate, 3));
23816 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23817 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23818 isolate->RunMicrotasks();
23819 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23820 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23821}
23822
23823
23824TEST(PromiseThen) {
23825 LocalContext context;
23826 v8::Isolate* isolate = context->GetIsolate();
23827 v8::HandleScope scope(isolate);
23828 Handle<Object> global = context->Global();
23829
23830 // Creation.
23831 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23832 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
23833 Handle<v8::Promise> p = pr->GetPromise();
23834 Handle<v8::Promise> q = qr->GetPromise();
23835
23836 CHECK(p->IsPromise());
23837 CHECK(q->IsPromise());
23838
23839 pr->Resolve(v8::Integer::New(isolate, 1));
23840 qr->Resolve(p);
23841
23842 // Chaining non-pending promises.
23843 CompileRun(
23844 "var x1 = 0;\n"
23845 "var x2 = 0;\n"
23846 "function f1(x) { x1 = x; return x+1 };\n"
23847 "function f2(x) { x2 = x; return x+1 };\n");
23848 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23849 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23850
23851 // Chain
23852 q->Chain(f1);
23853 CHECK(global->Get(v8_str("x1"))->IsNumber());
23854 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23855 isolate->RunMicrotasks();
23856 CHECK(!global->Get(v8_str("x1"))->IsNumber());
23857 CHECK_EQ(p, global->Get(v8_str("x1")));
23858
23859 // Then
23860 CompileRun("x1 = x2 = 0;");
23861 q->Then(f1);
23862 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23863 isolate->RunMicrotasks();
23864 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23865
23866 // Then
23867 CompileRun("x1 = x2 = 0;");
23868 pr = v8::Promise::Resolver::New(isolate);
23869 qr = v8::Promise::Resolver::New(isolate);
23870
23871 qr->Resolve(pr);
23872 qr->GetPromise()->Then(f1)->Then(f2);
23873
23874 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23875 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23876 isolate->RunMicrotasks();
23877 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23878 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23879
23880 pr->Resolve(v8::Integer::New(isolate, 3));
23881
23882 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23883 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23884 isolate->RunMicrotasks();
23885 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23886 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23887}
23888
23889
23890TEST(DisallowJavascriptExecutionScope) {
23891 LocalContext context;
23892 v8::Isolate* isolate = context->GetIsolate();
23893 v8::HandleScope scope(isolate);
23894 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23895 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23896 CompileRun("2+2");
23897}
23898
23899
23900TEST(AllowJavascriptExecutionScope) {
23901 LocalContext context;
23902 v8::Isolate* isolate = context->GetIsolate();
23903 v8::HandleScope scope(isolate);
23904 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23905 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23906 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23907 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23908 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23909 CompileRun("1+1");
23910 }
23911}
23912
23913
23914TEST(ThrowOnJavascriptExecution) {
23915 LocalContext context;
23916 v8::Isolate* isolate = context->GetIsolate();
23917 v8::HandleScope scope(isolate);
23918 v8::TryCatch try_catch;
23919 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23920 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23921 CompileRun("1+1");
23922 CHECK(try_catch.HasCaught());
23923}
23924
23925
23926TEST(Regress354123) {
23927 LocalContext current;
23928 v8::Isolate* isolate = current->GetIsolate();
23929 v8::HandleScope scope(isolate);
23930
23931 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23932 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
23933 current->Global()->Set(v8_str("friend"), templ->NewInstance());
23934
23935 // Test access using __proto__ from the prototype chain.
23936 named_access_count = 0;
23937 CompileRun("friend.__proto__ = {};");
23938 CHECK_EQ(2, named_access_count);
23939 CompileRun("friend.__proto__;");
23940 CHECK_EQ(4, named_access_count);
23941
23942 // Test access using __proto__ as a hijacked function (A).
23943 named_access_count = 0;
23944 CompileRun("var p = Object.prototype;"
23945 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23946 "f.call(friend, {});");
23947 CHECK_EQ(1, named_access_count);
23948 CompileRun("var p = Object.prototype;"
23949 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23950 "f.call(friend);");
23951 CHECK_EQ(2, named_access_count);
23952
23953 // Test access using __proto__ as a hijacked function (B).
23954 named_access_count = 0;
23955 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23956 "f.call(friend, {});");
23957 CHECK_EQ(1, named_access_count);
23958 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23959 "f.call(friend);");
23960 CHECK_EQ(2, named_access_count);
23961
23962 // Test access using Object.setPrototypeOf reflective method.
23963 named_access_count = 0;
23964 CompileRun("Object.setPrototypeOf(friend, {});");
23965 CHECK_EQ(1, named_access_count);
23966 CompileRun("Object.getPrototypeOf(friend);");
23967 CHECK_EQ(2, named_access_count);
23968}
23969
23970
23971TEST(CaptureStackTraceForStackOverflow) {
23972 v8::internal::FLAG_stack_size = 150;
23973 LocalContext current;
23974 v8::Isolate* isolate = current->GetIsolate();
23975 v8::HandleScope scope(isolate);
23976 V8::SetCaptureStackTraceForUncaughtExceptions(
23977 true, 10, v8::StackTrace::kDetailed);
23978 v8::TryCatch try_catch;
23979 CompileRun("(function f(x) { f(x+1); })(0)");
23980 CHECK(try_catch.HasCaught());
23981}
23982
23983
23984TEST(ScriptNameAndLineNumber) {
23985 LocalContext env;
23986 v8::Isolate* isolate = env->GetIsolate();
23987 v8::HandleScope scope(isolate);
23988 const char* url = "http://www.foo.com/foo.js";
23989 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23990 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23991 Local<Script> script = v8::ScriptCompiler::Compile(
23992 isolate, &script_source);
23993 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23994 CHECK(!script_name.IsEmpty());
23995 CHECK(script_name->IsString());
23996 String::Utf8Value utf8_name(script_name);
23997 CHECK_EQ(url, *utf8_name);
23998 int line_number = script->GetUnboundScript()->GetLineNumber(0);
23999 CHECK_EQ(13, line_number);
24000}
24001
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024002void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
24003 const char* expected_source_mapping_url) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024004 if (expected_source_url != NULL) {
24005 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
24006 CHECK_EQ(expected_source_url, *url);
24007 } else {
24008 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24009 }
24010 if (expected_source_mapping_url != NULL) {
24011 v8::String::Utf8Value url(
24012 script->GetUnboundScript()->GetSourceMappingURL());
24013 CHECK_EQ(expected_source_mapping_url, *url);
24014 } else {
24015 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24016 }
24017}
24018
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024019void SourceURLHelper(const char* source, const char* expected_source_url,
24020 const char* expected_source_mapping_url) {
24021 Local<Script> script = v8_compile(source);
24022 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
24023}
24024
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024025
24026TEST(ScriptSourceURLAndSourceMappingURL) {
24027 LocalContext env;
24028 v8::Isolate* isolate = env->GetIsolate();
24029 v8::HandleScope scope(isolate);
24030 SourceURLHelper("function foo() {}\n"
24031 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
24032 SourceURLHelper("function foo() {}\n"
24033 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
24034
24035 // Both sourceURL and sourceMappingURL.
24036 SourceURLHelper("function foo() {}\n"
24037 "//# sourceURL=bar3.js\n"
24038 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
24039
24040 // Two source URLs; the first one is ignored.
24041 SourceURLHelper("function foo() {}\n"
24042 "//# sourceURL=ignoreme.js\n"
24043 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
24044 SourceURLHelper("function foo() {}\n"
24045 "//# sourceMappingURL=ignoreme.js\n"
24046 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
24047
24048 // SourceURL or sourceMappingURL in the middle of the script.
24049 SourceURLHelper("function foo() {}\n"
24050 "//# sourceURL=bar7.js\n"
24051 "function baz() {}\n", "bar7.js", NULL);
24052 SourceURLHelper("function foo() {}\n"
24053 "//# sourceMappingURL=bar8.js\n"
24054 "function baz() {}\n", NULL, "bar8.js");
24055
24056 // Too much whitespace.
24057 SourceURLHelper("function foo() {}\n"
24058 "//# sourceURL=bar9.js\n"
24059 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
24060 SourceURLHelper("function foo() {}\n"
24061 "//# sourceURL =bar11.js\n"
24062 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
24063
24064 // Disallowed characters in value.
24065 SourceURLHelper("function foo() {}\n"
24066 "//# sourceURL=bar13 .js \n"
24067 "//# sourceMappingURL=bar14 .js \n",
24068 NULL, NULL);
24069 SourceURLHelper("function foo() {}\n"
24070 "//# sourceURL=bar15\t.js \n"
24071 "//# sourceMappingURL=bar16\t.js \n",
24072 NULL, NULL);
24073 SourceURLHelper("function foo() {}\n"
24074 "//# sourceURL=bar17'.js \n"
24075 "//# sourceMappingURL=bar18'.js \n",
24076 NULL, NULL);
24077 SourceURLHelper("function foo() {}\n"
24078 "//# sourceURL=bar19\".js \n"
24079 "//# sourceMappingURL=bar20\".js \n",
24080 NULL, NULL);
24081
24082 // Not too much whitespace.
24083 SourceURLHelper("function foo() {}\n"
24084 "//# sourceURL= bar21.js \n"
24085 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
24086}
24087
24088
24089TEST(GetOwnPropertyDescriptor) {
24090 LocalContext env;
24091 v8::Isolate* isolate = env->GetIsolate();
24092 v8::HandleScope scope(isolate);
24093 CompileRun(
24094 "var x = { value : 13};"
24095 "Object.defineProperty(x, 'p0', {value : 12});"
24096 "Object.defineProperty(x, 'p1', {"
24097 " set : function(value) { this.value = value; },"
24098 " get : function() { return this.value; },"
24099 "});");
24100 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
24101 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
24102 CHECK(desc->IsUndefined());
24103 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
24104 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
24105 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
24106 Local<Function> set =
24107 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
24108 Local<Function> get =
24109 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
24110 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
24111 Handle<Value> args[] = { v8_num(14) };
24112 set->Call(x, 1, args);
24113 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
24114}
24115
24116
24117TEST(Regress411877) {
24118 v8::Isolate* isolate = CcTest::isolate();
24119 v8::HandleScope handle_scope(isolate);
24120 v8::Handle<v8::ObjectTemplate> object_template =
24121 v8::ObjectTemplate::New(isolate);
24122 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24123 IndexedAccessCounter);
24124
24125 v8::Handle<Context> context = Context::New(isolate);
24126 v8::Context::Scope context_scope(context);
24127
24128 context->Global()->Set(v8_str("o"), object_template->NewInstance());
24129 CompileRun("Object.getOwnPropertyNames(o)");
24130}
24131
24132
24133TEST(GetHiddenPropertyTableAfterAccessCheck) {
24134 v8::Isolate* isolate = CcTest::isolate();
24135 v8::HandleScope handle_scope(isolate);
24136 v8::Handle<v8::ObjectTemplate> object_template =
24137 v8::ObjectTemplate::New(isolate);
24138 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24139 IndexedAccessCounter);
24140
24141 v8::Handle<Context> context = Context::New(isolate);
24142 v8::Context::Scope context_scope(context);
24143
24144 v8::Handle<v8::Object> obj = object_template->NewInstance();
24145 obj->Set(v8_str("key"), v8_str("value"));
24146 obj->Delete(v8_str("key"));
24147
24148 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
24149}
24150
24151
24152TEST(Regress411793) {
24153 v8::Isolate* isolate = CcTest::isolate();
24154 v8::HandleScope handle_scope(isolate);
24155 v8::Handle<v8::ObjectTemplate> object_template =
24156 v8::ObjectTemplate::New(isolate);
24157 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24158 IndexedAccessCounter);
24159
24160 v8::Handle<Context> context = Context::New(isolate);
24161 v8::Context::Scope context_scope(context);
24162
24163 context->Global()->Set(v8_str("o"), object_template->NewInstance());
24164 CompileRun(
24165 "Object.defineProperty(o, 'key', "
24166 " { get: function() {}, set: function() {} });");
24167}
24168
24169class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24170 public:
24171 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24172
24173 virtual size_t GetMoreData(const uint8_t** src) {
24174 // Unlike in real use cases, this function will never block.
24175 if (chunks_[index_] == NULL) {
24176 return 0;
24177 }
24178 // Copy the data, since the caller takes ownership of it.
24179 size_t len = strlen(chunks_[index_]);
24180 // We don't need to zero-terminate since we return the length.
24181 uint8_t* copy = new uint8_t[len];
24182 memcpy(copy, chunks_[index_], len);
24183 *src = copy;
24184 ++index_;
24185 return len;
24186 }
24187
24188 // Helper for constructing a string from chunks (the compilation needs it
24189 // too).
24190 static char* FullSourceString(const char** chunks) {
24191 size_t total_len = 0;
24192 for (size_t i = 0; chunks[i] != NULL; ++i) {
24193 total_len += strlen(chunks[i]);
24194 }
24195 char* full_string = new char[total_len + 1];
24196 size_t offset = 0;
24197 for (size_t i = 0; chunks[i] != NULL; ++i) {
24198 size_t len = strlen(chunks[i]);
24199 memcpy(full_string + offset, chunks[i], len);
24200 offset += len;
24201 }
24202 full_string[total_len] = 0;
24203 return full_string;
24204 }
24205
24206 private:
24207 const char** chunks_;
24208 unsigned index_;
24209};
24210
24211
24212// Helper function for running streaming tests.
24213void RunStreamingTest(const char** chunks,
24214 v8::ScriptCompiler::StreamedSource::Encoding encoding =
24215 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024216 bool expected_success = true,
24217 const char* expected_source_url = NULL,
24218 const char* expected_source_mapping_url = NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024219 LocalContext env;
24220 v8::Isolate* isolate = env->GetIsolate();
24221 v8::HandleScope scope(isolate);
24222 v8::TryCatch try_catch;
24223
24224 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
24225 encoding);
24226 v8::ScriptCompiler::ScriptStreamingTask* task =
24227 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24228
24229 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24230 // task here in the main thread.
24231 task->Run();
24232 delete task;
24233
24234 v8::ScriptOrigin origin(v8_str("http://foo.com"));
24235 char* full_source = TestSourceStream::FullSourceString(chunks);
24236
24237 // The possible errors are only produced while compiling.
24238 CHECK_EQ(false, try_catch.HasCaught());
24239
24240 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
24241 isolate, &source, v8_str(full_source), origin);
24242 if (expected_success) {
24243 CHECK(!script.IsEmpty());
24244 v8::Handle<Value> result(script->Run());
24245 // All scripts are supposed to return the fixed value 13 when ran.
24246 CHECK_EQ(13, result->Int32Value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024247 CheckMagicComments(script, expected_source_url,
24248 expected_source_mapping_url);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024249 } else {
24250 CHECK(script.IsEmpty());
24251 CHECK(try_catch.HasCaught());
24252 }
24253 delete[] full_source;
24254}
24255
24256
24257TEST(StreamingSimpleScript) {
24258 // This script is unrealistically small, since no one chunk is enough to fill
24259 // the backing buffer of Scanner, let alone overflow it.
24260 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24261 NULL};
24262 RunStreamingTest(chunks);
24263}
24264
24265
24266TEST(StreamingBiggerScript) {
24267 const char* chunk1 =
24268 "function foo() {\n"
24269 " // Make this chunk sufficiently long so that it will overflow the\n"
24270 " // backing buffer of the Scanner.\n"
24271 " var i = 0;\n"
24272 " var result = 0;\n"
24273 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24274 " result = 0;\n"
24275 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24276 " result = 0;\n"
24277 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24278 " result = 0;\n"
24279 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24280 " return result;\n"
24281 "}\n";
24282 const char* chunks[] = {chunk1, "foo(); ", NULL};
24283 RunStreamingTest(chunks);
24284}
24285
24286
24287TEST(StreamingScriptWithParseError) {
24288 // Test that parse errors from streamed scripts are propagated correctly.
24289 {
24290 char chunk1[] =
24291 " // This will result in a parse error.\n"
24292 " var if else then foo";
24293 char chunk2[] = " 13\n";
24294 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24295
24296 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24297 false);
24298 }
24299 // Test that the next script succeeds normally.
24300 {
24301 char chunk1[] =
24302 " // This will be parsed successfully.\n"
24303 " function foo() { return ";
24304 char chunk2[] = " 13; }\n";
24305 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24306
24307 RunStreamingTest(chunks);
24308 }
24309}
24310
24311
24312TEST(StreamingUtf8Script) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024313 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024314 // don't like it.
24315 const char* chunk1 =
24316 "function foo() {\n"
24317 " // This function will contain an UTF-8 character which is not in\n"
24318 " // ASCII.\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024319 " var foob\xec\x92\x81r = 13;\n"
24320 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024321 "}\n";
24322 const char* chunks[] = {chunk1, "foo(); ", NULL};
24323 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24324}
24325
24326
24327TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24328 // A sanity check to prove that the approach of splitting UTF-8
24329 // characters is correct. Here is an UTF-8 character which will take three
24330 // bytes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024331 const char* reference = "\xec\x92\x81";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024332 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
24333
24334 char chunk1[] =
24335 "function foo() {\n"
24336 " // This function will contain an UTF-8 character which is not in\n"
24337 " // ASCII.\n"
24338 " var foob";
24339 char chunk2[] =
24340 "XXXr = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024341 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024342 "}\n";
24343 for (int i = 0; i < 3; ++i) {
24344 chunk2[i] = reference[i];
24345 }
24346 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24347 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24348}
24349
24350
24351TEST(StreamingUtf8ScriptWithSplitCharacters) {
24352 // Stream data where a multi-byte UTF-8 character is split between two data
24353 // chunks.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024354 const char* reference = "\xec\x92\x81";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024355 char chunk1[] =
24356 "function foo() {\n"
24357 " // This function will contain an UTF-8 character which is not in\n"
24358 " // ASCII.\n"
24359 " var foobX";
24360 char chunk2[] =
24361 "XXr = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024362 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024363 "}\n";
24364 chunk1[strlen(chunk1) - 1] = reference[0];
24365 chunk2[0] = reference[1];
24366 chunk2[1] = reference[2];
24367 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24368 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24369}
24370
24371
24372TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24373 // Tests edge cases which should still be decoded correctly.
24374
24375 // Case 1: a chunk contains only bytes for a split character (and no other
24376 // data). This kind of a chunk would be exceptionally small, but we should
24377 // still decode it correctly.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024378 const char* reference = "\xec\x92\x81";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024379 // The small chunk is at the beginning of the split character
24380 {
24381 char chunk1[] =
24382 "function foo() {\n"
24383 " // This function will contain an UTF-8 character which is not in\n"
24384 " // ASCII.\n"
24385 " var foob";
24386 char chunk2[] = "XX";
24387 char chunk3[] =
24388 "Xr = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024389 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024390 "}\n";
24391 chunk2[0] = reference[0];
24392 chunk2[1] = reference[1];
24393 chunk3[0] = reference[2];
24394 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24395 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24396 }
24397 // The small chunk is at the end of a character
24398 {
24399 char chunk1[] =
24400 "function foo() {\n"
24401 " // This function will contain an UTF-8 character which is not in\n"
24402 " // ASCII.\n"
24403 " var foobX";
24404 char chunk2[] = "XX";
24405 char chunk3[] =
24406 "r = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024407 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024408 "}\n";
24409 chunk1[strlen(chunk1) - 1] = reference[0];
24410 chunk2[0] = reference[1];
24411 chunk2[1] = reference[2];
24412 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24413 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24414 }
24415 // Case 2: the script ends with a multi-byte character. Make sure that it's
24416 // decoded correctly and not just ignored.
24417 {
24418 char chunk1[] =
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024419 "var foob\xec\x92\x81 = 13;\n"
24420 "foob\xec\x92\x81";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024421 const char* chunks[] = {chunk1, NULL};
24422 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24423 }
24424}
24425
24426
24427TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24428 // Test cases where a UTF-8 character is split over several chunks. Those
24429 // cases are not supported (the embedder should give the data in big enough
24430 // chunks), but we shouldn't crash, just produce a parse error.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024431 const char* reference = "\xec\x92\x81";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024432 char chunk1[] =
24433 "function foo() {\n"
24434 " // This function will contain an UTF-8 character which is not in\n"
24435 " // ASCII.\n"
24436 " var foobX";
24437 char chunk2[] = "X";
24438 char chunk3[] =
24439 "Xr = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024440 " return foob\xec\x92\x81r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024441 "}\n";
24442 chunk1[strlen(chunk1) - 1] = reference[0];
24443 chunk2[0] = reference[1];
24444 chunk3[0] = reference[2];
24445 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24446
24447 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24448}
24449
24450
24451TEST(StreamingProducesParserCache) {
24452 i::FLAG_min_preparse_length = 0;
24453 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24454 NULL};
24455
24456 LocalContext env;
24457 v8::Isolate* isolate = env->GetIsolate();
24458 v8::HandleScope scope(isolate);
24459
24460 v8::ScriptCompiler::StreamedSource source(
24461 new TestSourceStream(chunks),
24462 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24463 v8::ScriptCompiler::ScriptStreamingTask* task =
24464 v8::ScriptCompiler::StartStreamingScript(
24465 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24466
24467 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24468 // task here in the main thread.
24469 task->Run();
24470 delete task;
24471
24472 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24473 CHECK(cached_data != NULL);
24474 CHECK(cached_data->data != NULL);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024475 CHECK(!cached_data->rejected);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024476 CHECK_GT(cached_data->length, 0);
24477}
24478
24479
24480TEST(StreamingScriptWithInvalidUtf8) {
24481 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24482 // chunk don't produce a crash.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024483 const char* reference = "\xec\x92\x81\x80\x80";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024484 char chunk1[] =
24485 "function foo() {\n"
24486 " // This function will contain an UTF-8 character which is not in\n"
24487 " // ASCII.\n"
24488 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
24489 char chunk2[] =
24490 "r = 13;\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024491 " return foob\xec\x92\x81\x80\x80r;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024492 "}\n";
24493 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24494
24495 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24496 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24497}
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024498
24499
24500TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24501 // Regression test: Stream data where there are several multi-byte UTF-8
24502 // characters in a sequence and one of them is split between two data chunks.
24503 const char* reference = "\xec\x92\x81";
24504 char chunk1[] =
24505 "function foo() {\n"
24506 " // This function will contain an UTF-8 character which is not in\n"
24507 " // ASCII.\n"
24508 " var foob\xec\x92\x81X";
24509 char chunk2[] =
24510 "XXr = 13;\n"
24511 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24512 "}\n";
24513 chunk1[strlen(chunk1) - 1] = reference[0];
24514 chunk2[0] = reference[1];
24515 chunk2[1] = reference[2];
24516 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24517 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24518}
24519
24520
24521TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24522 // Another regression test, similar to the previous one. The difference is
24523 // that the split character is not the last one in the sequence.
24524 const char* reference = "\xec\x92\x81";
24525 char chunk1[] =
24526 "function foo() {\n"
24527 " // This function will contain an UTF-8 character which is not in\n"
24528 " // ASCII.\n"
24529 " var foobX";
24530 char chunk2[] =
24531 "XX\xec\x92\x81r = 13;\n"
24532 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24533 "}\n";
24534 chunk1[strlen(chunk1) - 1] = reference[0];
24535 chunk2[0] = reference[1];
24536 chunk2[1] = reference[2];
24537 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24538 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24539}
24540
24541
24542void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
24543 const char* garbage = "garbage garbage garbage garbage garbage garbage";
24544 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
24545 int length = 16;
24546 v8::ScriptCompiler::CachedData* cached_data =
24547 new v8::ScriptCompiler::CachedData(data, length);
24548 DCHECK(!cached_data->rejected);
24549 v8::ScriptOrigin origin(v8_str("origin"));
24550 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
24551 v8::Handle<v8::Script> script =
24552 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
24553 CHECK(cached_data->rejected);
24554 CHECK_EQ(42, script->Run()->Int32Value());
24555}
24556
24557
24558TEST(InvalidCacheData) {
24559 v8::V8::Initialize();
24560 v8::HandleScope scope(CcTest::isolate());
24561 LocalContext context;
24562 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
24563 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
24564}
24565
24566
24567TEST(ParserCacheRejectedGracefully) {
24568 i::FLAG_min_preparse_length = 0;
24569 v8::V8::Initialize();
24570 v8::HandleScope scope(CcTest::isolate());
24571 LocalContext context;
24572 // Produce valid cached data.
24573 v8::ScriptOrigin origin(v8_str("origin"));
24574 v8::Local<v8::String> source_str = v8_str("function foo() {}");
24575 v8::ScriptCompiler::Source source(source_str, origin);
24576 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
24577 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
24578 CHECK(!script.IsEmpty());
24579 const v8::ScriptCompiler::CachedData* original_cached_data =
24580 source.GetCachedData();
24581 CHECK(original_cached_data != NULL);
24582 CHECK(original_cached_data->data != NULL);
24583 CHECK(!original_cached_data->rejected);
24584 CHECK_GT(original_cached_data->length, 0);
24585 // Recompiling the same script with it won't reject the data.
24586 {
24587 v8::ScriptCompiler::Source source_with_cached_data(
24588 source_str, origin,
24589 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24590 original_cached_data->length));
24591 v8::Handle<v8::Script> script =
24592 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24593 v8::ScriptCompiler::kConsumeParserCache);
24594 CHECK(!script.IsEmpty());
24595 const v8::ScriptCompiler::CachedData* new_cached_data =
24596 source_with_cached_data.GetCachedData();
24597 CHECK(new_cached_data != NULL);
24598 CHECK(!new_cached_data->rejected);
24599 }
24600 // Compile an incompatible script with the cached data. The new script doesn't
24601 // have the same starting position for the function as the old one, so the old
24602 // cached data will be incompatible with it and will be rejected.
24603 {
24604 v8::Local<v8::String> incompatible_source_str =
24605 v8_str(" function foo() {}");
24606 v8::ScriptCompiler::Source source_with_cached_data(
24607 incompatible_source_str, origin,
24608 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24609 original_cached_data->length));
24610 v8::Handle<v8::Script> script =
24611 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24612 v8::ScriptCompiler::kConsumeParserCache);
24613 CHECK(!script.IsEmpty());
24614 const v8::ScriptCompiler::CachedData* new_cached_data =
24615 source_with_cached_data.GetCachedData();
24616 CHECK(new_cached_data != NULL);
24617 CHECK(new_cached_data->rejected);
24618 }
24619}
24620
24621
24622TEST(StringConcatOverflow) {
24623 v8::V8::Initialize();
24624 v8::HandleScope scope(CcTest::isolate());
24625 RandomLengthOneByteResource* r =
24626 new RandomLengthOneByteResource(i::String::kMaxLength);
24627 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
24628 CHECK(!str.IsEmpty());
24629 v8::TryCatch try_catch;
24630 v8::Local<v8::String> result = v8::String::Concat(str, str);
24631 CHECK(result.IsEmpty());
24632 CHECK(!try_catch.HasCaught());
24633}
24634
24635
24636TEST(TurboAsmDisablesNeuter) {
24637 v8::V8::Initialize();
24638 v8::HandleScope scope(CcTest::isolate());
24639 LocalContext context;
24640#if V8_TURBOFAN_TARGET
24641 bool should_be_neuterable = !i::FLAG_turbo_asm;
24642#else
24643 bool should_be_neuterable = true;
24644#endif
24645 const char* load =
24646 "function Module(stdlib, foreign, heap) {"
24647 " 'use asm';"
24648 " var MEM32 = new stdlib.Int32Array(heap);"
24649 " function load() { return MEM32[0]; }"
24650 " return { load: load };"
24651 "}"
24652 "var buffer = new ArrayBuffer(4);"
24653 "Module(this, {}, buffer).load();"
24654 "buffer";
24655
24656 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
24657 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24658
24659 const char* store =
24660 "function Module(stdlib, foreign, heap) {"
24661 " 'use asm';"
24662 " var MEM32 = new stdlib.Int32Array(heap);"
24663 " function store() { MEM32[0] = 0; }"
24664 " return { store: store };"
24665 "}"
24666 "var buffer = new ArrayBuffer(4);"
24667 "Module(this, {}, buffer).store();"
24668 "buffer";
24669
24670 result = CompileRun(store).As<v8::ArrayBuffer>();
24671 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24672}
24673
24674
24675TEST(GetPrototypeAccessControl) {
24676 i::FLAG_allow_natives_syntax = true;
24677 v8::Isolate* isolate = CcTest::isolate();
24678 v8::HandleScope handle_scope(isolate);
24679 LocalContext env;
24680
24681 v8::Handle<v8::ObjectTemplate> obj_template =
24682 v8::ObjectTemplate::New(isolate);
24683 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
24684 BlockEverythingIndexed);
24685
24686 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
24687
24688 {
24689 v8::TryCatch try_catch;
24690 CompileRun(
24691 "function f() { %_GetPrototype(prohibited); }"
24692 "%OptimizeFunctionOnNextCall(f);"
24693 "f();");
24694 CHECK(try_catch.HasCaught());
24695 }
24696}
24697
24698
24699TEST(GetPrototypeHidden) {
24700 i::FLAG_allow_natives_syntax = true;
24701 v8::Isolate* isolate = CcTest::isolate();
24702 v8::HandleScope handle_scope(isolate);
24703 LocalContext env;
24704
24705 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
24706 t->SetHiddenPrototype(true);
24707 Handle<Object> proto = t->GetFunction()->NewInstance();
24708 Handle<Object> object = Object::New(isolate);
24709 Handle<Object> proto2 = Object::New(isolate);
24710 object->SetPrototype(proto);
24711 proto->SetPrototype(proto2);
24712
24713 env->Global()->Set(v8_str("object"), object);
24714 env->Global()->Set(v8_str("proto"), proto);
24715 env->Global()->Set(v8_str("proto2"), proto2);
24716
24717 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
24718 CHECK(result->Equals(proto2));
24719
24720 result = CompileRun(
24721 "function f() { return %_GetPrototype(object); }"
24722 "%OptimizeFunctionOnNextCall(f);"
24723 "f()");
24724 CHECK(result->Equals(proto2));
24725}
24726
24727
24728TEST(ClassPrototypeCreationContext) {
24729 i::FLAG_harmony_classes = true;
24730 v8::Isolate* isolate = CcTest::isolate();
24731 v8::HandleScope handle_scope(isolate);
24732 LocalContext env;
24733
24734 Handle<Object> result = Handle<Object>::Cast(
24735 CompileRun("'use strict'; class Example { }; Example.prototype"));
24736 CHECK(env.local() == result->CreationContext());
24737}
24738
24739
24740TEST(SimpleStreamingScriptWithSourceURL) {
24741 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
24742 "//# sourceURL=bar2.js\n", NULL};
24743 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
24744 "bar2.js");
24745}
24746
24747
24748TEST(StreamingScriptWithSplitSourceURL) {
24749 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
24750 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
24751 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
24752 "bar2.js");
24753}
24754
24755
24756TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
24757 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
24758 " sourceMappingURL=bar2.js\n", "foo();", NULL};
24759 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
24760 "bar2.js");
24761}