blob: 0e80384125c260e4edd7ec94818e1cf671bb383b [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
188static void TestSignature(const char* loop_js, Local<Value> receiver) {
189 i::ScopedVector<char> source(200);
190 i::SNPrintF(source,
191 "for (var i = 0; i < 10; i++) {"
192 " %s"
193 "}",
194 loop_js);
195 signature_callback_count = 0;
196 signature_expected_receiver = receiver;
197 bool expected_to_throw = receiver.IsEmpty();
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 CompileRun(source.start());
200 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
201 if (!expected_to_throw) {
202 CHECK_EQ(10, signature_callback_count);
203 } else {
204 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
205 try_catch.Exception()->ToString());
206 }
207}
208
209
210THREADED_TEST(ReceiverSignature) {
211 LocalContext env;
212 v8::Isolate* isolate = env->GetIsolate();
213 v8::HandleScope scope(isolate);
214 // Setup templates.
215 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
216 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
217 v8::Handle<v8::FunctionTemplate> callback_sig =
218 v8::FunctionTemplate::New(
219 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
220 v8::Handle<v8::FunctionTemplate> callback =
221 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
222 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 sub_fun->Inherit(fun);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 v8::Handle<v8::FunctionTemplate> unrel_fun =
225 v8::FunctionTemplate::New(isolate);
226 // Install properties.
227 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
228 fun_proto->Set(v8_str("prop_sig"), callback_sig);
229 fun_proto->Set(v8_str("prop"), callback);
230 fun_proto->SetAccessorProperty(
231 v8_str("accessor_sig"), callback_sig, callback_sig);
232 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
233 // Instantiate templates.
234 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
235 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
236 // Setup global variables.
237 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 env->Global()->Set(v8_str("fun_instance"), fun_instance);
240 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 "var accessor_sig_key = 'accessor_sig';"
243 "var accessor_key = 'accessor';"
244 "var prop_sig_key = 'prop_sig';"
245 "var prop_key = 'prop';"
246 ""
247 "function copy_props(obj) {"
248 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
249 " var source = Fun.prototype;"
250 " for (var i in keys) {"
251 " var key = keys[i];"
252 " var desc = Object.getOwnPropertyDescriptor(source, key);"
253 " Object.defineProperty(obj, key, desc);"
254 " }"
255 "}"
256 ""
257 "var obj = {};"
258 "copy_props(obj);"
259 "var unrel = new UnrelFun();"
260 "copy_props(unrel);");
261 // Test with and without ICs
262 const char* test_objects[] = {
263 "fun_instance", "sub_fun_instance", "obj", "unrel" };
264 unsigned bad_signature_start_offset = 2;
265 for (unsigned i = 0; i < arraysize(test_objects); i++) {
266 i::ScopedVector<char> source(200);
267 i::SNPrintF(
268 source, "var test_object = %s; test_object", test_objects[i]);
269 Local<Value> test_object = CompileRun(source.start());
270 TestSignature("test_object.prop();", test_object);
271 TestSignature("test_object.accessor;", test_object);
272 TestSignature("test_object[accessor_key];", test_object);
273 TestSignature("test_object.accessor = 1;", test_object);
274 TestSignature("test_object[accessor_key] = 1;", test_object);
275 if (i >= bad_signature_start_offset) test_object = Local<Value>();
276 TestSignature("test_object.prop_sig();", test_object);
277 TestSignature("test_object.accessor_sig;", test_object);
278 TestSignature("test_object[accessor_sig_key];", test_object);
279 TestSignature("test_object.accessor_sig = 1;", test_object);
280 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
281 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000282}
283
284
Steve Blocka7e24c12009-10-30 11:49:00 +0000285THREADED_TEST(ArgumentSignature) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 v8::Isolate* isolate = env->GetIsolate();
288 v8::HandleScope scope(isolate);
289 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 cons->SetClassName(v8_str("Cons"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 v8::Handle<v8::Signature> sig = v8::Signature::New(
292 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 v8::Handle<v8::FunctionTemplate> fun =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000294 v8::FunctionTemplate::New(isolate,
295 SignatureCallback,
296 v8::Handle<Value>(),
297 sig);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
299 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300
301 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
302 CHECK(value1->IsTrue());
303
304 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
305 CHECK(value2->IsTrue());
306
307 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
308 CHECK(value3->IsTrue());
309
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 cons1->SetClassName(v8_str("Cons1"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 cons2->SetClassName(v8_str("Cons2"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000314 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 cons3->SetClassName(v8_str("Cons3"));
316
317 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 v8::Handle<v8::Signature> wsig = v8::Signature::New(
319 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 v8::Handle<v8::FunctionTemplate> fun2 =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 v8::FunctionTemplate::New(isolate,
322 SignatureCallback,
323 v8::Handle<Value>(),
324 wsig);
Steve Blocka7e24c12009-10-30 11:49:00 +0000325
326 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
327 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
328 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
329 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
330 v8::Handle<Value> value4 = CompileRun(
331 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
332 "'[object Cons1],[object Cons2],[object Cons3]'");
333 CHECK(value4->IsTrue());
334
335 v8::Handle<Value> value5 = CompileRun(
336 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
337 CHECK(value5->IsTrue());
338
339 v8::Handle<Value> value6 = CompileRun(
340 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
341 CHECK(value6->IsTrue());
342
343 v8::Handle<Value> value7 = CompileRun(
344 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
345 "'[object Cons1],[object Cons2],[object Cons3],d';");
346 CHECK(value7->IsTrue());
347
348 v8::Handle<Value> value8 = CompileRun(
349 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
350 CHECK(value8->IsTrue());
351}
352
353
354THREADED_TEST(HulIgennem) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000356 v8::Isolate* isolate = env->GetIsolate();
357 v8::HandleScope scope(isolate);
358 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000359 Local<String> undef_str = undef->ToString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361 undef_str->WriteUtf8(value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 CHECK_EQ(0, strcmp(value, "undefined"));
363 i::DeleteArray(value);
364}
365
366
367THREADED_TEST(Access) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 v8::Isolate* isolate = env->GetIsolate();
370 v8::HandleScope scope(isolate);
371 Local<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 Local<Value> foo_before = obj->Get(v8_str("foo"));
373 CHECK(foo_before->IsUndefined());
374 Local<String> bar_str = v8_str("bar");
375 obj->Set(v8_str("foo"), bar_str);
376 Local<Value> foo_after = obj->Get(v8_str("foo"));
377 CHECK(!foo_after->IsUndefined());
378 CHECK(foo_after->IsString());
379 CHECK_EQ(bar_str, foo_after);
380}
381
382
Steve Block6ded16b2010-05-10 14:33:55 +0100383THREADED_TEST(AccessElement) {
Steve Block6ded16b2010-05-10 14:33:55 +0100384 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000385 v8::HandleScope scope(env->GetIsolate());
386 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +0100387 Local<Value> before = obj->Get(1);
388 CHECK(before->IsUndefined());
389 Local<String> bar_str = v8_str("bar");
390 obj->Set(1, bar_str);
391 Local<Value> after = obj->Get(1);
392 CHECK(!after->IsUndefined());
393 CHECK(after->IsString());
394 CHECK_EQ(bar_str, after);
395
396 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
397 CHECK_EQ(v8_str("a"), value->Get(0));
398 CHECK_EQ(v8_str("b"), value->Get(1));
399}
400
401
Steve Blocka7e24c12009-10-30 11:49:00 +0000402THREADED_TEST(Script) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 v8::HandleScope scope(env->GetIsolate());
405 const char* source = "1 + 2 + 3";
406 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000407 CHECK_EQ(6, script->Run()->Int32Value());
408}
409
410
Steve Blocka7e24c12009-10-30 11:49:00 +0000411class TestResource: public String::ExternalStringResource {
412 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 explicit TestResource(uint16_t* data, int* counter = NULL,
414 bool owning_data = true)
415 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000416 while (data[length_]) ++length_;
417 }
418
419 ~TestResource() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420 if (owning_data_) i::DeleteArray(data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000421 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 }
423
424 const uint16_t* data() const {
425 return data_;
426 }
427
428 size_t length() const {
429 return length_;
430 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 private:
433 uint16_t* data_;
434 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000435 int* counter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 bool owning_data_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000437};
438
439
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440class TestOneByteResource : public String::ExternalOneByteStringResource {
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 explicit TestOneByteResource(const char* data, int* counter = NULL,
443 size_t offset = 0)
444 : orig_data_(data),
445 data_(data + offset),
446 length_(strlen(data) - offset),
447 counter_(counter) {}
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 ~TestOneByteResource() {
450 i::DeleteArray(orig_data_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000451 if (counter_ != NULL) ++*counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 }
453
454 const char* data() const {
455 return data_;
456 }
457
458 size_t length() const {
459 return length_;
460 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 const char* orig_data_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 const char* data_;
465 size_t length_;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000466 int* counter_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000467};
468
469
Steve Blocka7e24c12009-10-30 11:49:00 +0000470THREADED_TEST(ScriptUsingStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000471 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 const char* c_source = "1 + 2 * 3";
473 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
474 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000477 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 Local<Value> value = script->Run();
481 CHECK(value->IsNumber());
482 CHECK_EQ(7, value->Int32Value());
483 CHECK(source->IsExternal());
484 CHECK_EQ(resource,
485 static_cast<TestResource*>(source->GetExternalStringResource()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 String::Encoding encoding = String::UNKNOWN_ENCODING;
487 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
488 source->GetExternalStringResourceBase(&encoding));
489 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
490 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000491 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000492 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000493 CcTest::i_isolate()->compilation_cache()->Clear();
494 CcTest::heap()->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000495 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000496}
497
498
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499THREADED_TEST(ScriptUsingOneByteStringResource) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000500 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000501 const char* c_source = "1 + 2 * 3";
502 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000503 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 v8::HandleScope scope(env->GetIsolate());
505 TestOneByteResource* resource =
506 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
507 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
508 CHECK(source->IsExternalOneByte());
509 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510 source->GetExternalOneByteStringResource());
511 String::Encoding encoding = String::UNKNOWN_ENCODING;
512 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
513 source->GetExternalStringResourceBase(&encoding));
514 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
515 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000516 Local<Value> value = script->Run();
517 CHECK(value->IsNumber());
518 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000520 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522 CcTest::i_isolate()->compilation_cache()->Clear();
523 CcTest::heap()->CollectAllAvailableGarbage();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000524 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000525}
526
527
528THREADED_TEST(ScriptMakingExternalString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000529 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000530 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
531 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 v8::HandleScope scope(env->GetIsolate());
534 Local<String> source =
535 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000536 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
538 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
539 CHECK_EQ(source->IsExternal(), false);
540 CHECK_EQ(source->IsExternalOneByte(), false);
541 String::Encoding encoding = String::UNKNOWN_ENCODING;
542 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
543 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000544 bool success = source->MakeExternal(new TestResource(two_byte_source,
545 &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 CHECK(success);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000548 Local<Value> value = script->Run();
549 CHECK(value->IsNumber());
550 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000552 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000553 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000554 CcTest::i_isolate()->compilation_cache()->Clear();
555 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000556 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000557}
558
559
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560THREADED_TEST(ScriptMakingExternalOneByteString) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000561 int dispose_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000562 const char* c_source = "1 + 2 * 3";
563 {
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000567 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 bool success = source->MakeExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 CHECK(success);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 Local<Script> script = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000574 Local<Value> value = script->Run();
575 CHECK(value->IsNumber());
576 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000578 CHECK_EQ(0, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000579 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 CcTest::i_isolate()->compilation_cache()->Clear();
581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000582 CHECK_EQ(1, dispose_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000583}
584
585
Andrei Popescu402d9372010-02-26 13:31:12 +0000586TEST(MakingExternalStringConditions) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000587 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 v8::HandleScope scope(env->GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +0000589
590 // Free some space in the new space so that we can check freshness.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000593
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100594 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 Local<String> small_string =
596 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100597 i::DeleteArray(two_byte_string);
598
Andrei Popescu402d9372010-02-26 13:31:12 +0000599 // We should refuse to externalize newly created small string.
600 CHECK(!small_string->CanMakeExternal());
601 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000602 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000604 // Old space strings should be accepted.
605 CHECK(small_string->CanMakeExternal());
606
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100607 two_byte_string = AsciiToTwoByteString("small string 2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100609 i::DeleteArray(two_byte_string);
610
Andrei Popescu402d9372010-02-26 13:31:12 +0000611 // We should refuse externalizing newly created small string.
612 CHECK(!small_string->CanMakeExternal());
613 for (int i = 0; i < 100; i++) {
614 String::Value value(small_string);
615 }
616 // Frequently used strings should be accepted.
617 CHECK(small_string->CanMakeExternal());
618
619 const int buf_size = 10 * 1024;
620 char* buf = i::NewArray<char>(buf_size);
621 memset(buf, 'a', buf_size);
622 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100623
624 two_byte_string = AsciiToTwoByteString(buf);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 Local<String> large_string =
626 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000627 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100628 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000629 // Large strings should be immediately accepted.
630 CHECK(large_string->CanMakeExternal());
631}
632
633
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634TEST(MakingExternalOneByteStringConditions) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000635 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 v8::HandleScope scope(env->GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +0000637
638 // Free some space in the new space so that we can check freshness.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000641
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000642 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
Andrei Popescu402d9372010-02-26 13:31:12 +0000643 // We should refuse to externalize newly created small string.
644 CHECK(!small_string->CanMakeExternal());
645 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000648 // Old space strings should be accepted.
649 CHECK(small_string->CanMakeExternal());
650
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
Andrei Popescu402d9372010-02-26 13:31:12 +0000652 // We should refuse externalizing newly created small string.
653 CHECK(!small_string->CanMakeExternal());
654 for (int i = 0; i < 100; i++) {
655 String::Value value(small_string);
656 }
657 // Frequently used strings should be accepted.
658 CHECK(small_string->CanMakeExternal());
659
660 const int buf_size = 10 * 1024;
661 char* buf = i::NewArray<char>(buf_size);
662 memset(buf, 'a', buf_size);
663 buf[buf_size - 1] = '\0';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
Andrei Popescu402d9372010-02-26 13:31:12 +0000665 i::DeleteArray(buf);
666 // Large strings should be immediately accepted.
667 CHECK(large_string->CanMakeExternal());
668}
669
670
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671TEST(MakingExternalUnalignedOneByteString) {
672 LocalContext env;
673 v8::HandleScope scope(env->GetIsolate());
674
675 CompileRun("function cons(a, b) { return a + b; }"
676 "function slice(a) { return a.substring(1); }");
677 // Create a cons string that will land in old pointer space.
678 Local<String> cons = Local<String>::Cast(CompileRun(
679 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
680 // Create a sliced string that will land in old pointer space.
681 Local<String> slice = Local<String>::Cast(CompileRun(
682 "slice('abcdefghijklmnopqrstuvwxyz');"));
683
684 // Trigger GCs so that the newly allocated string moves to old gen.
685 SimulateFullSpace(CcTest::heap()->old_pointer_space());
686 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
687 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
688
689 // Turn into external string with unaligned resource data.
690 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
691 bool success =
692 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
693 CHECK(success);
694 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
695 success =
696 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
697 CHECK(success);
698
699 // Trigger GCs and force evacuation.
700 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
701 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
Steve Blocka7e24c12009-10-30 11:49:00 +0000702}
703
704
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705THREADED_TEST(UsingExternalString) {
706 i::Factory* factory = CcTest::i_isolate()->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708 v8::HandleScope scope(CcTest::isolate());
709 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
Steve Blocka7e24c12009-10-30 11:49:00 +0000710 Local<String> string = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 CcTest::isolate(), new TestResource(two_byte_string));
Steve Blocka7e24c12009-10-30 11:49:00 +0000712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
716 i::Handle<i::String> isymbol =
717 factory->InternalizeString(istring);
718 CHECK(isymbol->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000719 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722}
723
724
725THREADED_TEST(UsingExternalOneByteString) {
726 i::Factory* factory = CcTest::i_isolate()->factory();
727 {
728 v8::HandleScope scope(CcTest::isolate());
729 const char* one_byte_string = "test string";
730 Local<String> string = String::NewExternal(
731 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
732 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
733 // Trigger GCs so that the newly allocated string moves to old gen.
734 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
736 i::Handle<i::String> isymbol =
737 factory->InternalizeString(istring);
738 CHECK(isymbol->IsInternalizedString());
739 }
740 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000742}
743
744
Leon Clarkee46be812010-01-19 14:06:41 +0000745THREADED_TEST(ScavengeExternalString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746 i::FLAG_stress_compaction = false;
747 i::FLAG_gc_global = false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000748 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100749 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000750 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751 v8::HandleScope scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000752 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 Local<String> string = String::NewExternal(
754 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000755 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000756 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
757 in_new_space = CcTest::heap()->InNewSpace(*istring);
758 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000759 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000760 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 CcTest::heap()->CollectGarbage(
762 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000763 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000764}
765
766
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767THREADED_TEST(ScavengeExternalOneByteString) {
768 i::FLAG_stress_compaction = false;
769 i::FLAG_gc_global = false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000770 int dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100771 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000772 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773 v8::HandleScope scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +0000774 const char* one_byte_string = "test string";
775 Local<String> string = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776 CcTest::isolate(),
777 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
Leon Clarkee46be812010-01-19 14:06:41 +0000778 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000779 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
780 in_new_space = CcTest::heap()->InNewSpace(*istring);
781 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000782 CHECK_EQ(0, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000783 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000784 CcTest::heap()->CollectGarbage(
785 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000786 CHECK_EQ(1, dispose_count);
Leon Clarkee46be812010-01-19 14:06:41 +0000787}
788
789
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000790class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100791 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000792 // Only used by non-threaded tests, so it can use static fields.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100793 static int dispose_calls;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000794 static int dispose_count;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100795
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000796 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
797 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100798
799 void Dispose() {
800 ++dispose_calls;
801 if (dispose_) delete this;
802 }
803 private:
804 bool dispose_;
805};
806
807
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808int TestOneByteResourceWithDisposeControl::dispose_count = 0;
809int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100810
811
812TEST(ExternalStringWithDisposeHandling) {
813 const char* c_source = "1 + 2 * 3";
814
815 // Use a stack allocated external string resource allocated object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000816 TestOneByteResourceWithDisposeControl::dispose_count = 0;
817 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
818 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100819 {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100820 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000821 v8::HandleScope scope(env->GetIsolate());
822 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
823 Local<Script> script = v8_compile(source);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100824 Local<Value> value = script->Run();
825 CHECK(value->IsNumber());
826 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000827 CcTest::heap()->CollectAllAvailableGarbage();
828 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100829 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830 CcTest::i_isolate()->compilation_cache()->Clear();
831 CcTest::heap()->CollectAllAvailableGarbage();
832 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
833 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100834
835 // Use a heap allocated external string resource allocated object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000836 TestOneByteResourceWithDisposeControl::dispose_count = 0;
837 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
838 TestOneByteResource* res_heap =
839 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100840 {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100841 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 v8::HandleScope scope(env->GetIsolate());
843 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
844 Local<Script> script = v8_compile(source);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100845 Local<Value> value = script->Run();
846 CHECK(value->IsNumber());
847 CHECK_EQ(7, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 CcTest::heap()->CollectAllAvailableGarbage();
849 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100850 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000851 CcTest::i_isolate()->compilation_cache()->Clear();
852 CcTest::heap()->CollectAllAvailableGarbage();
853 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
854 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100855}
856
857
Steve Block3ce2e202009-11-05 08:53:23 +0000858THREADED_TEST(StringConcat) {
859 {
Steve Block3ce2e202009-11-05 08:53:23 +0000860 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 v8::HandleScope scope(env->GetIsolate());
Steve Block3ce2e202009-11-05 08:53:23 +0000862 const char* one_byte_string_1 = "function a_times_t";
863 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
864 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
865 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
866 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
867 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
868 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
869 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100870
871 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000872 Local<String> right =
873 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100874 i::DeleteArray(two_byte_source);
875
Steve Block3ce2e202009-11-05 08:53:23 +0000876 Local<String> source = String::Concat(left, right);
877 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 env->GetIsolate(),
879 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
Steve Block3ce2e202009-11-05 08:53:23 +0000880 source = String::Concat(source, right);
881 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000882 env->GetIsolate(),
Steve Block3ce2e202009-11-05 08:53:23 +0000883 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
884 source = String::Concat(source, right);
885 right = v8_str(one_byte_string_2);
886 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100887
888 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100890 i::DeleteArray(two_byte_source);
891
Steve Block3ce2e202009-11-05 08:53:23 +0000892 source = String::Concat(source, right);
893 right = String::NewExternal(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000894 env->GetIsolate(),
Steve Block3ce2e202009-11-05 08:53:23 +0000895 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
896 source = String::Concat(source, right);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000897 Local<Script> script = v8_compile(source);
Steve Block3ce2e202009-11-05 08:53:23 +0000898 Local<Value> value = script->Run();
899 CHECK(value->IsNumber());
900 CHECK_EQ(68, value->Int32Value());
901 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902 CcTest::i_isolate()->compilation_cache()->Clear();
903 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
904 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +0000905}
906
907
Steve Blocka7e24c12009-10-30 11:49:00 +0000908THREADED_TEST(GlobalProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000910 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 v8::Handle<v8::Object> global = env->Global();
912 global->Set(v8_str("pi"), v8_num(3.1415926));
913 Local<Value> pi = global->Get(v8_str("pi"));
914 CHECK_EQ(3.1415926, pi->NumberValue());
915}
916
917
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918template<typename T>
919static void CheckReturnValue(const T& t, i::Address callback) {
920 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
921 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
922 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
923 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
924 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
925 // Verify reset
926 bool is_runtime = (*o)->IsTheHole();
927 rv.Set(true);
928 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
929 rv.Set(v8::Handle<v8::Object>());
930 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
931 CHECK_EQ(is_runtime, (*o)->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +0000932
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000933 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
934 // If CPU profiler is active check that when API callback is invoked
935 // VMState is set to EXTERNAL.
936 if (isolate->cpu_profiler()->is_profiling()) {
937 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
938 CHECK(isolate->external_callback_scope());
939 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
Steve Blocka7e24c12009-10-30 11:49:00 +0000940 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941}
942
943
944static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
945 i::Address callback) {
946 ApiTestFuzzer::Fuzz();
947 CheckReturnValue(info, callback);
948 info.GetReturnValue().Set(v8_str("bad value"));
949 info.GetReturnValue().Set(v8_num(102));
950}
951
952
953static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
954 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
955}
956
957
958static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
959 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
960}
961
962static void construct_callback(
963 const v8::FunctionCallbackInfo<Value>& info) {
964 ApiTestFuzzer::Fuzz();
965 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
966 info.This()->Set(v8_str("x"), v8_num(1));
967 info.This()->Set(v8_str("y"), v8_num(2));
968 info.GetReturnValue().Set(v8_str("bad value"));
969 info.GetReturnValue().Set(info.This());
970}
971
972
973static void Return239Callback(
974 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
975 ApiTestFuzzer::Fuzz();
976 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
977 info.GetReturnValue().Set(v8_str("bad value"));
978 info.GetReturnValue().Set(v8_num(239));
979}
980
981
982template<typename Handler>
983static void TestFunctionTemplateInitializer(Handler handler,
984 Handler handler_2) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 // Test constructor calls.
986 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987 LocalContext env;
988 v8::Isolate* isolate = env->GetIsolate();
989 v8::HandleScope scope(isolate);
990
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 v8::FunctionTemplate::New(isolate, handler);
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 Local<Function> fun = fun_templ->GetFunction();
994 env->Global()->Set(v8_str("obj"), fun);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000995 Local<Script> script = v8_compile("obj()");
996 for (int i = 0; i < 30; i++) {
997 CHECK_EQ(102, script->Run()->Int32Value());
998 }
999 }
1000 // Use SetCallHandler to initialize a function template, should work like
1001 // the previous one.
1002 {
1003 LocalContext env;
1004 v8::Isolate* isolate = env->GetIsolate();
1005 v8::HandleScope scope(isolate);
1006
1007 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1008 fun_templ->SetCallHandler(handler_2);
1009 Local<Function> fun = fun_templ->GetFunction();
1010 env->Global()->Set(v8_str("obj"), fun);
1011 Local<Script> script = v8_compile("obj()");
1012 for (int i = 0; i < 30; i++) {
1013 CHECK_EQ(102, script->Run()->Int32Value());
1014 }
1015 }
1016}
1017
1018
1019template<typename Constructor, typename Accessor>
1020static void TestFunctionTemplateAccessor(Constructor constructor,
1021 Accessor accessor) {
1022 LocalContext env;
1023 v8::HandleScope scope(env->GetIsolate());
1024
1025 Local<v8::FunctionTemplate> fun_templ =
1026 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1027 fun_templ->SetClassName(v8_str("funky"));
1028 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1029 Local<Function> fun = fun_templ->GetFunction();
1030 env->Global()->Set(v8_str("obj"), fun);
1031 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1032 CHECK_EQ(v8_str("[object funky]"), result);
1033 CompileRun("var obj_instance = new obj();");
1034 Local<Script> script;
1035 script = v8_compile("obj_instance.x");
1036 for (int i = 0; i < 30; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 CHECK_EQ(1, script->Run()->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001038 }
1039 script = v8_compile("obj_instance.m");
1040 for (int i = 0; i < 30; i++) {
1041 CHECK_EQ(239, script->Run()->Int32Value());
1042 }
1043}
Steve Blocka7e24c12009-10-30 11:49:00 +00001044
Ben Murdochf87a2032010-10-22 12:50:53 +01001045
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046THREADED_PROFILED_TEST(FunctionTemplate) {
1047 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1048 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1049}
1050
1051
1052static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1053 ApiTestFuzzer::Fuzz();
1054 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1055 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1056}
1057
1058
1059template<typename Callback>
1060static void TestSimpleCallback(Callback callback) {
1061 LocalContext env;
1062 v8::Isolate* isolate = env->GetIsolate();
1063 v8::HandleScope scope(isolate);
1064
1065 v8::Handle<v8::ObjectTemplate> object_template =
1066 v8::ObjectTemplate::New(isolate);
1067 object_template->Set(isolate, "callback",
1068 v8::FunctionTemplate::New(isolate, callback));
1069 v8::Local<v8::Object> object = object_template->NewInstance();
1070 (*env)->Global()->Set(v8_str("callback_object"), object);
1071 v8::Handle<v8::Script> script;
1072 script = v8_compile("callback_object.callback(17)");
1073 for (int i = 0; i < 30; i++) {
1074 CHECK_EQ(51424, script->Run()->Int32Value());
1075 }
1076 script = v8_compile("callback_object.callback(17, 24)");
1077 for (int i = 0; i < 30; i++) {
1078 CHECK_EQ(51425, script->Run()->Int32Value());
1079 }
1080}
1081
1082
1083THREADED_PROFILED_TEST(SimpleCallback) {
1084 TestSimpleCallback(SimpleCallback);
1085}
1086
1087
1088template<typename T>
1089void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1090
1091// constant return values
1092static int32_t fast_return_value_int32 = 471;
1093static uint32_t fast_return_value_uint32 = 571;
1094static const double kFastReturnValueDouble = 2.7;
1095// variable return values
1096static bool fast_return_value_bool = false;
1097enum ReturnValueOddball {
1098 kNullReturnValue,
1099 kUndefinedReturnValue,
1100 kEmptyStringReturnValue
1101};
1102static ReturnValueOddball fast_return_value_void;
1103static bool fast_return_value_object_is_empty = false;
1104
1105// Helper function to avoid compiler error: insufficient contextual information
1106// to determine type when applying FUNCTION_ADDR to a template function.
1107static i::Address address_of(v8::FunctionCallback callback) {
1108 return FUNCTION_ADDR(callback);
1109}
1110
1111template<>
1112void FastReturnValueCallback<int32_t>(
1113 const v8::FunctionCallbackInfo<v8::Value>& info) {
1114 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1115 info.GetReturnValue().Set(fast_return_value_int32);
1116}
1117
1118template<>
1119void FastReturnValueCallback<uint32_t>(
1120 const v8::FunctionCallbackInfo<v8::Value>& info) {
1121 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1122 info.GetReturnValue().Set(fast_return_value_uint32);
1123}
1124
1125template<>
1126void FastReturnValueCallback<double>(
1127 const v8::FunctionCallbackInfo<v8::Value>& info) {
1128 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1129 info.GetReturnValue().Set(kFastReturnValueDouble);
1130}
1131
1132template<>
1133void FastReturnValueCallback<bool>(
1134 const v8::FunctionCallbackInfo<v8::Value>& info) {
1135 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1136 info.GetReturnValue().Set(fast_return_value_bool);
1137}
1138
1139template<>
1140void FastReturnValueCallback<void>(
1141 const v8::FunctionCallbackInfo<v8::Value>& info) {
1142 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1143 switch (fast_return_value_void) {
1144 case kNullReturnValue:
1145 info.GetReturnValue().SetNull();
1146 break;
1147 case kUndefinedReturnValue:
1148 info.GetReturnValue().SetUndefined();
1149 break;
1150 case kEmptyStringReturnValue:
1151 info.GetReturnValue().SetEmptyString();
1152 break;
1153 }
1154}
1155
1156template<>
1157void FastReturnValueCallback<Object>(
1158 const v8::FunctionCallbackInfo<v8::Value>& info) {
1159 v8::Handle<v8::Object> object;
1160 if (!fast_return_value_object_is_empty) {
1161 object = Object::New(info.GetIsolate());
1162 }
1163 info.GetReturnValue().Set(object);
1164}
1165
1166template<typename T>
1167Handle<Value> TestFastReturnValues() {
1168 LocalContext env;
1169 v8::Isolate* isolate = env->GetIsolate();
1170 v8::EscapableHandleScope scope(isolate);
1171 v8::Handle<v8::ObjectTemplate> object_template =
1172 v8::ObjectTemplate::New(isolate);
1173 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1174 object_template->Set(isolate, "callback",
1175 v8::FunctionTemplate::New(isolate, callback));
1176 v8::Local<v8::Object> object = object_template->NewInstance();
1177 (*env)->Global()->Set(v8_str("callback_object"), object);
1178 return scope.Escape(CompileRun("callback_object.callback()"));
1179}
1180
1181
1182THREADED_PROFILED_TEST(FastReturnValues) {
1183 LocalContext env;
1184 v8::HandleScope scope(CcTest::isolate());
1185 v8::Handle<v8::Value> value;
1186 // check int32_t and uint32_t
1187 int32_t int_values[] = {
1188 0, 234, -723,
1189 i::Smi::kMinValue, i::Smi::kMaxValue
1190 };
1191 for (size_t i = 0; i < arraysize(int_values); i++) {
1192 for (int modifier = -1; modifier <= 1; modifier++) {
1193 int int_value = int_values[i] + modifier;
1194 // check int32_t
1195 fast_return_value_int32 = int_value;
1196 value = TestFastReturnValues<int32_t>();
1197 CHECK(value->IsInt32());
1198 CHECK(fast_return_value_int32 == value->Int32Value());
1199 // check uint32_t
1200 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1201 value = TestFastReturnValues<uint32_t>();
1202 CHECK(value->IsUint32());
1203 CHECK(fast_return_value_uint32 == value->Uint32Value());
1204 }
1205 }
1206 // check double
1207 value = TestFastReturnValues<double>();
1208 CHECK(value->IsNumber());
1209 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1210 // check bool values
1211 for (int i = 0; i < 2; i++) {
1212 fast_return_value_bool = i == 0;
1213 value = TestFastReturnValues<bool>();
1214 CHECK(value->IsBoolean());
1215 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1216 }
1217 // check oddballs
1218 ReturnValueOddball oddballs[] = {
1219 kNullReturnValue,
1220 kUndefinedReturnValue,
1221 kEmptyStringReturnValue
1222 };
1223 for (size_t i = 0; i < arraysize(oddballs); i++) {
1224 fast_return_value_void = oddballs[i];
1225 value = TestFastReturnValues<void>();
1226 switch (fast_return_value_void) {
1227 case kNullReturnValue:
1228 CHECK(value->IsNull());
1229 break;
1230 case kUndefinedReturnValue:
1231 CHECK(value->IsUndefined());
1232 break;
1233 case kEmptyStringReturnValue:
1234 CHECK(value->IsString());
1235 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1236 break;
1237 }
1238 }
1239 // check handles
1240 fast_return_value_object_is_empty = false;
1241 value = TestFastReturnValues<Object>();
1242 CHECK(value->IsObject());
1243 fast_return_value_object_is_empty = true;
1244 value = TestFastReturnValues<Object>();
1245 CHECK(value->IsUndefined());
1246}
1247
1248
1249THREADED_TEST(FunctionTemplateSetLength) {
1250 LocalContext env;
1251 v8::Isolate* isolate = env->GetIsolate();
1252 v8::HandleScope scope(isolate);
1253 {
1254 Local<v8::FunctionTemplate> fun_templ =
1255 v8::FunctionTemplate::New(isolate,
1256 handle_callback,
1257 Handle<v8::Value>(),
1258 Handle<v8::Signature>(),
1259 23);
1260 Local<Function> fun = fun_templ->GetFunction();
1261 env->Global()->Set(v8_str("obj"), fun);
1262 Local<Script> script = v8_compile("obj.length");
1263 CHECK_EQ(23, script->Run()->Int32Value());
1264 }
1265 {
1266 Local<v8::FunctionTemplate> fun_templ =
1267 v8::FunctionTemplate::New(isolate, handle_callback);
1268 fun_templ->SetLength(22);
1269 Local<Function> fun = fun_templ->GetFunction();
1270 env->Global()->Set(v8_str("obj"), fun);
1271 Local<Script> script = v8_compile("obj.length");
1272 CHECK_EQ(22, script->Run()->Int32Value());
1273 }
1274 {
1275 // Without setting length it defaults to 0.
1276 Local<v8::FunctionTemplate> fun_templ =
1277 v8::FunctionTemplate::New(isolate, handle_callback);
1278 Local<Function> fun = fun_templ->GetFunction();
1279 env->Global()->Set(v8_str("obj"), fun);
1280 Local<Script> script = v8_compile("obj.length");
1281 CHECK_EQ(0, script->Run()->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001282 }
1283}
1284
1285
Ben Murdochb8e0da22011-05-16 14:20:40 +01001286static void* expected_ptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1288 void* ptr = v8::External::Cast(*args.Data())->Value();
Ben Murdochb8e0da22011-05-16 14:20:40 +01001289 CHECK_EQ(expected_ptr, ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001290 args.GetReturnValue().Set(true);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001291}
1292
1293
1294static void TestExternalPointerWrapping() {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001295 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 v8::Isolate* isolate = env->GetIsolate();
1297 v8::HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001298
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 v8::Handle<v8::Value> data =
1300 v8::External::New(isolate, expected_ptr);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001301
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001302 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001303 obj->Set(v8_str("func"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001304 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001305 env->Global()->Set(v8_str("obj"), obj);
1306
1307 CHECK(CompileRun(
1308 "function foo() {\n"
1309 " for (var i = 0; i < 13; i++) obj.func();\n"
1310 "}\n"
1311 "foo(), true")->BooleanValue());
1312}
1313
1314
1315THREADED_TEST(ExternalWrap) {
1316 // Check heap allocated object.
1317 int* ptr = new int;
1318 expected_ptr = ptr;
1319 TestExternalPointerWrapping();
1320 delete ptr;
1321
1322 // Check stack allocated object.
1323 int foo;
1324 expected_ptr = &foo;
1325 TestExternalPointerWrapping();
1326
1327 // Check not aligned addresses.
1328 const int n = 100;
1329 char* s = new char[n];
1330 for (int i = 0; i < n; i++) {
1331 expected_ptr = s + i;
1332 TestExternalPointerWrapping();
1333 }
1334
1335 delete[] s;
1336
1337 // Check several invalid addresses.
1338 expected_ptr = reinterpret_cast<void*>(1);
1339 TestExternalPointerWrapping();
1340
1341 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1342 TestExternalPointerWrapping();
1343
1344 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1345 TestExternalPointerWrapping();
1346
1347#if defined(V8_HOST_ARCH_X64)
Steve Block1e0659c2011-05-24 12:43:12 +01001348 // Check a value with a leading 1 bit in x64 Smi encoding.
1349 expected_ptr = reinterpret_cast<void*>(0x400000000);
1350 TestExternalPointerWrapping();
1351
Ben Murdochb8e0da22011-05-16 14:20:40 +01001352 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1353 TestExternalPointerWrapping();
1354
1355 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1356 TestExternalPointerWrapping();
1357#endif
1358}
1359
1360
Steve Blocka7e24c12009-10-30 11:49:00 +00001361THREADED_TEST(FindInstanceInPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001362 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001363 v8::Isolate* isolate = env->GetIsolate();
1364 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001365
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001366 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1367 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1368 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 derived->Inherit(base);
1370
1371 Local<v8::Function> base_function = base->GetFunction();
1372 Local<v8::Function> derived_function = derived->GetFunction();
1373 Local<v8::Function> other_function = other->GetFunction();
1374
1375 Local<v8::Object> base_instance = base_function->NewInstance();
1376 Local<v8::Object> derived_instance = derived_function->NewInstance();
1377 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1378 Local<v8::Object> other_instance = other_function->NewInstance();
1379 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1380 other_instance->Set(v8_str("__proto__"), derived_instance2);
1381
1382 // base_instance is only an instance of base.
1383 CHECK_EQ(base_instance,
1384 base_instance->FindInstanceInPrototypeChain(base));
1385 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1386 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1387
1388 // derived_instance is an instance of base and derived.
1389 CHECK_EQ(derived_instance,
1390 derived_instance->FindInstanceInPrototypeChain(base));
1391 CHECK_EQ(derived_instance,
1392 derived_instance->FindInstanceInPrototypeChain(derived));
1393 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1394
1395 // other_instance is an instance of other and its immediate
1396 // prototype derived_instance2 is an instance of base and derived.
1397 // Note, derived_instance is an instance of base and derived too,
1398 // but it comes after derived_instance2 in the prototype chain of
1399 // other_instance.
1400 CHECK_EQ(derived_instance2,
1401 other_instance->FindInstanceInPrototypeChain(base));
1402 CHECK_EQ(derived_instance2,
1403 other_instance->FindInstanceInPrototypeChain(derived));
1404 CHECK_EQ(other_instance,
1405 other_instance->FindInstanceInPrototypeChain(other));
1406}
1407
1408
Steve Block3ce2e202009-11-05 08:53:23 +00001409THREADED_TEST(TinyInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001410 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411 v8::Isolate* isolate = env->GetIsolate();
1412 v8::HandleScope scope(isolate);
1413
Steve Block3ce2e202009-11-05 08:53:23 +00001414 int32_t value = 239;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001415 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1416 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1417
1418 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001419 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1420}
1421
1422
1423THREADED_TEST(BigSmiInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001424 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001425 v8::HandleScope scope(env->GetIsolate());
1426 v8::Isolate* isolate = CcTest::isolate();
1427
Steve Block3ce2e202009-11-05 08:53:23 +00001428 int32_t value = i::Smi::kMaxValue;
1429 // We cannot add one to a Smi::kMaxValue without wrapping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 if (i::SmiValuesAre31Bits()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001431 CHECK(i::Smi::IsValid(value));
1432 CHECK(!i::Smi::IsValid(value + 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001433
1434 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1435 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1436
1437 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001438 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1439 }
1440}
1441
1442
1443THREADED_TEST(BigInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001444 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001445 v8::HandleScope scope(env->GetIsolate());
1446 v8::Isolate* isolate = CcTest::isolate();
1447
Steve Block3ce2e202009-11-05 08:53:23 +00001448 // We cannot add one to a Smi::kMaxValue without wrapping.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449 if (i::SmiValuesAre31Bits()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001450 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1451 // The code will not be run in that case, due to the "if" guard.
1452 int32_t value =
1453 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1454 CHECK(value > i::Smi::kMaxValue);
1455 CHECK(!i::Smi::IsValid(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456
1457 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459
1460 value_obj = v8::Integer::New(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462 }
1463}
1464
1465
1466THREADED_TEST(TinyUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001467 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001468 v8::HandleScope scope(env->GetIsolate());
1469 v8::Isolate* isolate = CcTest::isolate();
1470
Steve Block3ce2e202009-11-05 08:53:23 +00001471 uint32_t value = 239;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472
1473 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1474 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1475
1476 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001477 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1478}
1479
1480
1481THREADED_TEST(BigUnsignedSmiInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001482 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483 v8::HandleScope scope(env->GetIsolate());
1484 v8::Isolate* isolate = CcTest::isolate();
1485
Steve Block3ce2e202009-11-05 08:53:23 +00001486 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1487 CHECK(i::Smi::IsValid(value));
1488 CHECK(!i::Smi::IsValid(value + 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489
1490 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1491 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1492
1493 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001494 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1495}
1496
1497
1498THREADED_TEST(BigUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001499 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001500 v8::HandleScope scope(env->GetIsolate());
1501 v8::Isolate* isolate = CcTest::isolate();
1502
Steve Block3ce2e202009-11-05 08:53:23 +00001503 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1504 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1505 CHECK(!i::Smi::IsValid(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001506
1507 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509
1510 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512}
1513
1514
1515THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
Steve Block3ce2e202009-11-05 08:53:23 +00001516 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 v8::HandleScope scope(env->GetIsolate());
1518 v8::Isolate* isolate = CcTest::isolate();
1519
Steve Block3ce2e202009-11-05 08:53:23 +00001520 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1521 uint32_t value = INT32_MAX_AS_UINT + 1;
1522 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523
1524 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1525 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1526
1527 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
Steve Block3ce2e202009-11-05 08:53:23 +00001528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529}
1530
1531
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001532THREADED_TEST(IsNativeError) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001533 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001535 v8::Handle<Value> syntax_error = CompileRun(
1536 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1537 CHECK(syntax_error->IsNativeError());
1538 v8::Handle<Value> not_error = CompileRun("{a:42}");
1539 CHECK(!not_error->IsNativeError());
1540 v8::Handle<Value> not_object = CompileRun("42");
1541 CHECK(!not_object->IsNativeError());
1542}
1543
1544
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001545THREADED_TEST(ArgumentsObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001546 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001547 v8::HandleScope scope(env->GetIsolate());
1548 v8::Handle<Value> arguments_object =
1549 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1550 CHECK(arguments_object->IsArgumentsObject());
1551 v8::Handle<Value> array = CompileRun("[1,2,3]");
1552 CHECK(!array->IsArgumentsObject());
1553 v8::Handle<Value> object = CompileRun("{a:42}");
1554 CHECK(!object->IsArgumentsObject());
1555}
1556
1557
1558THREADED_TEST(IsMapOrSet) {
1559 LocalContext env;
1560 v8::HandleScope scope(env->GetIsolate());
1561 v8::Handle<Value> map = CompileRun("new Map()");
1562 v8::Handle<Value> set = CompileRun("new Set()");
1563 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1564 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1565 CHECK(map->IsMap());
1566 CHECK(set->IsSet());
1567 CHECK(weak_map->IsWeakMap());
1568 CHECK(weak_set->IsWeakSet());
1569
1570 CHECK(!map->IsSet());
1571 CHECK(!map->IsWeakMap());
1572 CHECK(!map->IsWeakSet());
1573
1574 CHECK(!set->IsMap());
1575 CHECK(!set->IsWeakMap());
1576 CHECK(!set->IsWeakSet());
1577
1578 CHECK(!weak_map->IsMap());
1579 CHECK(!weak_map->IsSet());
1580 CHECK(!weak_map->IsWeakSet());
1581
1582 CHECK(!weak_set->IsMap());
1583 CHECK(!weak_set->IsSet());
1584 CHECK(!weak_set->IsWeakMap());
1585
1586 v8::Handle<Value> object = CompileRun("{a:42}");
1587 CHECK(!object->IsMap());
1588 CHECK(!object->IsSet());
1589 CHECK(!object->IsWeakMap());
1590 CHECK(!object->IsWeakSet());
1591}
1592
1593
1594THREADED_TEST(StringObject) {
1595 LocalContext env;
1596 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001597 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598 CHECK(boxed_string->IsStringObject());
1599 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600 CHECK(!unboxed_string->IsStringObject());
1601 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602 CHECK(!boxed_not_string->IsStringObject());
1603 v8::Handle<Value> not_object = CompileRun("0");
1604 CHECK(!not_object->IsStringObject());
1605 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 Local<v8::String> the_string = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001608 CHECK(!the_string.IsEmpty());
1609 ExpectObject("\"test\"", the_string);
1610 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611 CHECK(new_boxed_string->IsStringObject());
1612 as_boxed = new_boxed_string.As<v8::StringObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 the_string = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001614 CHECK(!the_string.IsEmpty());
1615 ExpectObject("\"test\"", the_string);
1616}
1617
1618
1619THREADED_TEST(NumberObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001620 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001621 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001622 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623 CHECK(boxed_number->IsNumberObject());
1624 v8::Handle<Value> unboxed_number = CompileRun("42");
1625 CHECK(!unboxed_number->IsNumberObject());
1626 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627 CHECK(!boxed_not_number->IsNumberObject());
1628 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001630 double the_number = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001631 CHECK_EQ(42.0, the_number);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001632 v8::Handle<v8::Value> new_boxed_number =
1633 v8::NumberObject::New(env->GetIsolate(), 43);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001634 CHECK(new_boxed_number->IsNumberObject());
1635 as_boxed = new_boxed_number.As<v8::NumberObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001636 the_number = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001637 CHECK_EQ(43.0, the_number);
1638}
1639
1640
1641THREADED_TEST(BooleanObject) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001642 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001643 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001644 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645 CHECK(boxed_boolean->IsBooleanObject());
1646 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647 CHECK(!unboxed_boolean->IsBooleanObject());
1648 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649 CHECK(!boxed_not_boolean->IsBooleanObject());
1650 v8::Handle<v8::BooleanObject> as_boxed =
1651 boxed_boolean.As<v8::BooleanObject>();
1652 CHECK(!as_boxed.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 bool the_boolean = as_boxed->ValueOf();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001654 CHECK_EQ(true, the_boolean);
1655 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657 CHECK(boxed_true->IsBooleanObject());
1658 CHECK(boxed_false->IsBooleanObject());
1659 as_boxed = boxed_true.As<v8::BooleanObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660 CHECK_EQ(true, as_boxed->ValueOf());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001661 as_boxed = boxed_false.As<v8::BooleanObject>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001662 CHECK_EQ(false, as_boxed->ValueOf());
1663}
1664
1665
1666THREADED_TEST(PrimitiveAndWrappedBooleans) {
1667 LocalContext env;
1668 v8::HandleScope scope(env->GetIsolate());
1669
1670 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671 CHECK(primitive_false->IsBoolean());
1672 CHECK(!primitive_false->IsBooleanObject());
1673 CHECK(!primitive_false->BooleanValue());
1674 CHECK(!primitive_false->IsTrue());
1675 CHECK(primitive_false->IsFalse());
1676
1677 Local<Value> false_value = BooleanObject::New(false);
1678 CHECK(!false_value->IsBoolean());
1679 CHECK(false_value->IsBooleanObject());
1680 CHECK(false_value->BooleanValue());
1681 CHECK(!false_value->IsTrue());
1682 CHECK(!false_value->IsFalse());
1683
1684 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685 CHECK(!false_boolean_object->IsBoolean());
1686 CHECK(false_boolean_object->IsBooleanObject());
1687 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688 // CHECK(false_boolean_object->BooleanValue());
1689 CHECK(!false_boolean_object->ValueOf());
1690 CHECK(!false_boolean_object->IsTrue());
1691 CHECK(!false_boolean_object->IsFalse());
1692
1693 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694 CHECK(primitive_true->IsBoolean());
1695 CHECK(!primitive_true->IsBooleanObject());
1696 CHECK(primitive_true->BooleanValue());
1697 CHECK(primitive_true->IsTrue());
1698 CHECK(!primitive_true->IsFalse());
1699
1700 Local<Value> true_value = BooleanObject::New(true);
1701 CHECK(!true_value->IsBoolean());
1702 CHECK(true_value->IsBooleanObject());
1703 CHECK(true_value->BooleanValue());
1704 CHECK(!true_value->IsTrue());
1705 CHECK(!true_value->IsFalse());
1706
1707 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708 CHECK(!true_boolean_object->IsBoolean());
1709 CHECK(true_boolean_object->IsBooleanObject());
1710 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711 // CHECK(true_boolean_object->BooleanValue());
1712 CHECK(true_boolean_object->ValueOf());
1713 CHECK(!true_boolean_object->IsTrue());
1714 CHECK(!true_boolean_object->IsFalse());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001715}
1716
1717
Steve Blocka7e24c12009-10-30 11:49:00 +00001718THREADED_TEST(Number) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 double PI = 3.1415926;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001722 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 CHECK_EQ(PI, pi_obj->NumberValue());
1724}
1725
1726
1727THREADED_TEST(ToNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001728 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 v8::Isolate* isolate = CcTest::isolate();
1730 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 Local<String> str = v8_str("3.1415926");
1732 CHECK_EQ(3.1415926, str->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001733 v8::Handle<v8::Boolean> t = v8::True(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001734 CHECK_EQ(1.0, t->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 v8::Handle<v8::Boolean> f = v8::False(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001736 CHECK_EQ(0.0, f->NumberValue());
1737}
1738
1739
1740THREADED_TEST(Date) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001742 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 double PI = 3.1415926;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001744 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
Ben Murdoch257744e2011-11-30 15:57:28 +00001745 CHECK_EQ(3.0, date->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001746 date.As<v8::Date>()->Set(v8_str("property"),
1747 v8::Integer::New(env->GetIsolate(), 42));
Ben Murdoch257744e2011-11-30 15:57:28 +00001748 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001749}
1750
1751
1752THREADED_TEST(Boolean) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001753 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001754 v8::Isolate* isolate = env->GetIsolate();
1755 v8::HandleScope scope(isolate);
1756 v8::Handle<v8::Boolean> t = v8::True(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 CHECK(t->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001758 v8::Handle<v8::Boolean> f = v8::False(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001759 CHECK(!f->Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001760 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001761 CHECK(!u->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762 v8::Handle<v8::Primitive> n = v8::Null(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001763 CHECK(!n->BooleanValue());
1764 v8::Handle<String> str1 = v8_str("");
1765 CHECK(!str1->BooleanValue());
1766 v8::Handle<String> str2 = v8_str("x");
1767 CHECK(str2->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001768 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773}
1774
1775
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001776static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001777 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001778 args.GetReturnValue().Set(v8_num(13.4));
Steve Blocka7e24c12009-10-30 11:49:00 +00001779}
1780
1781
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001782static void GetM(Local<String> name,
1783 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001784 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001785 info.GetReturnValue().Set(v8_num(876));
Steve Blocka7e24c12009-10-30 11:49:00 +00001786}
1787
1788
1789THREADED_TEST(GlobalPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790 v8::Isolate* isolate = CcTest::isolate();
1791 v8::HandleScope scope(isolate);
1792 v8::Handle<v8::FunctionTemplate> func_templ =
1793 v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001794 func_templ->PrototypeTemplate()->Set(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001795 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 templ->Set(isolate, "x", v8_num(200));
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 templ->SetAccessor(v8_str("m"), GetM);
1799 LocalContext env(0, templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001800 v8::Handle<Script> script(v8_compile("dummy()"));
1801 v8::Handle<Value> result(script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 CHECK_EQ(13.4, result->NumberValue());
1803 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1805}
1806
1807
Steve Blocka7e24c12009-10-30 11:49:00 +00001808THREADED_TEST(ObjectTemplate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001809 v8::Isolate* isolate = CcTest::isolate();
1810 v8::HandleScope scope(isolate);
1811 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812 templ1->Set(isolate, "x", v8_num(10));
1813 templ1->Set(isolate, "y", v8_num(13));
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 LocalContext env;
1815 Local<v8::Object> instance1 = templ1->NewInstance();
1816 env->Global()->Set(v8_str("p"), instance1);
1817 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001819 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
Steve Blocka7e24c12009-10-30 11:49:00 +00001821 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001822 templ2->Set(isolate, "a", v8_num(12));
1823 templ2->Set(isolate, "b", templ1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001824 Local<v8::Object> instance2 = templ2->NewInstance();
1825 env->Global()->Set(v8_str("q"), instance2);
1826 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1830}
1831
1832
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001834 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 args.GetReturnValue().Set(v8_num(17.2));
Steve Blocka7e24c12009-10-30 11:49:00 +00001836}
1837
1838
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839static void GetKnurd(Local<String> property,
1840 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001842 info.GetReturnValue().Set(v8_num(15.2));
Steve Blocka7e24c12009-10-30 11:49:00 +00001843}
1844
1845
1846THREADED_TEST(DescriptorInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001847 v8::Isolate* isolate = CcTest::isolate();
1848 v8::HandleScope scope(isolate);
1849 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850 super->PrototypeTemplate()->Set(isolate, "flabby",
1851 v8::FunctionTemplate::New(isolate,
1852 GetFlabby));
1853 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
Steve Blocka7e24c12009-10-30 11:49:00 +00001854
1855 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 base1->Inherit(super);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001859 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001860
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001861 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001862 base2->Inherit(super);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001864
1865 LocalContext env;
1866
1867 env->Global()->Set(v8_str("s"), super->GetFunction());
1868 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1870
1871 // Checks right __proto__ chain.
1872 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1874
1875 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1876
1877 // Instance accessor should not be visible on function object or its prototype
1878 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1881
1882 env->Global()->Set(v8_str("obj"),
1883 base1->GetFunction()->NewInstance());
1884 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1889
1890 env->Global()->Set(v8_str("obj2"),
1891 base2->GetFunction()->NewInstance());
1892 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1897
1898 // base1 and base2 cannot cross reference to each's prototype
1899 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1901}
1902
1903
1904int echo_named_call_count;
1905
1906
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907static void EchoNamedProperty(Local<String> name,
1908 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001909 ApiTestFuzzer::Fuzz();
1910 CHECK_EQ(v8_str("data"), info.Data());
1911 echo_named_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001912 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001913}
1914
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001915
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001916// Helper functions for Interceptor/Accessor interaction tests
1917
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918void SimpleAccessorGetter(Local<String> name,
1919 const v8::PropertyCallbackInfo<v8::Value>& info) {
1920 Handle<Object> self = Handle<Object>::Cast(info.This());
1921 info.GetReturnValue().Set(
1922 self->Get(String::Concat(v8_str("accessor_"), name)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001923}
1924
1925void SimpleAccessorSetter(Local<String> name, Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 const v8::PropertyCallbackInfo<void>& info) {
1927 Handle<Object> self = Handle<Object>::Cast(info.This());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001928 self->Set(String::Concat(v8_str("accessor_"), name), value);
1929}
1930
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001931void SymbolAccessorGetter(Local<Name> name,
1932 const v8::PropertyCallbackInfo<v8::Value>& info) {
1933 CHECK(name->IsSymbol());
1934 Local<Symbol> sym = Local<Symbol>::Cast(name);
1935 if (sym->Name()->IsUndefined())
1936 return;
1937 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001938}
1939
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001940void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1941 const v8::PropertyCallbackInfo<void>& info) {
1942 CHECK(name->IsSymbol());
1943 Local<Symbol> sym = Local<Symbol>::Cast(name);
1944 if (sym->Name()->IsUndefined())
1945 return;
1946 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001947}
1948
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001949void EmptyInterceptorGetter(Local<String> name,
1950 const v8::PropertyCallbackInfo<v8::Value>& info) {
1951}
1952
1953void EmptyInterceptorSetter(Local<String> name,
1954 Local<Value> value,
1955 const v8::PropertyCallbackInfo<v8::Value>& info) {
1956}
1957
1958void InterceptorGetter(Local<String> name,
1959 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001960 // Intercept names that start with 'interceptor_'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 String::Utf8Value utf8(name);
1962 char* name_str = *utf8;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001963 char prefix[] = "interceptor_";
1964 int i;
1965 for (i = 0; name_str[i] && prefix[i]; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001966 if (name_str[i] != prefix[i]) return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001967 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968 Handle<Object> self = Handle<Object>::Cast(info.This());
1969 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001970}
1971
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001972void InterceptorSetter(Local<String> name,
1973 Local<Value> value,
1974 const v8::PropertyCallbackInfo<v8::Value>& info) {
1975 // Intercept accesses that set certain integer values, for which the name does
1976 // not start with 'accessor_'.
1977 String::Utf8Value utf8(name);
1978 char* name_str = *utf8;
1979 char prefix[] = "accessor_";
1980 int i;
1981 for (i = 0; name_str[i] && prefix[i]; ++i) {
1982 if (name_str[i] != prefix[i]) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001983 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001984 if (!prefix[i]) return;
1985
1986 if (value->IsInt32() && value->Int32Value() < 10000) {
1987 Handle<Object> self = Handle<Object>::Cast(info.This());
1988 self->SetHiddenValue(name, value);
1989 info.GetReturnValue().Set(value);
1990 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001991}
1992
1993void AddAccessor(Handle<FunctionTemplate> templ,
1994 Handle<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995 v8::AccessorGetterCallback getter,
1996 v8::AccessorSetterCallback setter) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001997 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1998}
1999
2000void AddInterceptor(Handle<FunctionTemplate> templ,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002001 v8::NamedPropertyGetterCallback getter,
2002 v8::NamedPropertySetterCallback setter) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002003 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2004}
2005
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002006
2007void AddAccessor(Handle<FunctionTemplate> templ,
2008 Handle<Name> name,
2009 v8::AccessorNameGetterCallback getter,
2010 v8::AccessorNameSetterCallback setter) {
2011 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2012}
2013
2014
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002015THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002016 v8::HandleScope scope(CcTest::isolate());
2017 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2018 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002019 child->Inherit(parent);
2020 AddAccessor(parent, v8_str("age"),
2021 SimpleAccessorGetter, SimpleAccessorSetter);
2022 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2023 LocalContext env;
2024 env->Global()->Set(v8_str("Child"), child->GetFunction());
2025 CompileRun("var child = new Child;"
2026 "child.age = 10;");
2027 ExpectBoolean("child.hasOwnProperty('age')", false);
2028 ExpectInt32("child.age", 10);
2029 ExpectInt32("child.accessor_age", 10);
2030}
2031
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002032
2033THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2034 v8::Isolate* isolate = CcTest::isolate();
2035 v8::HandleScope scope(isolate);
2036 LocalContext env;
2037 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2038 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2039 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2040 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2041 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2042 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2043 // But we should still have an ExecutableAccessorInfo.
2044 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2045 i::LookupResult lookup(i_isolate);
2046 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2047 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2048 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2049 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2050}
2051
2052
2053THREADED_TEST(EmptyInterceptorBreakTransitions) {
2054 v8::HandleScope scope(CcTest::isolate());
2055 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2056 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2057 LocalContext env;
2058 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2059 CompileRun("var o1 = new Constructor;"
2060 "o1.a = 1;" // Ensure a and x share the descriptor array.
2061 "Object.defineProperty(o1, 'x', {value: 10});");
2062 CompileRun("var o2 = new Constructor;"
2063 "o2.a = 1;"
2064 "Object.defineProperty(o2, 'x', {value: 10});");
2065}
2066
2067
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002068THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002069 v8::Isolate* isolate = CcTest::isolate();
2070 v8::HandleScope scope(isolate);
2071 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2072 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002073 child->Inherit(parent);
2074 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2075 LocalContext env;
2076 env->Global()->Set(v8_str("Child"), child->GetFunction());
2077 CompileRun("var child = new Child;"
2078 "var parent = child.__proto__;"
2079 "Object.defineProperty(parent, 'age', "
2080 " {get: function(){ return this.accessor_age; }, "
2081 " set: function(v){ this.accessor_age = v; }, "
2082 " enumerable: true, configurable: true});"
2083 "child.age = 10;");
2084 ExpectBoolean("child.hasOwnProperty('age')", false);
2085 ExpectInt32("child.age", 10);
2086 ExpectInt32("child.accessor_age", 10);
2087}
2088
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002089
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002090THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002091 v8::Isolate* isolate = CcTest::isolate();
2092 v8::HandleScope scope(isolate);
2093 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2094 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002095 child->Inherit(parent);
2096 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2097 LocalContext env;
2098 env->Global()->Set(v8_str("Child"), child->GetFunction());
2099 CompileRun("var child = new Child;"
2100 "var parent = child.__proto__;"
2101 "parent.name = 'Alice';");
2102 ExpectBoolean("child.hasOwnProperty('name')", false);
2103 ExpectString("child.name", "Alice");
2104 CompileRun("child.name = 'Bob';");
2105 ExpectString("child.name", "Bob");
2106 ExpectBoolean("child.hasOwnProperty('name')", true);
2107 ExpectString("parent.name", "Alice");
2108}
2109
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002110
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002111THREADED_TEST(SwitchFromInterceptorToAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002112 v8::HandleScope scope(CcTest::isolate());
2113 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002114 AddAccessor(templ, v8_str("age"),
2115 SimpleAccessorGetter, SimpleAccessorSetter);
2116 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2117 LocalContext env;
2118 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2119 CompileRun("var obj = new Obj;"
2120 "function setAge(i){ obj.age = i; };"
2121 "for(var i = 0; i <= 10000; i++) setAge(i);");
2122 // All i < 10000 go to the interceptor.
2123 ExpectInt32("obj.interceptor_age", 9999);
2124 // The last i goes to the accessor.
2125 ExpectInt32("obj.accessor_age", 10000);
2126}
2127
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002128
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002129THREADED_TEST(SwitchFromAccessorToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002130 v8::HandleScope scope(CcTest::isolate());
2131 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002132 AddAccessor(templ, v8_str("age"),
2133 SimpleAccessorGetter, SimpleAccessorSetter);
2134 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2135 LocalContext env;
2136 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2137 CompileRun("var obj = new Obj;"
2138 "function setAge(i){ obj.age = i; };"
2139 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2140 // All i >= 10000 go to the accessor.
2141 ExpectInt32("obj.accessor_age", 10000);
2142 // The last i goes to the interceptor.
2143 ExpectInt32("obj.interceptor_age", 9999);
2144}
2145
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002146
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002147THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002148 v8::HandleScope scope(CcTest::isolate());
2149 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2150 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002151 child->Inherit(parent);
2152 AddAccessor(parent, v8_str("age"),
2153 SimpleAccessorGetter, SimpleAccessorSetter);
2154 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2155 LocalContext env;
2156 env->Global()->Set(v8_str("Child"), child->GetFunction());
2157 CompileRun("var child = new Child;"
2158 "function setAge(i){ child.age = i; };"
2159 "for(var i = 0; i <= 10000; i++) setAge(i);");
2160 // All i < 10000 go to the interceptor.
2161 ExpectInt32("child.interceptor_age", 9999);
2162 // The last i goes to the accessor.
2163 ExpectInt32("child.accessor_age", 10000);
2164}
2165
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002166
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002167THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002168 v8::HandleScope scope(CcTest::isolate());
2169 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2170 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002171 child->Inherit(parent);
2172 AddAccessor(parent, v8_str("age"),
2173 SimpleAccessorGetter, SimpleAccessorSetter);
2174 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2175 LocalContext env;
2176 env->Global()->Set(v8_str("Child"), child->GetFunction());
2177 CompileRun("var child = new Child;"
2178 "function setAge(i){ child.age = i; };"
2179 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2180 // All i >= 10000 go to the accessor.
2181 ExpectInt32("child.accessor_age", 10000);
2182 // The last i goes to the interceptor.
2183 ExpectInt32("child.interceptor_age", 9999);
2184}
2185
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002186
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002187THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002188 v8::HandleScope scope(CcTest::isolate());
2189 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002190 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2191 LocalContext env;
2192 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2193 CompileRun("var obj = new Obj;"
2194 "function setter(i) { this.accessor_age = i; };"
2195 "function getter() { return this.accessor_age; };"
2196 "function setAge(i) { obj.age = i; };"
2197 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2198 "for(var i = 0; i <= 10000; i++) setAge(i);");
2199 // All i < 10000 go to the interceptor.
2200 ExpectInt32("obj.interceptor_age", 9999);
2201 // The last i goes to the JavaScript accessor.
2202 ExpectInt32("obj.accessor_age", 10000);
2203 // The installed JavaScript getter is still intact.
2204 // This last part is a regression test for issue 1651 and relies on the fact
2205 // that both interceptor and accessor are being installed on the same object.
2206 ExpectInt32("obj.age", 10000);
2207 ExpectBoolean("obj.hasOwnProperty('age')", true);
2208 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2209}
2210
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002211
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002212THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002213 v8::HandleScope scope(CcTest::isolate());
2214 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002215 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2216 LocalContext env;
2217 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2218 CompileRun("var obj = new Obj;"
2219 "function setter(i) { this.accessor_age = i; };"
2220 "function getter() { return this.accessor_age; };"
2221 "function setAge(i) { obj.age = i; };"
2222 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2223 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2224 // All i >= 10000 go to the accessor.
2225 ExpectInt32("obj.accessor_age", 10000);
2226 // The last i goes to the interceptor.
2227 ExpectInt32("obj.interceptor_age", 9999);
2228 // The installed JavaScript getter is still intact.
2229 // This last part is a regression test for issue 1651 and relies on the fact
2230 // that both interceptor and accessor are being installed on the same object.
2231 ExpectInt32("obj.age", 10000);
2232 ExpectBoolean("obj.hasOwnProperty('age')", true);
2233 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2234}
2235
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002236
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002237THREADED_TEST(SwitchFromInterceptorToProperty) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238 v8::HandleScope scope(CcTest::isolate());
2239 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2240 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002241 child->Inherit(parent);
2242 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2243 LocalContext env;
2244 env->Global()->Set(v8_str("Child"), child->GetFunction());
2245 CompileRun("var child = new Child;"
2246 "function setAge(i){ child.age = i; };"
2247 "for(var i = 0; i <= 10000; i++) setAge(i);");
2248 // All i < 10000 go to the interceptor.
2249 ExpectInt32("child.interceptor_age", 9999);
2250 // The last i goes to child's own property.
2251 ExpectInt32("child.age", 10000);
2252}
2253
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002255THREADED_TEST(SwitchFromPropertyToInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 v8::HandleScope scope(CcTest::isolate());
2257 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2258 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002259 child->Inherit(parent);
2260 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2261 LocalContext env;
2262 env->Global()->Set(v8_str("Child"), child->GetFunction());
2263 CompileRun("var child = new Child;"
2264 "function setAge(i){ child.age = i; };"
2265 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2266 // All i >= 10000 go to child's own property.
2267 ExpectInt32("child.age", 10000);
2268 // The last i goes to the interceptor.
2269 ExpectInt32("child.interceptor_age", 9999);
2270}
Steve Blocka7e24c12009-10-30 11:49:00 +00002271
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002272
Steve Blocka7e24c12009-10-30 11:49:00 +00002273THREADED_TEST(NamedPropertyHandlerGetter) {
2274 echo_named_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002275 v8::HandleScope scope(CcTest::isolate());
2276 v8::Handle<v8::FunctionTemplate> templ =
2277 v8::FunctionTemplate::New(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002278 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2279 0, 0, 0, 0,
2280 v8_str("data"));
2281 LocalContext env;
2282 env->Global()->Set(v8_str("obj"),
2283 templ->GetFunction()->NewInstance());
2284 CHECK_EQ(echo_named_call_count, 0);
2285 v8_compile("obj.x")->Run();
2286 CHECK_EQ(echo_named_call_count, 1);
2287 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2288 v8::Handle<Value> str = CompileRun(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002289 String::Utf8Value value(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00002290 CHECK_EQ(*value, "oddlepoddle");
2291 // Check default behavior
2292 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2293 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2294 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2295}
2296
2297
2298int echo_indexed_call_count = 0;
2299
2300
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002301static void EchoIndexedProperty(
2302 uint32_t index,
2303 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002304 ApiTestFuzzer::Fuzz();
2305 CHECK_EQ(v8_num(637), info.Data());
2306 echo_indexed_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002307 info.GetReturnValue().Set(v8_num(index));
Steve Blocka7e24c12009-10-30 11:49:00 +00002308}
2309
2310
2311THREADED_TEST(IndexedPropertyHandlerGetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002312 v8::Isolate* isolate = CcTest::isolate();
2313 v8::HandleScope scope(isolate);
2314 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2316 0, 0, 0, 0,
2317 v8_num(637));
2318 LocalContext env;
2319 env->Global()->Set(v8_str("obj"),
2320 templ->GetFunction()->NewInstance());
2321 Local<Script> script = v8_compile("obj[900]");
2322 CHECK_EQ(script->Run()->Int32Value(), 900);
2323}
2324
2325
2326v8::Handle<v8::Object> bottom;
2327
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002328static void CheckThisIndexedPropertyHandler(
Steve Blocka7e24c12009-10-30 11:49:00 +00002329 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002330 const v8::PropertyCallbackInfo<v8::Value>& info) {
2331 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00002332 ApiTestFuzzer::Fuzz();
2333 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002334}
2335
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002336static void CheckThisNamedPropertyHandler(
Steve Blocka7e24c12009-10-30 11:49:00 +00002337 Local<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002338 const v8::PropertyCallbackInfo<v8::Value>& info) {
2339 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00002340 ApiTestFuzzer::Fuzz();
2341 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002342}
2343
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002344void CheckThisIndexedPropertySetter(
Steve Blocka7e24c12009-10-30 11:49:00 +00002345 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002346 Local<Value> value,
2347 const v8::PropertyCallbackInfo<v8::Value>& info) {
2348 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002349 ApiTestFuzzer::Fuzz();
2350 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002351}
2352
2353
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002354void CheckThisNamedPropertySetter(
Steve Blocka7e24c12009-10-30 11:49:00 +00002355 Local<String> property,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002356 Local<Value> value,
2357 const v8::PropertyCallbackInfo<v8::Value>& info) {
2358 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002359 ApiTestFuzzer::Fuzz();
2360 CHECK(info.This()->Equals(bottom));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002361}
2362
2363void CheckThisIndexedPropertyQuery(
2364 uint32_t index,
2365 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2366 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2367 ApiTestFuzzer::Fuzz();
2368 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002369}
2370
2371
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002372void CheckThisNamedPropertyQuery(
2373 Local<String> property,
2374 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2375 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
Steve Blocka7e24c12009-10-30 11:49:00 +00002376 ApiTestFuzzer::Fuzz();
2377 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002378}
2379
2380
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002381void CheckThisIndexedPropertyDeleter(
2382 uint32_t index,
2383 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2384 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
Steve Blocka7e24c12009-10-30 11:49:00 +00002385 ApiTestFuzzer::Fuzz();
2386 CHECK(info.This()->Equals(bottom));
Steve Blocka7e24c12009-10-30 11:49:00 +00002387}
2388
2389
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002390void CheckThisNamedPropertyDeleter(
2391 Local<String> property,
2392 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2393 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2394 ApiTestFuzzer::Fuzz();
2395 CHECK(info.This()->Equals(bottom));
2396}
2397
2398
2399void CheckThisIndexedPropertyEnumerator(
2400 const v8::PropertyCallbackInfo<v8::Array>& info) {
2401 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2402 ApiTestFuzzer::Fuzz();
2403 CHECK(info.This()->Equals(bottom));
2404}
2405
2406
2407void CheckThisNamedPropertyEnumerator(
2408 const v8::PropertyCallbackInfo<v8::Array>& info) {
2409 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2410 ApiTestFuzzer::Fuzz();
2411 CHECK(info.This()->Equals(bottom));
2412}
2413
2414
2415THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002416 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417 v8::Isolate* isolate = env->GetIsolate();
2418 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002419
2420 // Set up a prototype chain with three interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002421 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002422 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2423 CheckThisIndexedPropertyHandler,
2424 CheckThisIndexedPropertySetter,
2425 CheckThisIndexedPropertyQuery,
2426 CheckThisIndexedPropertyDeleter,
2427 CheckThisIndexedPropertyEnumerator);
2428
2429 templ->InstanceTemplate()->SetNamedPropertyHandler(
2430 CheckThisNamedPropertyHandler,
2431 CheckThisNamedPropertySetter,
2432 CheckThisNamedPropertyQuery,
2433 CheckThisNamedPropertyDeleter,
2434 CheckThisNamedPropertyEnumerator);
2435
2436 bottom = templ->GetFunction()->NewInstance();
2437 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2438 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2439
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002440 bottom->SetPrototype(middle);
2441 middle->SetPrototype(top);
Steve Blocka7e24c12009-10-30 11:49:00 +00002442 env->Global()->Set(v8_str("obj"), bottom);
2443
2444 // Indexed and named get.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002445 CompileRun("obj[0]");
2446 CompileRun("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00002447
2448 // Indexed and named set.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002449 CompileRun("obj[1] = 42");
2450 CompileRun("obj.y = 42");
Steve Blocka7e24c12009-10-30 11:49:00 +00002451
2452 // Indexed and named query.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002453 CompileRun("0 in obj");
2454 CompileRun("'x' in obj");
Steve Blocka7e24c12009-10-30 11:49:00 +00002455
2456 // Indexed and named deleter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002457 CompileRun("delete obj[0]");
2458 CompileRun("delete obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00002459
2460 // Enumerators.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002461 CompileRun("for (var p in obj) ;");
Steve Blocka7e24c12009-10-30 11:49:00 +00002462}
2463
2464
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002465static void PrePropertyHandlerGet(
2466 Local<String> key,
2467 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002468 ApiTestFuzzer::Fuzz();
2469 if (v8_str("pre")->Equals(key)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002470 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
Steve Blocka7e24c12009-10-30 11:49:00 +00002471 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002472}
2473
2474
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002475static void PrePropertyHandlerQuery(
2476 Local<String> key,
2477 const v8::PropertyCallbackInfo<v8::Integer>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002478 if (v8_str("pre")->Equals(key)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002479 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
Steve Blocka7e24c12009-10-30 11:49:00 +00002480 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002481}
2482
2483
2484THREADED_TEST(PrePropertyHandler) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002485 v8::Isolate* isolate = CcTest::isolate();
2486 v8::HandleScope scope(isolate);
2487 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002488 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2489 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002490 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00002491 LocalContext env(NULL, desc->InstanceTemplate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2493 v8::Handle<Value> result_pre = CompileRun("pre");
Steve Blocka7e24c12009-10-30 11:49:00 +00002494 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002495 v8::Handle<Value> result_on = CompileRun("on");
Steve Blocka7e24c12009-10-30 11:49:00 +00002496 CHECK_EQ(v8_str("Object: on"), result_on);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002497 v8::Handle<Value> result_post = CompileRun("post");
Steve Blocka7e24c12009-10-30 11:49:00 +00002498 CHECK(result_post.IsEmpty());
2499}
2500
2501
2502THREADED_TEST(UndefinedIsNotEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002503 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002504 v8::HandleScope scope(env->GetIsolate());
2505 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
Steve Blocka7e24c12009-10-30 11:49:00 +00002506 CHECK(result->IsFalse());
2507}
2508
2509
2510v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00002511static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00002512
2513
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002514static void CallScriptRecursivelyCall(
2515 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002516 ApiTestFuzzer::Fuzz();
2517 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002518 if (depth == kTargetRecursionDepth) return;
2519 args.This()->Set(v8_str("depth"),
2520 v8::Integer::New(args.GetIsolate(), depth + 1));
2521 args.GetReturnValue().Set(call_recursively_script->Run());
Steve Blocka7e24c12009-10-30 11:49:00 +00002522}
2523
2524
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002525static void CallFunctionRecursivelyCall(
2526 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002527 ApiTestFuzzer::Fuzz();
2528 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2529 if (depth == kTargetRecursionDepth) {
2530 printf("[depth = %d]\n", depth);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002531 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002532 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002533 args.This()->Set(v8_str("depth"),
2534 v8::Integer::New(args.GetIsolate(), depth + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 v8::Handle<Value> function =
2536 args.This()->Get(v8_str("callFunctionRecursively"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002537 args.GetReturnValue().Set(
2538 function.As<Function>()->Call(args.This(), 0, NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00002539}
2540
2541
2542THREADED_TEST(DeepCrossLanguageRecursion) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002543 v8::Isolate* isolate = CcTest::isolate();
2544 v8::HandleScope scope(isolate);
2545 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002546 global->Set(v8_str("callScriptRecursively"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002547 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
Steve Blocka7e24c12009-10-30 11:49:00 +00002548 global->Set(v8_str("callFunctionRecursively"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002549 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
Steve Blocka7e24c12009-10-30 11:49:00 +00002550 LocalContext env(NULL, global);
2551
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002552 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
Steve Blocka7e24c12009-10-30 11:49:00 +00002553 call_recursively_script = v8_compile("callScriptRecursively()");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002554 call_recursively_script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00002555 call_recursively_script = v8::Handle<Script>();
2556
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002557 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2558 CompileRun("callFunctionRecursively()");
Steve Blocka7e24c12009-10-30 11:49:00 +00002559}
2560
2561
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002562static void ThrowingPropertyHandlerGet(
2563 Local<String> key,
2564 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002565 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002566 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
Steve Blocka7e24c12009-10-30 11:49:00 +00002567}
2568
2569
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002570static void ThrowingPropertyHandlerSet(
2571 Local<String> key,
2572 Local<Value>,
2573 const v8::PropertyCallbackInfo<v8::Value>& info) {
2574 info.GetIsolate()->ThrowException(key);
2575 info.GetReturnValue().SetUndefined(); // not the same as empty handle
Steve Blocka7e24c12009-10-30 11:49:00 +00002576}
2577
2578
2579THREADED_TEST(CallbackExceptionRegression) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002580 v8::Isolate* isolate = CcTest::isolate();
2581 v8::HandleScope scope(isolate);
2582 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002583 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2584 ThrowingPropertyHandlerSet);
2585 LocalContext env;
2586 env->Global()->Set(v8_str("obj"), obj->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002587 v8::Handle<Value> otto = CompileRun(
2588 "try { with (obj) { otto; } } catch (e) { e; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002589 CHECK_EQ(v8_str("otto"), otto);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002590 v8::Handle<Value> netto = CompileRun(
2591 "try { with (obj) { netto = 4; } } catch (e) { e; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002592 CHECK_EQ(v8_str("netto"), netto);
2593}
2594
2595
Steve Blocka7e24c12009-10-30 11:49:00 +00002596THREADED_TEST(FunctionPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002597 v8::Isolate* isolate = CcTest::isolate();
2598 v8::HandleScope scope(isolate);
2599 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002600 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2601 LocalContext env;
2602 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002603 Local<Script> script = v8_compile("Foo.prototype.plak");
Steve Blocka7e24c12009-10-30 11:49:00 +00002604 CHECK_EQ(script->Run()->Int32Value(), 321);
2605}
2606
2607
2608THREADED_TEST(InternalFields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002609 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002610 v8::Isolate* isolate = env->GetIsolate();
2611 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002612
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002613 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002614 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2615 instance_templ->SetInternalFieldCount(1);
2616 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2617 CHECK_EQ(1, obj->InternalFieldCount());
2618 CHECK(obj->GetInternalField(0)->IsUndefined());
2619 obj->SetInternalField(0, v8_num(17));
2620 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2621}
2622
2623
Steve Block6ded16b2010-05-10 14:33:55 +01002624THREADED_TEST(GlobalObjectInternalFields) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002625 v8::Isolate* isolate = CcTest::isolate();
2626 v8::HandleScope scope(isolate);
2627 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01002628 global_template->SetInternalFieldCount(1);
2629 LocalContext env(NULL, global_template);
2630 v8::Handle<v8::Object> global_proxy = env->Global();
2631 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2632 CHECK_EQ(1, global->InternalFieldCount());
2633 CHECK(global->GetInternalField(0)->IsUndefined());
2634 global->SetInternalField(0, v8_num(17));
2635 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2636}
2637
2638
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002639THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002640 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002641 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002642
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002643 v8::Local<v8::Object> global = env->Global();
2644 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2645 CHECK(global->HasRealIndexedProperty(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00002646}
2647
2648
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002649static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2650 void* value) {
2651 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2652 obj->SetAlignedPointerInInternalField(0, value);
2653 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2654 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2655}
Steve Block3ce2e202009-11-05 08:53:23 +00002656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002657
2658THREADED_TEST(InternalFieldsAlignedPointers) {
2659 LocalContext env;
2660 v8::Isolate* isolate = env->GetIsolate();
2661 v8::HandleScope scope(isolate);
2662
2663 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Block3ce2e202009-11-05 08:53:23 +00002664 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2665 instance_templ->SetInternalFieldCount(1);
2666 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2667 CHECK_EQ(1, obj->InternalFieldCount());
Steve Block3ce2e202009-11-05 08:53:23 +00002668
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002669 CheckAlignedPointerInInternalField(obj, NULL);
Steve Block3ce2e202009-11-05 08:53:23 +00002670
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002671 int* heap_allocated = new int[100];
2672 CheckAlignedPointerInInternalField(obj, heap_allocated);
2673 delete[] heap_allocated;
Steve Block3ce2e202009-11-05 08:53:23 +00002674
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002675 int stack_allocated[100];
2676 CheckAlignedPointerInInternalField(obj, stack_allocated);
Steve Block3ce2e202009-11-05 08:53:23 +00002677
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002678 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2679 CheckAlignedPointerInInternalField(obj, huge);
Steve Block3ce2e202009-11-05 08:53:23 +00002680
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002681 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2682 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2683 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2684}
Steve Block3ce2e202009-11-05 08:53:23 +00002685
Steve Block3ce2e202009-11-05 08:53:23 +00002686
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002687static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2688 int index,
2689 void* value) {
2690 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2691 (*env)->SetAlignedPointerInEmbedderData(index, value);
2692 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2693 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2694}
2695
2696
2697static void* AlignedTestPointer(int i) {
2698 return reinterpret_cast<void*>(i * 1234);
2699}
2700
2701
2702THREADED_TEST(EmbedderDataAlignedPointers) {
2703 LocalContext env;
2704 v8::HandleScope scope(env->GetIsolate());
2705
2706 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2707
2708 int* heap_allocated = new int[100];
2709 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2710 delete[] heap_allocated;
2711
2712 int stack_allocated[100];
2713 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2714
2715 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2716 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2717
2718 // Test growing of the embedder data's backing store.
2719 for (int i = 0; i < 100; i++) {
2720 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2721 }
2722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2723 for (int i = 0; i < 100; i++) {
2724 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2725 }
2726}
2727
2728
2729static void CheckEmbedderData(LocalContext* env,
2730 int index,
2731 v8::Handle<Value> data) {
2732 (*env)->SetEmbedderData(index, data);
2733 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2734}
2735
2736
2737THREADED_TEST(EmbedderData) {
2738 LocalContext env;
2739 v8::Isolate* isolate = env->GetIsolate();
2740 v8::HandleScope scope(isolate);
2741
2742 CheckEmbedderData(
2743 &env, 3,
2744 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2745 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2746 "over the lazy dog."));
2747 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2748 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
Steve Block3ce2e202009-11-05 08:53:23 +00002749}
2750
2751
Steve Blocka7e24c12009-10-30 11:49:00 +00002752THREADED_TEST(IdentityHash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002753 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002754 v8::Isolate* isolate = env->GetIsolate();
2755 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002756
2757 // Ensure that the test starts with an fresh heap to test whether the hash
2758 // code is based on the address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002759 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2760 Local<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002761 int hash = obj->GetIdentityHash();
2762 int hash1 = obj->GetIdentityHash();
2763 CHECK_EQ(hash, hash1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002764 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
Steve Blocka7e24c12009-10-30 11:49:00 +00002765 // Since the identity hash is essentially a random number two consecutive
2766 // objects should not be assigned the same hash code. If the test below fails
2767 // the random number generator should be evaluated.
2768 CHECK_NE(hash, hash2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2770 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
Steve Blocka7e24c12009-10-30 11:49:00 +00002771 // Make sure that the identity hash is not based on the initial address of
2772 // the object alone. If the test below fails the random number generator
2773 // should be evaluated.
2774 CHECK_NE(hash, hash3);
2775 int hash4 = obj->GetIdentityHash();
2776 CHECK_EQ(hash, hash4);
Steve Block1e0659c2011-05-24 12:43:12 +01002777
2778 // Check identity hashes behaviour in the presence of JS accessors.
2779 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2780 {
2781 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002782 Local<v8::Object> o1 = v8::Object::New(isolate);
2783 Local<v8::Object> o2 = v8::Object::New(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +01002784 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2785 }
2786 {
2787 CompileRun(
2788 "function cnst() { return 42; };\n"
2789 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002790 Local<v8::Object> o1 = v8::Object::New(isolate);
2791 Local<v8::Object> o2 = v8::Object::New(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +01002792 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2793 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002794}
2795
2796
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002797THREADED_TEST(GlobalProxyIdentityHash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002798 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002799 v8::Isolate* isolate = env->GetIsolate();
2800 v8::HandleScope scope(isolate);
2801 Handle<Object> global_proxy = env->Global();
2802 int hash1 = global_proxy->GetIdentityHash();
2803 // Hash should be retained after being detached.
2804 env->DetachGlobal();
2805 int hash2 = global_proxy->GetIdentityHash();
2806 CHECK_EQ(hash1, hash2);
2807 {
2808 // Re-attach global proxy to a new context, hash should stay the same.
2809 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2810 int hash3 = global_proxy->GetIdentityHash();
2811 CHECK_EQ(hash1, hash3);
2812 }
2813}
Steve Blocka7e24c12009-10-30 11:49:00 +00002814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002815
2816THREADED_TEST(SymbolProperties) {
2817 LocalContext env;
2818 v8::Isolate* isolate = env->GetIsolate();
2819 v8::HandleScope scope(isolate);
2820
2821 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2822 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2823 v8::Local<v8::Symbol> sym2 =
2824 v8::Symbol::New(isolate, v8_str("my-symbol"));
2825 v8::Local<v8::Symbol> sym3 =
2826 v8::Symbol::New(isolate, v8_str("sym3"));
2827
2828 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2829
2830 // Check basic symbol functionality.
2831 CHECK(sym1->IsSymbol());
2832 CHECK(sym2->IsSymbol());
2833 CHECK(!obj->IsSymbol());
2834
2835 CHECK(sym1->Equals(sym1));
2836 CHECK(sym2->Equals(sym2));
2837 CHECK(!sym1->Equals(sym2));
2838 CHECK(!sym2->Equals(sym1));
2839 CHECK(sym1->StrictEquals(sym1));
2840 CHECK(sym2->StrictEquals(sym2));
2841 CHECK(!sym1->StrictEquals(sym2));
2842 CHECK(!sym2->StrictEquals(sym1));
2843
2844 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2845
2846 v8::Local<v8::Value> sym_val = sym2;
2847 CHECK(sym_val->IsSymbol());
2848 CHECK(sym_val->Equals(sym2));
2849 CHECK(sym_val->StrictEquals(sym2));
2850 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2851
2852 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2853 CHECK(sym_obj->IsSymbolObject());
2854 CHECK(!sym2->IsSymbolObject());
2855 CHECK(!obj->IsSymbolObject());
2856 CHECK(!sym_obj->Equals(sym2));
2857 CHECK(!sym_obj->StrictEquals(sym2));
2858 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2859 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2860
2861 // Make sure delete of a non-existent symbol property works.
2862 CHECK(obj->Delete(sym1));
2863 CHECK(!obj->Has(sym1));
2864
2865 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2866 CHECK(obj->Has(sym1));
2867 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2868 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2869 CHECK(obj->Has(sym1));
2870 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2871 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2872
2873 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2874 int num_props = obj->GetPropertyNames()->Length();
2875 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2876 v8::Integer::New(isolate, 20)));
2877 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2878 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2879
2880 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2881
2882 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2883 CHECK(obj->Get(sym3)->IsUndefined());
2884 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2885 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2886 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2887 v8::Integer::New(isolate, 42)));
2888
2889 // Add another property and delete it afterwards to force the object in
2890 // slow case.
2891 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2892 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2893 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2894 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2895 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2896
2897 CHECK(obj->Has(sym1));
2898 CHECK(obj->Has(sym2));
2899 CHECK(obj->Has(sym3));
2900 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2901 CHECK(obj->Delete(sym2));
2902 CHECK(obj->Has(sym1));
2903 CHECK(!obj->Has(sym2));
2904 CHECK(obj->Has(sym3));
2905 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2906 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2907 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2908 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2909 v8::Integer::New(isolate, 42)));
2910 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2911
2912 // Symbol properties are inherited.
2913 v8::Local<v8::Object> child = v8::Object::New(isolate);
2914 child->SetPrototype(obj);
2915 CHECK(child->Has(sym1));
2916 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2917 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2918 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2919 v8::Integer::New(isolate, 42)));
2920 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2921}
2922
2923
2924THREADED_TEST(SymbolTemplateProperties) {
2925 LocalContext env;
2926 v8::Isolate* isolate = env->GetIsolate();
2927 v8::HandleScope scope(isolate);
2928 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2929 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2930 CHECK(!name.IsEmpty());
2931 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2932 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2933 CHECK(!new_instance.IsEmpty());
2934 CHECK(new_instance->Has(name));
2935}
2936
2937
2938THREADED_TEST(PrivateProperties) {
2939 LocalContext env;
2940 v8::Isolate* isolate = env->GetIsolate();
2941 v8::HandleScope scope(isolate);
2942
2943 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2944 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2945 v8::Local<v8::Private> priv2 =
2946 v8::Private::New(isolate, v8_str("my-private"));
2947
2948 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2949
2950 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2951
2952 // Make sure delete of a non-existent private symbol property works.
2953 CHECK(obj->DeletePrivate(priv1));
2954 CHECK(!obj->HasPrivate(priv1));
2955
2956 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2957 CHECK(obj->HasPrivate(priv1));
2958 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2959 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2960 CHECK(obj->HasPrivate(priv1));
2961 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2962
2963 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2964 int num_props = obj->GetPropertyNames()->Length();
2965 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2966 v8::Integer::New(isolate, 20)));
2967 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2968 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2969
2970 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2971
2972 // Add another property and delete it afterwards to force the object in
2973 // slow case.
2974 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2975 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2976 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2977 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2978 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2979
2980 CHECK(obj->HasPrivate(priv1));
2981 CHECK(obj->HasPrivate(priv2));
2982 CHECK(obj->DeletePrivate(priv2));
2983 CHECK(obj->HasPrivate(priv1));
2984 CHECK(!obj->HasPrivate(priv2));
2985 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2986 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2987
2988 // Private properties are inherited (for the time being).
2989 v8::Local<v8::Object> child = v8::Object::New(isolate);
2990 child->SetPrototype(obj);
2991 CHECK(child->HasPrivate(priv1));
2992 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2993 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2994}
2995
2996
2997THREADED_TEST(GlobalSymbols) {
2998 LocalContext env;
2999 v8::Isolate* isolate = env->GetIsolate();
3000 v8::HandleScope scope(isolate);
3001
3002 v8::Local<String> name = v8_str("my-symbol");
3003 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3004 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3005 CHECK(glob2->SameValue(glob));
3006
3007 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3008 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3009 CHECK(glob_api2->SameValue(glob_api));
3010 CHECK(!glob_api->SameValue(glob));
3011
3012 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3013 CHECK(!sym->SameValue(glob));
3014
3015 CompileRun("var sym2 = Symbol.for('my-symbol')");
3016 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3017 CHECK(sym2->SameValue(glob));
3018 CHECK(!sym2->SameValue(glob_api));
3019}
3020
3021
3022static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3023 const char* name) {
3024 LocalContext env;
3025 v8::Isolate* isolate = env->GetIsolate();
3026 v8::HandleScope scope(isolate);
3027
3028 v8::Local<v8::Symbol> symbol = getter(isolate);
3029 std::string script = std::string("var sym = ") + name;
3030 CompileRun(script.c_str());
3031 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3032
3033 CHECK(!value.IsEmpty());
3034 CHECK(!symbol.IsEmpty());
3035 CHECK(value->SameValue(symbol));
3036}
3037
3038
3039THREADED_TEST(WellKnownSymbols) {
3040 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3041 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3042}
3043
3044
3045THREADED_TEST(GlobalPrivates) {
3046 LocalContext env;
3047 v8::Isolate* isolate = env->GetIsolate();
3048 v8::HandleScope scope(isolate);
3049
3050 v8::Local<String> name = v8_str("my-private");
3051 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3052 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3053 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3054
3055 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3056 CHECK(obj->HasPrivate(glob2));
3057
3058 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3059 CHECK(!obj->HasPrivate(priv));
3060
3061 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3062 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3063 CHECK(!obj->Has(intern));
3064}
3065
3066
3067class ScopedArrayBufferContents {
3068 public:
3069 explicit ScopedArrayBufferContents(
3070 const v8::ArrayBuffer::Contents& contents)
3071 : contents_(contents) {}
3072 ~ScopedArrayBufferContents() { free(contents_.Data()); }
3073 void* Data() const { return contents_.Data(); }
3074 size_t ByteLength() const { return contents_.ByteLength(); }
3075 private:
3076 const v8::ArrayBuffer::Contents contents_;
3077};
3078
3079template <typename T>
3080static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3081 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3082 for (int i = 0; i < value->InternalFieldCount(); i++) {
3083 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3084 }
3085}
3086
3087
3088THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3089 LocalContext env;
3090 v8::Isolate* isolate = env->GetIsolate();
3091 v8::HandleScope handle_scope(isolate);
3092
3093 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3094 CheckInternalFieldsAreZero(ab);
3095 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3096 CHECK(!ab->IsExternal());
3097 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3098
3099 ScopedArrayBufferContents ab_contents(ab->Externalize());
3100 CHECK(ab->IsExternal());
3101
3102 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3103 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3104 DCHECK(data != NULL);
3105 env->Global()->Set(v8_str("ab"), ab);
3106
3107 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3108 CHECK_EQ(1024, result->Int32Value());
3109
3110 result = CompileRun("var u8 = new Uint8Array(ab);"
3111 "u8[0] = 0xFF;"
3112 "u8[1] = 0xAA;"
3113 "u8.length");
3114 CHECK_EQ(1024, result->Int32Value());
3115 CHECK_EQ(0xFF, data[0]);
3116 CHECK_EQ(0xAA, data[1]);
3117 data[0] = 0xCC;
3118 data[1] = 0x11;
3119 result = CompileRun("u8[0] + u8[1]");
3120 CHECK_EQ(0xDD, result->Int32Value());
3121}
3122
3123
3124THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3125 LocalContext env;
3126 v8::Isolate* isolate = env->GetIsolate();
3127 v8::HandleScope handle_scope(isolate);
3128
3129
3130 v8::Local<v8::Value> result =
3131 CompileRun("var ab1 = new ArrayBuffer(2);"
3132 "var u8_a = new Uint8Array(ab1);"
3133 "u8_a[0] = 0xAA;"
3134 "u8_a[1] = 0xFF; u8_a.buffer");
3135 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3136 CheckInternalFieldsAreZero(ab1);
3137 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3138 CHECK(!ab1->IsExternal());
3139 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3140 CHECK(ab1->IsExternal());
3141
3142 result = CompileRun("ab1.byteLength");
3143 CHECK_EQ(2, result->Int32Value());
3144 result = CompileRun("u8_a[0]");
3145 CHECK_EQ(0xAA, result->Int32Value());
3146 result = CompileRun("u8_a[1]");
3147 CHECK_EQ(0xFF, result->Int32Value());
3148 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3149 "u8_b[0] = 0xBB;"
3150 "u8_a[0]");
3151 CHECK_EQ(0xBB, result->Int32Value());
3152 result = CompileRun("u8_b[1]");
3153 CHECK_EQ(0xFF, result->Int32Value());
3154
3155 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3156 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3157 CHECK_EQ(0xBB, ab1_data[0]);
3158 CHECK_EQ(0xFF, ab1_data[1]);
3159 ab1_data[0] = 0xCC;
3160 ab1_data[1] = 0x11;
3161 result = CompileRun("u8_a[0] + u8_a[1]");
3162 CHECK_EQ(0xDD, result->Int32Value());
3163}
3164
3165
3166THREADED_TEST(ArrayBuffer_External) {
3167 LocalContext env;
3168 v8::Isolate* isolate = env->GetIsolate();
3169 v8::HandleScope handle_scope(isolate);
3170
3171 i::ScopedVector<uint8_t> my_data(100);
3172 memset(my_data.start(), 0, 100);
3173 Local<v8::ArrayBuffer> ab3 =
3174 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3175 CheckInternalFieldsAreZero(ab3);
3176 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3177 CHECK(ab3->IsExternal());
3178
3179 env->Global()->Set(v8_str("ab3"), ab3);
3180
3181 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3182 CHECK_EQ(100, result->Int32Value());
3183
3184 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3185 "u8_b[0] = 0xBB;"
3186 "u8_b[1] = 0xCC;"
3187 "u8_b.length");
3188 CHECK_EQ(100, result->Int32Value());
3189 CHECK_EQ(0xBB, my_data[0]);
3190 CHECK_EQ(0xCC, my_data[1]);
3191 my_data[0] = 0xCC;
3192 my_data[1] = 0x11;
3193 result = CompileRun("u8_b[0] + u8_b[1]");
3194 CHECK_EQ(0xDD, result->Int32Value());
3195}
3196
3197
3198static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3199 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3200 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3201}
3202
3203
3204static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3205 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3206 CHECK_EQ(0, static_cast<int>(ta->Length()));
3207 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3208}
3209
3210
3211static void CheckIsTypedArrayVarNeutered(const char* name) {
3212 i::ScopedVector<char> source(1024);
3213 i::SNPrintF(source,
3214 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3215 name, name, name);
3216 CHECK(CompileRun(source.start())->IsTrue());
3217 v8::Handle<v8::TypedArray> ta =
3218 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3219 CheckIsNeutered(ta);
3220}
3221
3222
3223template <typename TypedArray, int kElementSize>
3224static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3225 int byteOffset,
3226 int length) {
3227 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3228 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3229 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3230 CHECK_EQ(length, static_cast<int>(ta->Length()));
3231 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3232 return ta;
3233}
3234
3235
3236THREADED_TEST(ArrayBuffer_NeuteringApi) {
3237 LocalContext env;
3238 v8::Isolate* isolate = env->GetIsolate();
3239 v8::HandleScope handle_scope(isolate);
3240
3241 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3242
3243 v8::Handle<v8::Uint8Array> u8a =
3244 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3245 v8::Handle<v8::Uint8ClampedArray> u8c =
3246 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3247 v8::Handle<v8::Int8Array> i8a =
3248 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3249
3250 v8::Handle<v8::Uint16Array> u16a =
3251 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3252 v8::Handle<v8::Int16Array> i16a =
3253 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3254
3255 v8::Handle<v8::Uint32Array> u32a =
3256 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3257 v8::Handle<v8::Int32Array> i32a =
3258 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3259
3260 v8::Handle<v8::Float32Array> f32a =
3261 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3262 v8::Handle<v8::Float64Array> f64a =
3263 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3264
3265 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3266 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3267 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3268 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3269
3270 ScopedArrayBufferContents contents(buffer->Externalize());
3271 buffer->Neuter();
3272 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3273 CheckIsNeutered(u8a);
3274 CheckIsNeutered(u8c);
3275 CheckIsNeutered(i8a);
3276 CheckIsNeutered(u16a);
3277 CheckIsNeutered(i16a);
3278 CheckIsNeutered(u32a);
3279 CheckIsNeutered(i32a);
3280 CheckIsNeutered(f32a);
3281 CheckIsNeutered(f64a);
3282 CheckDataViewIsNeutered(dv);
3283}
3284
3285
3286THREADED_TEST(ArrayBuffer_NeuteringScript) {
3287 LocalContext env;
3288 v8::Isolate* isolate = env->GetIsolate();
3289 v8::HandleScope handle_scope(isolate);
3290
3291 CompileRun(
3292 "var ab = new ArrayBuffer(1024);"
3293 "var u8a = new Uint8Array(ab, 1, 1023);"
3294 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3295 "var i8a = new Int8Array(ab, 1, 1023);"
3296 "var u16a = new Uint16Array(ab, 2, 511);"
3297 "var i16a = new Int16Array(ab, 2, 511);"
3298 "var u32a = new Uint32Array(ab, 4, 255);"
3299 "var i32a = new Int32Array(ab, 4, 255);"
3300 "var f32a = new Float32Array(ab, 4, 255);"
3301 "var f64a = new Float64Array(ab, 8, 127);"
3302 "var dv = new DataView(ab, 1, 1023);");
3303
3304 v8::Handle<v8::ArrayBuffer> ab =
3305 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3306
3307 v8::Handle<v8::DataView> dv =
3308 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3309
3310 ScopedArrayBufferContents contents(ab->Externalize());
3311 ab->Neuter();
3312 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3313 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3314
3315 CheckIsTypedArrayVarNeutered("u8a");
3316 CheckIsTypedArrayVarNeutered("u8c");
3317 CheckIsTypedArrayVarNeutered("i8a");
3318 CheckIsTypedArrayVarNeutered("u16a");
3319 CheckIsTypedArrayVarNeutered("i16a");
3320 CheckIsTypedArrayVarNeutered("u32a");
3321 CheckIsTypedArrayVarNeutered("i32a");
3322 CheckIsTypedArrayVarNeutered("f32a");
3323 CheckIsTypedArrayVarNeutered("f64a");
3324
3325 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3326 CheckDataViewIsNeutered(dv);
3327}
3328
3329
3330
3331THREADED_TEST(HiddenProperties) {
3332 LocalContext env;
3333 v8::Isolate* isolate = env->GetIsolate();
3334 v8::HandleScope scope(isolate);
3335
3336 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003337 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3338 v8::Local<v8::String> empty = v8_str("");
3339 v8::Local<v8::String> prop_name = v8_str("prop_name");
3340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003341 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003342
3343 // Make sure delete of a non-existent hidden value works
3344 CHECK(obj->DeleteHiddenValue(key));
3345
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003346 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003347 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003348 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003349 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3350
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003351 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003352
3353 // Make sure we do not find the hidden property.
3354 CHECK(!obj->Has(empty));
3355 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3356 CHECK(obj->Get(empty)->IsUndefined());
3357 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003358 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003359 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3360 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3361
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003362 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003363
3364 // Add another property and delete it afterwards to force the object in
3365 // slow case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003366 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003367 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3368 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3369 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3370 CHECK(obj->Delete(prop_name));
3371 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3372
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003373 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00003374
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003375 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3376 CHECK(obj->GetHiddenValue(key).IsEmpty());
3377
3378 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003379 CHECK(obj->DeleteHiddenValue(key));
3380 CHECK(obj->GetHiddenValue(key).IsEmpty());
3381}
3382
3383
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003384THREADED_TEST(Regress97784) {
3385 // Regression test for crbug.com/97784
3386 // Messing with the Object.prototype should not have effect on
3387 // hidden properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003388 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003389 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003390
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003391 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003392 v8::Local<v8::String> key = v8_str("hidden");
3393
3394 CompileRun(
3395 "set_called = false;"
3396 "Object.defineProperty("
3397 " Object.prototype,"
3398 " 'hidden',"
3399 " {get: function() { return 45; },"
3400 " set: function() { set_called = true; }})");
3401
3402 CHECK(obj->GetHiddenValue(key).IsEmpty());
3403 // Make sure that the getter and setter from Object.prototype is not invoked.
3404 // If it did we would have full access to the hidden properties in
3405 // the accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003406 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003407 ExpectFalse("set_called");
3408 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3409}
3410
3411
Steve Blockd0582a62009-12-15 09:54:21 +00003412static bool interceptor_for_hidden_properties_called;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003413static void InterceptorForHiddenProperties(
3414 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00003415 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003416}
3417
3418
3419THREADED_TEST(HiddenPropertiesWithInterceptors) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003420 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003421 v8::Isolate* isolate = context->GetIsolate();
3422 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003423
Steve Blockd0582a62009-12-15 09:54:21 +00003424 interceptor_for_hidden_properties_called = false;
3425
Steve Blocka7e24c12009-10-30 11:49:00 +00003426 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3427
3428 // Associate an interceptor with an object and start setting hidden values.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003429 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003430 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3431 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3432 Local<v8::Function> function = fun_templ->GetFunction();
3433 Local<v8::Object> obj = function->NewInstance();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003434 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003435 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00003436 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00003437}
3438
3439
3440THREADED_TEST(External) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003441 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003442 int x = 3;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003443 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
Steve Blocka7e24c12009-10-30 11:49:00 +00003444 LocalContext env;
3445 env->Global()->Set(v8_str("ext"), ext);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003446 Local<Value> reext_obj = CompileRun("this.ext");
Steve Block6ded16b2010-05-10 14:33:55 +01003447 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003448 int* ptr = static_cast<int*>(reext->Value());
3449 CHECK_EQ(x, 3);
3450 *ptr = 10;
3451 CHECK_EQ(x, 10);
3452
3453 // Make sure unaligned pointers are wrapped properly.
3454 char* data = i::StrDup("0123456789");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003455 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3456 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3457 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3458 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003459
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003460 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003461 CHECK_EQ('0', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003462 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003463 CHECK_EQ('1', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003464 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003465 CHECK_EQ('2', *char_ptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003466 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003467 CHECK_EQ('3', *char_ptr);
3468 i::DeleteArray(data);
3469}
3470
3471
3472THREADED_TEST(GlobalHandle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003473 v8::Isolate* isolate = CcTest::isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003474 v8::Persistent<String> global;
3475 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003476 v8::HandleScope scope(isolate);
3477 global.Reset(isolate, v8_str("str"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003478 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003479 {
3480 v8::HandleScope scope(isolate);
3481 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3482 }
3483 global.Reset();
3484 {
3485 v8::HandleScope scope(isolate);
3486 global.Reset(isolate, v8_str("str"));
3487 }
3488 {
3489 v8::HandleScope scope(isolate);
3490 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3491 }
3492 global.Reset();
3493}
3494
3495
3496THREADED_TEST(ResettingGlobalHandle) {
3497 v8::Isolate* isolate = CcTest::isolate();
3498 v8::Persistent<String> global;
3499 {
3500 v8::HandleScope scope(isolate);
3501 global.Reset(isolate, v8_str("str"));
3502 }
3503 v8::internal::GlobalHandles* global_handles =
3504 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3505 int initial_handle_count = global_handles->global_handles_count();
3506 {
3507 v8::HandleScope scope(isolate);
3508 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3509 }
3510 {
3511 v8::HandleScope scope(isolate);
3512 global.Reset(isolate, v8_str("longer"));
3513 }
3514 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3515 {
3516 v8::HandleScope scope(isolate);
3517 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3518 }
3519 global.Reset();
3520 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3521}
3522
3523
3524THREADED_TEST(ResettingGlobalHandleToEmpty) {
3525 v8::Isolate* isolate = CcTest::isolate();
3526 v8::Persistent<String> global;
3527 {
3528 v8::HandleScope scope(isolate);
3529 global.Reset(isolate, v8_str("str"));
3530 }
3531 v8::internal::GlobalHandles* global_handles =
3532 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3533 int initial_handle_count = global_handles->global_handles_count();
3534 {
3535 v8::HandleScope scope(isolate);
3536 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3537 }
3538 {
3539 v8::HandleScope scope(isolate);
3540 Local<String> empty;
3541 global.Reset(isolate, empty);
3542 }
3543 CHECK(global.IsEmpty());
3544 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3545}
3546
3547
3548template<class T>
3549static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3550 return unique.Pass();
3551}
3552
3553
3554template<class T>
3555static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3556 const v8::Persistent<T> & global) {
3557 v8::UniquePersistent<String> unique(isolate, global);
3558 return unique.Pass();
3559}
3560
3561
3562THREADED_TEST(UniquePersistent) {
3563 v8::Isolate* isolate = CcTest::isolate();
3564 v8::Persistent<String> global;
3565 {
3566 v8::HandleScope scope(isolate);
3567 global.Reset(isolate, v8_str("str"));
3568 }
3569 v8::internal::GlobalHandles* global_handles =
3570 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3571 int initial_handle_count = global_handles->global_handles_count();
3572 {
3573 v8::UniquePersistent<String> unique(isolate, global);
3574 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3575 // Test assignment via Pass
3576 {
3577 v8::UniquePersistent<String> copy = unique.Pass();
3578 CHECK(unique.IsEmpty());
3579 CHECK(copy == global);
3580 CHECK_EQ(initial_handle_count + 1,
3581 global_handles->global_handles_count());
3582 unique = copy.Pass();
3583 }
3584 // Test ctor via Pass
3585 {
3586 v8::UniquePersistent<String> copy(unique.Pass());
3587 CHECK(unique.IsEmpty());
3588 CHECK(copy == global);
3589 CHECK_EQ(initial_handle_count + 1,
3590 global_handles->global_handles_count());
3591 unique = copy.Pass();
3592 }
3593 // Test pass through function call
3594 {
3595 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3596 CHECK(unique.IsEmpty());
3597 CHECK(copy == global);
3598 CHECK_EQ(initial_handle_count + 1,
3599 global_handles->global_handles_count());
3600 unique = copy.Pass();
3601 }
3602 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3603 }
3604 // Test pass from function call
3605 {
3606 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3607 CHECK(unique == global);
3608 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3609 }
3610 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3611 global.Reset();
3612}
3613
3614
3615template<typename K, typename V>
3616class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3617 public:
3618 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3619 MapType;
3620 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3621 struct WeakCallbackDataType {
3622 MapType* map;
3623 K key;
3624 };
3625 static WeakCallbackDataType* WeakCallbackParameter(
3626 MapType* map, const K& key, Local<V> value) {
3627 WeakCallbackDataType* data = new WeakCallbackDataType;
3628 data->map = map;
3629 data->key = key;
3630 return data;
3631 }
3632 static MapType* MapFromWeakCallbackData(
3633 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3634 return data.GetParameter()->map;
3635 }
3636 static K KeyFromWeakCallbackData(
3637 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3638 return data.GetParameter()->key;
3639 }
3640 static void DisposeCallbackData(WeakCallbackDataType* data) {
3641 delete data;
3642 }
3643 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3644 K key) { }
3645};
3646
3647
3648template<typename Map>
3649static void TestPersistentValueMap() {
3650 LocalContext env;
3651 v8::Isolate* isolate = env->GetIsolate();
3652 Map map(isolate);
3653 v8::internal::GlobalHandles* global_handles =
3654 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3655 int initial_handle_count = global_handles->global_handles_count();
3656 CHECK_EQ(0, static_cast<int>(map.Size()));
3657 {
3658 HandleScope scope(isolate);
3659 Local<v8::Object> obj = map.Get(7);
3660 CHECK(obj.IsEmpty());
3661 Local<v8::Object> expected = v8::Object::New(isolate);
3662 map.Set(7, expected);
3663 CHECK_EQ(1, static_cast<int>(map.Size()));
3664 obj = map.Get(7);
3665 CHECK_EQ(expected, obj);
3666 {
3667 typename Map::PersistentValueReference ref = map.GetReference(7);
3668 CHECK_EQ(expected, ref.NewLocal(isolate));
3669 }
3670 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3671 CHECK_EQ(0, static_cast<int>(map.Size()));
3672 CHECK(expected == removed);
3673 removed = map.Remove(7);
3674 CHECK(removed.IsEmpty());
3675 map.Set(8, expected);
3676 CHECK_EQ(1, static_cast<int>(map.Size()));
3677 map.Set(8, expected);
3678 CHECK_EQ(1, static_cast<int>(map.Size()));
3679 {
3680 typename Map::PersistentValueReference ref;
3681 Local<v8::Object> expected2 = v8::Object::New(isolate);
3682 removed = map.Set(8,
3683 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3684 CHECK_EQ(1, static_cast<int>(map.Size()));
3685 CHECK(expected == removed);
3686 CHECK_EQ(expected2, ref.NewLocal(isolate));
3687 }
3688 }
3689 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3690 if (map.IsWeak()) {
3691 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3692 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3693 } else {
3694 map.Clear();
3695 }
3696 CHECK_EQ(0, static_cast<int>(map.Size()));
3697 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3698}
3699
3700
3701TEST(PersistentValueMap) {
3702 // Default case, w/o weak callbacks:
3703 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3704
3705 // Custom traits with weak callbacks:
3706 typedef v8::PersistentValueMap<int, v8::Object,
3707 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3708 TestPersistentValueMap<WeakPersistentValueMap>();
3709}
3710
3711
3712TEST(PersistentValueVector) {
3713 LocalContext env;
3714 v8::Isolate* isolate = env->GetIsolate();
3715 v8::internal::GlobalHandles* global_handles =
3716 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3717 int handle_count = global_handles->global_handles_count();
3718 HandleScope scope(isolate);
3719
3720 v8::PersistentValueVector<v8::Object> vector(isolate);
3721
3722 Local<v8::Object> obj1 = v8::Object::New(isolate);
3723 Local<v8::Object> obj2 = v8::Object::New(isolate);
3724 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3725
3726 CHECK(vector.IsEmpty());
3727 CHECK_EQ(0, static_cast<int>(vector.Size()));
3728
3729 vector.ReserveCapacity(3);
3730 CHECK(vector.IsEmpty());
3731
3732 vector.Append(obj1);
3733 vector.Append(obj2);
3734 vector.Append(obj1);
3735 vector.Append(obj3.Pass());
3736 vector.Append(obj1);
3737
3738 CHECK(!vector.IsEmpty());
3739 CHECK_EQ(5, static_cast<int>(vector.Size()));
3740 CHECK(obj3.IsEmpty());
3741 CHECK_EQ(obj1, vector.Get(0));
3742 CHECK_EQ(obj1, vector.Get(2));
3743 CHECK_EQ(obj1, vector.Get(4));
3744 CHECK_EQ(obj2, vector.Get(1));
3745
3746 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3747
3748 vector.Clear();
3749 CHECK(vector.IsEmpty());
3750 CHECK_EQ(0, static_cast<int>(vector.Size()));
3751 CHECK_EQ(handle_count, global_handles->global_handles_count());
3752}
3753
3754
3755THREADED_TEST(GlobalHandleUpcast) {
3756 v8::Isolate* isolate = CcTest::isolate();
3757 v8::HandleScope scope(isolate);
3758 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3759 v8::Persistent<String> global_string(isolate, local);
3760 v8::Persistent<Value>& global_value =
3761 v8::Persistent<Value>::Cast(global_string);
3762 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3763 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3764 global_string.Reset();
3765}
3766
3767
3768THREADED_TEST(HandleEquality) {
3769 v8::Isolate* isolate = CcTest::isolate();
3770 v8::Persistent<String> global1;
3771 v8::Persistent<String> global2;
3772 {
3773 v8::HandleScope scope(isolate);
3774 global1.Reset(isolate, v8_str("str"));
3775 global2.Reset(isolate, v8_str("str2"));
3776 }
3777 CHECK_EQ(global1 == global1, true);
3778 CHECK_EQ(global1 != global1, false);
3779 {
3780 v8::HandleScope scope(isolate);
3781 Local<String> local1 = Local<String>::New(isolate, global1);
3782 Local<String> local2 = Local<String>::New(isolate, global2);
3783
3784 CHECK_EQ(global1 == local1, true);
3785 CHECK_EQ(global1 != local1, false);
3786 CHECK_EQ(local1 == global1, true);
3787 CHECK_EQ(local1 != global1, false);
3788
3789 CHECK_EQ(global1 == local2, false);
3790 CHECK_EQ(global1 != local2, true);
3791 CHECK_EQ(local2 == global1, false);
3792 CHECK_EQ(local2 != global1, true);
3793
3794 CHECK_EQ(local1 == local2, false);
3795 CHECK_EQ(local1 != local2, true);
3796
3797 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3798 CHECK_EQ(local1 == anotherLocal1, true);
3799 CHECK_EQ(local1 != anotherLocal1, false);
3800 }
3801 global1.Reset();
3802 global2.Reset();
3803}
3804
3805
3806THREADED_TEST(LocalHandle) {
3807 v8::HandleScope scope(CcTest::isolate());
3808 v8::Local<String> local =
3809 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3810 CHECK_EQ(local->Length(), 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00003811}
3812
3813
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003814class WeakCallCounter {
3815 public:
3816 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3817 int id() { return id_; }
3818 void increment() { number_of_weak_calls_++; }
3819 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3820 private:
3821 int id_;
3822 int number_of_weak_calls_;
3823};
3824
3825
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003826template<typename T>
3827struct WeakCallCounterAndPersistent {
3828 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3829 : counter(counter) {}
3830 WeakCallCounter* counter;
3831 v8::Persistent<T> handle;
3832};
3833
3834
3835template <typename T>
3836static void WeakPointerCallback(
3837 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3838 CHECK_EQ(1234, data.GetParameter()->counter->id());
3839 data.GetParameter()->counter->increment();
3840 data.GetParameter()->handle.Reset();
3841}
3842
3843
3844template<typename T>
3845static UniqueId MakeUniqueId(const Persistent<T>& p) {
3846 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
Steve Block44f0eee2011-05-26 01:26:41 +01003847}
3848
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003849
Steve Block44f0eee2011-05-26 01:26:41 +01003850THREADED_TEST(ApiObjectGroups) {
Steve Block44f0eee2011-05-26 01:26:41 +01003851 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003852 v8::Isolate* iso = env->GetIsolate();
3853 HandleScope scope(iso);
Steve Block44f0eee2011-05-26 01:26:41 +01003854
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003855 WeakCallCounter counter(1234);
3856
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003857 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3858 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3859 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3860 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3861 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3862 WeakCallCounterAndPersistent<Value> g2c1(&counter);
Steve Block44f0eee2011-05-26 01:26:41 +01003863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003864 {
3865 HandleScope scope(iso);
3866 g1s1.handle.Reset(iso, Object::New(iso));
3867 g1s2.handle.Reset(iso, Object::New(iso));
3868 g1c1.handle.Reset(iso, Object::New(iso));
3869 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3870 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3871 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3872
3873 g2s1.handle.Reset(iso, Object::New(iso));
3874 g2s2.handle.Reset(iso, Object::New(iso));
3875 g2c1.handle.Reset(iso, Object::New(iso));
3876 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3877 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3878 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01003879 }
3880
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003881 WeakCallCounterAndPersistent<Value> root(&counter);
3882 root.handle.Reset(iso, g1s1.handle); // make a root.
Steve Block44f0eee2011-05-26 01:26:41 +01003883
3884 // Connect group 1 and 2, make a cycle.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003885 {
3886 HandleScope scope(iso);
3887 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3888 Set(0, Local<Value>::New(iso, g2s2.handle)));
3889 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3890 Set(0, Local<Value>::New(iso, g1s1.handle)));
3891 }
Steve Block44f0eee2011-05-26 01:26:41 +01003892
3893 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003894 UniqueId id1 = MakeUniqueId(g1s1.handle);
3895 UniqueId id2 = MakeUniqueId(g2s2.handle);
3896 iso->SetObjectGroupId(g1s1.handle, id1);
3897 iso->SetObjectGroupId(g1s2.handle, id1);
3898 iso->SetReferenceFromGroup(id1, g1c1.handle);
3899 iso->SetObjectGroupId(g2s1.handle, id2);
3900 iso->SetObjectGroupId(g2s2.handle, id2);
3901 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01003902 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003903 // Do a single full GC, ensure incremental marking is stopped.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003904 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3905 iso)->heap();
3906 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01003907
3908 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003909 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01003910
3911 // Weaken the root.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003912 root.handle.SetWeak(&root, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01003913 // But make children strong roots---all the objects (except for children)
3914 // should be collectable now.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003915 g1c1.handle.ClearWeak();
3916 g2c1.handle.ClearWeak();
Steve Block44f0eee2011-05-26 01:26:41 +01003917
3918 // Groups are deleted, rebuild groups.
3919 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003920 UniqueId id1 = MakeUniqueId(g1s1.handle);
3921 UniqueId id2 = MakeUniqueId(g2s2.handle);
3922 iso->SetObjectGroupId(g1s1.handle, id1);
3923 iso->SetObjectGroupId(g1s2.handle, id1);
3924 iso->SetReferenceFromGroup(id1, g1c1.handle);
3925 iso->SetObjectGroupId(g2s1.handle, id2);
3926 iso->SetObjectGroupId(g2s2.handle, id2);
3927 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01003928 }
3929
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003930 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01003931
3932 // All objects should be gone. 5 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003933 CHECK_EQ(5, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01003934
3935 // And now make children weak again and collect them.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003936 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3937 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01003938
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003939 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003940 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01003941}
3942
3943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003944THREADED_TEST(ApiObjectGroupsForSubtypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003945 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003946 v8::Isolate* iso = env->GetIsolate();
3947 HandleScope scope(iso);
Steve Block44f0eee2011-05-26 01:26:41 +01003948
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003949 WeakCallCounter counter(1234);
Steve Block44f0eee2011-05-26 01:26:41 +01003950
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003951 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3952 WeakCallCounterAndPersistent<String> g1s2(&counter);
3953 WeakCallCounterAndPersistent<String> g1c1(&counter);
3954 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3955 WeakCallCounterAndPersistent<String> g2s2(&counter);
3956 WeakCallCounterAndPersistent<String> g2c1(&counter);
Steve Block44f0eee2011-05-26 01:26:41 +01003957
3958 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003959 HandleScope scope(iso);
3960 g1s1.handle.Reset(iso, Object::New(iso));
3961 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3962 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3963 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3964 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3965 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01003966
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003967 g2s1.handle.Reset(iso, Object::New(iso));
3968 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3969 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3970 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3971 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3972 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
Steve Block44f0eee2011-05-26 01:26:41 +01003973 }
3974
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003975 WeakCallCounterAndPersistent<Value> root(&counter);
3976 root.handle.Reset(iso, g1s1.handle); // make a root.
Steve Block44f0eee2011-05-26 01:26:41 +01003977
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003978 // Connect group 1 and 2, make a cycle.
Steve Block44f0eee2011-05-26 01:26:41 +01003979 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003980 HandleScope scope(iso);
3981 CHECK(Local<Object>::New(iso, g1s1.handle)
3982 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3983 CHECK(Local<Object>::New(iso, g2s1.handle)
3984 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
Steve Block44f0eee2011-05-26 01:26:41 +01003985 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003986
3987 {
3988 UniqueId id1 = MakeUniqueId(g1s1.handle);
3989 UniqueId id2 = MakeUniqueId(g2s2.handle);
3990 iso->SetObjectGroupId(g1s1.handle, id1);
3991 iso->SetObjectGroupId(g1s2.handle, id1);
3992 iso->SetReference(g1s1.handle, g1c1.handle);
3993 iso->SetObjectGroupId(g2s1.handle, id2);
3994 iso->SetObjectGroupId(g2s2.handle, id2);
3995 iso->SetReferenceFromGroup(id2, g2c1.handle);
3996 }
3997 // Do a single full GC, ensure incremental marking is stopped.
3998 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3999 iso)->heap();
4000 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Block44f0eee2011-05-26 01:26:41 +01004001
4002 // All object should be alive.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004003 CHECK_EQ(0, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004004
4005 // Weaken the root.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004006 root.handle.SetWeak(&root, &WeakPointerCallback);
4007 // But make children strong roots---all the objects (except for children)
4008 // should be collectable now.
4009 g1c1.handle.ClearWeak();
4010 g2c1.handle.ClearWeak();
Steve Block44f0eee2011-05-26 01:26:41 +01004011
4012 // Groups are deleted, rebuild groups.
4013 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004014 UniqueId id1 = MakeUniqueId(g1s1.handle);
4015 UniqueId id2 = MakeUniqueId(g2s2.handle);
4016 iso->SetObjectGroupId(g1s1.handle, id1);
4017 iso->SetObjectGroupId(g1s2.handle, id1);
4018 iso->SetReference(g1s1.handle, g1c1.handle);
4019 iso->SetObjectGroupId(g2s1.handle, id2);
4020 iso->SetObjectGroupId(g2s2.handle, id2);
4021 iso->SetReferenceFromGroup(id2, g2c1.handle);
Steve Block44f0eee2011-05-26 01:26:41 +01004022 }
4023
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004024 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4025
4026 // All objects should be gone. 5 global handles in total.
4027 CHECK_EQ(5, counter.NumberOfWeakCalls());
4028
4029 // And now make children weak again and collect them.
4030 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4031 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4032
4033 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4034 CHECK_EQ(7, counter.NumberOfWeakCalls());
4035}
4036
4037
4038THREADED_TEST(ApiObjectGroupsCycle) {
4039 LocalContext env;
4040 v8::Isolate* iso = env->GetIsolate();
4041 HandleScope scope(iso);
4042
4043 WeakCallCounter counter(1234);
4044
4045 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4046 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4047 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4048 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4049 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4050 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4051 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4052 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4053
4054 {
4055 HandleScope scope(iso);
4056 g1s1.handle.Reset(iso, Object::New(iso));
4057 g1s2.handle.Reset(iso, Object::New(iso));
4058 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4059 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4060 CHECK(g1s1.handle.IsWeak());
4061 CHECK(g1s2.handle.IsWeak());
4062
4063 g2s1.handle.Reset(iso, Object::New(iso));
4064 g2s2.handle.Reset(iso, Object::New(iso));
4065 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4066 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4067 CHECK(g2s1.handle.IsWeak());
4068 CHECK(g2s2.handle.IsWeak());
4069
4070 g3s1.handle.Reset(iso, Object::New(iso));
4071 g3s2.handle.Reset(iso, Object::New(iso));
4072 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4073 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4074 CHECK(g3s1.handle.IsWeak());
4075 CHECK(g3s2.handle.IsWeak());
4076
4077 g4s1.handle.Reset(iso, Object::New(iso));
4078 g4s2.handle.Reset(iso, Object::New(iso));
4079 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4080 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4081 CHECK(g4s1.handle.IsWeak());
4082 CHECK(g4s2.handle.IsWeak());
4083 }
4084
4085 WeakCallCounterAndPersistent<Value> root(&counter);
4086 root.handle.Reset(iso, g1s1.handle); // make a root.
4087
4088 // Connect groups. We're building the following cycle:
4089 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4090 // groups.
4091 {
4092 UniqueId id1 = MakeUniqueId(g1s1.handle);
4093 UniqueId id2 = MakeUniqueId(g2s1.handle);
4094 UniqueId id3 = MakeUniqueId(g3s1.handle);
4095 UniqueId id4 = MakeUniqueId(g4s1.handle);
4096 iso->SetObjectGroupId(g1s1.handle, id1);
4097 iso->SetObjectGroupId(g1s2.handle, id1);
4098 iso->SetReferenceFromGroup(id1, g2s1.handle);
4099 iso->SetObjectGroupId(g2s1.handle, id2);
4100 iso->SetObjectGroupId(g2s2.handle, id2);
4101 iso->SetReferenceFromGroup(id2, g3s1.handle);
4102 iso->SetObjectGroupId(g3s1.handle, id3);
4103 iso->SetObjectGroupId(g3s2.handle, id3);
4104 iso->SetReferenceFromGroup(id3, g4s1.handle);
4105 iso->SetObjectGroupId(g4s1.handle, id4);
4106 iso->SetObjectGroupId(g4s2.handle, id4);
4107 iso->SetReferenceFromGroup(id4, g1s1.handle);
4108 }
4109 // Do a single full GC
4110 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4111 iso)->heap();
4112 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4113
4114 // All object should be alive.
4115 CHECK_EQ(0, counter.NumberOfWeakCalls());
4116
4117 // Weaken the root.
4118 root.handle.SetWeak(&root, &WeakPointerCallback);
4119
4120 // Groups are deleted, rebuild groups.
4121 {
4122 UniqueId id1 = MakeUniqueId(g1s1.handle);
4123 UniqueId id2 = MakeUniqueId(g2s1.handle);
4124 UniqueId id3 = MakeUniqueId(g3s1.handle);
4125 UniqueId id4 = MakeUniqueId(g4s1.handle);
4126 iso->SetObjectGroupId(g1s1.handle, id1);
4127 iso->SetObjectGroupId(g1s2.handle, id1);
4128 iso->SetReferenceFromGroup(id1, g2s1.handle);
4129 iso->SetObjectGroupId(g2s1.handle, id2);
4130 iso->SetObjectGroupId(g2s2.handle, id2);
4131 iso->SetReferenceFromGroup(id2, g3s1.handle);
4132 iso->SetObjectGroupId(g3s1.handle, id3);
4133 iso->SetObjectGroupId(g3s2.handle, id3);
4134 iso->SetReferenceFromGroup(id3, g4s1.handle);
4135 iso->SetObjectGroupId(g4s1.handle, id4);
4136 iso->SetObjectGroupId(g4s2.handle, id4);
4137 iso->SetReferenceFromGroup(id4, g1s1.handle);
4138 }
4139
4140 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4141
4142 // All objects should be gone. 9 global handles in total.
4143 CHECK_EQ(9, counter.NumberOfWeakCalls());
4144}
4145
4146
4147// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4148// on the buildbots, so was made non-threaded for the time being.
4149TEST(ApiObjectGroupsCycleForScavenger) {
4150 i::FLAG_stress_compaction = false;
4151 i::FLAG_gc_global = false;
4152 LocalContext env;
4153 v8::Isolate* iso = env->GetIsolate();
4154 HandleScope scope(iso);
4155
4156 WeakCallCounter counter(1234);
4157
4158 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4159 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4160 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4161 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4162 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4163 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4164
4165 {
4166 HandleScope scope(iso);
4167 g1s1.handle.Reset(iso, Object::New(iso));
4168 g1s2.handle.Reset(iso, Object::New(iso));
4169 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4170 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4171
4172 g2s1.handle.Reset(iso, Object::New(iso));
4173 g2s2.handle.Reset(iso, Object::New(iso));
4174 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4175 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4176
4177 g3s1.handle.Reset(iso, Object::New(iso));
4178 g3s2.handle.Reset(iso, Object::New(iso));
4179 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4180 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4181 }
4182
4183 // Make a root.
4184 WeakCallCounterAndPersistent<Value> root(&counter);
4185 root.handle.Reset(iso, g1s1.handle);
4186 root.handle.MarkPartiallyDependent();
4187
4188 // Connect groups. We're building the following cycle:
4189 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4190 // groups.
4191 {
4192 HandleScope handle_scope(iso);
4193 g1s1.handle.MarkPartiallyDependent();
4194 g1s2.handle.MarkPartiallyDependent();
4195 g2s1.handle.MarkPartiallyDependent();
4196 g2s2.handle.MarkPartiallyDependent();
4197 g3s1.handle.MarkPartiallyDependent();
4198 g3s2.handle.MarkPartiallyDependent();
4199 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4200 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4201 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4202 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4203 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4204 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4205 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4206 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4207 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4208 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4209 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4210 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4211 }
4212
4213 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4214 iso)->heap();
4215 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4216
4217 // All objects should be alive.
4218 CHECK_EQ(0, counter.NumberOfWeakCalls());
4219
4220 // Weaken the root.
4221 root.handle.SetWeak(&root, &WeakPointerCallback);
4222 root.handle.MarkPartiallyDependent();
4223
4224 // Groups are deleted, rebuild groups.
4225 {
4226 HandleScope handle_scope(iso);
4227 g1s1.handle.MarkPartiallyDependent();
4228 g1s2.handle.MarkPartiallyDependent();
4229 g2s1.handle.MarkPartiallyDependent();
4230 g2s2.handle.MarkPartiallyDependent();
4231 g3s1.handle.MarkPartiallyDependent();
4232 g3s2.handle.MarkPartiallyDependent();
4233 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4234 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4235 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4236 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4237 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4238 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4239 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4240 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4241 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4242 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4243 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4244 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4245 }
4246
4247 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block44f0eee2011-05-26 01:26:41 +01004248
4249 // All objects should be gone. 7 global handles in total.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004250 CHECK_EQ(7, counter.NumberOfWeakCalls());
Steve Block44f0eee2011-05-26 01:26:41 +01004251}
4252
4253
Steve Blocka7e24c12009-10-30 11:49:00 +00004254THREADED_TEST(ScriptException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004255 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004256 v8::HandleScope scope(env->GetIsolate());
4257 Local<Script> script = v8_compile("throw 'panama!';");
Steve Blocka7e24c12009-10-30 11:49:00 +00004258 v8::TryCatch try_catch;
4259 Local<Value> result = script->Run();
4260 CHECK(result.IsEmpty());
4261 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004262 String::Utf8Value exception_value(try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00004263 CHECK_EQ(*exception_value, "panama!");
4264}
4265
4266
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004267TEST(TryCatchCustomException) {
4268 LocalContext env;
4269 v8::HandleScope scope(env->GetIsolate());
4270 v8::TryCatch try_catch;
4271 CompileRun("function CustomError() { this.a = 'b'; }"
4272 "(function f() { throw new CustomError(); })();");
4273 CHECK(try_catch.HasCaught());
4274 CHECK(try_catch.Exception()->ToObject()->
4275 Get(v8_str("a"))->Equals(v8_str("b")));
4276}
4277
4278
Steve Blocka7e24c12009-10-30 11:49:00 +00004279bool message_received;
4280
4281
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004282static void check_message_0(v8::Handle<v8::Message> message,
4283 v8::Handle<Value> data) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004284 CHECK_EQ(5.76, data->NumberValue());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004285 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4286 CHECK(!message->IsSharedCrossOrigin());
Steve Blocka7e24c12009-10-30 11:49:00 +00004287 message_received = true;
4288}
4289
4290
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004291THREADED_TEST(MessageHandler0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004292 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004293 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004294 CHECK(!message_received);
Steve Blocka7e24c12009-10-30 11:49:00 +00004295 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004296 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4297 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
Steve Blocka7e24c12009-10-30 11:49:00 +00004298 script->Run();
4299 CHECK(message_received);
4300 // clear out the message listener
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004301 v8::V8::RemoveMessageListeners(check_message_0);
4302}
4303
4304
4305static void check_message_1(v8::Handle<v8::Message> message,
4306 v8::Handle<Value> data) {
4307 CHECK(data->IsNumber());
4308 CHECK_EQ(1337, data->Int32Value());
4309 CHECK(!message->IsSharedCrossOrigin());
4310 message_received = true;
4311}
4312
4313
4314TEST(MessageHandler1) {
4315 message_received = false;
4316 v8::HandleScope scope(CcTest::isolate());
4317 CHECK(!message_received);
4318 v8::V8::AddMessageListener(check_message_1);
4319 LocalContext context;
4320 CompileRun("throw 1337;");
4321 CHECK(message_received);
4322 // clear out the message listener
4323 v8::V8::RemoveMessageListeners(check_message_1);
4324}
4325
4326
4327static void check_message_2(v8::Handle<v8::Message> message,
4328 v8::Handle<Value> data) {
4329 LocalContext context;
4330 CHECK(data->IsObject());
4331 v8::Local<v8::Value> hidden_property =
4332 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4333 CHECK(v8_str("hidden value")->Equals(hidden_property));
4334 CHECK(!message->IsSharedCrossOrigin());
4335 message_received = true;
4336}
4337
4338
4339TEST(MessageHandler2) {
4340 message_received = false;
4341 v8::HandleScope scope(CcTest::isolate());
4342 CHECK(!message_received);
4343 v8::V8::AddMessageListener(check_message_2);
4344 LocalContext context;
4345 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4346 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4347 v8_str("hidden value"));
4348 context->Global()->Set(v8_str("error"), error);
4349 CompileRun("throw error;");
4350 CHECK(message_received);
4351 // clear out the message listener
4352 v8::V8::RemoveMessageListeners(check_message_2);
4353}
4354
4355
4356static void check_message_3(v8::Handle<v8::Message> message,
4357 v8::Handle<Value> data) {
4358 CHECK(message->IsSharedCrossOrigin());
4359 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4360 message_received = true;
4361}
4362
4363
4364TEST(MessageHandler3) {
4365 message_received = false;
4366 v8::Isolate* isolate = CcTest::isolate();
4367 v8::HandleScope scope(isolate);
4368 CHECK(!message_received);
4369 v8::V8::AddMessageListener(check_message_3);
4370 LocalContext context;
4371 v8::ScriptOrigin origin =
4372 v8::ScriptOrigin(v8_str("6.75"),
4373 v8::Integer::New(isolate, 1),
4374 v8::Integer::New(isolate, 2),
4375 v8::True(isolate));
4376 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4377 &origin);
4378 script->Run();
4379 CHECK(message_received);
4380 // clear out the message listener
4381 v8::V8::RemoveMessageListeners(check_message_3);
4382}
4383
4384
4385static void check_message_4(v8::Handle<v8::Message> message,
4386 v8::Handle<Value> data) {
4387 CHECK(!message->IsSharedCrossOrigin());
4388 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4389 message_received = true;
4390}
4391
4392
4393TEST(MessageHandler4) {
4394 message_received = false;
4395 v8::Isolate* isolate = CcTest::isolate();
4396 v8::HandleScope scope(isolate);
4397 CHECK(!message_received);
4398 v8::V8::AddMessageListener(check_message_4);
4399 LocalContext context;
4400 v8::ScriptOrigin origin =
4401 v8::ScriptOrigin(v8_str("6.75"),
4402 v8::Integer::New(isolate, 1),
4403 v8::Integer::New(isolate, 2),
4404 v8::False(isolate));
4405 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4406 &origin);
4407 script->Run();
4408 CHECK(message_received);
4409 // clear out the message listener
4410 v8::V8::RemoveMessageListeners(check_message_4);
4411}
4412
4413
4414static void check_message_5a(v8::Handle<v8::Message> message,
4415 v8::Handle<Value> data) {
4416 CHECK(message->IsSharedCrossOrigin());
4417 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4418 message_received = true;
4419}
4420
4421
4422static void check_message_5b(v8::Handle<v8::Message> message,
4423 v8::Handle<Value> data) {
4424 CHECK(!message->IsSharedCrossOrigin());
4425 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4426 message_received = true;
4427}
4428
4429
4430TEST(MessageHandler5) {
4431 message_received = false;
4432 v8::Isolate* isolate = CcTest::isolate();
4433 v8::HandleScope scope(isolate);
4434 CHECK(!message_received);
4435 v8::V8::AddMessageListener(check_message_5a);
4436 LocalContext context;
4437 v8::ScriptOrigin origin =
4438 v8::ScriptOrigin(v8_str("6.75"),
4439 v8::Integer::New(isolate, 1),
4440 v8::Integer::New(isolate, 2),
4441 v8::True(isolate));
4442 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4443 &origin);
4444 script->Run();
4445 CHECK(message_received);
4446 // clear out the message listener
4447 v8::V8::RemoveMessageListeners(check_message_5a);
4448
4449 message_received = false;
4450 v8::V8::AddMessageListener(check_message_5b);
4451 origin =
4452 v8::ScriptOrigin(v8_str("6.75"),
4453 v8::Integer::New(isolate, 1),
4454 v8::Integer::New(isolate, 2),
4455 v8::False(isolate));
4456 script = Script::Compile(v8_str("throw 'error'"),
4457 &origin);
4458 script->Run();
4459 CHECK(message_received);
4460 // clear out the message listener
4461 v8::V8::RemoveMessageListeners(check_message_5b);
Steve Blocka7e24c12009-10-30 11:49:00 +00004462}
4463
4464
4465THREADED_TEST(GetSetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004466 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004467 v8::Isolate* isolate = context->GetIsolate();
4468 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004469 context->Global()->Set(v8_str("foo"), v8_num(14));
4470 context->Global()->Set(v8_str("12"), v8_num(92));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004471 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
Steve Blocka7e24c12009-10-30 11:49:00 +00004472 context->Global()->Set(v8_num(13), v8_num(56));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004473 Local<Value> foo = CompileRun("this.foo");
Steve Blocka7e24c12009-10-30 11:49:00 +00004474 CHECK_EQ(14, foo->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004475 Local<Value> twelve = CompileRun("this[12]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004476 CHECK_EQ(92, twelve->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004477 Local<Value> sixteen = CompileRun("this[16]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004478 CHECK_EQ(32, sixteen->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004479 Local<Value> thirteen = CompileRun("this[13]");
Steve Blocka7e24c12009-10-30 11:49:00 +00004480 CHECK_EQ(56, thirteen->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004481 CHECK_EQ(92,
4482 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004483 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4484 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004485 CHECK_EQ(32,
4486 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004487 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4488 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004489 CHECK_EQ(56,
4490 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004491 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4492 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4493}
4494
4495
4496THREADED_TEST(PropertyAttributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004497 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004498 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004499 // none
4500 Local<String> prop = v8_str("none");
4501 context->Global()->Set(prop, v8_num(7));
4502 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
Steve Blocka7e24c12009-10-30 11:49:00 +00004503 // read-only
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004504 prop = v8_str("read_only");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004505 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +00004506 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004507 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004508 CompileRun("read_only = 9");
Steve Blocka7e24c12009-10-30 11:49:00 +00004509 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4510 context->Global()->Set(prop, v8_num(10));
4511 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4512 // dont-delete
4513 prop = v8_str("dont_delete");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004514 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +00004515 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004516 CompileRun("delete dont_delete");
Steve Blocka7e24c12009-10-30 11:49:00 +00004517 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004518 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4519 // dont-enum
4520 prop = v8_str("dont_enum");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004521 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004522 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4523 // absent
4524 prop = v8_str("absent");
4525 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4526 Local<Value> fake_prop = v8_num(1);
4527 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4528 // exception
4529 TryCatch try_catch;
4530 Local<Value> exception =
4531 CompileRun("({ toString: function() { throw 'exception';} })");
4532 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4533 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004534 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004535 CHECK_EQ("exception", *exception_value);
4536 try_catch.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00004537}
4538
4539
4540THREADED_TEST(Array) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004541 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004542 v8::HandleScope scope(context->GetIsolate());
4543 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004544 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004545 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00004546 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01004547 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00004548 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01004549 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00004550 CHECK_EQ(3, array->Length());
4551 CHECK(!array->Has(0));
4552 CHECK(!array->Has(1));
4553 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01004554 CHECK_EQ(7, array->Get(2)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004555 Local<Value> obj = CompileRun("[1, 2, 3]");
Steve Block6ded16b2010-05-10 14:33:55 +01004556 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004557 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004558 CHECK_EQ(1, arr->Get(0)->Int32Value());
4559 CHECK_EQ(2, arr->Get(1)->Int32Value());
4560 CHECK_EQ(3, arr->Get(2)->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004561 array = v8::Array::New(context->GetIsolate(), 27);
Steve Block44f0eee2011-05-26 01:26:41 +01004562 CHECK_EQ(27, array->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004563 array = v8::Array::New(context->GetIsolate(), -27);
Steve Block44f0eee2011-05-26 01:26:41 +01004564 CHECK_EQ(0, array->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004565}
4566
4567
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004568void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4569 v8::EscapableHandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004570 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004571 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004572 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01004573 result->Set(i, args[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004574 args.GetReturnValue().Set(scope.Escape(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00004575}
4576
4577
4578THREADED_TEST(Vector) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004579 v8::Isolate* isolate = CcTest::isolate();
4580 v8::HandleScope scope(isolate);
4581 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4582 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
Steve Blocka7e24c12009-10-30 11:49:00 +00004583 LocalContext context(0, global);
4584
4585 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01004586 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004587 CHECK_EQ(0, a0->Length());
4588
4589 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01004590 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004591 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004592 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004593
4594 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01004595 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004596 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004597 CHECK_EQ(12, a2->Get(0)->Int32Value());
4598 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004599
4600 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01004601 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004602 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004603 CHECK_EQ(14, a3->Get(0)->Int32Value());
4604 CHECK_EQ(15, a3->Get(1)->Int32Value());
4605 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004606
4607 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01004608 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004609 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01004610 CHECK_EQ(17, a4->Get(0)->Int32Value());
4611 CHECK_EQ(18, a4->Get(1)->Int32Value());
4612 CHECK_EQ(19, a4->Get(2)->Int32Value());
4613 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004614}
4615
4616
4617THREADED_TEST(FunctionCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004618 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004619 v8::Isolate* isolate = context->GetIsolate();
4620 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004621 CompileRun(
4622 "function Foo() {"
4623 " var result = [];"
4624 " for (var i = 0; i < arguments.length; i++) {"
4625 " result.push(arguments[i]);"
4626 " }"
4627 " return result;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004628 "}"
4629 "function ReturnThisSloppy() {"
4630 " return this;"
4631 "}"
4632 "function ReturnThisStrict() {"
4633 " 'use strict';"
4634 " return this;"
Steve Blocka7e24c12009-10-30 11:49:00 +00004635 "}");
4636 Local<Function> Foo =
4637 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004638 Local<Function> ReturnThisSloppy =
4639 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4640 Local<Function> ReturnThisStrict =
4641 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
Steve Blocka7e24c12009-10-30 11:49:00 +00004642
4643 v8::Handle<Value>* args0 = NULL;
4644 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4645 CHECK_EQ(0, a0->Length());
4646
4647 v8::Handle<Value> args1[] = { v8_num(1.1) };
4648 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4649 CHECK_EQ(1, a1->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004650 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004651
4652 v8::Handle<Value> args2[] = { v8_num(2.2),
4653 v8_num(3.3) };
4654 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4655 CHECK_EQ(2, a2->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004656 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4657 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004658
4659 v8::Handle<Value> args3[] = { v8_num(4.4),
4660 v8_num(5.5),
4661 v8_num(6.6) };
4662 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4663 CHECK_EQ(3, a3->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004664 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4665 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4666 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004667
4668 v8::Handle<Value> args4[] = { v8_num(7.7),
4669 v8_num(8.8),
4670 v8_num(9.9),
4671 v8_num(10.11) };
4672 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4673 CHECK_EQ(4, a4->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004674 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4675 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4676 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4677 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004678
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004679 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4680 CHECK(r1->StrictEquals(context->Global()));
4681 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4682 CHECK(r2->StrictEquals(context->Global()));
4683 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4684 CHECK(r3->IsNumberObject());
4685 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4686 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4687 CHECK(r4->IsStringObject());
4688 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4689 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4690 CHECK(r5->IsBooleanObject());
4691 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
Steve Blocka7e24c12009-10-30 11:49:00 +00004692
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004693 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4694 CHECK(r6->IsUndefined());
4695 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4696 CHECK(r7->IsNull());
4697 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4698 CHECK(r8->StrictEquals(v8_num(42)));
4699 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4700 CHECK(r9->StrictEquals(v8_str("hello")));
4701 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4702 CHECK(r10->StrictEquals(v8::True(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00004703}
4704
4705
4706THREADED_TEST(ConstructCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004707 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004708 v8::Isolate* isolate = context->GetIsolate();
4709 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004710 CompileRun(
4711 "function Foo() {"
4712 " var result = [];"
4713 " for (var i = 0; i < arguments.length; i++) {"
4714 " result.push(arguments[i]);"
4715 " }"
4716 " return result;"
4717 "}");
4718 Local<Function> Foo =
4719 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4720
4721 v8::Handle<Value>* args0 = NULL;
4722 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4723 CHECK_EQ(0, a0->Length());
4724
4725 v8::Handle<Value> args1[] = { v8_num(1.1) };
4726 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4727 CHECK_EQ(1, a1->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004728 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004729
4730 v8::Handle<Value> args2[] = { v8_num(2.2),
4731 v8_num(3.3) };
4732 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4733 CHECK_EQ(2, a2->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004734 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4735 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004736
4737 v8::Handle<Value> args3[] = { v8_num(4.4),
4738 v8_num(5.5),
4739 v8_num(6.6) };
4740 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4741 CHECK_EQ(3, a3->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004742 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4743 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4744 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004745
4746 v8::Handle<Value> args4[] = { v8_num(7.7),
4747 v8_num(8.8),
4748 v8_num(9.9),
4749 v8_num(10.11) };
4750 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4751 CHECK_EQ(4, a4->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004752 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4753 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4754 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4755 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00004756}
4757
4758
4759static void CheckUncle(v8::TryCatch* try_catch) {
4760 CHECK(try_catch->HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004761 String::Utf8Value str_value(try_catch->Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00004762 CHECK_EQ(*str_value, "uncle?");
4763 try_catch->Reset();
4764}
4765
4766
Steve Block6ded16b2010-05-10 14:33:55 +01004767THREADED_TEST(ConversionNumber) {
Steve Block6ded16b2010-05-10 14:33:55 +01004768 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004769 v8::HandleScope scope(env->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01004770 // Very large number.
4771 CompileRun("var obj = Math.pow(2,32) * 1237;");
4772 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4773 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4774 CHECK_EQ(0, obj->ToInt32()->Value());
4775 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4776 // Large number.
4777 CompileRun("var obj = -1234567890123;");
4778 obj = env->Global()->Get(v8_str("obj"));
4779 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4780 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4781 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4782 // Small positive integer.
4783 CompileRun("var obj = 42;");
4784 obj = env->Global()->Get(v8_str("obj"));
4785 CHECK_EQ(42.0, obj->ToNumber()->Value());
4786 CHECK_EQ(42, obj->ToInt32()->Value());
4787 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4788 // Negative integer.
4789 CompileRun("var obj = -37;");
4790 obj = env->Global()->Get(v8_str("obj"));
4791 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4792 CHECK_EQ(-37, obj->ToInt32()->Value());
4793 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4794 // Positive non-int32 integer.
4795 CompileRun("var obj = 0x81234567;");
4796 obj = env->Global()->Get(v8_str("obj"));
4797 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4798 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4799 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4800 // Fraction.
4801 CompileRun("var obj = 42.3;");
4802 obj = env->Global()->Get(v8_str("obj"));
4803 CHECK_EQ(42.3, obj->ToNumber()->Value());
4804 CHECK_EQ(42, obj->ToInt32()->Value());
4805 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4806 // Large negative fraction.
4807 CompileRun("var obj = -5726623061.75;");
4808 obj = env->Global()->Get(v8_str("obj"));
4809 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4810 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4811 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4812}
4813
4814
4815THREADED_TEST(isNumberType) {
Steve Block6ded16b2010-05-10 14:33:55 +01004816 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004817 v8::HandleScope scope(env->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01004818 // Very large number.
4819 CompileRun("var obj = Math.pow(2,32) * 1237;");
4820 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4821 CHECK(!obj->IsInt32());
4822 CHECK(!obj->IsUint32());
4823 // Large negative number.
4824 CompileRun("var obj = -1234567890123;");
4825 obj = env->Global()->Get(v8_str("obj"));
4826 CHECK(!obj->IsInt32());
4827 CHECK(!obj->IsUint32());
4828 // Small positive integer.
4829 CompileRun("var obj = 42;");
4830 obj = env->Global()->Get(v8_str("obj"));
4831 CHECK(obj->IsInt32());
4832 CHECK(obj->IsUint32());
4833 // Negative integer.
4834 CompileRun("var obj = -37;");
4835 obj = env->Global()->Get(v8_str("obj"));
4836 CHECK(obj->IsInt32());
4837 CHECK(!obj->IsUint32());
4838 // Positive non-int32 integer.
4839 CompileRun("var obj = 0x81234567;");
4840 obj = env->Global()->Get(v8_str("obj"));
4841 CHECK(!obj->IsInt32());
4842 CHECK(obj->IsUint32());
4843 // Fraction.
4844 CompileRun("var obj = 42.3;");
4845 obj = env->Global()->Get(v8_str("obj"));
4846 CHECK(!obj->IsInt32());
4847 CHECK(!obj->IsUint32());
4848 // Large negative fraction.
4849 CompileRun("var obj = -5726623061.75;");
4850 obj = env->Global()->Get(v8_str("obj"));
4851 CHECK(!obj->IsInt32());
4852 CHECK(!obj->IsUint32());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004853 // Positive zero
4854 CompileRun("var obj = 0.0;");
4855 obj = env->Global()->Get(v8_str("obj"));
4856 CHECK(obj->IsInt32());
4857 CHECK(obj->IsUint32());
4858 // Positive zero
4859 CompileRun("var obj = -0.0;");
4860 obj = env->Global()->Get(v8_str("obj"));
4861 CHECK(!obj->IsInt32());
4862 CHECK(!obj->IsUint32());
Steve Block6ded16b2010-05-10 14:33:55 +01004863}
4864
4865
Steve Blocka7e24c12009-10-30 11:49:00 +00004866THREADED_TEST(ConversionException) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004867 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004868 v8::Isolate* isolate = env->GetIsolate();
4869 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004870 CompileRun(
4871 "function TestClass() { };"
4872 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4873 "var obj = new TestClass();");
4874 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4875
4876 v8::TryCatch try_catch;
4877
4878 Local<Value> to_string_result = obj->ToString();
4879 CHECK(to_string_result.IsEmpty());
4880 CheckUncle(&try_catch);
4881
4882 Local<Value> to_number_result = obj->ToNumber();
4883 CHECK(to_number_result.IsEmpty());
4884 CheckUncle(&try_catch);
4885
4886 Local<Value> to_integer_result = obj->ToInteger();
4887 CHECK(to_integer_result.IsEmpty());
4888 CheckUncle(&try_catch);
4889
4890 Local<Value> to_uint32_result = obj->ToUint32();
4891 CHECK(to_uint32_result.IsEmpty());
4892 CheckUncle(&try_catch);
4893
4894 Local<Value> to_int32_result = obj->ToInt32();
4895 CHECK(to_int32_result.IsEmpty());
4896 CheckUncle(&try_catch);
4897
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004898 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00004899 CHECK(to_object_result.IsEmpty());
4900 CHECK(try_catch.HasCaught());
4901 try_catch.Reset();
4902
4903 int32_t int32_value = obj->Int32Value();
4904 CHECK_EQ(0, int32_value);
4905 CheckUncle(&try_catch);
4906
4907 uint32_t uint32_value = obj->Uint32Value();
4908 CHECK_EQ(0, uint32_value);
4909 CheckUncle(&try_catch);
4910
4911 double number_value = obj->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004912 CHECK_NE(0, std::isnan(number_value));
Steve Blocka7e24c12009-10-30 11:49:00 +00004913 CheckUncle(&try_catch);
4914
4915 int64_t integer_value = obj->IntegerValue();
4916 CHECK_EQ(0.0, static_cast<double>(integer_value));
4917 CheckUncle(&try_catch);
4918}
4919
4920
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004921void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004922 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004923 args.GetIsolate()->ThrowException(v8_str("konto"));
Steve Blocka7e24c12009-10-30 11:49:00 +00004924}
4925
4926
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004927void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4928 if (args.Length() < 1) {
4929 args.GetReturnValue().Set(false);
4930 return;
4931 }
4932 v8::HandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004933 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004934 Local<Value> result = CompileRun(args[0]->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00004935 CHECK(!try_catch.HasCaught() || result.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004936 args.GetReturnValue().Set(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +00004937}
4938
4939
4940THREADED_TEST(APICatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004941 v8::Isolate* isolate = CcTest::isolate();
4942 v8::HandleScope scope(isolate);
4943 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004944 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004945 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00004946 LocalContext context(0, templ);
4947 CompileRun(
4948 "var thrown = false;"
4949 "try {"
4950 " ThrowFromC();"
4951 "} catch (e) {"
4952 " thrown = true;"
4953 "}");
4954 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4955 CHECK(thrown->BooleanValue());
4956}
4957
4958
4959THREADED_TEST(APIThrowTryCatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004960 v8::Isolate* isolate = CcTest::isolate();
4961 v8::HandleScope scope(isolate);
4962 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004963 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004964 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00004965 LocalContext context(0, templ);
4966 v8::TryCatch try_catch;
4967 CompileRun("ThrowFromC();");
4968 CHECK(try_catch.HasCaught());
4969}
4970
4971
4972// Test that a try-finally block doesn't shadow a try-catch block
4973// when setting up an external handler.
4974//
4975// BUG(271): Some of the exception propagation does not work on the
4976// ARM simulator because the simulator separates the C++ stack and the
4977// JS stack. This test therefore fails on the simulator. The test is
4978// not threaded to allow the threading tests to run on the simulator.
4979TEST(TryCatchInTryFinally) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004980 v8::Isolate* isolate = CcTest::isolate();
4981 v8::HandleScope scope(isolate);
4982 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004983 templ->Set(v8_str("CCatcher"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004984 v8::FunctionTemplate::New(isolate, CCatcher));
Steve Blocka7e24c12009-10-30 11:49:00 +00004985 LocalContext context(0, templ);
4986 Local<Value> result = CompileRun("try {"
4987 " try {"
4988 " CCatcher('throw 7;');"
4989 " } finally {"
4990 " }"
4991 "} catch (e) {"
4992 "}");
4993 CHECK(result->IsTrue());
4994}
4995
4996
Ben Murdochb8e0da22011-05-16 14:20:40 +01004997static void check_reference_error_message(
4998 v8::Handle<v8::Message> message,
4999 v8::Handle<v8::Value> data) {
5000 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5001 CHECK(message->Get()->Equals(v8_str(reference_error)));
5002}
5003
5004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005005static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block1e0659c2011-05-24 12:43:12 +01005006 ApiTestFuzzer::Fuzz();
5007 CHECK(false);
Steve Block1e0659c2011-05-24 12:43:12 +01005008}
5009
5010
5011// Test that overwritten methods are not invoked on uncaught exception
5012// formatting. However, they are invoked when performing normal error
5013// string conversions.
Ben Murdochb8e0da22011-05-16 14:20:40 +01005014TEST(APIThrowMessageOverwrittenToString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005015 v8::Isolate* isolate = CcTest::isolate();
5016 v8::HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005017 v8::V8::AddMessageListener(check_reference_error_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005018 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5019 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
Steve Block1e0659c2011-05-24 12:43:12 +01005020 LocalContext context(NULL, templ);
5021 CompileRun("asdf;");
5022 CompileRun("var limit = {};"
5023 "limit.valueOf = fail;"
5024 "Error.stackTraceLimit = limit;");
5025 CompileRun("asdf");
5026 CompileRun("Array.prototype.pop = fail;");
5027 CompileRun("Object.prototype.hasOwnProperty = fail;");
5028 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5029 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5030 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
Ben Murdochb8e0da22011-05-16 14:20:40 +01005031 CompileRun("ReferenceError.prototype.toString ="
5032 " function() { return 'Whoops' }");
5033 CompileRun("asdf;");
Steve Block1e0659c2011-05-24 12:43:12 +01005034 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5035 CompileRun("asdf;");
5036 CompileRun("ReferenceError.prototype.constructor = void 0;");
5037 CompileRun("asdf;");
5038 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5039 CompileRun("asdf;");
5040 CompileRun("ReferenceError.prototype = new Object();");
5041 CompileRun("asdf;");
Ben Murdochb8e0da22011-05-16 14:20:40 +01005042 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5043 CHECK(string->Equals(v8_str("Whoops")));
Steve Block1e0659c2011-05-24 12:43:12 +01005044 CompileRun("ReferenceError.prototype.constructor = new Object();"
5045 "ReferenceError.prototype.constructor.name = 1;"
5046 "Number.prototype.toString = function() { return 'Whoops'; };"
5047 "ReferenceError.prototype.toString = Object.prototype.toString;");
5048 CompileRun("asdf;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005049 v8::V8::RemoveMessageListeners(check_reference_error_message);
5050}
5051
5052
5053static void check_custom_error_tostring(
5054 v8::Handle<v8::Message> message,
5055 v8::Handle<v8::Value> data) {
5056 const char* uncaught_error = "Uncaught MyError toString";
5057 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5058}
5059
5060
5061TEST(CustomErrorToString) {
5062 LocalContext context;
5063 v8::HandleScope scope(context->GetIsolate());
5064 v8::V8::AddMessageListener(check_custom_error_tostring);
5065 CompileRun(
5066 "function MyError(name, message) { "
5067 " this.name = name; "
5068 " this.message = message; "
5069 "} "
5070 "MyError.prototype = Object.create(Error.prototype); "
5071 "MyError.prototype.toString = function() { "
5072 " return 'MyError toString'; "
5073 "}; "
5074 "throw new MyError('my name', 'my message'); ");
5075 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5076}
5077
5078
5079static void check_custom_error_message(
5080 v8::Handle<v8::Message> message,
5081 v8::Handle<v8::Value> data) {
5082 const char* uncaught_error = "Uncaught MyError: my message";
5083 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5084 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5085}
5086
5087
5088TEST(CustomErrorMessage) {
5089 LocalContext context;
5090 v8::HandleScope scope(context->GetIsolate());
5091 v8::V8::AddMessageListener(check_custom_error_message);
5092
5093 // Handlebars.
5094 CompileRun(
5095 "function MyError(msg) { "
5096 " this.name = 'MyError'; "
5097 " this.message = msg; "
5098 "} "
5099 "MyError.prototype = new Error(); "
5100 "throw new MyError('my message'); ");
5101
5102 // Closure.
5103 CompileRun(
5104 "function MyError(msg) { "
5105 " this.name = 'MyError'; "
5106 " this.message = msg; "
5107 "} "
5108 "inherits = function(childCtor, parentCtor) { "
5109 " function tempCtor() {}; "
5110 " tempCtor.prototype = parentCtor.prototype; "
5111 " childCtor.superClass_ = parentCtor.prototype; "
5112 " childCtor.prototype = new tempCtor(); "
5113 " childCtor.prototype.constructor = childCtor; "
5114 "}; "
5115 "inherits(MyError, Error); "
5116 "throw new MyError('my message'); ");
5117
5118 // Object.create.
5119 CompileRun(
5120 "function MyError(msg) { "
5121 " this.name = 'MyError'; "
5122 " this.message = msg; "
5123 "} "
5124 "MyError.prototype = Object.create(Error.prototype); "
5125 "throw new MyError('my message'); ");
5126
5127 v8::V8::RemoveMessageListeners(check_custom_error_message);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005128}
5129
5130
Steve Blocka7e24c12009-10-30 11:49:00 +00005131static void receive_message(v8::Handle<v8::Message> message,
5132 v8::Handle<v8::Value> data) {
5133 message->Get();
5134 message_received = true;
5135}
5136
5137
5138TEST(APIThrowMessage) {
5139 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005140 v8::Isolate* isolate = CcTest::isolate();
5141 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005142 v8::V8::AddMessageListener(receive_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005143 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005144 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005145 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005146 LocalContext context(0, templ);
5147 CompileRun("ThrowFromC();");
5148 CHECK(message_received);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005149 v8::V8::RemoveMessageListeners(receive_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00005150}
5151
5152
5153TEST(APIThrowMessageAndVerboseTryCatch) {
5154 message_received = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005155 v8::Isolate* isolate = CcTest::isolate();
5156 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005157 v8::V8::AddMessageListener(receive_message);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005158 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005159 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005160 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005161 LocalContext context(0, templ);
5162 v8::TryCatch try_catch;
5163 try_catch.SetVerbose(true);
5164 Local<Value> result = CompileRun("ThrowFromC();");
5165 CHECK(try_catch.HasCaught());
5166 CHECK(result.IsEmpty());
5167 CHECK(message_received);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005168 v8::V8::RemoveMessageListeners(receive_message);
Steve Blocka7e24c12009-10-30 11:49:00 +00005169}
5170
5171
Ben Murdoch8b112d22011-06-08 16:22:53 +01005172TEST(APIStackOverflowAndVerboseTryCatch) {
5173 message_received = false;
Ben Murdoch8b112d22011-06-08 16:22:53 +01005174 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005175 v8::HandleScope scope(context->GetIsolate());
5176 v8::V8::AddMessageListener(receive_message);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005177 v8::TryCatch try_catch;
5178 try_catch.SetVerbose(true);
5179 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5180 CHECK(try_catch.HasCaught());
5181 CHECK(result.IsEmpty());
5182 CHECK(message_received);
5183 v8::V8::RemoveMessageListeners(receive_message);
5184}
5185
5186
Steve Blocka7e24c12009-10-30 11:49:00 +00005187THREADED_TEST(ExternalScriptException) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005188 v8::Isolate* isolate = CcTest::isolate();
5189 v8::HandleScope scope(isolate);
5190 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005191 templ->Set(v8_str("ThrowFromC"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005192 v8::FunctionTemplate::New(isolate, ThrowFromC));
Steve Blocka7e24c12009-10-30 11:49:00 +00005193 LocalContext context(0, templ);
5194
5195 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005196 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
Steve Blocka7e24c12009-10-30 11:49:00 +00005197 CHECK(result.IsEmpty());
5198 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005199 String::Utf8Value exception_value(try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00005200 CHECK_EQ("konto", *exception_value);
5201}
5202
5203
5204
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005205void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005206 ApiTestFuzzer::Fuzz();
5207 CHECK_EQ(4, args.Length());
5208 int count = args[0]->Int32Value();
5209 int cInterval = args[2]->Int32Value();
5210 if (count == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005211 args.GetIsolate()->ThrowException(v8_str("FromC"));
5212 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005213 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005214 Local<v8::Object> global =
5215 args.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00005216 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5217 v8::Handle<Value> argv[] = { v8_num(count - 1),
5218 args[1],
5219 args[2],
5220 args[3] };
5221 if (count % cInterval == 0) {
5222 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01005223 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00005224 int expected = args[3]->Int32Value();
5225 if (try_catch.HasCaught()) {
5226 CHECK_EQ(expected, count);
5227 CHECK(result.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005228 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00005229 } else {
5230 CHECK_NE(expected, count);
5231 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005232 args.GetReturnValue().Set(result);
5233 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005234 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005235 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5236 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005237 }
5238 }
5239}
5240
5241
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005242void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005243 ApiTestFuzzer::Fuzz();
5244 CHECK_EQ(3, args.Length());
5245 bool equality = args[0]->BooleanValue();
5246 int count = args[1]->Int32Value();
5247 int expected = args[2]->Int32Value();
5248 if (equality) {
5249 CHECK_EQ(count, expected);
5250 } else {
5251 CHECK_NE(count, expected);
5252 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005253}
5254
5255
5256THREADED_TEST(EvalInTryFinally) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005257 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005258 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005259 v8::TryCatch try_catch;
5260 CompileRun("(function() {"
5261 " try {"
5262 " eval('asldkf (*&^&*^');"
5263 " } finally {"
5264 " return;"
5265 " }"
5266 "})()");
5267 CHECK(!try_catch.HasCaught());
5268}
5269
5270
5271// This test works by making a stack of alternating JavaScript and C
5272// activations. These activations set up exception handlers with regular
5273// intervals, one interval for C activations and another for JavaScript
5274// activations. When enough activations have been created an exception is
5275// thrown and we check that the right activation catches the exception and that
5276// no other activations do. The right activation is always the topmost one with
5277// a handler, regardless of whether it is in JavaScript or C.
5278//
5279// The notation used to describe a test case looks like this:
5280//
5281// *JS[4] *C[3] @JS[2] C[1] JS[0]
5282//
5283// Each entry is an activation, either JS or C. The index is the count at that
5284// level. Stars identify activations with exception handlers, the @ identifies
5285// the exception handler that should catch the exception.
5286//
5287// BUG(271): Some of the exception propagation does not work on the
5288// ARM simulator because the simulator separates the C++ stack and the
5289// JS stack. This test therefore fails on the simulator. The test is
5290// not threaded to allow the threading tests to run on the simulator.
5291TEST(ExceptionOrder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005292 v8::Isolate* isolate = CcTest::isolate();
5293 v8::HandleScope scope(isolate);
5294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5295 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
Steve Blocka7e24c12009-10-30 11:49:00 +00005296 templ->Set(v8_str("CThrowCountDown"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005297 v8::FunctionTemplate::New(isolate, CThrowCountDown));
Steve Blocka7e24c12009-10-30 11:49:00 +00005298 LocalContext context(0, templ);
5299 CompileRun(
5300 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5301 " if (count == 0) throw 'FromJS';"
5302 " if (count % jsInterval == 0) {"
5303 " try {"
5304 " var value = CThrowCountDown(count - 1,"
5305 " jsInterval,"
5306 " cInterval,"
5307 " expected);"
5308 " check(false, count, expected);"
5309 " return value;"
5310 " } catch (e) {"
5311 " check(true, count, expected);"
5312 " }"
5313 " } else {"
5314 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5315 " }"
5316 "}");
5317 Local<Function> fun =
5318 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5319
5320 const int argc = 4;
5321 // count jsInterval cInterval expected
5322
5323 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5324 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5325 fun->Call(fun, argc, a0);
5326
5327 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5328 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5329 fun->Call(fun, argc, a1);
5330
5331 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5332 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5333 fun->Call(fun, argc, a2);
5334
5335 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5336 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5337 fun->Call(fun, argc, a3);
5338
5339 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5340 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5341 fun->Call(fun, argc, a4);
5342
5343 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5344 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5345 fun->Call(fun, argc, a5);
5346}
5347
5348
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005349void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005350 ApiTestFuzzer::Fuzz();
5351 CHECK_EQ(1, args.Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005352 args.GetIsolate()->ThrowException(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00005353}
5354
5355
5356THREADED_TEST(ThrowValues) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005357 v8::Isolate* isolate = CcTest::isolate();
5358 v8::HandleScope scope(isolate);
5359 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5360 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
Steve Blocka7e24c12009-10-30 11:49:00 +00005361 LocalContext context(0, templ);
5362 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5363 "function Run(obj) {"
5364 " try {"
5365 " Throw(obj);"
5366 " } catch (e) {"
5367 " return e;"
5368 " }"
5369 " return 'no exception';"
5370 "}"
5371 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5372 CHECK_EQ(5, result->Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005373 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5374 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5375 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5376 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5377 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5378 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5379 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00005380}
5381
5382
5383THREADED_TEST(CatchZero) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005384 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005385 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005386 v8::TryCatch try_catch;
5387 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005388 CompileRun("throw 10");
Steve Blocka7e24c12009-10-30 11:49:00 +00005389 CHECK(try_catch.HasCaught());
5390 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5391 try_catch.Reset();
5392 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005393 CompileRun("throw 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00005394 CHECK(try_catch.HasCaught());
5395 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5396}
5397
5398
5399THREADED_TEST(CatchExceptionFromWith) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005400 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005401 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005402 v8::TryCatch try_catch;
5403 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005404 CompileRun("var o = {}; with (o) { throw 42; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00005405 CHECK(try_catch.HasCaught());
5406}
5407
5408
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005409THREADED_TEST(TryCatchAndFinallyHidingException) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005410 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005411 v8::HandleScope scope(context->GetIsolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005412 v8::TryCatch try_catch;
5413 CHECK(!try_catch.HasCaught());
5414 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5415 CompileRun("f({toString: function() { throw 42; }});");
5416 CHECK(!try_catch.HasCaught());
5417}
5418
5419
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005420void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005421 v8::TryCatch try_catch;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005422}
5423
5424
5425THREADED_TEST(TryCatchAndFinally) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005426 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005427 v8::Isolate* isolate = context->GetIsolate();
5428 v8::HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005429 context->Global()->Set(
5430 v8_str("native_with_try_catch"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005431 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005432 v8::TryCatch try_catch;
5433 CHECK(!try_catch.HasCaught());
5434 CompileRun(
5435 "try {\n"
5436 " throw new Error('a');\n"
5437 "} finally {\n"
5438 " native_with_try_catch();\n"
5439 "}\n");
5440 CHECK(try_catch.HasCaught());
5441}
5442
5443
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005444static void TryCatchNested1Helper(int depth) {
5445 if (depth > 0) {
5446 v8::TryCatch try_catch;
5447 try_catch.SetVerbose(true);
5448 TryCatchNested1Helper(depth - 1);
5449 CHECK(try_catch.HasCaught());
5450 try_catch.ReThrow();
5451 } else {
5452 CcTest::isolate()->ThrowException(v8_str("E1"));
5453 }
5454}
5455
5456
5457static void TryCatchNested2Helper(int depth) {
5458 if (depth > 0) {
5459 v8::TryCatch try_catch;
5460 try_catch.SetVerbose(true);
5461 TryCatchNested2Helper(depth - 1);
5462 CHECK(try_catch.HasCaught());
5463 try_catch.ReThrow();
5464 } else {
5465 CompileRun("throw 'E2';");
5466 }
5467}
5468
5469
5470TEST(TryCatchNested) {
5471 v8::V8::Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00005472 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005473 v8::HandleScope scope(context->GetIsolate());
5474
5475 {
5476 // Test nested try-catch with a native throw in the end.
5477 v8::TryCatch try_catch;
5478 TryCatchNested1Helper(5);
5479 CHECK(try_catch.HasCaught());
5480 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5481 }
5482
5483 {
5484 // Test nested try-catch with a JavaScript throw in the end.
5485 v8::TryCatch try_catch;
5486 TryCatchNested2Helper(5);
5487 CHECK(try_catch.HasCaught());
5488 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5489 }
5490}
5491
5492
5493void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5494 CHECK(try_catch->HasCaught());
5495 Handle<Message> message = try_catch->Message();
5496 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5497 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5498 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5499 "Uncaught Error: a"));
5500 CHECK_EQ(1, message->GetLineNumber());
5501 CHECK_EQ(6, message->GetStartColumn());
5502}
5503
5504
5505void TryCatchMixedNestingHelper(
5506 const v8::FunctionCallbackInfo<v8::Value>& args) {
5507 ApiTestFuzzer::Fuzz();
5508 v8::TryCatch try_catch;
5509 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5510 CHECK(try_catch.HasCaught());
5511 TryCatchMixedNestingCheck(&try_catch);
5512 try_catch.ReThrow();
5513}
5514
5515
5516// This test ensures that an outer TryCatch in the following situation:
5517// C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5518// does not clobber the Message object generated for the inner TryCatch.
5519// This exercises the ability of TryCatch.ReThrow() to restore the
5520// inner pending Message before throwing the exception again.
5521TEST(TryCatchMixedNesting) {
5522 v8::Isolate* isolate = CcTest::isolate();
5523 v8::HandleScope scope(isolate);
5524 v8::V8::Initialize();
5525 v8::TryCatch try_catch;
5526 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5527 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5528 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5529 LocalContext context(0, templ);
5530 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5531 TryCatchMixedNestingCheck(&try_catch);
5532}
5533
5534
5535void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5536 ApiTestFuzzer::Fuzz();
5537 v8::TryCatch try_catch;
5538 args.GetIsolate()->ThrowException(v8_str("boom"));
5539 CHECK(try_catch.HasCaught());
5540}
5541
5542
5543TEST(TryCatchNative) {
5544 v8::Isolate* isolate = CcTest::isolate();
5545 v8::HandleScope scope(isolate);
5546 v8::V8::Initialize();
5547 v8::TryCatch try_catch;
5548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5549 templ->Set(v8_str("TryCatchNativeHelper"),
5550 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5551 LocalContext context(0, templ);
5552 CompileRun("TryCatchNativeHelper();");
5553 CHECK(!try_catch.HasCaught());
5554}
5555
5556
5557void TryCatchNativeResetHelper(
5558 const v8::FunctionCallbackInfo<v8::Value>& args) {
5559 ApiTestFuzzer::Fuzz();
5560 v8::TryCatch try_catch;
5561 args.GetIsolate()->ThrowException(v8_str("boom"));
5562 CHECK(try_catch.HasCaught());
5563 try_catch.Reset();
5564 CHECK(!try_catch.HasCaught());
5565}
5566
5567
5568TEST(TryCatchNativeReset) {
5569 v8::Isolate* isolate = CcTest::isolate();
5570 v8::HandleScope scope(isolate);
5571 v8::V8::Initialize();
5572 v8::TryCatch try_catch;
5573 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5574 templ->Set(v8_str("TryCatchNativeResetHelper"),
5575 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5576 LocalContext context(0, templ);
5577 CompileRun("TryCatchNativeResetHelper();");
5578 CHECK(!try_catch.HasCaught());
5579}
5580
5581
5582THREADED_TEST(Equality) {
5583 LocalContext context;
5584 v8::Isolate* isolate = context->GetIsolate();
5585 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00005586 // Check that equality works at all before relying on CHECK_EQ
5587 CHECK(v8_str("a")->Equals(v8_str("a")));
5588 CHECK(!v8_str("a")->Equals(v8_str("b")));
5589
5590 CHECK_EQ(v8_str("a"), v8_str("a"));
5591 CHECK_NE(v8_str("a"), v8_str("b"));
5592 CHECK_EQ(v8_num(1), v8_num(1));
5593 CHECK_EQ(v8_num(1.00), v8_num(1));
5594 CHECK_NE(v8_num(1), v8_num(2));
5595
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005596 // Assume String is not internalized.
Steve Blocka7e24c12009-10-30 11:49:00 +00005597 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5598 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5599 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5600 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5601 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005602 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5603 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005604 CHECK(!not_a_number->StrictEquals(not_a_number));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005605 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5606 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00005607
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005608 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5609 v8::Persistent<v8::Object> alias(isolate, obj);
5610 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5611 alias.Reset();
5612
5613 CHECK(v8_str("a")->SameValue(v8_str("a")));
5614 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5615 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5616 CHECK(v8_num(1)->SameValue(v8_num(1)));
5617 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5618 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5619 CHECK(not_a_number->SameValue(not_a_number));
5620 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5621 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +00005622}
5623
5624
5625THREADED_TEST(MultiRun) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005626 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005627 v8::HandleScope scope(context->GetIsolate());
5628 Local<Script> script = v8_compile("x");
Steve Blocka7e24c12009-10-30 11:49:00 +00005629 for (int i = 0; i < 10; i++)
5630 script->Run();
5631}
5632
5633
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005634static void GetXValue(Local<String> name,
5635 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005636 ApiTestFuzzer::Fuzz();
5637 CHECK_EQ(info.Data(), v8_str("donut"));
5638 CHECK_EQ(name, v8_str("x"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005639 info.GetReturnValue().Set(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00005640}
5641
5642
5643THREADED_TEST(SimplePropertyRead) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005644 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005645 v8::Isolate* isolate = context->GetIsolate();
5646 v8::HandleScope scope(isolate);
5647 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5648 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
Steve Blocka7e24c12009-10-30 11:49:00 +00005649 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005650 Local<Script> script = v8_compile("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00005651 for (int i = 0; i < 10; i++) {
5652 Local<Value> result = script->Run();
5653 CHECK_EQ(result, v8_str("x"));
5654 }
5655}
5656
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005657
Andrei Popescu31002712010-02-23 13:46:05 +00005658THREADED_TEST(DefinePropertyOnAPIAccessor) {
Andrei Popescu31002712010-02-23 13:46:05 +00005659 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005660 v8::Isolate* isolate = context->GetIsolate();
5661 v8::HandleScope scope(isolate);
5662 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5663 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
Andrei Popescu31002712010-02-23 13:46:05 +00005664 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5665
5666 // Uses getOwnPropertyDescriptor to check the configurable status
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005667 Local<Script> script_desc = v8_compile(
5668 "var prop = Object.getOwnPropertyDescriptor( "
5669 "obj, 'x');"
5670 "prop.configurable;");
Andrei Popescu31002712010-02-23 13:46:05 +00005671 Local<Value> result = script_desc->Run();
5672 CHECK_EQ(result->BooleanValue(), true);
5673
5674 // Redefine get - but still configurable
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005675 Local<Script> script_define = v8_compile(
5676 "var desc = { get: function(){return 42; },"
5677 " configurable: true };"
5678 "Object.defineProperty(obj, 'x', desc);"
5679 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00005680 result = script_define->Run();
5681 CHECK_EQ(result, v8_num(42));
5682
5683 // Check that the accessor is still configurable
5684 result = script_desc->Run();
5685 CHECK_EQ(result->BooleanValue(), true);
5686
5687 // Redefine to a non-configurable
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005688 script_define = v8_compile(
5689 "var desc = { get: function(){return 43; },"
5690 " configurable: false };"
5691 "Object.defineProperty(obj, 'x', desc);"
5692 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00005693 result = script_define->Run();
5694 CHECK_EQ(result, v8_num(43));
5695 result = script_desc->Run();
5696 CHECK_EQ(result->BooleanValue(), false);
5697
5698 // Make sure that it is not possible to redefine again
5699 v8::TryCatch try_catch;
5700 result = script_define->Run();
5701 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005702 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005703 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00005704}
5705
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005706
Andrei Popescu31002712010-02-23 13:46:05 +00005707THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005708 v8::Isolate* isolate = CcTest::isolate();
5709 v8::HandleScope scope(isolate);
5710 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00005711 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5712 LocalContext context;
5713 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5714
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005715 Local<Script> script_desc = v8_compile(
5716 "var prop ="
5717 "Object.getOwnPropertyDescriptor( "
5718 "obj, 'x');"
5719 "prop.configurable;");
Andrei Popescu31002712010-02-23 13:46:05 +00005720 Local<Value> result = script_desc->Run();
5721 CHECK_EQ(result->BooleanValue(), true);
5722
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005723 Local<Script> script_define = v8_compile(
5724 "var desc = {get: function(){return 42; },"
5725 " configurable: true };"
5726 "Object.defineProperty(obj, 'x', desc);"
5727 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00005728 result = script_define->Run();
5729 CHECK_EQ(result, v8_num(42));
5730
5731
5732 result = script_desc->Run();
5733 CHECK_EQ(result->BooleanValue(), true);
5734
5735
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005736 script_define = v8_compile(
5737 "var desc = {get: function(){return 43; },"
5738 " configurable: false };"
5739 "Object.defineProperty(obj, 'x', desc);"
5740 "obj.x");
Andrei Popescu31002712010-02-23 13:46:05 +00005741 result = script_define->Run();
5742 CHECK_EQ(result, v8_num(43));
5743 result = script_desc->Run();
5744
5745 CHECK_EQ(result->BooleanValue(), false);
5746
5747 v8::TryCatch try_catch;
5748 result = script_define->Run();
5749 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005750 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005751 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Andrei Popescu31002712010-02-23 13:46:05 +00005752}
5753
5754
Leon Clarkef7060e22010-06-03 12:02:55 +01005755static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5756 char const* name) {
5757 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5758}
Andrei Popescu31002712010-02-23 13:46:05 +00005759
5760
Leon Clarkef7060e22010-06-03 12:02:55 +01005761THREADED_TEST(DefineAPIAccessorOnObject) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005762 v8::Isolate* isolate = CcTest::isolate();
5763 v8::HandleScope scope(isolate);
5764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01005765 LocalContext context;
5766
5767 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5768 CompileRun("var obj2 = {};");
5769
5770 CHECK(CompileRun("obj1.x")->IsUndefined());
5771 CHECK(CompileRun("obj2.x")->IsUndefined());
5772
5773 CHECK(GetGlobalProperty(&context, "obj1")->
5774 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5775
5776 ExpectString("obj1.x", "x");
5777 CHECK(CompileRun("obj2.x")->IsUndefined());
5778
5779 CHECK(GetGlobalProperty(&context, "obj2")->
5780 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5781
5782 ExpectString("obj1.x", "x");
5783 ExpectString("obj2.x", "x");
5784
5785 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5786 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5787
5788 CompileRun("Object.defineProperty(obj1, 'x',"
5789 "{ get: function() { return 'y'; }, configurable: true })");
5790
5791 ExpectString("obj1.x", "y");
5792 ExpectString("obj2.x", "x");
5793
5794 CompileRun("Object.defineProperty(obj2, 'x',"
5795 "{ get: function() { return 'y'; }, configurable: true })");
5796
5797 ExpectString("obj1.x", "y");
5798 ExpectString("obj2.x", "y");
5799
5800 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5801 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5802
5803 CHECK(GetGlobalProperty(&context, "obj1")->
5804 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5805 CHECK(GetGlobalProperty(&context, "obj2")->
5806 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5807
5808 ExpectString("obj1.x", "x");
5809 ExpectString("obj2.x", "x");
5810
5811 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5812 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5813
5814 // Define getters/setters, but now make them not configurable.
5815 CompileRun("Object.defineProperty(obj1, 'x',"
5816 "{ get: function() { return 'z'; }, configurable: false })");
5817 CompileRun("Object.defineProperty(obj2, 'x',"
5818 "{ get: function() { return 'z'; }, configurable: false })");
5819
5820 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5821 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5822
5823 ExpectString("obj1.x", "z");
5824 ExpectString("obj2.x", "z");
5825
5826 CHECK(!GetGlobalProperty(&context, "obj1")->
5827 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5828 CHECK(!GetGlobalProperty(&context, "obj2")->
5829 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5830
5831 ExpectString("obj1.x", "z");
5832 ExpectString("obj2.x", "z");
5833}
5834
5835
5836THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005837 v8::Isolate* isolate = CcTest::isolate();
5838 v8::HandleScope scope(isolate);
5839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01005840 LocalContext context;
5841
5842 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5843 CompileRun("var obj2 = {};");
5844
5845 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5846 v8_str("x"),
5847 GetXValue, NULL,
5848 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5849 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5850 v8_str("x"),
5851 GetXValue, NULL,
5852 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5853
5854 ExpectString("obj1.x", "x");
5855 ExpectString("obj2.x", "x");
5856
5857 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5858 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5859
5860 CHECK(!GetGlobalProperty(&context, "obj1")->
5861 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5862 CHECK(!GetGlobalProperty(&context, "obj2")->
5863 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5864
5865 {
5866 v8::TryCatch try_catch;
5867 CompileRun("Object.defineProperty(obj1, 'x',"
5868 "{get: function() { return 'func'; }})");
5869 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005870 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005871 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01005872 }
5873 {
5874 v8::TryCatch try_catch;
5875 CompileRun("Object.defineProperty(obj2, 'x',"
5876 "{get: function() { return 'func'; }})");
5877 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005878 String::Utf8Value exception_value(try_catch.Exception());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005879 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
Leon Clarkef7060e22010-06-03 12:02:55 +01005880 }
5881}
5882
5883
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005884static void Get239Value(Local<String> name,
5885 const v8::PropertyCallbackInfo<v8::Value>& info) {
Leon Clarkef7060e22010-06-03 12:02:55 +01005886 ApiTestFuzzer::Fuzz();
5887 CHECK_EQ(info.Data(), v8_str("donut"));
5888 CHECK_EQ(name, v8_str("239"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005889 info.GetReturnValue().Set(name);
Leon Clarkef7060e22010-06-03 12:02:55 +01005890}
5891
5892
5893THREADED_TEST(ElementAPIAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005894 v8::Isolate* isolate = CcTest::isolate();
5895 v8::HandleScope scope(isolate);
5896 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01005897 LocalContext context;
5898
5899 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5900 CompileRun("var obj2 = {};");
5901
5902 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5903 v8_str("239"),
5904 Get239Value, NULL,
5905 v8_str("donut")));
5906 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5907 v8_str("239"),
5908 Get239Value, NULL,
5909 v8_str("donut")));
5910
5911 ExpectString("obj1[239]", "239");
5912 ExpectString("obj2[239]", "239");
5913 ExpectString("obj1['239']", "239");
5914 ExpectString("obj2['239']", "239");
5915}
5916
Steve Blocka7e24c12009-10-30 11:49:00 +00005917
5918v8::Persistent<Value> xValue;
5919
5920
5921static void SetXValue(Local<String> name,
5922 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005923 const v8::PropertyCallbackInfo<void>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005924 CHECK_EQ(value, v8_num(4));
5925 CHECK_EQ(info.Data(), v8_str("donut"));
5926 CHECK_EQ(name, v8_str("x"));
5927 CHECK(xValue.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005928 xValue.Reset(info.GetIsolate(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005929}
5930
5931
5932THREADED_TEST(SimplePropertyWrite) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005933 v8::Isolate* isolate = CcTest::isolate();
5934 v8::HandleScope scope(isolate);
5935 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005936 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5937 LocalContext context;
5938 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005939 Local<Script> script = v8_compile("obj.x = 4");
Steve Blocka7e24c12009-10-30 11:49:00 +00005940 for (int i = 0; i < 10; i++) {
5941 CHECK(xValue.IsEmpty());
5942 script->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005943 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5944 xValue.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00005945 }
5946}
5947
5948
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005949THREADED_TEST(SetterOnly) {
5950 v8::Isolate* isolate = CcTest::isolate();
5951 v8::HandleScope scope(isolate);
5952 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5953 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5954 LocalContext context;
5955 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5956 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5957 for (int i = 0; i < 10; i++) {
5958 CHECK(xValue.IsEmpty());
5959 script->Run();
5960 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5961 xValue.Reset();
5962 }
5963}
5964
5965
5966THREADED_TEST(NoAccessors) {
5967 v8::Isolate* isolate = CcTest::isolate();
5968 v8::HandleScope scope(isolate);
5969 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5970 templ->SetAccessor(v8_str("x"),
5971 static_cast<v8::AccessorGetterCallback>(NULL),
5972 NULL,
5973 v8_str("donut"));
5974 LocalContext context;
5975 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5976 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5977 for (int i = 0; i < 10; i++) {
5978 script->Run();
5979 }
5980}
5981
5982
5983static void XPropertyGetter(Local<String> property,
5984 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005985 ApiTestFuzzer::Fuzz();
5986 CHECK(info.Data()->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005987 info.GetReturnValue().Set(property);
Steve Blocka7e24c12009-10-30 11:49:00 +00005988}
5989
5990
5991THREADED_TEST(NamedInterceptorPropertyRead) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005992 v8::Isolate* isolate = CcTest::isolate();
5993 v8::HandleScope scope(isolate);
5994 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005995 templ->SetNamedPropertyHandler(XPropertyGetter);
5996 LocalContext context;
5997 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005998 Local<Script> script = v8_compile("obj.x");
Steve Blocka7e24c12009-10-30 11:49:00 +00005999 for (int i = 0; i < 10; i++) {
6000 Local<Value> result = script->Run();
6001 CHECK_EQ(result, v8_str("x"));
6002 }
6003}
6004
6005
Steve Block6ded16b2010-05-10 14:33:55 +01006006THREADED_TEST(NamedInterceptorDictionaryIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006007 v8::Isolate* isolate = CcTest::isolate();
6008 v8::HandleScope scope(isolate);
6009 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01006010 templ->SetNamedPropertyHandler(XPropertyGetter);
6011 LocalContext context;
6012 // Create an object with a named interceptor.
6013 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006014 Local<Script> script = v8_compile("interceptor_obj.x");
Steve Block6ded16b2010-05-10 14:33:55 +01006015 for (int i = 0; i < 10; i++) {
6016 Local<Value> result = script->Run();
6017 CHECK_EQ(result, v8_str("x"));
6018 }
6019 // Create a slow case object and a function accessing a property in
6020 // that slow case object (with dictionary probing in generated
6021 // code). Then force object with a named interceptor into slow-case,
6022 // pass it to the function, and check that the interceptor is called
6023 // instead of accessing the local property.
6024 Local<Value> result =
6025 CompileRun("function get_x(o) { return o.x; };"
6026 "var obj = { x : 42, y : 0 };"
6027 "delete obj.y;"
6028 "for (var i = 0; i < 10; i++) get_x(obj);"
6029 "interceptor_obj.x = 42;"
6030 "interceptor_obj.y = 10;"
6031 "delete interceptor_obj.y;"
6032 "get_x(interceptor_obj)");
6033 CHECK_EQ(result, v8_str("x"));
6034}
6035
6036
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006037THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006038 v8::Isolate* isolate = CcTest::isolate();
6039 v8::HandleScope scope(isolate);
6040 v8::Local<Context> context1 = Context::New(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006041
6042 context1->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006043 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006044 templ->SetNamedPropertyHandler(XPropertyGetter);
6045 // Create an object with a named interceptor.
6046 v8::Local<v8::Object> object = templ->NewInstance();
6047 context1->Global()->Set(v8_str("interceptor_obj"), object);
6048
6049 // Force the object into the slow case.
6050 CompileRun("interceptor_obj.y = 0;"
6051 "delete interceptor_obj.y;");
6052 context1->Exit();
6053
6054 {
6055 // Introduce the object into a different context.
6056 // Repeat named loads to exercise ICs.
6057 LocalContext context2;
6058 context2->Global()->Set(v8_str("interceptor_obj"), object);
6059 Local<Value> result =
6060 CompileRun("function get_x(o) { return o.x; }"
6061 "interceptor_obj.x = 42;"
6062 "for (var i=0; i != 10; i++) {"
6063 " get_x(interceptor_obj);"
6064 "}"
6065 "get_x(interceptor_obj)");
6066 // Check that the interceptor was actually invoked.
6067 CHECK_EQ(result, v8_str("x"));
6068 }
6069
6070 // Return to the original context and force some object to the slow case
6071 // to cause the NormalizedMapCache to verify.
6072 context1->Enter();
6073 CompileRun("var obj = { x : 0 }; delete obj.x;");
6074 context1->Exit();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006075}
6076
6077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006078static void SetXOnPrototypeGetter(
6079 Local<String> property,
6080 const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006081 // Set x on the prototype object and do not handle the get request.
6082 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006083 proto.As<v8::Object>()->Set(v8_str("x"),
6084 v8::Integer::New(info.GetIsolate(), 23));
Andrei Popescu402d9372010-02-26 13:31:12 +00006085}
6086
6087
6088// This is a regression test for http://crbug.com/20104. Map
6089// transitions should not interfere with post interceptor lookup.
6090THREADED_TEST(NamedInterceptorMapTransitionRead) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006091 v8::Isolate* isolate = CcTest::isolate();
6092 v8::HandleScope scope(isolate);
6093 Local<v8::FunctionTemplate> function_template =
6094 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006095 Local<v8::ObjectTemplate> instance_template
6096 = function_template->InstanceTemplate();
6097 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6098 LocalContext context;
6099 context->Global()->Set(v8_str("F"), function_template->GetFunction());
6100 // Create an instance of F and introduce a map transition for x.
6101 CompileRun("var o = new F(); o.x = 23;");
6102 // Create an instance of F and invoke the getter. The result should be 23.
6103 Local<Value> result = CompileRun("o = new F(); o.x");
6104 CHECK_EQ(result->Int32Value(), 23);
6105}
6106
6107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006108static void IndexedPropertyGetter(
6109 uint32_t index,
6110 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006111 ApiTestFuzzer::Fuzz();
6112 if (index == 37) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006113 info.GetReturnValue().Set(v8_num(625));
Steve Blocka7e24c12009-10-30 11:49:00 +00006114 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006115}
6116
6117
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006118static void IndexedPropertySetter(
6119 uint32_t index,
6120 Local<Value> value,
6121 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006122 ApiTestFuzzer::Fuzz();
6123 if (index == 39) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006124 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006125 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006126}
6127
6128
6129THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006130 v8::Isolate* isolate = CcTest::isolate();
6131 v8::HandleScope scope(isolate);
6132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006133 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6134 IndexedPropertySetter);
6135 LocalContext context;
6136 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006137 Local<Script> getter_script = v8_compile(
6138 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6139 Local<Script> setter_script = v8_compile(
Steve Blocka7e24c12009-10-30 11:49:00 +00006140 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6141 "obj[17] = 23;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006142 "obj.foo;");
6143 Local<Script> interceptor_setter_script = v8_compile(
Steve Blocka7e24c12009-10-30 11:49:00 +00006144 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6145 "obj[39] = 47;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006146 "obj.foo;"); // This setter should not run, due to the interceptor.
6147 Local<Script> interceptor_getter_script = v8_compile(
6148 "obj[37];");
Steve Blocka7e24c12009-10-30 11:49:00 +00006149 Local<Value> result = getter_script->Run();
6150 CHECK_EQ(v8_num(5), result);
6151 result = setter_script->Run();
6152 CHECK_EQ(v8_num(23), result);
6153 result = interceptor_setter_script->Run();
6154 CHECK_EQ(v8_num(23), result);
6155 result = interceptor_getter_script->Run();
6156 CHECK_EQ(v8_num(625), result);
6157}
6158
6159
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006160static void UnboxedDoubleIndexedPropertyGetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006161 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006162 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006163 ApiTestFuzzer::Fuzz();
6164 if (index < 25) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006165 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006166 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006167}
6168
6169
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006170static void UnboxedDoubleIndexedPropertySetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006171 uint32_t index,
6172 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006173 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006174 ApiTestFuzzer::Fuzz();
6175 if (index < 25) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006176 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006177 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006178}
6179
6180
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006181void UnboxedDoubleIndexedPropertyEnumerator(
6182 const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006183 // Force the list of returned keys to be stored in a FastDoubleArray.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006184 Local<Script> indexed_property_names_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006185 "keys = new Array(); keys[125000] = 1;"
6186 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006187 "keys.length = 25; keys;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006188 Local<Value> result = indexed_property_names_script->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006189 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006190}
6191
6192
6193// Make sure that the the interceptor code in the runtime properly handles
6194// merging property name lists for double-array-backed arrays.
6195THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006196 v8::Isolate* isolate = CcTest::isolate();
6197 v8::HandleScope scope(isolate);
6198 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006199 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6200 UnboxedDoubleIndexedPropertySetter,
6201 0,
6202 0,
6203 UnboxedDoubleIndexedPropertyEnumerator);
6204 LocalContext context;
6205 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6206 // When obj is created, force it to be Stored in a FastDoubleArray.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006207 Local<Script> create_unboxed_double_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006208 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6209 "key_count = 0; "
6210 "for (x in obj) {key_count++;};"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006211 "obj;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006212 Local<Value> result = create_unboxed_double_script->Run();
6213 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006214 Local<Script> key_count_check = v8_compile("key_count;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006215 result = key_count_check->Run();
6216 CHECK_EQ(v8_num(40013), result);
6217}
6218
6219
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006220void SloppyArgsIndexedPropertyEnumerator(
6221 const v8::PropertyCallbackInfo<v8::Array>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006222 // Force the list of returned keys to be stored in a Arguments object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006223 Local<Script> indexed_property_names_script = v8_compile(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006224 "function f(w,x) {"
6225 " return arguments;"
6226 "}"
6227 "keys = f(0, 1, 2, 3);"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006228 "keys;");
6229 Local<Object> result =
6230 Local<Object>::Cast(indexed_property_names_script->Run());
6231 // Have to populate the handle manually, as it's not Cast-able.
6232 i::Handle<i::JSObject> o =
6233 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6234 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6235 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006236}
6237
6238
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006239static void SloppyIndexedPropertyGetter(
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006240 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006241 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006242 ApiTestFuzzer::Fuzz();
6243 if (index < 4) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006244 info.GetReturnValue().Set(v8_num(index));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006245 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006246}
6247
6248
6249// Make sure that the the interceptor code in the runtime properly handles
6250// merging property name lists for non-string arguments arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006251THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6252 v8::Isolate* isolate = CcTest::isolate();
6253 v8::HandleScope scope(isolate);
6254 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6255 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006256 0,
6257 0,
6258 0,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006259 SloppyArgsIndexedPropertyEnumerator);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006260 LocalContext context;
6261 context->Global()->Set(v8_str("obj"), templ->NewInstance());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006262 Local<Script> create_args_script = v8_compile(
6263 "var key_count = 0;"
6264 "for (x in obj) {key_count++;} key_count;");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006265 Local<Value> result = create_args_script->Run();
6266 CHECK_EQ(v8_num(4), result);
6267}
6268
6269
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006270static void IdentityIndexedPropertyGetter(
Leon Clarked91b9f72010-01-27 17:25:45 +00006271 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006272 const v8::PropertyCallbackInfo<v8::Value>& info) {
6273 info.GetReturnValue().Set(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00006274}
6275
6276
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006277THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006278 v8::Isolate* isolate = CcTest::isolate();
6279 v8::HandleScope scope(isolate);
6280 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006281 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6282
6283 LocalContext context;
6284 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6285
6286 // Check fast object case.
6287 const char* fast_case_code =
6288 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6289 ExpectString(fast_case_code, "0");
6290
6291 // Check slow case.
6292 const char* slow_case_code =
6293 "obj.x = 1; delete obj.x;"
6294 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6295 ExpectString(slow_case_code, "1");
6296}
6297
6298
Leon Clarked91b9f72010-01-27 17:25:45 +00006299THREADED_TEST(IndexedInterceptorWithNoSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006300 v8::Isolate* isolate = CcTest::isolate();
6301 v8::HandleScope scope(isolate);
6302 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Leon Clarked91b9f72010-01-27 17:25:45 +00006303 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6304
6305 LocalContext context;
6306 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6307
6308 const char* code =
6309 "try {"
6310 " obj[0] = 239;"
6311 " for (var i = 0; i < 100; i++) {"
6312 " var v = obj[0];"
6313 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6314 " }"
6315 " 'PASSED'"
6316 "} catch(e) {"
6317 " e"
6318 "}";
6319 ExpectString(code, "PASSED");
6320}
6321
6322
Andrei Popescu402d9372010-02-26 13:31:12 +00006323THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006324 v8::Isolate* isolate = CcTest::isolate();
6325 v8::HandleScope scope(isolate);
6326 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006327 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6328
6329 LocalContext context;
6330 Local<v8::Object> obj = templ->NewInstance();
6331 obj->TurnOnAccessCheck();
6332 context->Global()->Set(v8_str("obj"), obj);
6333
6334 const char* code =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006335 "var result = 'PASSED';"
6336 "for (var i = 0; i < 100; i++) {"
6337 " try {"
Andrei Popescu402d9372010-02-26 13:31:12 +00006338 " var v = obj[0];"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006339 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6340 " break;"
6341 " } catch (e) {"
6342 " /* pass */"
Andrei Popescu402d9372010-02-26 13:31:12 +00006343 " }"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006344 "}"
6345 "result";
Andrei Popescu402d9372010-02-26 13:31:12 +00006346 ExpectString(code, "PASSED");
6347}
6348
6349
6350THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6351 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006352 v8::Isolate* isolate = CcTest::isolate();
6353 v8::HandleScope scope(isolate);
6354 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006355 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6356
6357 LocalContext context;
6358 Local<v8::Object> obj = templ->NewInstance();
6359 context->Global()->Set(v8_str("obj"), obj);
6360
6361 const char* code =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006362 "var result = 'PASSED';"
6363 "for (var i = 0; i < 100; i++) {"
6364 " var expected = i;"
6365 " if (i == 5) {"
6366 " %EnableAccessChecks(obj);"
Andrei Popescu402d9372010-02-26 13:31:12 +00006367 " }"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006368 " try {"
6369 " var v = obj[i];"
6370 " if (i == 5) {"
6371 " result = 'Should not have reached this!';"
6372 " break;"
6373 " } else if (v != expected) {"
6374 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6375 " break;"
6376 " }"
6377 " } catch (e) {"
6378 " if (i != 5) {"
6379 " result = e;"
6380 " }"
6381 " }"
6382 " if (i == 5) %DisableAccessChecks(obj);"
6383 "}"
6384 "result";
Andrei Popescu402d9372010-02-26 13:31:12 +00006385 ExpectString(code, "PASSED");
6386}
6387
6388
6389THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006390 v8::Isolate* isolate = CcTest::isolate();
6391 v8::HandleScope scope(isolate);
6392 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006393 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6394
6395 LocalContext context;
6396 Local<v8::Object> obj = templ->NewInstance();
6397 context->Global()->Set(v8_str("obj"), obj);
6398
6399 const char* code =
6400 "try {"
6401 " for (var i = 0; i < 100; i++) {"
6402 " var v = obj[i];"
6403 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6404 " }"
6405 " 'PASSED'"
6406 "} catch(e) {"
6407 " e"
6408 "}";
6409 ExpectString(code, "PASSED");
6410}
6411
6412
Ben Murdochf87a2032010-10-22 12:50:53 +01006413THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006414 v8::Isolate* isolate = CcTest::isolate();
6415 v8::HandleScope scope(isolate);
6416 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +01006417 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6418
6419 LocalContext context;
6420 Local<v8::Object> obj = templ->NewInstance();
6421 context->Global()->Set(v8_str("obj"), obj);
6422
6423 const char* code =
6424 "try {"
6425 " for (var i = 0; i < 100; i++) {"
6426 " var expected = i;"
6427 " var key = i;"
6428 " if (i == 25) {"
6429 " key = -1;"
6430 " expected = undefined;"
6431 " }"
6432 " if (i == 50) {"
6433 " /* probe minimal Smi number on 32-bit platforms */"
6434 " key = -(1 << 30);"
6435 " expected = undefined;"
6436 " }"
6437 " if (i == 75) {"
6438 " /* probe minimal Smi number on 64-bit platforms */"
6439 " key = 1 << 31;"
6440 " expected = undefined;"
6441 " }"
6442 " var v = obj[key];"
6443 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6444 " }"
6445 " 'PASSED'"
6446 "} catch(e) {"
6447 " e"
6448 "}";
6449 ExpectString(code, "PASSED");
6450}
6451
6452
Andrei Popescu402d9372010-02-26 13:31:12 +00006453THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006454 v8::Isolate* isolate = CcTest::isolate();
6455 v8::HandleScope scope(isolate);
6456 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006457 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6458
6459 LocalContext context;
6460 Local<v8::Object> obj = templ->NewInstance();
6461 context->Global()->Set(v8_str("obj"), obj);
6462
6463 const char* code =
6464 "try {"
6465 " for (var i = 0; i < 100; i++) {"
6466 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01006467 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00006468 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01006469 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00006470 " expected = undefined;"
6471 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01006472 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00006473 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6474 " }"
6475 " 'PASSED'"
6476 "} catch(e) {"
6477 " e"
6478 "}";
6479 ExpectString(code, "PASSED");
6480}
6481
6482
6483THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006484 v8::Isolate* isolate = CcTest::isolate();
6485 v8::HandleScope scope(isolate);
6486 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006487 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6488
6489 LocalContext context;
6490 Local<v8::Object> obj = templ->NewInstance();
6491 context->Global()->Set(v8_str("obj"), obj);
6492
6493 const char* code =
6494 "var original = obj;"
6495 "try {"
6496 " for (var i = 0; i < 100; i++) {"
6497 " var expected = i;"
6498 " if (i == 50) {"
6499 " obj = {50: 'foobar'};"
6500 " expected = 'foobar';"
6501 " }"
6502 " var v = obj[i];"
6503 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6504 " if (i == 50) obj = original;"
6505 " }"
6506 " 'PASSED'"
6507 "} catch(e) {"
6508 " e"
6509 "}";
6510 ExpectString(code, "PASSED");
6511}
6512
6513
6514THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006515 v8::Isolate* isolate = CcTest::isolate();
6516 v8::HandleScope scope(isolate);
6517 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006518 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6519
6520 LocalContext context;
6521 Local<v8::Object> obj = templ->NewInstance();
6522 context->Global()->Set(v8_str("obj"), obj);
6523
6524 const char* code =
6525 "var original = obj;"
6526 "try {"
6527 " for (var i = 0; i < 100; i++) {"
6528 " var expected = i;"
6529 " if (i == 5) {"
6530 " obj = 239;"
6531 " expected = undefined;"
6532 " }"
6533 " var v = obj[i];"
6534 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6535 " if (i == 5) obj = original;"
6536 " }"
6537 " 'PASSED'"
6538 "} catch(e) {"
6539 " e"
6540 "}";
6541 ExpectString(code, "PASSED");
6542}
6543
6544
6545THREADED_TEST(IndexedInterceptorOnProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006546 v8::Isolate* isolate = CcTest::isolate();
6547 v8::HandleScope scope(isolate);
6548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00006549 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6550
6551 LocalContext context;
6552 Local<v8::Object> obj = templ->NewInstance();
6553 context->Global()->Set(v8_str("obj"), obj);
6554
6555 const char* code =
6556 "var o = {__proto__: obj};"
6557 "try {"
6558 " for (var i = 0; i < 100; i++) {"
6559 " var v = o[i];"
6560 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6561 " }"
6562 " 'PASSED'"
6563 "} catch(e) {"
6564 " e"
6565 "}";
6566 ExpectString(code, "PASSED");
6567}
6568
6569
Steve Blocka7e24c12009-10-30 11:49:00 +00006570THREADED_TEST(MultiContexts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006571 v8::Isolate* isolate = CcTest::isolate();
6572 v8::HandleScope scope(isolate);
6573 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6574 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6575 DummyCallHandler));
Steve Blocka7e24c12009-10-30 11:49:00 +00006576
6577 Local<String> password = v8_str("Password");
6578
6579 // Create an environment
6580 LocalContext context0(0, templ);
6581 context0->SetSecurityToken(password);
6582 v8::Handle<v8::Object> global0 = context0->Global();
6583 global0->Set(v8_str("custom"), v8_num(1234));
6584 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6585
6586 // Create an independent environment
6587 LocalContext context1(0, templ);
6588 context1->SetSecurityToken(password);
6589 v8::Handle<v8::Object> global1 = context1->Global();
6590 global1->Set(v8_str("custom"), v8_num(1234));
6591 CHECK_NE(global0, global1);
6592 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6593 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6594
6595 // Now create a new context with the old global
6596 LocalContext context2(0, templ, global1);
6597 context2->SetSecurityToken(password);
6598 v8::Handle<v8::Object> global2 = context2->Global();
6599 CHECK_EQ(global1, global2);
6600 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6601 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6602}
6603
6604
6605THREADED_TEST(FunctionPrototypeAcrossContexts) {
6606 // Make sure that functions created by cloning boilerplates cannot
6607 // communicate through their __proto__ field.
6608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006609 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006610
6611 LocalContext env0;
6612 v8::Handle<v8::Object> global0 =
6613 env0->Global();
6614 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006615 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006616 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006617 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006618 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01006619 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006620 proto0->Set(v8_str("custom"), v8_num(1234));
6621
6622 LocalContext env1;
6623 v8::Handle<v8::Object> global1 =
6624 env1->Global();
6625 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006626 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006627 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006628 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006629 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01006630 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006631 CHECK(!proto1->Has(v8_str("custom")));
6632}
6633
6634
6635THREADED_TEST(Regress892105) {
6636 // Make sure that object and array literals created by cloning
6637 // boilerplates cannot communicate through their __proto__
6638 // field. This is rather difficult to check, but we try to add stuff
6639 // to Object.prototype and Array.prototype and create a new
6640 // environment. This should succeed.
6641
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006642 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006643
6644 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6645 "Array.prototype.arr = 4567;"
6646 "8901");
6647
6648 LocalContext env0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006649 Local<Script> script0 = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +00006650 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6651
6652 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006653 Local<Script> script1 = v8_compile(source);
Steve Blocka7e24c12009-10-30 11:49:00 +00006654 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6655}
6656
6657
Steve Blocka7e24c12009-10-30 11:49:00 +00006658THREADED_TEST(UndetectableObject) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006659 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006660 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006661
6662 Local<v8::FunctionTemplate> desc =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006663 v8::FunctionTemplate::New(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006664 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6665
6666 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6667 env->Global()->Set(v8_str("undetectable"), obj);
6668
6669 ExpectString("undetectable.toString()", "[object Object]");
6670 ExpectString("typeof undetectable", "undefined");
6671 ExpectString("typeof(undetectable)", "undefined");
6672 ExpectBoolean("typeof undetectable == 'undefined'", true);
6673 ExpectBoolean("typeof undetectable == 'object'", false);
6674 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6675 ExpectBoolean("!undetectable", true);
6676
6677 ExpectObject("true&&undetectable", obj);
6678 ExpectBoolean("false&&undetectable", false);
6679 ExpectBoolean("true||undetectable", true);
6680 ExpectObject("false||undetectable", obj);
6681
6682 ExpectObject("undetectable&&true", obj);
6683 ExpectObject("undetectable&&false", obj);
6684 ExpectBoolean("undetectable||true", true);
6685 ExpectBoolean("undetectable||false", false);
6686
6687 ExpectBoolean("undetectable==null", true);
6688 ExpectBoolean("null==undetectable", true);
6689 ExpectBoolean("undetectable==undefined", true);
6690 ExpectBoolean("undefined==undetectable", true);
6691 ExpectBoolean("undetectable==undetectable", true);
6692
6693
6694 ExpectBoolean("undetectable===null", false);
6695 ExpectBoolean("null===undetectable", false);
6696 ExpectBoolean("undetectable===undefined", false);
6697 ExpectBoolean("undefined===undetectable", false);
6698 ExpectBoolean("undetectable===undetectable", true);
6699}
6700
6701
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006702THREADED_TEST(VoidLiteral) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006703 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006704 v8::Isolate* isolate = env->GetIsolate();
6705 v8::HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006706
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006707 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006708 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6709
6710 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6711 env->Global()->Set(v8_str("undetectable"), obj);
6712
6713 ExpectBoolean("undefined == void 0", true);
6714 ExpectBoolean("undetectable == void 0", true);
6715 ExpectBoolean("null == void 0", true);
6716 ExpectBoolean("undefined === void 0", true);
6717 ExpectBoolean("undetectable === void 0", false);
6718 ExpectBoolean("null === void 0", false);
6719
6720 ExpectBoolean("void 0 == undefined", true);
6721 ExpectBoolean("void 0 == undetectable", true);
6722 ExpectBoolean("void 0 == null", true);
6723 ExpectBoolean("void 0 === undefined", true);
6724 ExpectBoolean("void 0 === undetectable", false);
6725 ExpectBoolean("void 0 === null", false);
6726
6727 ExpectString("(function() {"
6728 " try {"
6729 " return x === void 0;"
6730 " } catch(e) {"
6731 " return e.toString();"
6732 " }"
6733 "})()",
6734 "ReferenceError: x is not defined");
6735 ExpectString("(function() {"
6736 " try {"
6737 " return void 0 === x;"
6738 " } catch(e) {"
6739 " return e.toString();"
6740 " }"
6741 "})()",
6742 "ReferenceError: x is not defined");
6743}
6744
Steve Block8defd9f2010-07-08 12:39:36 +01006745
6746THREADED_TEST(ExtensibleOnUndetectable) {
Steve Block8defd9f2010-07-08 12:39:36 +01006747 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006748 v8::Isolate* isolate = env->GetIsolate();
6749 v8::HandleScope scope(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +01006750
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006751 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +01006752 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6753
6754 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6755 env->Global()->Set(v8_str("undetectable"), obj);
6756
6757 Local<String> source = v8_str("undetectable.x = 42;"
6758 "undetectable.x");
6759
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006760 Local<Script> script = v8_compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01006761
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006762 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
Steve Block8defd9f2010-07-08 12:39:36 +01006763
6764 ExpectBoolean("Object.isExtensible(undetectable)", true);
6765
6766 source = v8_str("Object.preventExtensions(undetectable);");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006767 script = v8_compile(source);
Steve Block8defd9f2010-07-08 12:39:36 +01006768 script->Run();
6769 ExpectBoolean("Object.isExtensible(undetectable)", false);
6770
6771 source = v8_str("undetectable.y = 2000;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006772 script = v8_compile(source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006773 script->Run();
Steve Block44f0eee2011-05-26 01:26:41 +01006774 ExpectBoolean("undetectable.y == undefined", true);
Steve Block8defd9f2010-07-08 12:39:36 +01006775}
6776
6777
6778
Steve Blocka7e24c12009-10-30 11:49:00 +00006779THREADED_TEST(UndetectableString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006780 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006781 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006783 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6784 String::kUndetectableString);
Steve Blocka7e24c12009-10-30 11:49:00 +00006785 env->Global()->Set(v8_str("undetectable"), obj);
6786
6787 ExpectString("undetectable", "foo");
6788 ExpectString("typeof undetectable", "undefined");
6789 ExpectString("typeof(undetectable)", "undefined");
6790 ExpectBoolean("typeof undetectable == 'undefined'", true);
6791 ExpectBoolean("typeof undetectable == 'string'", false);
6792 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6793 ExpectBoolean("!undetectable", true);
6794
6795 ExpectObject("true&&undetectable", obj);
6796 ExpectBoolean("false&&undetectable", false);
6797 ExpectBoolean("true||undetectable", true);
6798 ExpectObject("false||undetectable", obj);
6799
6800 ExpectObject("undetectable&&true", obj);
6801 ExpectObject("undetectable&&false", obj);
6802 ExpectBoolean("undetectable||true", true);
6803 ExpectBoolean("undetectable||false", false);
6804
6805 ExpectBoolean("undetectable==null", true);
6806 ExpectBoolean("null==undetectable", true);
6807 ExpectBoolean("undetectable==undefined", true);
6808 ExpectBoolean("undefined==undetectable", true);
6809 ExpectBoolean("undetectable==undetectable", true);
6810
6811
6812 ExpectBoolean("undetectable===null", false);
6813 ExpectBoolean("null===undetectable", false);
6814 ExpectBoolean("undetectable===undefined", false);
6815 ExpectBoolean("undefined===undetectable", false);
6816 ExpectBoolean("undetectable===undetectable", true);
6817}
6818
6819
Ben Murdoch257744e2011-11-30 15:57:28 +00006820TEST(UndetectableOptimized) {
6821 i::FLAG_allow_natives_syntax = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00006822 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006823 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +00006824
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006825 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6826 String::kUndetectableString);
Ben Murdoch257744e2011-11-30 15:57:28 +00006827 env->Global()->Set(v8_str("undetectable"), obj);
6828 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6829
6830 ExpectString(
6831 "function testBranch() {"
6832 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6833 " if (%_IsUndetectableObject(detectable)) throw 2;"
6834 "}\n"
6835 "function testBool() {"
6836 " var b1 = !%_IsUndetectableObject(undetectable);"
6837 " var b2 = %_IsUndetectableObject(detectable);"
6838 " if (b1) throw 3;"
6839 " if (b2) throw 4;"
6840 " return b1 == b2;"
6841 "}\n"
6842 "%OptimizeFunctionOnNextCall(testBranch);"
6843 "%OptimizeFunctionOnNextCall(testBool);"
6844 "for (var i = 0; i < 10; i++) {"
6845 " testBranch();"
6846 " testBool();"
6847 "}\n"
6848 "\"PASS\"",
6849 "PASS");
6850}
6851
6852
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006853// The point of this test is type checking. We run it only so compilers
6854// don't complain about an unused function.
6855TEST(PersistentHandles) {
6856 LocalContext env;
6857 v8::Isolate* isolate = CcTest::isolate();
6858 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006859 Local<String> str = v8_str("foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006860 v8::Persistent<String> p_str(isolate, str);
6861 p_str.Reset();
6862 Local<Script> scr = v8_compile("");
6863 v8::Persistent<Script> p_scr(isolate, scr);
6864 p_scr.Reset();
6865 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6866 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6867 p_templ.Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +00006868}
6869
6870
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006871static void HandleLogDelegator(
6872 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006873 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00006874}
6875
6876
6877THREADED_TEST(GlobalObjectTemplate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006878 v8::Isolate* isolate = CcTest::isolate();
6879 v8::HandleScope handle_scope(isolate);
6880 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006881 global_template->Set(v8_str("JSNI_Log"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006882 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6883 v8::Local<Context> context = Context::New(isolate, 0, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00006884 Context::Scope context_scope(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006885 CompileRun("JSNI_Log('LOG')");
Steve Blocka7e24c12009-10-30 11:49:00 +00006886}
6887
6888
6889static const char* kSimpleExtensionSource =
6890 "function Foo() {"
6891 " return 4;"
6892 "}";
6893
6894
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006895TEST(SimpleExtensions) {
6896 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00006897 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6898 const char* extension_names[] = { "simpletest" };
6899 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006900 v8::Handle<Context> context =
6901 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00006902 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006903 v8::Handle<Value> result = CompileRun("Foo()");
6904 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6905}
6906
6907
6908static const char* kStackTraceFromExtensionSource =
6909 "function foo() {"
6910 " throw new Error();"
6911 "}"
6912 "function bar() {"
6913 " foo();"
6914 "}";
6915
6916
6917TEST(StackTraceInExtension) {
6918 v8::HandleScope handle_scope(CcTest::isolate());
6919 v8::RegisterExtension(new Extension("stacktracetest",
6920 kStackTraceFromExtensionSource));
6921 const char* extension_names[] = { "stacktracetest" };
6922 v8::ExtensionConfiguration extensions(1, extension_names);
6923 v8::Handle<Context> context =
6924 Context::New(CcTest::isolate(), &extensions);
6925 Context::Scope lock(context);
6926 CompileRun("function user() { bar(); }"
6927 "var error;"
6928 "try{ user(); } catch (e) { error = e; }");
6929 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6930 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6931 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6932}
6933
6934
6935TEST(NullExtensions) {
6936 v8::HandleScope handle_scope(CcTest::isolate());
6937 v8::RegisterExtension(new Extension("nulltest", NULL));
6938 const char* extension_names[] = { "nulltest" };
6939 v8::ExtensionConfiguration extensions(1, extension_names);
6940 v8::Handle<Context> context =
6941 Context::New(CcTest::isolate(), &extensions);
6942 Context::Scope lock(context);
6943 v8::Handle<Value> result = CompileRun("1+3");
6944 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
Steve Blocka7e24c12009-10-30 11:49:00 +00006945}
6946
6947
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006948static const char* kEmbeddedExtensionSource =
6949 "function Ret54321(){return 54321;}~~@@$"
6950 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6951static const int kEmbeddedExtensionSourceValidLen = 34;
6952
6953
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006954TEST(ExtensionMissingSourceLength) {
6955 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006956 v8::RegisterExtension(new Extension("srclentest_fail",
6957 kEmbeddedExtensionSource));
6958 const char* extension_names[] = { "srclentest_fail" };
6959 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006960 v8::Handle<Context> context =
6961 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006962 CHECK_EQ(0, *context);
6963}
6964
6965
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006966TEST(ExtensionWithSourceLength) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006967 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6968 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006969 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006970 i::ScopedVector<char> extension_name(32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006971 i::SNPrintF(extension_name, "ext #%d", source_len);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006972 v8::RegisterExtension(new Extension(extension_name.start(),
6973 kEmbeddedExtensionSource, 0, 0,
6974 source_len));
6975 const char* extension_names[1] = { extension_name.start() };
6976 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006977 v8::Handle<Context> context =
6978 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006979 if (source_len == kEmbeddedExtensionSourceValidLen) {
6980 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006981 v8::Handle<Value> result = CompileRun("Ret54321()");
6982 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006983 } else {
6984 // Anything but exactly the right length should fail to compile.
6985 CHECK_EQ(0, *context);
6986 }
6987 }
6988}
6989
6990
Steve Blocka7e24c12009-10-30 11:49:00 +00006991static const char* kEvalExtensionSource1 =
6992 "function UseEval1() {"
6993 " var x = 42;"
6994 " return eval('x');"
6995 "}";
6996
6997
6998static const char* kEvalExtensionSource2 =
6999 "(function() {"
7000 " var x = 42;"
7001 " function e() {"
7002 " return eval('x');"
7003 " }"
7004 " this.UseEval2 = e;"
7005 "})()";
7006
7007
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007008TEST(UseEvalFromExtension) {
7009 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007010 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7011 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7012 const char* extension_names[] = { "evaltest1", "evaltest2" };
7013 v8::ExtensionConfiguration extensions(2, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007014 v8::Handle<Context> context =
7015 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00007016 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007017 v8::Handle<Value> result = CompileRun("UseEval1()");
7018 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7019 result = CompileRun("UseEval2()");
7020 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
Steve Blocka7e24c12009-10-30 11:49:00 +00007021}
7022
7023
7024static const char* kWithExtensionSource1 =
7025 "function UseWith1() {"
7026 " var x = 42;"
7027 " with({x:87}) { return x; }"
7028 "}";
7029
7030
7031
7032static const char* kWithExtensionSource2 =
7033 "(function() {"
7034 " var x = 42;"
7035 " function e() {"
7036 " with ({x:87}) { return x; }"
7037 " }"
7038 " this.UseWith2 = e;"
7039 "})()";
7040
7041
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007042TEST(UseWithFromExtension) {
7043 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007044 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7045 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7046 const char* extension_names[] = { "withtest1", "withtest2" };
7047 v8::ExtensionConfiguration extensions(2, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007048 v8::Handle<Context> context =
7049 Context::New(CcTest::isolate(), &extensions);
Steve Blocka7e24c12009-10-30 11:49:00 +00007050 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007051 v8::Handle<Value> result = CompileRun("UseWith1()");
7052 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7053 result = CompileRun("UseWith2()");
7054 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
Steve Blocka7e24c12009-10-30 11:49:00 +00007055}
7056
7057
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007058TEST(AutoExtensions) {
7059 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007060 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7061 extension->set_auto_enable(true);
7062 v8::RegisterExtension(extension);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007063 v8::Handle<Context> context =
7064 Context::New(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007065 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007066 v8::Handle<Value> result = CompileRun("Foo()");
7067 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
Steve Blocka7e24c12009-10-30 11:49:00 +00007068}
7069
7070
Steve Blockd0582a62009-12-15 09:54:21 +00007071static const char* kSyntaxErrorInExtensionSource =
7072 "[";
7073
7074
7075// Test that a syntax error in an extension does not cause a fatal
7076// error but results in an empty context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007077TEST(SyntaxErrorExtensions) {
7078 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007079 v8::RegisterExtension(new Extension("syntaxerror",
7080 kSyntaxErrorInExtensionSource));
7081 const char* extension_names[] = { "syntaxerror" };
7082 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007083 v8::Handle<Context> context =
7084 Context::New(CcTest::isolate(), &extensions);
Steve Blockd0582a62009-12-15 09:54:21 +00007085 CHECK(context.IsEmpty());
7086}
7087
7088
7089static const char* kExceptionInExtensionSource =
7090 "throw 42";
7091
7092
7093// Test that an exception when installing an extension does not cause
7094// a fatal error but results in an empty context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007095TEST(ExceptionExtensions) {
7096 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00007097 v8::RegisterExtension(new Extension("exception",
7098 kExceptionInExtensionSource));
7099 const char* extension_names[] = { "exception" };
7100 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007101 v8::Handle<Context> context =
7102 Context::New(CcTest::isolate(), &extensions);
Steve Blockd0582a62009-12-15 09:54:21 +00007103 CHECK(context.IsEmpty());
7104}
7105
7106
Iain Merrick9ac36c92010-09-13 15:29:50 +01007107static const char* kNativeCallInExtensionSource =
7108 "function call_runtime_last_index_of(x) {"
7109 " return %StringLastIndexOf(x, 'bob', 10);"
7110 "}";
7111
7112
7113static const char* kNativeCallTest =
7114 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7115
7116// Test that a native runtime calls are supported in extensions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007117TEST(NativeCallInExtensions) {
7118 v8::HandleScope handle_scope(CcTest::isolate());
Iain Merrick9ac36c92010-09-13 15:29:50 +01007119 v8::RegisterExtension(new Extension("nativecall",
7120 kNativeCallInExtensionSource));
7121 const char* extension_names[] = { "nativecall" };
7122 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007123 v8::Handle<Context> context =
7124 Context::New(CcTest::isolate(), &extensions);
Iain Merrick9ac36c92010-09-13 15:29:50 +01007125 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007126 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7127 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
Iain Merrick9ac36c92010-09-13 15:29:50 +01007128}
7129
7130
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007131class NativeFunctionExtension : public Extension {
7132 public:
7133 NativeFunctionExtension(const char* name,
7134 const char* source,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007135 v8::FunctionCallback fun = &Echo)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007136 : Extension(name, source),
7137 function_(fun) { }
7138
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007139 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7140 v8::Isolate* isolate,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007141 v8::Handle<v8::String> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007142 return v8::FunctionTemplate::New(isolate, function_);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007143 }
7144
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007145 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7146 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007147 }
7148 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007149 v8::FunctionCallback function_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007150};
7151
7152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007153TEST(NativeFunctionDeclaration) {
7154 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007155 const char* name = "nativedecl";
7156 v8::RegisterExtension(new NativeFunctionExtension(name,
7157 "native function foo();"));
7158 const char* extension_names[] = { name };
7159 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007160 v8::Handle<Context> context =
7161 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007162 Context::Scope lock(context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007163 v8::Handle<Value> result = CompileRun("foo(42);");
7164 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007165}
7166
7167
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007168TEST(NativeFunctionDeclarationError) {
7169 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007170 const char* name = "nativedeclerr";
7171 // Syntax error in extension code.
7172 v8::RegisterExtension(new NativeFunctionExtension(name,
7173 "native\nfunction foo();"));
7174 const char* extension_names[] = { name };
7175 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007176 v8::Handle<Context> context =
7177 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007178 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007179}
7180
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007181
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007182TEST(NativeFunctionDeclarationErrorEscape) {
7183 v8::HandleScope handle_scope(CcTest::isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007184 const char* name = "nativedeclerresc";
7185 // Syntax error in extension code - escape code in "native" means that
7186 // it's not treated as a keyword.
7187 v8::RegisterExtension(new NativeFunctionExtension(
7188 name,
7189 "nativ\\u0065 function foo();"));
7190 const char* extension_names[] = { name };
7191 v8::ExtensionConfiguration extensions(1, extension_names);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007192 v8::Handle<Context> context =
7193 Context::New(CcTest::isolate(), &extensions);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007194 CHECK(context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007195}
7196
7197
Steve Blocka7e24c12009-10-30 11:49:00 +00007198static void CheckDependencies(const char* name, const char* expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007199 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007200 v8::ExtensionConfiguration config(1, &name);
7201 LocalContext context(&config);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007202 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7203 context->Global()->Get(v8_str("loaded")));
Steve Blocka7e24c12009-10-30 11:49:00 +00007204}
7205
7206
7207/*
7208 * Configuration:
7209 *
7210 * /-- B <--\
7211 * A <- -- D <-- E
7212 * \-- C <--/
7213 */
7214THREADED_TEST(ExtensionDependency) {
7215 static const char* kEDeps[] = { "D" };
7216 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7217 static const char* kDDeps[] = { "B", "C" };
7218 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7219 static const char* kBCDeps[] = { "A" };
7220 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7221 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7222 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7223 CheckDependencies("A", "undefinedA");
7224 CheckDependencies("B", "undefinedAB");
7225 CheckDependencies("C", "undefinedAC");
7226 CheckDependencies("D", "undefinedABCD");
7227 CheckDependencies("E", "undefinedABCDE");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007228 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007229 static const char* exts[2] = { "C", "E" };
7230 v8::ExtensionConfiguration config(2, exts);
7231 LocalContext context(&config);
7232 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7233}
7234
7235
7236static const char* kExtensionTestScript =
7237 "native function A();"
7238 "native function B();"
7239 "native function C();"
7240 "function Foo(i) {"
7241 " if (i == 0) return A();"
7242 " if (i == 1) return B();"
7243 " if (i == 2) return C();"
7244 "}";
7245
7246
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007247static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007248 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00007249 if (args.IsConstructCall()) {
7250 args.This()->Set(v8_str("data"), args.Data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007251 args.GetReturnValue().SetNull();
7252 return;
Leon Clarkee46be812010-01-19 14:06:41 +00007253 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007254 args.GetReturnValue().Set(args.Data());
Steve Blocka7e24c12009-10-30 11:49:00 +00007255}
7256
7257
7258class FunctionExtension : public Extension {
7259 public:
7260 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007261 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7262 v8::Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +00007263 v8::Handle<String> name);
7264};
7265
7266
7267static int lookup_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007268v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7269 v8::Isolate* isolate, v8::Handle<String> name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007270 lookup_count++;
7271 if (name->Equals(v8_str("A"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007272 return v8::FunctionTemplate::New(
7273 isolate, CallFun, v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +00007274 } else if (name->Equals(v8_str("B"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007275 return v8::FunctionTemplate::New(
7276 isolate, CallFun, v8::Integer::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +00007277 } else if (name->Equals(v8_str("C"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007278 return v8::FunctionTemplate::New(
7279 isolate, CallFun, v8::Integer::New(isolate, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00007280 } else {
7281 return v8::Handle<v8::FunctionTemplate>();
7282 }
7283}
7284
7285
7286THREADED_TEST(FunctionLookup) {
7287 v8::RegisterExtension(new FunctionExtension());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007288 v8::HandleScope handle_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007289 static const char* exts[1] = { "functiontest" };
7290 v8::ExtensionConfiguration config(1, exts);
7291 LocalContext context(&config);
7292 CHECK_EQ(3, lookup_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007293 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7294 CompileRun("Foo(0)"));
7295 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7296 CompileRun("Foo(1)"));
7297 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7298 CompileRun("Foo(2)"));
Steve Blocka7e24c12009-10-30 11:49:00 +00007299}
7300
7301
Leon Clarkee46be812010-01-19 14:06:41 +00007302THREADED_TEST(NativeFunctionConstructCall) {
7303 v8::RegisterExtension(new FunctionExtension());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007304 v8::HandleScope handle_scope(CcTest::isolate());
Leon Clarkee46be812010-01-19 14:06:41 +00007305 static const char* exts[1] = { "functiontest" };
7306 v8::ExtensionConfiguration config(1, exts);
7307 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00007308 for (int i = 0; i < 10; i++) {
7309 // Run a few times to ensure that allocation of objects doesn't
7310 // change behavior of a constructor function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007311 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7312 CompileRun("(new A()).data"));
7313 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7314 CompileRun("(new B()).data"));
7315 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7316 CompileRun("(new C()).data"));
Leon Clarked91b9f72010-01-27 17:25:45 +00007317 }
Leon Clarkee46be812010-01-19 14:06:41 +00007318}
7319
7320
Steve Blocka7e24c12009-10-30 11:49:00 +00007321static const char* last_location;
7322static const char* last_message;
7323void StoringErrorCallback(const char* location, const char* message) {
7324 if (last_location == NULL) {
7325 last_location = location;
7326 last_message = message;
7327 }
7328}
7329
7330
7331// ErrorReporting creates a circular extensions configuration and
7332// tests that the fatal error handler gets called. This renders V8
7333// unusable and therefore this test cannot be run in parallel.
7334TEST(ErrorReporting) {
7335 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7336 static const char* aDeps[] = { "B" };
7337 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7338 static const char* bDeps[] = { "A" };
7339 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7340 last_location = NULL;
7341 v8::ExtensionConfiguration config(1, bDeps);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007342 v8::Handle<Context> context =
7343 Context::New(CcTest::isolate(), &config);
Steve Blocka7e24c12009-10-30 11:49:00 +00007344 CHECK(context.IsEmpty());
7345 CHECK_NE(last_location, NULL);
7346}
7347
7348
Steve Blocka7e24c12009-10-30 11:49:00 +00007349static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7350 v8::Handle<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007351 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7352 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7353 message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +00007354 message->GetLineNumber();
7355 message->GetSourceLine();
7356}
7357
7358
7359THREADED_TEST(ErrorWithMissingScriptInfo) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007360 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007361 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007362 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007363 CompileRun("throw Error()");
Steve Blocka7e24c12009-10-30 11:49:00 +00007364 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7365}
7366
7367
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007368struct FlagAndPersistent {
7369 bool flag;
7370 v8::Persistent<v8::Object> handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00007371};
7372
Steve Blocka7e24c12009-10-30 11:49:00 +00007373
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007374static void DisposeAndSetFlag(
7375 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7376 data.GetParameter()->handle.Reset();
7377 data.GetParameter()->flag = true;
Steve Blockd0582a62009-12-15 09:54:21 +00007378}
7379
Steve Blockd0582a62009-12-15 09:54:21 +00007380
Ben Murdoch257744e2011-11-30 15:57:28 +00007381THREADED_TEST(IndependentWeakHandle) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007382 v8::Isolate* iso = CcTest::isolate();
7383 v8::HandleScope scope(iso);
7384 v8::Handle<Context> context = Context::New(iso);
Steve Blockd0582a62009-12-15 09:54:21 +00007385 Context::Scope context_scope(context);
7386
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007387 FlagAndPersistent object_a, object_b;
Steve Blockd0582a62009-12-15 09:54:21 +00007388
7389 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007390 v8::HandleScope handle_scope(iso);
7391 object_a.handle.Reset(iso, v8::Object::New(iso));
7392 object_b.handle.Reset(iso, v8::Object::New(iso));
Steve Blockd0582a62009-12-15 09:54:21 +00007393 }
7394
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007395 object_a.flag = false;
7396 object_b.flag = false;
7397 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7398 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7399 CHECK(!object_b.handle.IsIndependent());
7400 object_a.handle.MarkIndependent();
7401 object_b.handle.MarkIndependent();
7402 CHECK(object_b.handle.IsIndependent());
7403 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7404 CHECK(object_a.flag);
7405 CHECK(object_b.flag);
Ben Murdoch257744e2011-11-30 15:57:28 +00007406}
Steve Blockd0582a62009-12-15 09:54:21 +00007407
Ben Murdoch257744e2011-11-30 15:57:28 +00007408
7409static void InvokeScavenge() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007410 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
Ben Murdoch257744e2011-11-30 15:57:28 +00007411}
7412
7413
7414static void InvokeMarkSweep() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007415 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdoch257744e2011-11-30 15:57:28 +00007416}
7417
7418
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007419static void ForceScavenge(
7420 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7421 data.GetParameter()->handle.Reset();
7422 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007423 InvokeScavenge();
7424}
7425
7426
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007427static void ForceMarkSweep(
7428 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7429 data.GetParameter()->handle.Reset();
7430 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007431 InvokeMarkSweep();
7432}
7433
7434
7435THREADED_TEST(GCFromWeakCallbacks) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007436 v8::Isolate* isolate = CcTest::isolate();
7437 v8::HandleScope scope(isolate);
7438 v8::Handle<Context> context = Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +00007439 Context::Scope context_scope(context);
7440
7441 static const int kNumberOfGCTypes = 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007442 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7443 Callback;
7444 Callback gc_forcing_callback[kNumberOfGCTypes] =
Ben Murdoch257744e2011-11-30 15:57:28 +00007445 {&ForceScavenge, &ForceMarkSweep};
7446
7447 typedef void (*GCInvoker)();
7448 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7449
7450 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7451 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007452 FlagAndPersistent object;
Ben Murdoch257744e2011-11-30 15:57:28 +00007453 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007454 v8::HandleScope handle_scope(isolate);
7455 object.handle.Reset(isolate, v8::Object::New(isolate));
Ben Murdoch257744e2011-11-30 15:57:28 +00007456 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007457 object.flag = false;
7458 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7459 object.handle.MarkIndependent();
Ben Murdoch257744e2011-11-30 15:57:28 +00007460 invoke_gc[outer_gc]();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007461 CHECK(object.flag);
Ben Murdoch257744e2011-11-30 15:57:28 +00007462 }
Steve Blockd0582a62009-12-15 09:54:21 +00007463 }
Ben Murdoch257744e2011-11-30 15:57:28 +00007464}
7465
7466
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007467static void RevivingCallback(
7468 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7469 data.GetParameter()->handle.ClearWeak();
7470 data.GetParameter()->flag = true;
Ben Murdoch257744e2011-11-30 15:57:28 +00007471}
7472
7473
7474THREADED_TEST(IndependentHandleRevival) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007475 v8::Isolate* isolate = CcTest::isolate();
7476 v8::HandleScope scope(isolate);
7477 v8::Handle<Context> context = Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +00007478 Context::Scope context_scope(context);
7479
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007480 FlagAndPersistent object;
Ben Murdoch257744e2011-11-30 15:57:28 +00007481 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007482 v8::HandleScope handle_scope(isolate);
7483 v8::Local<v8::Object> o = v8::Object::New(isolate);
7484 object.handle.Reset(isolate, o);
7485 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
Ben Murdoch257744e2011-11-30 15:57:28 +00007486 v8::Local<String> y_str = v8_str("y");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007487 o->Set(y_str, y_str);
Ben Murdoch257744e2011-11-30 15:57:28 +00007488 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007489 object.flag = false;
7490 object.handle.SetWeak(&object, &RevivingCallback);
7491 object.handle.MarkIndependent();
7492 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7493 CHECK(object.flag);
7494 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoch257744e2011-11-30 15:57:28 +00007495 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007496 v8::HandleScope handle_scope(isolate);
7497 v8::Local<v8::Object> o =
7498 v8::Local<v8::Object>::New(isolate, object.handle);
Ben Murdoch257744e2011-11-30 15:57:28 +00007499 v8::Local<String> y_str = v8_str("y");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007500 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7501 CHECK(o->Get(y_str)->Equals(y_str));
Ben Murdoch257744e2011-11-30 15:57:28 +00007502 }
Steve Blockd0582a62009-12-15 09:54:21 +00007503}
7504
7505
Steve Blocka7e24c12009-10-30 11:49:00 +00007506v8::Handle<Function> args_fun;
7507
7508
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007509static void ArgumentsTestCallback(
7510 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007511 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007512 v8::Isolate* isolate = args.GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007513 CHECK_EQ(args_fun, args.Callee());
7514 CHECK_EQ(3, args.Length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007515 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7516 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7517 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7518 CHECK_EQ(v8::Undefined(isolate), args[3]);
7519 v8::HandleScope scope(args.GetIsolate());
7520 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +00007521}
7522
7523
7524THREADED_TEST(Arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007525 v8::Isolate* isolate = CcTest::isolate();
7526 v8::HandleScope scope(isolate);
7527 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7528 global->Set(v8_str("f"),
7529 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +00007530 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01007531 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00007532 v8_compile("f(1, 2, 3)")->Run();
7533}
7534
7535
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007536static void NoBlockGetterX(Local<String> name,
7537 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007538}
7539
7540
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007541static void NoBlockGetterI(uint32_t index,
7542 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007543}
7544
7545
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007546static void PDeleter(Local<String> name,
7547 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007548 if (!name->Equals(v8_str("foo"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007549 return; // not intercepted
Steve Blocka7e24c12009-10-30 11:49:00 +00007550 }
7551
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007552 info.GetReturnValue().Set(false); // intercepted, don't delete the property
Steve Blocka7e24c12009-10-30 11:49:00 +00007553}
7554
7555
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007556static void IDeleter(uint32_t index,
7557 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007558 if (index != 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007559 return; // not intercepted
Steve Blocka7e24c12009-10-30 11:49:00 +00007560 }
7561
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007562 info.GetReturnValue().Set(false); // intercepted, don't delete the property
Steve Blocka7e24c12009-10-30 11:49:00 +00007563}
7564
7565
7566THREADED_TEST(Deleter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007567 v8::Isolate* isolate = CcTest::isolate();
7568 v8::HandleScope scope(isolate);
7569 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007570 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7571 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7572 LocalContext context;
7573 context->Global()->Set(v8_str("k"), obj->NewInstance());
7574 CompileRun(
7575 "k.foo = 'foo';"
7576 "k.bar = 'bar';"
7577 "k[2] = 2;"
7578 "k[4] = 4;");
7579 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7580 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7581
7582 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7583 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7584
7585 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7586 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7587
7588 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7589 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7590}
7591
7592
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007593static void GetK(Local<String> name,
7594 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007595 ApiTestFuzzer::Fuzz();
7596 if (name->Equals(v8_str("foo")) ||
7597 name->Equals(v8_str("bar")) ||
7598 name->Equals(v8_str("baz"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007599 info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00007600 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007601}
7602
7603
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007604static void IndexedGetK(uint32_t index,
7605 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007606 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007607 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00007608}
7609
7610
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007611static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007612 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007613 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7614 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7615 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7616 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7617 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007618}
7619
7620
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007621static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007622 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007623 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7624 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7625 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7626 info.GetReturnValue().Set(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007627}
7628
7629
7630THREADED_TEST(Enumerators) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007631 v8::Isolate* isolate = CcTest::isolate();
7632 v8::HandleScope scope(isolate);
7633 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007634 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7635 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7636 LocalContext context;
7637 context->Global()->Set(v8_str("k"), obj->NewInstance());
7638 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7639 "k[10] = 0;"
7640 "k.a = 0;"
7641 "k[5] = 0;"
7642 "k.b = 0;"
7643 "k[4294967295] = 0;"
7644 "k.c = 0;"
7645 "k[4294967296] = 0;"
7646 "k.d = 0;"
7647 "k[140000] = 0;"
7648 "k.e = 0;"
7649 "k[30000000000] = 0;"
7650 "k.f = 0;"
7651 "var result = [];"
7652 "for (var prop in k) {"
7653 " result.push(prop);"
7654 "}"
7655 "result"));
7656 // Check that we get all the property names returned including the
7657 // ones from the enumerators in the right order: indexed properties
7658 // in numerical order, indexed interceptor properties, named
7659 // properties in insertion order, named interceptor properties.
7660 // This order is not mandated by the spec, so this test is just
7661 // documenting our behavior.
7662 CHECK_EQ(17, result->Length());
7663 // Indexed properties in numerical order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007664 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7665 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7666 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7667 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007668 // Indexed interceptor properties in the order they are returned
7669 // from the enumerator interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007670 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7671 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007672 // Named properties in insertion order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007673 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7674 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7675 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7676 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7677 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7678 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7679 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7680 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007681 // Named interceptor properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007682 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7683 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7684 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007685}
7686
7687
7688int p_getter_count;
7689int p_getter_count2;
7690
7691
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007692static void PGetter(Local<String> name,
7693 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007694 ApiTestFuzzer::Fuzz();
7695 p_getter_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007696 v8::Handle<v8::Object> global =
7697 info.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00007698 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7699 if (name->Equals(v8_str("p1"))) {
7700 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7701 } else if (name->Equals(v8_str("p2"))) {
7702 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7703 } else if (name->Equals(v8_str("p3"))) {
7704 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7705 } else if (name->Equals(v8_str("p4"))) {
7706 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7707 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007708}
7709
7710
7711static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7712 ApiTestFuzzer::Fuzz();
7713 LocalContext context;
7714 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7715 CompileRun(
7716 "o1.__proto__ = { };"
7717 "var o2 = { __proto__: o1 };"
7718 "var o3 = { __proto__: o2 };"
7719 "var o4 = { __proto__: o3 };"
7720 "for (var i = 0; i < 10; i++) o4.p4;"
7721 "for (var i = 0; i < 10; i++) o3.p3;"
7722 "for (var i = 0; i < 10; i++) o2.p2;"
7723 "for (var i = 0; i < 10; i++) o1.p1;");
7724}
7725
7726
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007727static void PGetter2(Local<String> name,
7728 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007729 ApiTestFuzzer::Fuzz();
7730 p_getter_count2++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007731 v8::Handle<v8::Object> global =
7732 info.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00007733 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7734 if (name->Equals(v8_str("p1"))) {
7735 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7736 } else if (name->Equals(v8_str("p2"))) {
7737 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7738 } else if (name->Equals(v8_str("p3"))) {
7739 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7740 } else if (name->Equals(v8_str("p4"))) {
7741 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7742 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007743}
7744
7745
7746THREADED_TEST(GetterHolders) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007747 v8::Isolate* isolate = CcTest::isolate();
7748 v8::HandleScope scope(isolate);
7749 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007750 obj->SetAccessor(v8_str("p1"), PGetter);
7751 obj->SetAccessor(v8_str("p2"), PGetter);
7752 obj->SetAccessor(v8_str("p3"), PGetter);
7753 obj->SetAccessor(v8_str("p4"), PGetter);
7754 p_getter_count = 0;
7755 RunHolderTest(obj);
7756 CHECK_EQ(40, p_getter_count);
7757}
7758
7759
7760THREADED_TEST(PreInterceptorHolders) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007761 v8::Isolate* isolate = CcTest::isolate();
7762 v8::HandleScope scope(isolate);
7763 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007764 obj->SetNamedPropertyHandler(PGetter2);
7765 p_getter_count2 = 0;
7766 RunHolderTest(obj);
7767 CHECK_EQ(40, p_getter_count2);
7768}
7769
7770
7771THREADED_TEST(ObjectInstantiation) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007772 v8::Isolate* isolate = CcTest::isolate();
7773 v8::HandleScope scope(isolate);
7774 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007775 templ->SetAccessor(v8_str("t"), PGetter2);
7776 LocalContext context;
7777 context->Global()->Set(v8_str("o"), templ->NewInstance());
7778 for (int i = 0; i < 100; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007779 v8::HandleScope inner_scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007780 v8::Handle<v8::Object> obj = templ->NewInstance();
7781 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7782 context->Global()->Set(v8_str("o2"), obj);
7783 v8::Handle<Value> value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007784 CompileRun("o.__proto__ === o2.__proto__");
7785 CHECK_EQ(v8::True(isolate), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00007786 context->Global()->Set(v8_str("o"), obj);
7787 }
7788}
7789
7790
Ben Murdochb0fe1622011-05-05 13:52:32 +01007791static int StrCmp16(uint16_t* a, uint16_t* b) {
7792 while (true) {
7793 if (*a == 0 && *b == 0) return 0;
7794 if (*a != *b) return 0 + *a - *b;
7795 a++;
7796 b++;
7797 }
7798}
7799
7800
7801static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7802 while (true) {
7803 if (n-- == 0) return 0;
7804 if (*a == 0 && *b == 0) return 0;
7805 if (*a != *b) return 0 + *a - *b;
7806 a++;
7807 b++;
7808 }
7809}
7810
7811
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007812int GetUtf8Length(Handle<String> str) {
7813 int len = str->Utf8Length();
7814 if (len < 0) {
7815 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007816 i::String::Flatten(istr);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007817 len = str->Utf8Length();
7818 }
7819 return len;
7820}
7821
7822
Steve Blocka7e24c12009-10-30 11:49:00 +00007823THREADED_TEST(StringWrite) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007824 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007825 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00007826 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007827 // abc<Icelandic eth><Unicode snowman>.
7828 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007829 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7830 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7831 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7832 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7833 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7834 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7835 // single lead surrogate
7836 uint16_t lead[1] = { 0xd800 };
7837 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7838 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7839 // single trail surrogate
7840 uint16_t trail[1] = { 0xdc00 };
7841 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7842 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7843 // surrogate pair
7844 uint16_t pair[2] = { 0xd800, 0xdc00 };
7845 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7846 context->GetIsolate(), pair, v8::String::kNormalString, 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007847 const int kStride = 4; // Must match stride in for loops in JS below.
7848 CompileRun(
7849 "var left = '';"
7850 "for (var i = 0; i < 0xd800; i += 4) {"
7851 " left = left + String.fromCharCode(i);"
7852 "}");
7853 CompileRun(
7854 "var right = '';"
7855 "for (var i = 0; i < 0xd800; i += 4) {"
7856 " right = String.fromCharCode(i) + right;"
7857 "}");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007858 v8::Handle<v8::Object> global = context->Global();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007859 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7860 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007861
7862 CHECK_EQ(5, str2->Length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007863 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7864 CHECK_EQ(0xd800 / kStride, right_tree->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00007865
7866 char buf[100];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007867 char utf8buf[0xd800 * 3];
Ben Murdochb0fe1622011-05-05 13:52:32 +01007868 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00007869 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007870 int charlen;
7871
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007872 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007873 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007874 CHECK_EQ(9, len);
7875 CHECK_EQ(5, charlen);
7876 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007877
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007878 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007879 len = str2->WriteUtf8(utf8buf, 8, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007880 CHECK_EQ(8, len);
7881 CHECK_EQ(5, charlen);
7882 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007883
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007884 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007885 len = str2->WriteUtf8(utf8buf, 7, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007886 CHECK_EQ(5, len);
7887 CHECK_EQ(4, charlen);
7888 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007889
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007890 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007891 len = str2->WriteUtf8(utf8buf, 6, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007892 CHECK_EQ(5, len);
7893 CHECK_EQ(4, charlen);
7894 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007895
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007896 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007897 len = str2->WriteUtf8(utf8buf, 5, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007898 CHECK_EQ(5, len);
7899 CHECK_EQ(4, charlen);
7900 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007901
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007902 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007903 len = str2->WriteUtf8(utf8buf, 4, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007904 CHECK_EQ(3, len);
7905 CHECK_EQ(3, charlen);
7906 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007907
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007908 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007909 len = str2->WriteUtf8(utf8buf, 3, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007910 CHECK_EQ(3, len);
7911 CHECK_EQ(3, charlen);
7912 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007913
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007914 memset(utf8buf, 0x1, 1000);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007915 len = str2->WriteUtf8(utf8buf, 2, &charlen);
Steve Block44f0eee2011-05-26 01:26:41 +01007916 CHECK_EQ(2, len);
7917 CHECK_EQ(2, charlen);
7918 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
Steve Blocka7e24c12009-10-30 11:49:00 +00007919
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007920 // allow orphan surrogates by default
7921 memset(utf8buf, 0x1, 1000);
7922 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7923 CHECK_EQ(13, len);
7924 CHECK_EQ(8, charlen);
7925 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7926
7927 // replace orphan surrogates with unicode replacement character
7928 memset(utf8buf, 0x1, 1000);
7929 len = orphans_str->WriteUtf8(utf8buf,
7930 sizeof(utf8buf),
7931 &charlen,
7932 String::REPLACE_INVALID_UTF8);
7933 CHECK_EQ(13, len);
7934 CHECK_EQ(8, charlen);
7935 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7936
7937 // replace single lead surrogate with unicode replacement character
7938 memset(utf8buf, 0x1, 1000);
7939 len = lead_str->WriteUtf8(utf8buf,
7940 sizeof(utf8buf),
7941 &charlen,
7942 String::REPLACE_INVALID_UTF8);
7943 CHECK_EQ(4, len);
7944 CHECK_EQ(1, charlen);
7945 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7946
7947 // replace single trail surrogate with unicode replacement character
7948 memset(utf8buf, 0x1, 1000);
7949 len = trail_str->WriteUtf8(utf8buf,
7950 sizeof(utf8buf),
7951 &charlen,
7952 String::REPLACE_INVALID_UTF8);
7953 CHECK_EQ(4, len);
7954 CHECK_EQ(1, charlen);
7955 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7956
7957 // do not replace / write anything if surrogate pair does not fit the buffer
7958 // space
7959 memset(utf8buf, 0x1, 1000);
7960 len = pair_str->WriteUtf8(utf8buf,
7961 3,
7962 &charlen,
7963 String::REPLACE_INVALID_UTF8);
7964 CHECK_EQ(0, len);
7965 CHECK_EQ(0, charlen);
7966
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007967 memset(utf8buf, 0x1, sizeof(utf8buf));
7968 len = GetUtf8Length(left_tree);
7969 int utf8_expected =
7970 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7971 CHECK_EQ(utf8_expected, len);
7972 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7973 CHECK_EQ(utf8_expected, len);
7974 CHECK_EQ(0xd800 / kStride, charlen);
7975 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7976 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7977 CHECK_EQ(0xc0 - kStride,
7978 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7979 CHECK_EQ(1, utf8buf[utf8_expected]);
7980
7981 memset(utf8buf, 0x1, sizeof(utf8buf));
7982 len = GetUtf8Length(right_tree);
7983 CHECK_EQ(utf8_expected, len);
7984 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7985 CHECK_EQ(utf8_expected, len);
7986 CHECK_EQ(0xd800 / kStride, charlen);
7987 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7988 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7989 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7990 CHECK_EQ(1, utf8buf[utf8_expected]);
7991
Steve Blocka7e24c12009-10-30 11:49:00 +00007992 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007993 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007994 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
Steve Block44f0eee2011-05-26 01:26:41 +01007995 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007996 len = str->Write(wbuf);
Steve Block44f0eee2011-05-26 01:26:41 +01007997 CHECK_EQ(5, len);
7998 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007999 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008000 CHECK_EQ(0, StrCmp16(answer1, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008001
8002 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008003 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008004 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01008005 CHECK_EQ(4, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008006 len = str->Write(wbuf, 0, 4);
Steve Block44f0eee2011-05-26 01:26:41 +01008007 CHECK_EQ(4, len);
8008 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008009 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008010 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +00008011
8012 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008013 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008014 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01008015 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008016 len = str->Write(wbuf, 0, 5);
Steve Block44f0eee2011-05-26 01:26:41 +01008017 CHECK_EQ(5, len);
8018 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008019 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008020 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +00008021
8022 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008023 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008024 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008025 CHECK_EQ(5, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008026 len = str->Write(wbuf, 0, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008027 CHECK_EQ(5, len);
8028 CHECK_EQ(0, strcmp("abcde", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008029 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008030 CHECK_EQ(0, StrCmp16(answer4, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008031
8032 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008033 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008034 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01008035 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008036 len = str->Write(wbuf, 4, -1);
Steve Block44f0eee2011-05-26 01:26:41 +01008037 CHECK_EQ(1, len);
8038 CHECK_EQ(0, strcmp("e", buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008039 uint16_t answer5[] = {'e', '\0'};
Steve Block44f0eee2011-05-26 01:26:41 +01008040 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008041
8042 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008043 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008044 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008045 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008046 len = str->Write(wbuf, 4, 6);
Steve Block44f0eee2011-05-26 01:26:41 +01008047 CHECK_EQ(1, len);
8048 CHECK_EQ(0, strcmp("e", buf));
8049 CHECK_EQ(0, StrCmp16(answer5, wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00008050
8051 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008052 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008053 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008054 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008055 len = str->Write(wbuf, 4, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008056 CHECK_EQ(1, len);
8057 CHECK_EQ(0, strncmp("e\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008058 uint16_t answer6[] = {'e', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008059 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008060
8061 memset(buf, 0x1, sizeof(buf));
8062 memset(wbuf, 0x1, sizeof(wbuf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008063 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008064 CHECK_EQ(1, len);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008065 len = str->Write(wbuf, 3, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008066 CHECK_EQ(1, len);
8067 CHECK_EQ(0, strncmp("d\1", buf, 2));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008068 uint16_t answer7[] = {'d', 0x101};
Steve Block44f0eee2011-05-26 01:26:41 +01008069 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008070
8071 memset(wbuf, 0x1, sizeof(wbuf));
8072 wbuf[5] = 'X';
8073 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8074 CHECK_EQ(5, len);
8075 CHECK_EQ('X', wbuf[5]);
8076 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8077 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8078 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8079 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8080 wbuf[5] = '\0';
8081 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8082
8083 memset(buf, 0x1, sizeof(buf));
8084 buf[5] = 'X';
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008085 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8086 0,
8087 6,
8088 String::NO_NULL_TERMINATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008089 CHECK_EQ(5, len);
8090 CHECK_EQ('X', buf[5]);
8091 CHECK_EQ(0, strncmp("abcde", buf, 5));
8092 CHECK_NE(0, strcmp("abcde", buf));
8093 buf[5] = '\0';
8094 CHECK_EQ(0, strcmp("abcde", buf));
8095
8096 memset(utf8buf, 0x1, sizeof(utf8buf));
8097 utf8buf[8] = 'X';
8098 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8099 String::NO_NULL_TERMINATION);
8100 CHECK_EQ(8, len);
8101 CHECK_EQ('X', utf8buf[8]);
8102 CHECK_EQ(5, charlen);
8103 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8104 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8105 utf8buf[8] = '\0';
8106 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008107
8108 memset(utf8buf, 0x1, sizeof(utf8buf));
8109 utf8buf[5] = 'X';
8110 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8111 String::NO_NULL_TERMINATION);
8112 CHECK_EQ(5, len);
8113 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8114 CHECK_EQ(5, charlen);
8115 utf8buf[5] = '\0';
8116 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8117
8118 memset(buf, 0x1, sizeof(buf));
8119 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8120 CHECK_EQ(7, len);
8121 CHECK_EQ(0, strcmp("abc", buf));
8122 CHECK_EQ(0, buf[3]);
8123 CHECK_EQ(0, strcmp("def", buf + 4));
8124
8125 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8126 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8127 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
Steve Blocka7e24c12009-10-30 11:49:00 +00008128}
8129
8130
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008131static void Utf16Helper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008132 LocalContext& context, // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008133 const char* name,
8134 const char* lengths_name,
8135 int len) {
8136 Local<v8::Array> a =
8137 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8138 Local<v8::Array> alens =
8139 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8140 for (int i = 0; i < len; i++) {
8141 Local<v8::String> string =
8142 Local<v8::String>::Cast(a->Get(i));
8143 Local<v8::Number> expected_len =
8144 Local<v8::Number>::Cast(alens->Get(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008145 int length = GetUtf8Length(string);
8146 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8147 }
8148}
8149
8150
8151static uint16_t StringGet(Handle<String> str, int index) {
8152 i::Handle<i::String> istring =
8153 v8::Utils::OpenHandle(String::Cast(*str));
8154 return istring->Get(index);
8155}
8156
8157
8158static void WriteUtf8Helper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008159 LocalContext& context, // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008160 const char* name,
8161 const char* lengths_name,
8162 int len) {
8163 Local<v8::Array> b =
8164 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8165 Local<v8::Array> alens =
8166 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8167 char buffer[1000];
8168 char buffer2[1000];
8169 for (int i = 0; i < len; i++) {
8170 Local<v8::String> string =
8171 Local<v8::String>::Cast(b->Get(i));
8172 Local<v8::Number> expected_len =
8173 Local<v8::Number>::Cast(alens->Get(i));
8174 int utf8_length = static_cast<int>(expected_len->Value());
8175 for (int j = utf8_length + 1; j >= 0; j--) {
8176 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8177 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8178 int nchars;
8179 int utf8_written =
8180 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8181 int utf8_written2 =
8182 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8183 CHECK_GE(utf8_length + 1, utf8_written);
8184 CHECK_GE(utf8_length, utf8_written2);
8185 for (int k = 0; k < utf8_written2; k++) {
8186 CHECK_EQ(buffer[k], buffer2[k]);
8187 }
8188 CHECK(nchars * 3 >= utf8_written - 1);
8189 CHECK(nchars <= utf8_written);
8190 if (j == utf8_length + 1) {
8191 CHECK_EQ(utf8_written2, utf8_length);
8192 CHECK_EQ(utf8_written2 + 1, utf8_written);
8193 }
8194 CHECK_EQ(buffer[utf8_written], 42);
8195 if (j > utf8_length) {
8196 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8197 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8198 Handle<String> roundtrip = v8_str(buffer);
8199 CHECK(roundtrip->Equals(string));
8200 } else {
8201 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8202 }
8203 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8204 if (nchars >= 2) {
8205 uint16_t trail = StringGet(string, nchars - 1);
8206 uint16_t lead = StringGet(string, nchars - 2);
8207 if (((lead & 0xfc00) == 0xd800) &&
8208 ((trail & 0xfc00) == 0xdc00)) {
8209 unsigned char u1 = buffer2[utf8_written2 - 4];
8210 unsigned char u2 = buffer2[utf8_written2 - 3];
8211 unsigned char u3 = buffer2[utf8_written2 - 2];
8212 unsigned char u4 = buffer2[utf8_written2 - 1];
8213 CHECK_EQ((u1 & 0xf8), 0xf0);
8214 CHECK_EQ((u2 & 0xc0), 0x80);
8215 CHECK_EQ((u3 & 0xc0), 0x80);
8216 CHECK_EQ((u4 & 0xc0), 0x80);
8217 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8218 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8219 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8220 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8221 CHECK_EQ((u1 & 0x3), c >> 18);
8222 }
8223 }
8224 }
8225 }
8226}
8227
8228
8229THREADED_TEST(Utf16) {
8230 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008231 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008232 CompileRun(
8233 "var pad = '01234567890123456789';"
8234 "var p = [];"
8235 "var plens = [20, 3, 3];"
8236 "p.push('01234567890123456789');"
8237 "var lead = 0xd800;"
8238 "var trail = 0xdc00;"
8239 "p.push(String.fromCharCode(0xd800));"
8240 "p.push(String.fromCharCode(0xdc00));"
8241 "var a = [];"
8242 "var b = [];"
8243 "var c = [];"
8244 "var alens = [];"
8245 "for (var i = 0; i < 3; i++) {"
8246 " p[1] = String.fromCharCode(lead++);"
8247 " for (var j = 0; j < 3; j++) {"
8248 " p[2] = String.fromCharCode(trail++);"
8249 " a.push(p[i] + p[j]);"
8250 " b.push(p[i] + p[j]);"
8251 " c.push(p[i] + p[j]);"
8252 " alens.push(plens[i] + plens[j]);"
8253 " }"
8254 "}"
8255 "alens[5] -= 2;" // Here the surrogate pairs match up.
8256 "var a2 = [];"
8257 "var b2 = [];"
8258 "var c2 = [];"
8259 "var a2lens = [];"
8260 "for (var m = 0; m < 9; m++) {"
8261 " for (var n = 0; n < 9; n++) {"
8262 " a2.push(a[m] + a[n]);"
8263 " b2.push(b[m] + b[n]);"
8264 " var newc = 'x' + c[m] + c[n] + 'y';"
8265 " c2.push(newc.substring(1, newc.length - 1));"
8266 " var utf = alens[m] + alens[n];" // And here.
8267 // The 'n's that start with 0xdc.. are 6-8
8268 // The 'm's that end with 0xd8.. are 1, 4 and 7
8269 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8270 " a2lens.push(utf);"
8271 " }"
8272 "}");
8273 Utf16Helper(context, "a", "alens", 9);
8274 Utf16Helper(context, "a2", "a2lens", 81);
8275 WriteUtf8Helper(context, "b", "alens", 9);
8276 WriteUtf8Helper(context, "b2", "a2lens", 81);
8277 WriteUtf8Helper(context, "c2", "a2lens", 81);
8278}
8279
8280
8281static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8282 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8283 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8284 return *is1 == *is2;
8285}
8286
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008287static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8288 const char* b) {
8289 Handle<String> symbol1 =
8290 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8291 Handle<String> symbol2 =
8292 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008293 CHECK(SameSymbol(symbol1, symbol2));
8294}
8295
8296
8297THREADED_TEST(Utf16Symbol) {
8298 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008299 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008300
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008301 Handle<String> symbol1 = v8::String::NewFromUtf8(
8302 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8303 Handle<String> symbol2 = v8::String::NewFromUtf8(
8304 context->GetIsolate(), "abc", v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008305 CHECK(SameSymbol(symbol1, symbol2));
8306
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008307 SameSymbolHelper(context->GetIsolate(),
8308 "\360\220\220\205", // 4 byte encoding.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008309 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008310 SameSymbolHelper(context->GetIsolate(),
8311 "\355\240\201\355\260\206", // 2 3-byte surrogates.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008312 "\360\220\220\206"); // 4 byte encoding.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008313 SameSymbolHelper(context->GetIsolate(),
8314 "x\360\220\220\205", // 4 byte encoding.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008315 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008316 SameSymbolHelper(context->GetIsolate(),
8317 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008318 "x\360\220\220\206"); // 4 byte encoding.
8319 CompileRun(
8320 "var sym0 = 'benedictus';"
8321 "var sym0b = 'S\303\270ren';"
8322 "var sym1 = '\355\240\201\355\260\207';"
8323 "var sym2 = '\360\220\220\210';"
8324 "var sym3 = 'x\355\240\201\355\260\207';"
8325 "var sym4 = 'x\360\220\220\210';"
8326 "if (sym1.length != 2) throw sym1;"
8327 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8328 "if (sym2.length != 2) throw sym2;"
8329 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8330 "if (sym3.length != 3) throw sym3;"
8331 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8332 "if (sym4.length != 3) throw sym4;"
8333 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008334 Handle<String> sym0 = v8::String::NewFromUtf8(
8335 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8336 Handle<String> sym0b = v8::String::NewFromUtf8(
8337 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8338 Handle<String> sym1 =
8339 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8340 v8::String::kInternalizedString);
8341 Handle<String> sym2 =
8342 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8343 v8::String::kInternalizedString);
8344 Handle<String> sym3 = v8::String::NewFromUtf8(
8345 context->GetIsolate(), "x\355\240\201\355\260\207",
8346 v8::String::kInternalizedString);
8347 Handle<String> sym4 =
8348 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8349 v8::String::kInternalizedString);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008350 v8::Local<v8::Object> global = context->Global();
8351 Local<Value> s0 = global->Get(v8_str("sym0"));
8352 Local<Value> s0b = global->Get(v8_str("sym0b"));
8353 Local<Value> s1 = global->Get(v8_str("sym1"));
8354 Local<Value> s2 = global->Get(v8_str("sym2"));
8355 Local<Value> s3 = global->Get(v8_str("sym3"));
8356 Local<Value> s4 = global->Get(v8_str("sym4"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008357 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8358 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8359 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8360 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8361 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8362 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008363}
8364
8365
Steve Blocka7e24c12009-10-30 11:49:00 +00008366THREADED_TEST(ToArrayIndex) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008367 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008368 v8::Isolate* isolate = context->GetIsolate();
8369 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008370
8371 v8::Handle<String> str = v8_str("42");
8372 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8373 CHECK(!index.IsEmpty());
8374 CHECK_EQ(42.0, index->Uint32Value());
8375 str = v8_str("42asdf");
8376 index = str->ToArrayIndex();
8377 CHECK(index.IsEmpty());
8378 str = v8_str("-42");
8379 index = str->ToArrayIndex();
8380 CHECK(index.IsEmpty());
8381 str = v8_str("4294967295");
8382 index = str->ToArrayIndex();
8383 CHECK(!index.IsEmpty());
8384 CHECK_EQ(4294967295.0, index->Uint32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008385 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00008386 index = num->ToArrayIndex();
8387 CHECK(!index.IsEmpty());
8388 CHECK_EQ(1.0, index->Uint32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008389 num = v8::Number::New(isolate, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +00008390 index = num->ToArrayIndex();
8391 CHECK(index.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008392 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008393 index = obj->ToArrayIndex();
8394 CHECK(index.IsEmpty());
8395}
8396
8397
8398THREADED_TEST(ErrorConstruction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008399 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008400 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008401
8402 v8::Handle<String> foo = v8_str("foo");
8403 v8::Handle<String> message = v8_str("message");
8404 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8405 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008406 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008407 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8408 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008409 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008410 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8411 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008412 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008413 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8414 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008415 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008416 v8::Handle<Value> error = v8::Exception::Error(foo);
8417 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01008418 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00008419}
8420
8421
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008422static void YGetter(Local<String> name,
8423 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008424 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008425 info.GetReturnValue().Set(v8_num(10));
Steve Blocka7e24c12009-10-30 11:49:00 +00008426}
8427
8428
8429static void YSetter(Local<String> name,
8430 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008431 const v8::PropertyCallbackInfo<void>& info) {
8432 Local<Object> this_obj = Local<Object>::Cast(info.This());
8433 if (this_obj->Has(name)) this_obj->Delete(name);
8434 this_obj->Set(name, value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008435}
8436
8437
8438THREADED_TEST(DeleteAccessor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008439 v8::Isolate* isolate = CcTest::isolate();
8440 v8::HandleScope scope(isolate);
8441 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008442 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8443 LocalContext context;
8444 v8::Handle<v8::Object> holder = obj->NewInstance();
8445 context->Global()->Set(v8_str("holder"), holder);
8446 v8::Handle<Value> result = CompileRun(
8447 "holder.y = 11; holder.y = 12; holder.y");
8448 CHECK_EQ(12, result->Uint32Value());
8449}
8450
8451
8452THREADED_TEST(TypeSwitch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008453 v8::Isolate* isolate = CcTest::isolate();
8454 v8::HandleScope scope(isolate);
8455 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8456 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8457 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008458 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8459 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8460 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008461 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008462 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8463 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8464 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8465 for (int i = 0; i < 10; i++) {
8466 CHECK_EQ(0, type_switch->match(obj0));
8467 CHECK_EQ(1, type_switch->match(obj1));
8468 CHECK_EQ(2, type_switch->match(obj2));
8469 CHECK_EQ(3, type_switch->match(obj3));
8470 CHECK_EQ(3, type_switch->match(obj3));
8471 CHECK_EQ(2, type_switch->match(obj2));
8472 CHECK_EQ(1, type_switch->match(obj1));
8473 CHECK_EQ(0, type_switch->match(obj0));
8474 }
8475}
8476
8477
Steve Blocka7e24c12009-10-30 11:49:00 +00008478static int trouble_nesting = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008479static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008480 ApiTestFuzzer::Fuzz();
8481 trouble_nesting++;
8482
8483 // Call a JS function that throws an uncaught exception.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008484 Local<v8::Object> arg_this =
8485 args.GetIsolate()->GetCurrentContext()->Global();
Steve Blocka7e24c12009-10-30 11:49:00 +00008486 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8487 arg_this->Get(v8_str("trouble_callee")) :
8488 arg_this->Get(v8_str("trouble_caller"));
8489 CHECK(trouble_callee->IsFunction());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008490 args.GetReturnValue().Set(
8491 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00008492}
8493
8494
8495static int report_count = 0;
8496static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8497 v8::Handle<Value>) {
8498 report_count++;
8499}
8500
8501
8502// Counts uncaught exceptions, but other tests running in parallel
8503// also have uncaught exceptions.
8504TEST(ApiUncaughtException) {
8505 report_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008506 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008507 v8::Isolate* isolate = env->GetIsolate();
8508 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008509 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8510
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008511 Local<v8::FunctionTemplate> fun =
8512 v8::FunctionTemplate::New(isolate, TroubleCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +00008513 v8::Local<v8::Object> global = env->Global();
8514 global->Set(v8_str("trouble"), fun->GetFunction());
8515
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008516 CompileRun(
8517 "function trouble_callee() {"
8518 " var x = null;"
8519 " return x.foo;"
8520 "};"
8521 "function trouble_caller() {"
8522 " trouble();"
8523 "};");
Steve Blocka7e24c12009-10-30 11:49:00 +00008524 Local<Value> trouble = global->Get(v8_str("trouble"));
8525 CHECK(trouble->IsFunction());
8526 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8527 CHECK(trouble_callee->IsFunction());
8528 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8529 CHECK(trouble_caller->IsFunction());
8530 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8531 CHECK_EQ(1, report_count);
8532 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8533}
8534
Leon Clarke4515c472010-02-03 11:58:03 +00008535static const char* script_resource_name = "ExceptionInNativeScript.js";
8536static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8537 v8::Handle<Value>) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008538 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
Leon Clarke4515c472010-02-03 11:58:03 +00008539 CHECK(!name_val.IsEmpty() && name_val->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008540 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
Leon Clarke4515c472010-02-03 11:58:03 +00008541 CHECK_EQ(script_resource_name, *name);
8542 CHECK_EQ(3, message->GetLineNumber());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008543 v8::String::Utf8Value source_line(message->GetSourceLine());
Leon Clarke4515c472010-02-03 11:58:03 +00008544 CHECK_EQ(" new o.foo();", *source_line);
8545}
8546
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008547
Leon Clarke4515c472010-02-03 11:58:03 +00008548TEST(ExceptionInNativeScript) {
Leon Clarke4515c472010-02-03 11:58:03 +00008549 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008550 v8::Isolate* isolate = env->GetIsolate();
8551 v8::HandleScope scope(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +00008552 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8553
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008554 Local<v8::FunctionTemplate> fun =
8555 v8::FunctionTemplate::New(isolate, TroubleCallback);
Leon Clarke4515c472010-02-03 11:58:03 +00008556 v8::Local<v8::Object> global = env->Global();
8557 global->Set(v8_str("trouble"), fun->GetFunction());
8558
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008559 CompileRunWithOrigin(
8560 "function trouble() {\n"
8561 " var o = {};\n"
8562 " new o.foo();\n"
8563 "};",
8564 script_resource_name);
Leon Clarke4515c472010-02-03 11:58:03 +00008565 Local<Value> trouble = global->Get(v8_str("trouble"));
8566 CHECK(trouble->IsFunction());
8567 Function::Cast(*trouble)->Call(global, 0, NULL);
8568 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8569}
8570
Steve Blocka7e24c12009-10-30 11:49:00 +00008571
8572TEST(CompilationErrorUsingTryCatchHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008573 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008574 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008575 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008576 v8_compile("This doesn't &*&@#$&*^ compile.");
Steve Blocka7e24c12009-10-30 11:49:00 +00008577 CHECK_NE(NULL, *try_catch.Exception());
8578 CHECK(try_catch.HasCaught());
8579}
8580
8581
8582TEST(TryCatchFinallyUsingTryCatchHandler) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008583 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008584 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008585 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008586 CompileRun("try { throw ''; } catch (e) {}");
Steve Blocka7e24c12009-10-30 11:49:00 +00008587 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008588 CompileRun("try { throw ''; } finally {}");
Steve Blocka7e24c12009-10-30 11:49:00 +00008589 CHECK(try_catch.HasCaught());
8590 try_catch.Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008591 CompileRun(
8592 "(function() {"
8593 "try { throw ''; } finally { return; }"
8594 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00008595 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008596 CompileRun(
8597 "(function()"
8598 " { try { throw ''; } finally { throw 0; }"
8599 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00008600 CHECK(try_catch.HasCaught());
8601}
8602
8603
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008604void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8605 v8::HandleScope scope(args.GetIsolate());
8606 CompileRun(args[0]->ToString());
8607}
8608
8609
8610TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8611 v8::Isolate* isolate = CcTest::isolate();
8612 v8::HandleScope scope(isolate);
8613 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8614 templ->Set(v8_str("CEvaluate"),
8615 v8::FunctionTemplate::New(isolate, CEvaluate));
8616 LocalContext context(0, templ);
8617 v8::TryCatch try_catch;
8618 CompileRun("try {"
8619 " CEvaluate('throw 1;');"
8620 "} finally {"
8621 "}");
8622 CHECK(try_catch.HasCaught());
8623 CHECK(!try_catch.Message().IsEmpty());
8624 String::Utf8Value exception_value(try_catch.Exception());
8625 CHECK_EQ(*exception_value, "1");
8626 try_catch.Reset();
8627 CompileRun("try {"
8628 " CEvaluate('throw 1;');"
8629 "} finally {"
8630 " throw 2;"
8631 "}");
8632 CHECK(try_catch.HasCaught());
8633 CHECK(!try_catch.Message().IsEmpty());
8634 String::Utf8Value finally_exception_value(try_catch.Exception());
8635 CHECK_EQ(*finally_exception_value, "2");
8636}
8637
8638
8639// For use within the TestSecurityHandler() test.
8640static bool g_security_callback_result = false;
8641static bool NamedSecurityTestCallback(Local<v8::Object> global,
8642 Local<Value> name,
8643 v8::AccessType type,
8644 Local<Value> data) {
8645 printf("a\n");
8646 // Always allow read access.
8647 if (type == v8::ACCESS_GET)
8648 return true;
8649
8650 // Sometimes allow other access.
8651 return g_security_callback_result;
8652}
8653
8654
8655static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8656 uint32_t key,
8657 v8::AccessType type,
8658 Local<Value> data) {
8659 printf("b\n");
8660 // Always allow read access.
8661 if (type == v8::ACCESS_GET)
8662 return true;
8663
8664 // Sometimes allow other access.
8665 return g_security_callback_result;
8666}
8667
8668
Steve Blocka7e24c12009-10-30 11:49:00 +00008669// SecurityHandler can't be run twice
8670TEST(SecurityHandler) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008671 v8::Isolate* isolate = CcTest::isolate();
8672 v8::HandleScope scope0(isolate);
8673 v8::Handle<v8::ObjectTemplate> global_template =
8674 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008675 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8676 IndexedSecurityTestCallback);
8677 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008678 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00008679 context0->Enter();
8680
8681 v8::Handle<v8::Object> global0 = context0->Global();
8682 v8::Handle<Script> script0 = v8_compile("foo = 111");
8683 script0->Run();
8684 global0->Set(v8_str("0"), v8_num(999));
8685 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8686 CHECK_EQ(111, foo0->Int32Value());
8687 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8688 CHECK_EQ(999, z0->Int32Value());
8689
8690 // Create another environment, should fail security checks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008691 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008692
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008693 v8::Handle<Context> context1 =
8694 Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00008695 context1->Enter();
8696
8697 v8::Handle<v8::Object> global1 = context1->Global();
8698 global1->Set(v8_str("othercontext"), global0);
8699 // This set will fail the security check.
8700 v8::Handle<Script> script1 =
8701 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8702 script1->Run();
8703 // This read will pass the security check.
8704 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8705 CHECK_EQ(111, foo1->Int32Value());
8706 // This read will pass the security check.
8707 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8708 CHECK_EQ(999, z1->Int32Value());
8709
8710 // Create another environment, should pass security checks.
8711 { g_security_callback_result = true; // allow security handler to pass.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008712 v8::HandleScope scope2(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008713 LocalContext context2;
8714 v8::Handle<v8::Object> global2 = context2->Global();
8715 global2->Set(v8_str("othercontext"), global0);
8716 v8::Handle<Script> script2 =
8717 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8718 script2->Run();
8719 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8720 CHECK_EQ(333, foo2->Int32Value());
8721 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8722 CHECK_EQ(888, z2->Int32Value());
8723 }
8724
8725 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00008726 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00008727}
8728
8729
8730THREADED_TEST(SecurityChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008731 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008732 v8::HandleScope handle_scope(env1->GetIsolate());
8733 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008734
8735 Local<Value> foo = v8_str("foo");
8736 Local<Value> bar = v8_str("bar");
8737
8738 // Set to the same domain.
8739 env1->SetSecurityToken(foo);
8740
8741 // Create a function in env1.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008742 CompileRun("spy=function(){return spy;}");
Steve Blocka7e24c12009-10-30 11:49:00 +00008743 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8744 CHECK(spy->IsFunction());
8745
8746 // Create another function accessing global objects.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008747 CompileRun("spy2=function(){return new this.Array();}");
Steve Blocka7e24c12009-10-30 11:49:00 +00008748 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8749 CHECK(spy2->IsFunction());
8750
8751 // Switch to env2 in the same domain and invoke spy on env2.
8752 {
8753 env2->SetSecurityToken(foo);
8754 // Enter env2
8755 Context::Scope scope_env2(env2);
8756 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8757 CHECK(result->IsFunction());
8758 }
8759
8760 {
8761 env2->SetSecurityToken(bar);
8762 Context::Scope scope_env2(env2);
8763
8764 // Call cross_domain_call, it should throw an exception
8765 v8::TryCatch try_catch;
8766 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8767 CHECK(try_catch.HasCaught());
8768 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008769}
8770
8771
8772// Regression test case for issue 1183439.
8773THREADED_TEST(SecurityChecksForPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008774 LocalContext current;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008775 v8::HandleScope scope(current->GetIsolate());
8776 v8::Handle<Context> other = Context::New(current->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008777
8778 // Change context to be able to get to the Object function in the
8779 // other context without hitting the security checks.
8780 v8::Local<Value> other_object;
8781 { Context::Scope scope(other);
8782 other_object = other->Global()->Get(v8_str("Object"));
8783 other->Global()->Set(v8_num(42), v8_num(87));
8784 }
8785
8786 current->Global()->Set(v8_str("other"), other->Global());
8787 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8788
8789 // Make sure the security check fails here and we get an undefined
8790 // result instead of getting the Object function. Repeat in a loop
8791 // to make sure to exercise the IC code.
8792 v8::Local<Script> access_other0 = v8_compile("other.Object");
8793 v8::Local<Script> access_other1 = v8_compile("other[42]");
8794 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008795 CHECK(access_other0->Run().IsEmpty());
8796 CHECK(access_other1->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00008797 }
8798
8799 // Create an object that has 'other' in its prototype chain and make
8800 // sure we cannot access the Object function indirectly through
8801 // that. Repeat in a loop to make sure to exercise the IC code.
8802 v8_compile("function F() { };"
8803 "F.prototype = other;"
8804 "var f = new F();")->Run();
8805 v8::Local<Script> access_f0 = v8_compile("f.Object");
8806 v8::Local<Script> access_f1 = v8_compile("f[42]");
8807 for (int j = 0; j < 5; j++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008808 CHECK(access_f0->Run().IsEmpty());
8809 CHECK(access_f1->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00008810 }
8811
8812 // Now it gets hairy: Set the prototype for the other global object
8813 // to be the current global object. The prototype chain for 'f' now
8814 // goes through 'other' but ends up in the current global object.
8815 { Context::Scope scope(other);
8816 other->Global()->Set(v8_str("__proto__"), current->Global());
8817 }
8818 // Set a named and an index property on the current global
8819 // object. To force the lookup to go through the other global object,
8820 // the properties must not exist in the other global object.
8821 current->Global()->Set(v8_str("foo"), v8_num(100));
8822 current->Global()->Set(v8_num(99), v8_num(101));
8823 // Try to read the properties from f and make sure that the access
8824 // gets stopped by the security checks on the other global object.
8825 Local<Script> access_f2 = v8_compile("f.foo");
8826 Local<Script> access_f3 = v8_compile("f[99]");
8827 for (int k = 0; k < 5; k++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008828 CHECK(access_f2->Run().IsEmpty());
8829 CHECK(access_f3->Run().IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00008830 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008831}
8832
8833
8834static bool named_security_check_with_gc_called;
8835
8836static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8837 Local<Value> name,
8838 v8::AccessType type,
8839 Local<Value> data) {
8840 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8841 named_security_check_with_gc_called = true;
8842 return true;
8843}
8844
8845
8846static bool indexed_security_check_with_gc_called;
8847
8848static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8849 uint32_t key,
8850 v8::AccessType type,
8851 Local<Value> data) {
8852 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8853 indexed_security_check_with_gc_called = true;
8854 return true;
8855}
8856
8857
8858TEST(SecurityTestGCAllowed) {
8859 v8::Isolate* isolate = CcTest::isolate();
8860 v8::HandleScope handle_scope(isolate);
8861 v8::Handle<v8::ObjectTemplate> object_template =
8862 v8::ObjectTemplate::New(isolate);
8863 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8864 IndexedSecurityTestCallbackWithGC);
8865
8866 v8::Handle<Context> context = Context::New(isolate);
8867 v8::Context::Scope context_scope(context);
8868
8869 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8870
8871 named_security_check_with_gc_called = false;
8872 CompileRun("obj.foo = new String(1001);");
8873 CHECK(named_security_check_with_gc_called);
8874
8875 indexed_security_check_with_gc_called = false;
8876 CompileRun("obj[0] = new String(1002);");
8877 CHECK(indexed_security_check_with_gc_called);
8878
8879 named_security_check_with_gc_called = false;
8880 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8881 CHECK(named_security_check_with_gc_called);
8882
8883 indexed_security_check_with_gc_called = false;
8884 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8885 CHECK(indexed_security_check_with_gc_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00008886}
8887
8888
8889THREADED_TEST(CrossDomainDelete) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008890 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008891 v8::HandleScope handle_scope(env1->GetIsolate());
8892 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008893
8894 Local<Value> foo = v8_str("foo");
8895 Local<Value> bar = v8_str("bar");
8896
8897 // Set to the same domain.
8898 env1->SetSecurityToken(foo);
8899 env2->SetSecurityToken(foo);
8900
8901 env1->Global()->Set(v8_str("prop"), v8_num(3));
8902 env2->Global()->Set(v8_str("env1"), env1->Global());
8903
8904 // Change env2 to a different domain and delete env1.prop.
8905 env2->SetSecurityToken(bar);
8906 {
8907 Context::Scope scope_env2(env2);
8908 Local<Value> result =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008909 CompileRun("delete env1.prop");
8910 CHECK(result.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00008911 }
8912
8913 // Check that env1.prop still exists.
8914 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8915 CHECK(v->IsNumber());
8916 CHECK_EQ(3, v->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008917}
8918
8919
8920THREADED_TEST(CrossDomainIsPropertyEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008921 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008922 v8::HandleScope handle_scope(env1->GetIsolate());
8923 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008924
8925 Local<Value> foo = v8_str("foo");
8926 Local<Value> bar = v8_str("bar");
8927
8928 // Set to the same domain.
8929 env1->SetSecurityToken(foo);
8930 env2->SetSecurityToken(foo);
8931
8932 env1->Global()->Set(v8_str("prop"), v8_num(3));
8933 env2->Global()->Set(v8_str("env1"), env1->Global());
8934
8935 // env1.prop is enumerable in env2.
8936 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8937 {
8938 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008939 Local<Value> result = CompileRun(test);
Steve Blocka7e24c12009-10-30 11:49:00 +00008940 CHECK(result->IsTrue());
8941 }
8942
8943 // Change env2 to a different domain and test again.
8944 env2->SetSecurityToken(bar);
8945 {
8946 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008947 Local<Value> result = CompileRun(test);
8948 CHECK(result.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00008949 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008950}
8951
8952
8953THREADED_TEST(CrossDomainForIn) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008954 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008955 v8::HandleScope handle_scope(env1->GetIsolate());
8956 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008957
8958 Local<Value> foo = v8_str("foo");
8959 Local<Value> bar = v8_str("bar");
8960
8961 // Set to the same domain.
8962 env1->SetSecurityToken(foo);
8963 env2->SetSecurityToken(foo);
8964
8965 env1->Global()->Set(v8_str("prop"), v8_num(3));
8966 env2->Global()->Set(v8_str("env1"), env1->Global());
8967
8968 // Change env2 to a different domain and set env1's global object
8969 // as the __proto__ of an object in env2 and enumerate properties
8970 // in for-in. It shouldn't enumerate properties on env1's global
8971 // object.
8972 env2->SetSecurityToken(bar);
8973 {
8974 Context::Scope scope_env2(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008975 Local<Value> result = CompileRun(
8976 "(function() {"
8977 " var obj = { '__proto__': env1 };"
8978 " try {"
8979 " for (var p in obj) {"
8980 " if (p == 'prop') return false;"
8981 " }"
8982 " return false;"
8983 " } catch (e) {"
8984 " return true;"
8985 " }"
8986 "})()");
Steve Blocka7e24c12009-10-30 11:49:00 +00008987 CHECK(result->IsTrue());
8988 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008989}
8990
8991
8992TEST(ContextDetachGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008993 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008994 v8::HandleScope handle_scope(env1->GetIsolate());
8995 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00008996
8997 Local<v8::Object> global1 = env1->Global();
8998
8999 Local<Value> foo = v8_str("foo");
9000
9001 // Set to the same domain.
9002 env1->SetSecurityToken(foo);
9003 env2->SetSecurityToken(foo);
9004
9005 // Enter env2
9006 env2->Enter();
9007
Andrei Popescu74b3c142010-03-29 12:03:09 +01009008 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00009009 Local<v8::Object> global2 = env2->Global();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009010 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009011 CompileRun("function getProp() {return prop;}");
9012
9013 env1->Global()->Set(v8_str("getProp"),
9014 global2->Get(v8_str("getProp")));
9015
Andrei Popescu74b3c142010-03-29 12:03:09 +01009016 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00009017 env2->Exit();
9018 env2->DetachGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00009019
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009020 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9021 0,
9022 v8::Handle<v8::ObjectTemplate>(),
9023 global2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009024 env3->SetSecurityToken(v8_str("bar"));
9025 env3->Enter();
9026
9027 Local<v8::Object> global3 = env3->Global();
9028 CHECK_EQ(global2, global3);
9029 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9030 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009031 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9032 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
Steve Blocka7e24c12009-10-30 11:49:00 +00009033 env3->Exit();
9034
9035 // Call getProp in env1, and it should return the value 1
9036 {
9037 Local<Value> get_prop = global1->Get(v8_str("getProp"));
9038 CHECK(get_prop->IsFunction());
9039 v8::TryCatch try_catch;
9040 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9041 CHECK(!try_catch.HasCaught());
9042 CHECK_EQ(1, r->Int32Value());
9043 }
9044
9045 // Check that env3 is not accessible from env1
9046 {
9047 Local<Value> r = global3->Get(v8_str("prop2"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009048 CHECK(r.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009049 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009050}
9051
9052
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009053TEST(DetachGlobal) {
Andrei Popescu74b3c142010-03-29 12:03:09 +01009054 LocalContext env1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009055 v8::HandleScope scope(env1->GetIsolate());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009056
9057 // Create second environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009058 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009059
9060 Local<Value> foo = v8_str("foo");
9061
9062 // Set same security token for env1 and env2.
9063 env1->SetSecurityToken(foo);
9064 env2->SetSecurityToken(foo);
9065
9066 // Create a property on the global object in env2.
9067 {
9068 v8::Context::Scope scope(env2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009069 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
Andrei Popescu74b3c142010-03-29 12:03:09 +01009070 }
9071
9072 // Create a reference to env2 global from env1 global.
9073 env1->Global()->Set(v8_str("other"), env2->Global());
9074
9075 // Check that we have access to other.p in env2 from env1.
9076 Local<Value> result = CompileRun("other.p");
9077 CHECK(result->IsInt32());
9078 CHECK_EQ(42, result->Int32Value());
9079
9080 // Hold on to global from env2 and detach global from env2.
9081 Local<v8::Object> global2 = env2->Global();
9082 env2->DetachGlobal();
9083
9084 // Check that the global has been detached. No other.p property can
9085 // be found.
9086 result = CompileRun("other.p");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009087 CHECK(result.IsEmpty());
Andrei Popescu74b3c142010-03-29 12:03:09 +01009088
9089 // Reuse global2 for env3.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009090 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9091 0,
9092 v8::Handle<v8::ObjectTemplate>(),
9093 global2);
Andrei Popescu74b3c142010-03-29 12:03:09 +01009094 CHECK_EQ(global2, env3->Global());
9095
9096 // Start by using the same security token for env3 as for env1 and env2.
9097 env3->SetSecurityToken(foo);
9098
9099 // Create a property on the global object in env3.
9100 {
9101 v8::Context::Scope scope(env3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009102 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
Andrei Popescu74b3c142010-03-29 12:03:09 +01009103 }
9104
9105 // Check that other.p is now the property in env3 and that we have access.
9106 result = CompileRun("other.p");
9107 CHECK(result->IsInt32());
9108 CHECK_EQ(24, result->Int32Value());
9109
9110 // Change security token for env3 to something different from env1 and env2.
9111 env3->SetSecurityToken(v8_str("bar"));
9112
9113 // Check that we do not have access to other.p in env1. |other| is now
9114 // the global object for env3 which has a different security token,
9115 // so access should be blocked.
9116 result = CompileRun("other.p");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009117 CHECK(result.IsEmpty());
9118}
Andrei Popescu74b3c142010-03-29 12:03:09 +01009119
Andrei Popescu74b3c142010-03-29 12:03:09 +01009120
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009121void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9122 info.GetReturnValue().Set(
9123 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9124}
Andrei Popescu74b3c142010-03-29 12:03:09 +01009125
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009126
9127TEST(DetachedAccesses) {
9128 LocalContext env1;
9129 v8::HandleScope scope(env1->GetIsolate());
9130
9131 // Create second environment.
9132 Local<ObjectTemplate> inner_global_template =
9133 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9134 inner_global_template ->SetAccessorProperty(
9135 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9136 v8::Local<Context> env2 =
9137 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9138
9139 Local<Value> foo = v8_str("foo");
9140
9141 // Set same security token for env1 and env2.
9142 env1->SetSecurityToken(foo);
9143 env2->SetSecurityToken(foo);
9144
9145 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9146
9147 {
9148 v8::Context::Scope scope(env2);
9149 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9150 CompileRun(
9151 "function bound_x() { return x; }"
9152 "function get_x() { return this.x; }"
9153 "function get_x_w() { return (function() {return this.x;})(); }");
9154 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9155 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9156 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9157 env1->Global()->Set(
9158 v8_str("this_x"),
9159 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9160 }
9161
9162 Local<Object> env2_global = env2->Global();
9163 env2_global->TurnOnAccessCheck();
9164 env2->DetachGlobal();
9165
9166 Local<Value> result;
9167 result = CompileRun("bound_x()");
9168 CHECK_EQ(v8_str("env2_x"), result);
9169 result = CompileRun("get_x()");
9170 CHECK(result.IsEmpty());
9171 result = CompileRun("get_x_w()");
9172 CHECK(result.IsEmpty());
9173 result = CompileRun("this_x()");
9174 CHECK_EQ(v8_str("env2_x"), result);
9175
9176 // Reattach env2's proxy
9177 env2 = Context::New(env1->GetIsolate(),
9178 0,
9179 v8::Handle<v8::ObjectTemplate>(),
9180 env2_global);
9181 env2->SetSecurityToken(foo);
9182 {
9183 v8::Context::Scope scope(env2);
9184 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9185 env2->Global()->Set(v8_str("env1"), env1->Global());
9186 result = CompileRun(
9187 "results = [];"
9188 "for (var i = 0; i < 4; i++ ) {"
9189 " results.push(env1.bound_x());"
9190 " results.push(env1.get_x());"
9191 " results.push(env1.get_x_w());"
9192 " results.push(env1.this_x());"
9193 "}"
9194 "results");
9195 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9196 CHECK_EQ(16, results->Length());
9197 for (int i = 0; i < 16; i += 4) {
9198 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9199 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9200 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9201 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9202 }
9203 }
9204
9205 result = CompileRun(
9206 "results = [];"
9207 "for (var i = 0; i < 4; i++ ) {"
9208 " results.push(bound_x());"
9209 " results.push(get_x());"
9210 " results.push(get_x_w());"
9211 " results.push(this_x());"
9212 "}"
9213 "results");
9214 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9215 CHECK_EQ(16, results->Length());
9216 for (int i = 0; i < 16; i += 4) {
9217 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9218 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9219 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9220 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9221 }
9222
9223 result = CompileRun(
9224 "results = [];"
9225 "for (var i = 0; i < 4; i++ ) {"
9226 " results.push(this.bound_x());"
9227 " results.push(this.get_x());"
9228 " results.push(this.get_x_w());"
9229 " results.push(this.this_x());"
9230 "}"
9231 "results");
9232 results = Local<v8::Array>::Cast(result);
9233 CHECK_EQ(16, results->Length());
9234 for (int i = 0; i < 16; i += 4) {
9235 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9236 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9237 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9238 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9239 }
Andrei Popescu74b3c142010-03-29 12:03:09 +01009240}
9241
9242
Steve Block1e0659c2011-05-24 12:43:12 +01009243static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
Steve Blocka7e24c12009-10-30 11:49:00 +00009244static bool NamedAccessBlocker(Local<v8::Object> global,
9245 Local<Value> name,
9246 v8::AccessType type,
9247 Local<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009248 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
Steve Block1e0659c2011-05-24 12:43:12 +01009249 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00009250}
9251
9252
9253static bool IndexedAccessBlocker(Local<v8::Object> global,
9254 uint32_t key,
9255 v8::AccessType type,
9256 Local<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009257 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
Steve Block1e0659c2011-05-24 12:43:12 +01009258 allowed_access_type[type];
Steve Blocka7e24c12009-10-30 11:49:00 +00009259}
9260
9261
9262static int g_echo_value = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009263
9264
9265static void EchoGetter(
9266 Local<String> name,
9267 const v8::PropertyCallbackInfo<v8::Value>& info) {
9268 info.GetReturnValue().Set(v8_num(g_echo_value));
Steve Blocka7e24c12009-10-30 11:49:00 +00009269}
9270
9271
9272static void EchoSetter(Local<String> name,
9273 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009274 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009275 if (value->IsNumber())
9276 g_echo_value = value->Int32Value();
9277}
9278
9279
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009280static void UnreachableGetter(
9281 Local<String> name,
9282 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009283 CHECK(false); // This function should not be called..
Steve Blocka7e24c12009-10-30 11:49:00 +00009284}
9285
9286
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009287static void UnreachableSetter(Local<String>,
9288 Local<Value>,
9289 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009290 CHECK(false); // This function should nto be called.
9291}
9292
9293
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009294static void UnreachableFunction(
9295 const v8::FunctionCallbackInfo<v8::Value>& info) {
9296 CHECK(false); // This function should not be called..
9297}
9298
9299
Steve Block1e0659c2011-05-24 12:43:12 +01009300TEST(AccessControl) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009301 v8::Isolate* isolate = CcTest::isolate();
9302 v8::HandleScope handle_scope(isolate);
9303 v8::Handle<v8::ObjectTemplate> global_template =
9304 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009305
9306 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9307 IndexedAccessBlocker);
9308
9309 // Add an accessor accessible by cross-domain JS code.
9310 global_template->SetAccessor(
9311 v8_str("accessible_prop"),
9312 EchoGetter, EchoSetter,
9313 v8::Handle<Value>(),
9314 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9315
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009316
Steve Blocka7e24c12009-10-30 11:49:00 +00009317 // Add an accessor that is not accessible by cross-domain JS code.
9318 global_template->SetAccessor(v8_str("blocked_prop"),
9319 UnreachableGetter, UnreachableSetter,
9320 v8::Handle<Value>(),
9321 v8::DEFAULT);
9322
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009323 global_template->SetAccessorProperty(
9324 v8_str("blocked_js_prop"),
9325 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9326 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9327 v8::None,
9328 v8::DEFAULT);
9329
Steve Blocka7e24c12009-10-30 11:49:00 +00009330 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009331 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00009332 context0->Enter();
9333
9334 v8::Handle<v8::Object> global0 = context0->Global();
9335
Steve Block1e0659c2011-05-24 12:43:12 +01009336 // Define a property with JS getter and setter.
9337 CompileRun(
9338 "function getter() { return 'getter'; };\n"
9339 "function setter() { return 'setter'; }\n"
9340 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9341
9342 Local<Value> getter = global0->Get(v8_str("getter"));
9343 Local<Value> setter = global0->Get(v8_str("setter"));
9344
9345 // And define normal element.
9346 global0->Set(239, v8_str("239"));
9347
9348 // Define an element with JS getter and setter.
9349 CompileRun(
9350 "function el_getter() { return 'el_getter'; };\n"
9351 "function el_setter() { return 'el_setter'; };\n"
9352 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9353
9354 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9355 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9356
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009357 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009358
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009359 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009360 context1->Enter();
9361
9362 v8::Handle<v8::Object> global1 = context1->Global();
9363 global1->Set(v8_str("other"), global0);
9364
Steve Block1e0659c2011-05-24 12:43:12 +01009365 // Access blocked property.
9366 CompileRun("other.blocked_prop = 1");
9367
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009368 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9369 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9370 .IsEmpty());
9371 CHECK(
9372 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009373
9374 // Access blocked element.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009375 CHECK(CompileRun("other[239] = 1").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009376
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009377 CHECK(CompileRun("other[239]").IsEmpty());
9378 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9379 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009380
9381 // Enable ACCESS_HAS
9382 allowed_access_type[v8::ACCESS_HAS] = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009383 CHECK(CompileRun("other[239]").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009384 // ... and now we can get the descriptor...
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009385 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9386 .IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009387 // ... and enumerate the property.
9388 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9389 allowed_access_type[v8::ACCESS_HAS] = false;
9390
9391 // Access a property with JS accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009392 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009393
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009394 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9395 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9396 .IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009397
9398 // Enable both ACCESS_HAS and ACCESS_GET.
9399 allowed_access_type[v8::ACCESS_HAS] = true;
9400 allowed_access_type[v8::ACCESS_GET] = true;
9401
9402 ExpectString("other.js_accessor_p", "getter");
9403 ExpectObject(
9404 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
Steve Block1e0659c2011-05-24 12:43:12 +01009405 ExpectObject(
9406 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9407 ExpectUndefined(
9408 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9409
Steve Block1e0659c2011-05-24 12:43:12 +01009410 allowed_access_type[v8::ACCESS_HAS] = false;
Steve Block1e0659c2011-05-24 12:43:12 +01009411 allowed_access_type[v8::ACCESS_GET] = false;
Steve Block1e0659c2011-05-24 12:43:12 +01009412
9413 // Access an element with JS accessor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009414 CHECK(CompileRun("other[42] = 2").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009415
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009416 CHECK(CompileRun("other[42]").IsEmpty());
9417 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
Steve Block1e0659c2011-05-24 12:43:12 +01009418
9419 // Enable both ACCESS_HAS and ACCESS_GET.
9420 allowed_access_type[v8::ACCESS_HAS] = true;
9421 allowed_access_type[v8::ACCESS_GET] = true;
9422
9423 ExpectString("other[42]", "el_getter");
9424 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
Steve Block1e0659c2011-05-24 12:43:12 +01009425 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9426 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9427
Steve Block1e0659c2011-05-24 12:43:12 +01009428 allowed_access_type[v8::ACCESS_HAS] = false;
Steve Block1e0659c2011-05-24 12:43:12 +01009429 allowed_access_type[v8::ACCESS_GET] = false;
Steve Block1e0659c2011-05-24 12:43:12 +01009430
Steve Blocka7e24c12009-10-30 11:49:00 +00009431 v8::Handle<Value> value;
9432
Steve Blocka7e24c12009-10-30 11:49:00 +00009433 // Access accessible property
Steve Block1e0659c2011-05-24 12:43:12 +01009434 value = CompileRun("other.accessible_prop = 3");
Steve Blocka7e24c12009-10-30 11:49:00 +00009435 CHECK(value->IsNumber());
9436 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00009437 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009438
Steve Block1e0659c2011-05-24 12:43:12 +01009439 value = CompileRun("other.accessible_prop");
Steve Blocka7e24c12009-10-30 11:49:00 +00009440 CHECK(value->IsNumber());
9441 CHECK_EQ(3, value->Int32Value());
9442
Steve Block1e0659c2011-05-24 12:43:12 +01009443 value = CompileRun(
9444 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9445 CHECK(value->IsNumber());
9446 CHECK_EQ(3, value->Int32Value());
9447
9448 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
Steve Blocka7e24c12009-10-30 11:49:00 +00009449 CHECK(value->IsTrue());
9450
9451 // Enumeration doesn't enumerate accessors from inaccessible objects in
9452 // the prototype chain even if the accessors are in themselves accessible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009453 value = CompileRun(
9454 "(function() {"
9455 " var obj = { '__proto__': other };"
9456 " try {"
9457 " for (var p in obj) {"
9458 " if (p == 'accessible_prop' ||"
9459 " p == 'blocked_js_prop' ||"
9460 " p == 'blocked_js_prop') {"
9461 " return false;"
9462 " }"
9463 " }"
9464 " return false;"
9465 " } catch (e) {"
9466 " return true;"
9467 " }"
9468 "})()");
Steve Block1e0659c2011-05-24 12:43:12 +01009469 CHECK(value->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00009470
9471 context1->Exit();
9472 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009473}
9474
9475
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009476TEST(AccessControlES5) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009477 v8::Isolate* isolate = CcTest::isolate();
9478 v8::HandleScope handle_scope(isolate);
9479 v8::Handle<v8::ObjectTemplate> global_template =
9480 v8::ObjectTemplate::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009481
9482 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9483 IndexedAccessBlocker);
9484
Steve Block44f0eee2011-05-26 01:26:41 +01009485 // Add accessible accessor.
9486 global_template->SetAccessor(
9487 v8_str("accessible_prop"),
9488 EchoGetter, EchoSetter,
9489 v8::Handle<Value>(),
9490 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9491
9492
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009493 // Add an accessor that is not accessible by cross-domain JS code.
9494 global_template->SetAccessor(v8_str("blocked_prop"),
9495 UnreachableGetter, UnreachableSetter,
9496 v8::Handle<Value>(),
9497 v8::DEFAULT);
9498
9499 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009500 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009501 context0->Enter();
9502
9503 v8::Handle<v8::Object> global0 = context0->Global();
9504
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009505 v8::Local<Context> context1 = Context::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009506 context1->Enter();
9507 v8::Handle<v8::Object> global1 = context1->Global();
9508 global1->Set(v8_str("other"), global0);
9509
9510 // Regression test for issue 1154.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009511 CHECK(CompileRun("Object.keys(other)").IsEmpty());
9512 CHECK(CompileRun("other.blocked_prop").IsEmpty());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009513
9514 // Regression test for issue 1027.
9515 CompileRun("Object.defineProperty(\n"
9516 " other, 'blocked_prop', {configurable: false})");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009517 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9518 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9519 .IsEmpty());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009520
9521 // Regression test for issue 1171.
9522 ExpectTrue("Object.isExtensible(other)");
9523 CompileRun("Object.preventExtensions(other)");
9524 ExpectTrue("Object.isExtensible(other)");
9525
9526 // Object.seal and Object.freeze.
9527 CompileRun("Object.freeze(other)");
9528 ExpectTrue("Object.isExtensible(other)");
9529
9530 CompileRun("Object.seal(other)");
9531 ExpectTrue("Object.isExtensible(other)");
Steve Block44f0eee2011-05-26 01:26:41 +01009532
9533 // Regression test for issue 1250.
9534 // Make sure that we can set the accessible accessors value using normal
9535 // assignment.
9536 CompileRun("other.accessible_prop = 42");
9537 CHECK_EQ(42, g_echo_value);
9538
9539 v8::Handle<Value> value;
Steve Block44f0eee2011-05-26 01:26:41 +01009540 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9541 value = CompileRun("other.accessible_prop == 42");
9542 CHECK(value->IsTrue());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009543}
9544
9545
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009546static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9547 v8::AccessType type, Local<Value> data) {
Leon Clarke4515c472010-02-03 11:58:03 +00009548 return false;
9549}
9550
9551
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009552static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9553 v8::AccessType type, Local<Value> data) {
Leon Clarke4515c472010-02-03 11:58:03 +00009554 return false;
9555}
9556
9557
9558THREADED_TEST(AccessControlGetOwnPropertyNames) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009559 v8::Isolate* isolate = CcTest::isolate();
9560 v8::HandleScope handle_scope(isolate);
9561 v8::Handle<v8::ObjectTemplate> obj_template =
9562 v8::ObjectTemplate::New(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +00009563
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009564 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9565 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9566 BlockEverythingIndexed);
Leon Clarke4515c472010-02-03 11:58:03 +00009567
9568 // Create an environment
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009569 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
Leon Clarke4515c472010-02-03 11:58:03 +00009570 context0->Enter();
9571
9572 v8::Handle<v8::Object> global0 = context0->Global();
9573
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009574 v8::HandleScope scope1(CcTest::isolate());
Leon Clarke4515c472010-02-03 11:58:03 +00009575
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009576 v8::Local<Context> context1 = Context::New(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +00009577 context1->Enter();
9578
9579 v8::Handle<v8::Object> global1 = context1->Global();
9580 global1->Set(v8_str("other"), global0);
9581 global1->Set(v8_str("object"), obj_template->NewInstance());
9582
9583 v8::Handle<Value> value;
9584
9585 // Attempt to get the property names of the other global object and
9586 // of an object that requires access checks. Accessing the other
9587 // global object should be blocked by access checks on the global
9588 // proxy object. Accessing the object that requires access checks
9589 // is blocked by the access checks on the object itself.
9590 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009591 CHECK(value.IsEmpty());
Leon Clarke4515c472010-02-03 11:58:03 +00009592
9593 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009594 CHECK(value.IsEmpty());
Leon Clarke4515c472010-02-03 11:58:03 +00009595
9596 context1->Exit();
9597 context0->Exit();
Leon Clarke4515c472010-02-03 11:58:03 +00009598}
9599
9600
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009601TEST(SuperAccessControl) {
9602 i::FLAG_harmony_classes = true;
9603 v8::Isolate* isolate = CcTest::isolate();
9604 v8::HandleScope handle_scope(isolate);
9605 v8::Handle<v8::ObjectTemplate> obj_template =
9606 v8::ObjectTemplate::New(isolate);
9607 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9608 BlockEverythingIndexed);
9609 LocalContext env;
9610 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9611
9612 v8::TryCatch try_catch;
9613 CompileRun(
9614 "function f() { return super.hasOwnProperty; };"
9615 "var m = f.toMethod(prohibited);"
9616 "m();");
9617 CHECK(try_catch.HasCaught());
9618}
9619
9620
9621static void IndexedPropertyEnumerator(
9622 const v8::PropertyCallbackInfo<v8::Array>& info) {
9623 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9624 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9625 result->Set(1, v8::Object::New(info.GetIsolate()));
9626 info.GetReturnValue().Set(result);
9627}
9628
9629
9630static void NamedPropertyEnumerator(
9631 const v8::PropertyCallbackInfo<v8::Array>& info) {
9632 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
Steve Block8defd9f2010-07-08 12:39:36 +01009633 result->Set(0, v8_str("x"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009634 result->Set(1, v8::Object::New(info.GetIsolate()));
9635 info.GetReturnValue().Set(result);
Steve Block8defd9f2010-07-08 12:39:36 +01009636}
9637
9638
9639THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009640 v8::Isolate* isolate = CcTest::isolate();
9641 v8::HandleScope handle_scope(isolate);
9642 v8::Handle<v8::ObjectTemplate> obj_template =
9643 v8::ObjectTemplate::New(isolate);
Steve Block8defd9f2010-07-08 12:39:36 +01009644
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009645 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9646 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9647 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9648 IndexedPropertyEnumerator);
Steve Block8defd9f2010-07-08 12:39:36 +01009649 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9650 NamedPropertyEnumerator);
9651
9652 LocalContext context;
9653 v8::Handle<v8::Object> global = context->Global();
9654 global->Set(v8_str("object"), obj_template->NewInstance());
9655
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009656 v8::Handle<v8::Value> result =
9657 CompileRun("Object.getOwnPropertyNames(object)");
9658 CHECK(result->IsArray());
9659 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9660 CHECK_EQ(3, result_array->Length());
9661 CHECK(result_array->Get(0)->IsString());
9662 CHECK(result_array->Get(1)->IsString());
9663 CHECK(result_array->Get(2)->IsString());
9664 CHECK_EQ(v8_str("7"), result_array->Get(0));
9665 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9666 CHECK_EQ(v8_str("x"), result_array->Get(2));
Steve Block8defd9f2010-07-08 12:39:36 +01009667}
9668
9669
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009670static void ConstTenGetter(Local<String> name,
9671 const v8::PropertyCallbackInfo<v8::Value>& info) {
9672 info.GetReturnValue().Set(v8_num(10));
Steve Blocka7e24c12009-10-30 11:49:00 +00009673}
9674
9675
9676THREADED_TEST(CrossDomainAccessors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009677 v8::Isolate* isolate = CcTest::isolate();
9678 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009679
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009680 v8::Handle<v8::FunctionTemplate> func_template =
9681 v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009682
9683 v8::Handle<v8::ObjectTemplate> global_template =
9684 func_template->InstanceTemplate();
9685
9686 v8::Handle<v8::ObjectTemplate> proto_template =
9687 func_template->PrototypeTemplate();
9688
9689 // Add an accessor to proto that's accessible by cross-domain JS code.
9690 proto_template->SetAccessor(v8_str("accessible"),
9691 ConstTenGetter, 0,
9692 v8::Handle<Value>(),
9693 v8::ALL_CAN_READ);
9694
9695 // Add an accessor that is not accessible by cross-domain JS code.
9696 global_template->SetAccessor(v8_str("unreachable"),
9697 UnreachableGetter, 0,
9698 v8::Handle<Value>(),
9699 v8::DEFAULT);
9700
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009701 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00009702 context0->Enter();
9703
9704 Local<v8::Object> global = context0->Global();
9705 // Add a normal property that shadows 'accessible'
9706 global->Set(v8_str("accessible"), v8_num(11));
9707
9708 // Enter a new context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009709 v8::HandleScope scope1(CcTest::isolate());
9710 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009711 context1->Enter();
9712
9713 v8::Handle<v8::Object> global1 = context1->Global();
9714 global1->Set(v8_str("other"), global);
9715
9716 // Should return 10, instead of 11
9717 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9718 CHECK(value->IsNumber());
9719 CHECK_EQ(10, value->Int32Value());
9720
9721 value = v8_compile("other.unreachable")->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009722 CHECK(value.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +00009723
9724 context1->Exit();
9725 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009726}
9727
9728
9729static int named_access_count = 0;
9730static int indexed_access_count = 0;
9731
9732static bool NamedAccessCounter(Local<v8::Object> global,
9733 Local<Value> name,
9734 v8::AccessType type,
9735 Local<Value> data) {
9736 named_access_count++;
9737 return true;
9738}
9739
9740
9741static bool IndexedAccessCounter(Local<v8::Object> global,
9742 uint32_t key,
9743 v8::AccessType type,
9744 Local<Value> data) {
9745 indexed_access_count++;
9746 return true;
9747}
9748
9749
9750// This one is too easily disturbed by other tests.
9751TEST(AccessControlIC) {
9752 named_access_count = 0;
9753 indexed_access_count = 0;
9754
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009755 v8::Isolate* isolate = CcTest::isolate();
9756 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009757
9758 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009759 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009760 context0->Enter();
9761
9762 // Create an object that requires access-check functions to be
9763 // called for cross-domain access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009764 v8::Handle<v8::ObjectTemplate> object_template =
9765 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009766 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9767 IndexedAccessCounter);
9768 Local<v8::Object> object = object_template->NewInstance();
9769
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009770 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009771
9772 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009773 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009774 context1->Enter();
9775
9776 // Make easy access to the object from the other environment.
9777 v8::Handle<v8::Object> global1 = context1->Global();
9778 global1->Set(v8_str("obj"), object);
9779
9780 v8::Handle<Value> value;
9781
9782 // Check that the named access-control function is called every time.
9783 CompileRun("function testProp(obj) {"
9784 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9785 " for (var j = 0; j < 10; j++) obj.prop;"
9786 " return obj.prop"
9787 "}");
9788 value = CompileRun("testProp(obj)");
9789 CHECK(value->IsNumber());
9790 CHECK_EQ(1, value->Int32Value());
9791 CHECK_EQ(21, named_access_count);
9792
9793 // Check that the named access-control function is called every time.
9794 CompileRun("var p = 'prop';"
9795 "function testKeyed(obj) {"
9796 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9797 " for (var j = 0; j < 10; j++) obj[p];"
9798 " return obj[p];"
9799 "}");
9800 // Use obj which requires access checks. No inline caching is used
9801 // in that case.
9802 value = CompileRun("testKeyed(obj)");
9803 CHECK(value->IsNumber());
9804 CHECK_EQ(1, value->Int32Value());
9805 CHECK_EQ(42, named_access_count);
9806 // Force the inline caches into generic state and try again.
9807 CompileRun("testKeyed({ a: 0 })");
9808 CompileRun("testKeyed({ b: 0 })");
9809 value = CompileRun("testKeyed(obj)");
9810 CHECK(value->IsNumber());
9811 CHECK_EQ(1, value->Int32Value());
9812 CHECK_EQ(63, named_access_count);
9813
9814 // Check that the indexed access-control function is called every time.
9815 CompileRun("function testIndexed(obj) {"
9816 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9817 " for (var j = 0; j < 10; j++) obj[0];"
9818 " return obj[0]"
9819 "}");
9820 value = CompileRun("testIndexed(obj)");
9821 CHECK(value->IsNumber());
9822 CHECK_EQ(1, value->Int32Value());
9823 CHECK_EQ(21, indexed_access_count);
9824 // Force the inline caches into generic state.
9825 CompileRun("testIndexed(new Array(1))");
9826 // Test that the indexed access check is called.
9827 value = CompileRun("testIndexed(obj)");
9828 CHECK(value->IsNumber());
9829 CHECK_EQ(1, value->Int32Value());
9830 CHECK_EQ(42, indexed_access_count);
9831
9832 // Check that the named access check is called when invoking
9833 // functions on an object that requires access checks.
9834 CompileRun("obj.f = function() {}");
9835 CompileRun("function testCallNormal(obj) {"
9836 " for (var i = 0; i < 10; i++) obj.f();"
9837 "}");
9838 CompileRun("testCallNormal(obj)");
9839 CHECK_EQ(74, named_access_count);
9840
9841 // Force obj into slow case.
9842 value = CompileRun("delete obj.prop");
9843 CHECK(value->BooleanValue());
9844 // Force inline caches into dictionary probing mode.
9845 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9846 // Test that the named access check is called.
9847 value = CompileRun("testProp(obj);");
9848 CHECK(value->IsNumber());
9849 CHECK_EQ(1, value->Int32Value());
9850 CHECK_EQ(96, named_access_count);
9851
9852 // Force the call inline cache into dictionary probing mode.
9853 CompileRun("o.f = function() {}; testCallNormal(o)");
9854 // Test that the named access check is still called for each
9855 // invocation of the function.
9856 value = CompileRun("testCallNormal(obj)");
9857 CHECK_EQ(106, named_access_count);
9858
9859 context1->Exit();
9860 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009861}
9862
9863
9864static bool NamedAccessFlatten(Local<v8::Object> global,
9865 Local<Value> name,
9866 v8::AccessType type,
9867 Local<Value> data) {
9868 char buf[100];
9869 int len;
9870
9871 CHECK(name->IsString());
9872
9873 memset(buf, 0x1, sizeof(buf));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009874 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
Steve Blocka7e24c12009-10-30 11:49:00 +00009875 CHECK_EQ(4, len);
9876
9877 uint16_t buf2[100];
9878
9879 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01009880 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009881 CHECK_EQ(4, len);
9882
9883 return true;
9884}
9885
9886
9887static bool IndexedAccessFlatten(Local<v8::Object> global,
9888 uint32_t key,
9889 v8::AccessType type,
9890 Local<Value> data) {
9891 return true;
9892}
9893
9894
9895// Regression test. In access checks, operations that may cause
9896// garbage collection are not allowed. It used to be the case that
9897// using the Write operation on a string could cause a garbage
9898// collection due to flattening of the string. This is no longer the
9899// case.
9900THREADED_TEST(AccessControlFlatten) {
9901 named_access_count = 0;
9902 indexed_access_count = 0;
9903
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009904 v8::Isolate* isolate = CcTest::isolate();
9905 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009906
9907 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009908 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009909 context0->Enter();
9910
9911 // Create an object that requires access-check functions to be
9912 // called for cross-domain access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009913 v8::Handle<v8::ObjectTemplate> object_template =
9914 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009915 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9916 IndexedAccessFlatten);
9917 Local<v8::Object> object = object_template->NewInstance();
9918
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009919 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009920
9921 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009922 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009923 context1->Enter();
9924
9925 // Make easy access to the object from the other environment.
9926 v8::Handle<v8::Object> global1 = context1->Global();
9927 global1->Set(v8_str("obj"), object);
9928
9929 v8::Handle<Value> value;
9930
9931 value = v8_compile("var p = 'as' + 'df';")->Run();
9932 value = v8_compile("obj[p];")->Run();
9933
9934 context1->Exit();
9935 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +00009936}
9937
9938
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009939static void AccessControlNamedGetter(
9940 Local<String>,
9941 const v8::PropertyCallbackInfo<v8::Value>& info) {
9942 info.GetReturnValue().Set(42);
Steve Blocka7e24c12009-10-30 11:49:00 +00009943}
9944
9945
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009946static void AccessControlNamedSetter(
9947 Local<String>,
9948 Local<Value> value,
9949 const v8::PropertyCallbackInfo<v8::Value>& info) {
9950 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009951}
9952
9953
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009954static void AccessControlIndexedGetter(
Steve Blocka7e24c12009-10-30 11:49:00 +00009955 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009956 const v8::PropertyCallbackInfo<v8::Value>& info) {
9957 info.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +00009958}
9959
9960
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009961static void AccessControlIndexedSetter(
9962 uint32_t,
9963 Local<Value> value,
9964 const v8::PropertyCallbackInfo<v8::Value>& info) {
9965 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009966}
9967
9968
9969THREADED_TEST(AccessControlInterceptorIC) {
9970 named_access_count = 0;
9971 indexed_access_count = 0;
9972
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009973 v8::Isolate* isolate = CcTest::isolate();
9974 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009975
9976 // Create an environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009977 v8::Local<Context> context0 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009978 context0->Enter();
9979
9980 // Create an object that requires access-check functions to be
9981 // called for cross-domain access. The object also has interceptors
9982 // interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009983 v8::Handle<v8::ObjectTemplate> object_template =
9984 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009985 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9986 IndexedAccessCounter);
9987 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9988 AccessControlNamedSetter);
9989 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9990 AccessControlIndexedSetter);
9991 Local<v8::Object> object = object_template->NewInstance();
9992
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009993 v8::HandleScope scope1(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009994
9995 // Create another environment.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009996 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009997 context1->Enter();
9998
9999 // Make easy access to the object from the other environment.
10000 v8::Handle<v8::Object> global1 = context1->Global();
10001 global1->Set(v8_str("obj"), object);
10002
10003 v8::Handle<Value> value;
10004
10005 // Check that the named access-control function is called every time
10006 // eventhough there is an interceptor on the object.
10007 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10008 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10009 "obj.x")->Run();
10010 CHECK(value->IsNumber());
10011 CHECK_EQ(42, value->Int32Value());
10012 CHECK_EQ(21, named_access_count);
10013
10014 value = v8_compile("var p = 'x';")->Run();
10015 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10016 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10017 "obj[p]")->Run();
10018 CHECK(value->IsNumber());
10019 CHECK_EQ(42, value->Int32Value());
10020 CHECK_EQ(42, named_access_count);
10021
10022 // Check that the indexed access-control function is called every
10023 // time eventhough there is an interceptor on the object.
10024 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10025 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10026 "obj[0]")->Run();
10027 CHECK(value->IsNumber());
10028 CHECK_EQ(42, value->Int32Value());
10029 CHECK_EQ(21, indexed_access_count);
10030
10031 context1->Exit();
10032 context0->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000010033}
10034
10035
10036THREADED_TEST(Version) {
10037 v8::V8::GetVersion();
10038}
10039
10040
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010041static void InstanceFunctionCallback(
10042 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010043 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010044 args.GetReturnValue().Set(v8_num(12));
Steve Blocka7e24c12009-10-30 11:49:00 +000010045}
10046
10047
10048THREADED_TEST(InstanceProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010049 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010050 v8::Isolate* isolate = context->GetIsolate();
10051 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010052
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010053 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010054 Local<ObjectTemplate> instance = t->InstanceTemplate();
10055
10056 instance->Set(v8_str("x"), v8_num(42));
10057 instance->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010058 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000010059
10060 Local<Value> o = t->GetFunction()->NewInstance();
10061
10062 context->Global()->Set(v8_str("i"), o);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010063 Local<Value> value = CompileRun("i.x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010064 CHECK_EQ(42, value->Int32Value());
10065
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010066 value = CompileRun("i.f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010067 CHECK_EQ(12, value->Int32Value());
10068}
10069
10070
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010071static void GlobalObjectInstancePropertiesGet(
10072 Local<String> key,
10073 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010074 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000010075}
10076
10077
10078THREADED_TEST(GlobalObjectInstanceProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010079 v8::Isolate* isolate = CcTest::isolate();
10080 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010081
10082 Local<Value> global_object;
10083
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010084 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010085 t->InstanceTemplate()->SetNamedPropertyHandler(
10086 GlobalObjectInstancePropertiesGet);
10087 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10088 instance_template->Set(v8_str("x"), v8_num(42));
10089 instance_template->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010090 v8::FunctionTemplate::New(isolate,
10091 InstanceFunctionCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000010092
Ben Murdochb0fe1622011-05-05 13:52:32 +010010093 // The script to check how Crankshaft compiles missing global function
10094 // invocations. function g is not defined and should throw on call.
10095 const char* script =
10096 "function wrapper(call) {"
10097 " var x = 0, y = 1;"
10098 " for (var i = 0; i < 1000; i++) {"
10099 " x += i * 100;"
10100 " y += i * 100;"
10101 " }"
10102 " if (call) g();"
10103 "}"
10104 "for (var i = 0; i < 17; i++) wrapper(false);"
10105 "var thrown = 0;"
10106 "try { wrapper(true); } catch (e) { thrown = 1; };"
10107 "thrown";
10108
Steve Blocka7e24c12009-10-30 11:49:00 +000010109 {
10110 LocalContext env(NULL, instance_template);
10111 // Hold on to the global object so it can be used again in another
10112 // environment initialization.
10113 global_object = env->Global();
10114
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010115 Local<Value> value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010116 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010117 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010118 CHECK_EQ(12, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010119 value = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010120 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010121 }
10122
10123 {
10124 // Create new environment reusing the global object.
10125 LocalContext env(NULL, instance_template, global_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010126 Local<Value> value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010127 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010128 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010129 CHECK_EQ(12, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010130 value = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010131 CHECK_EQ(1, value->Int32Value());
10132 }
10133}
10134
10135
10136THREADED_TEST(CallKnownGlobalReceiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010137 v8::Isolate* isolate = CcTest::isolate();
10138 v8::HandleScope handle_scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010139
10140 Local<Value> global_object;
10141
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010142 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010143 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10144
10145 // The script to check that we leave global object not
10146 // global object proxy on stack when we deoptimize from inside
10147 // arguments evaluation.
10148 // To provoke error we need to both force deoptimization
10149 // from arguments evaluation and to force CallIC to take
10150 // CallIC_Miss code path that can't cope with global proxy.
10151 const char* script =
10152 "function bar(x, y) { try { } finally { } }"
10153 "function baz(x) { try { } finally { } }"
10154 "function bom(x) { try { } finally { } }"
10155 "function foo(x) { bar([x], bom(2)); }"
10156 "for (var i = 0; i < 10000; i++) foo(1);"
10157 "foo";
10158
10159 Local<Value> foo;
10160 {
10161 LocalContext env(NULL, instance_template);
10162 // Hold on to the global object so it can be used again in another
10163 // environment initialization.
10164 global_object = env->Global();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010165 foo = CompileRun(script);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010166 }
10167
10168 {
10169 // Create new environment reusing the global object.
10170 LocalContext env(NULL, instance_template, global_object);
10171 env->Global()->Set(v8_str("foo"), foo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010172 CompileRun("foo()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010173 }
10174}
10175
10176
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010177static void ShadowFunctionCallback(
10178 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010179 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010180 args.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000010181}
10182
10183
10184static int shadow_y;
10185static int shadow_y_setter_call_count;
10186static int shadow_y_getter_call_count;
10187
10188
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010189static void ShadowYSetter(Local<String>,
10190 Local<Value>,
10191 const v8::PropertyCallbackInfo<void>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010192 shadow_y_setter_call_count++;
10193 shadow_y = 42;
10194}
10195
10196
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010197static void ShadowYGetter(Local<String> name,
10198 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010199 ApiTestFuzzer::Fuzz();
10200 shadow_y_getter_call_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010201 info.GetReturnValue().Set(v8_num(shadow_y));
Steve Blocka7e24c12009-10-30 11:49:00 +000010202}
10203
10204
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010205static void ShadowIndexedGet(uint32_t index,
10206 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010207}
10208
10209
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010210static void ShadowNamedGet(Local<String> key,
10211 const v8::PropertyCallbackInfo<v8::Value>&) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010212}
10213
10214
10215THREADED_TEST(ShadowObject) {
10216 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010217 v8::Isolate* isolate = CcTest::isolate();
10218 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010219
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010220 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010221 LocalContext context(NULL, global_template);
10222
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010223 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010224 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10225 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10226 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10227 Local<ObjectTemplate> instance = t->InstanceTemplate();
10228
Steve Blocka7e24c12009-10-30 11:49:00 +000010229 proto->Set(v8_str("f"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010230 v8::FunctionTemplate::New(isolate,
10231 ShadowFunctionCallback,
10232 Local<Value>()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010233 proto->Set(v8_str("x"), v8_num(12));
10234
10235 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10236
10237 Local<Value> o = t->GetFunction()->NewInstance();
10238 context->Global()->Set(v8_str("__proto__"), o);
10239
10240 Local<Value> value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010241 CompileRun("this.propertyIsEnumerable(0)");
Steve Blocka7e24c12009-10-30 11:49:00 +000010242 CHECK(value->IsBoolean());
10243 CHECK(!value->BooleanValue());
10244
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010245 value = CompileRun("x");
Steve Blocka7e24c12009-10-30 11:49:00 +000010246 CHECK_EQ(12, value->Int32Value());
10247
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010248 value = CompileRun("f()");
Steve Blocka7e24c12009-10-30 11:49:00 +000010249 CHECK_EQ(42, value->Int32Value());
10250
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010251 CompileRun("y = 43");
Steve Blocka7e24c12009-10-30 11:49:00 +000010252 CHECK_EQ(1, shadow_y_setter_call_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010253 value = CompileRun("y");
Steve Blocka7e24c12009-10-30 11:49:00 +000010254 CHECK_EQ(1, shadow_y_getter_call_count);
10255 CHECK_EQ(42, value->Int32Value());
10256}
10257
10258
10259THREADED_TEST(HiddenPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010260 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010261 v8::Isolate* isolate = context->GetIsolate();
10262 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010263
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010264 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010265 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010266 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010267 t1->SetHiddenPrototype(true);
10268 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010269 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010270 t2->SetHiddenPrototype(true);
10271 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010272 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010273 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10274
10275 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10276 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10277 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10278 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10279
10280 // Setting the prototype on an object skips hidden prototypes.
10281 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10282 o0->Set(v8_str("__proto__"), o1);
10283 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10284 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10285 o0->Set(v8_str("__proto__"), o2);
10286 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10287 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10288 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10289 o0->Set(v8_str("__proto__"), o3);
10290 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10291 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10292 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10293 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10294
10295 // Getting the prototype of o0 should get the first visible one
10296 // which is o3. Therefore, z should not be defined on the prototype
10297 // object.
10298 Local<Value> proto = o0->Get(v8_str("__proto__"));
10299 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010300 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +000010301}
10302
10303
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010304THREADED_TEST(HiddenPrototypeSet) {
Andrei Popescu402d9372010-02-26 13:31:12 +000010305 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010306 v8::Isolate* isolate = context->GetIsolate();
10307 v8::HandleScope handle_scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010308
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010309 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10310 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10311 ht->SetHiddenPrototype(true);
10312 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10313 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10314
10315 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10316 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10317 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10318 o->Set(v8_str("__proto__"), h);
10319 h->Set(v8_str("__proto__"), p);
10320
10321 // Setting a property that exists on the hidden prototype goes there.
10322 o->Set(v8_str("x"), v8_num(7));
10323 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10324 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10325 CHECK(p->Get(v8_str("x"))->IsUndefined());
10326
10327 // Setting a new property should not be forwarded to the hidden prototype.
10328 o->Set(v8_str("y"), v8_num(6));
10329 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10330 CHECK(h->Get(v8_str("y"))->IsUndefined());
10331 CHECK(p->Get(v8_str("y"))->IsUndefined());
10332
10333 // Setting a property that only exists on a prototype of the hidden prototype
10334 // is treated normally again.
10335 p->Set(v8_str("z"), v8_num(8));
10336 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10337 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10338 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10339 o->Set(v8_str("z"), v8_num(9));
10340 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10341 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10342 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10343}
10344
10345
10346// Regression test for issue 2457.
10347THREADED_TEST(HiddenPrototypeIdentityHash) {
10348 LocalContext context;
10349 v8::HandleScope handle_scope(context->GetIsolate());
10350
10351 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10352 t->SetHiddenPrototype(true);
10353 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10354 Handle<Object> p = t->GetFunction()->NewInstance();
10355 Handle<Object> o = Object::New(context->GetIsolate());
10356 o->SetPrototype(p);
10357
10358 int hash = o->GetIdentityHash();
10359 USE(hash);
10360 o->Set(v8_str("foo"), v8_num(42));
10361 DCHECK_EQ(hash, o->GetIdentityHash());
10362}
10363
10364
10365THREADED_TEST(SetPrototype) {
10366 LocalContext context;
10367 v8::Isolate* isolate = context->GetIsolate();
10368 v8::HandleScope handle_scope(isolate);
10369
10370 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010371 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010372 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010373 t1->SetHiddenPrototype(true);
10374 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010375 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010376 t2->SetHiddenPrototype(true);
10377 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010378 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010379 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10380
10381 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10382 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10383 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10384 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10385
10386 // Setting the prototype on an object does not skip hidden prototypes.
10387 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10388 CHECK(o0->SetPrototype(o1));
10389 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10390 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10391 CHECK(o1->SetPrototype(o2));
10392 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10393 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10394 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10395 CHECK(o2->SetPrototype(o3));
10396 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10397 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10398 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10399 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10400
10401 // Getting the prototype of o0 should get the first visible one
10402 // which is o3. Therefore, z should not be defined on the prototype
10403 // object.
10404 Local<Value> proto = o0->Get(v8_str("__proto__"));
10405 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010406 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +000010407
10408 // However, Object::GetPrototype ignores hidden prototype.
10409 Local<Value> proto0 = o0->GetPrototype();
10410 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010411 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +000010412
10413 Local<Value> proto1 = o1->GetPrototype();
10414 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010415 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +000010416
10417 Local<Value> proto2 = o2->GetPrototype();
10418 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010010419 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +000010420}
10421
10422
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010423// Getting property names of an object with a prototype chain that
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010424// triggers dictionary elements in GetOwnPropertyNames() shouldn't
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010425// crash the runtime.
10426THREADED_TEST(Regress91517) {
10427 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010428 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010429 v8::Isolate* isolate = context->GetIsolate();
10430 v8::HandleScope handle_scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010431
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010432 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010433 t1->SetHiddenPrototype(true);
10434 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010435 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010436 t2->SetHiddenPrototype(true);
10437 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010438 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010439 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010440 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010441 t3->SetHiddenPrototype(true);
10442 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010443 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010444 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10445
10446 // Force dictionary-based properties.
10447 i::ScopedVector<char> name_buf(1024);
10448 for (int i = 1; i <= 1000; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010449 i::SNPrintF(name_buf, "sdf%d", i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010450 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10451 }
10452
10453 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10454 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10455 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10456 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10457
10458 // Create prototype chain of hidden prototypes.
10459 CHECK(o4->SetPrototype(o3));
10460 CHECK(o3->SetPrototype(o2));
10461 CHECK(o2->SetPrototype(o1));
10462
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010463 // Call the runtime version of GetOwnPropertyNames() on the natively
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010464 // created object through JavaScript.
10465 context->Global()->Set(v8_str("obj"), o4);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010466 // PROPERTY_ATTRIBUTES_NONE = 0
10467 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010468
10469 ExpectInt32("names.length", 1006);
10470 ExpectTrue("names.indexOf(\"baz\") >= 0");
10471 ExpectTrue("names.indexOf(\"boo\") >= 0");
10472 ExpectTrue("names.indexOf(\"foo\") >= 0");
10473 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10474 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10475 ExpectFalse("names[1005] == undefined");
10476}
10477
10478
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010479// Getting property names of an object with a hidden and inherited
10480// prototype should not duplicate the accessor properties inherited.
10481THREADED_TEST(Regress269562) {
10482 i::FLAG_allow_natives_syntax = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010483 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010484 v8::HandleScope handle_scope(context->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010485
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010486 Local<v8::FunctionTemplate> t1 =
10487 v8::FunctionTemplate::New(context->GetIsolate());
10488 t1->SetHiddenPrototype(true);
10489
10490 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10491 i1->SetAccessor(v8_str("foo"),
10492 SimpleAccessorGetter, SimpleAccessorSetter);
10493 i1->SetAccessor(v8_str("bar"),
10494 SimpleAccessorGetter, SimpleAccessorSetter);
10495 i1->SetAccessor(v8_str("baz"),
10496 SimpleAccessorGetter, SimpleAccessorSetter);
10497 i1->Set(v8_str("n1"), v8_num(1));
10498 i1->Set(v8_str("n2"), v8_num(2));
10499
10500 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10501 Local<v8::FunctionTemplate> t2 =
10502 v8::FunctionTemplate::New(context->GetIsolate());
10503 t2->SetHiddenPrototype(true);
10504
10505 // Inherit from t1 and mark prototype as hidden.
10506 t2->Inherit(t1);
10507 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10508
10509 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10510 CHECK(o2->SetPrototype(o1));
10511
10512 v8::Local<v8::Symbol> sym =
10513 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10514 o1->Set(sym, v8_num(3));
10515 o1->SetHiddenValue(
10516 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10517
10518 // Call the runtime version of GetOwnPropertyNames() on
10519 // the natively created object through JavaScript.
10520 context->Global()->Set(v8_str("obj"), o2);
10521 context->Global()->Set(v8_str("sym"), sym);
10522 // PROPERTY_ATTRIBUTES_NONE = 0
10523 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10524
10525 ExpectInt32("names.length", 7);
10526 ExpectTrue("names.indexOf(\"foo\") >= 0");
10527 ExpectTrue("names.indexOf(\"bar\") >= 0");
10528 ExpectTrue("names.indexOf(\"baz\") >= 0");
10529 ExpectTrue("names.indexOf(\"n1\") >= 0");
10530 ExpectTrue("names.indexOf(\"n2\") >= 0");
10531 ExpectTrue("names.indexOf(sym) >= 0");
10532 ExpectTrue("names.indexOf(\"mine\") >= 0");
10533}
10534
10535
10536THREADED_TEST(FunctionReadOnlyPrototype) {
10537 LocalContext context;
10538 v8::Isolate* isolate = context->GetIsolate();
10539 v8::HandleScope handle_scope(isolate);
10540
10541 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10542 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010543 t1->ReadOnlyPrototype();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010544 context->Global()->Set(v8_str("func1"), t1->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010545 // Configured value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010546 CHECK(CompileRun(
10547 "(function() {"
10548 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010549 " return (descriptor['writable'] == false);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010550 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010551 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10552 CHECK_EQ(42,
10553 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010554
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010555 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10556 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010557 context->Global()->Set(v8_str("func2"), t2->GetFunction());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010558 // Default value of ReadOnly flag.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010559 CHECK(CompileRun(
10560 "(function() {"
10561 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010562 " return (descriptor['writable'] == true);"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010563 "})()")->BooleanValue());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010564 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010565}
10566
10567
Andrei Popescu402d9372010-02-26 13:31:12 +000010568THREADED_TEST(SetPrototypeThrows) {
Andrei Popescu402d9372010-02-26 13:31:12 +000010569 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010570 v8::Isolate* isolate = context->GetIsolate();
10571 v8::HandleScope handle_scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010572
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010573 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000010574
10575 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10576 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10577
10578 CHECK(o0->SetPrototype(o1));
10579 // If setting the prototype leads to the cycle, SetPrototype should
10580 // return false and keep VM in sane state.
10581 v8::TryCatch try_catch;
10582 CHECK(!o1->SetPrototype(o0));
10583 CHECK(!try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010584 DCHECK(!CcTest::i_isolate()->has_pending_exception());
Andrei Popescu402d9372010-02-26 13:31:12 +000010585
10586 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10587}
10588
10589
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010590THREADED_TEST(FunctionRemovePrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010591 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010592 v8::Isolate* isolate = context->GetIsolate();
10593 v8::HandleScope handle_scope(isolate);
10594
10595 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10596 t1->RemovePrototype();
10597 Local<v8::Function> fun = t1->GetFunction();
10598 context->Global()->Set(v8_str("fun"), fun);
10599 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10600
10601 v8::TryCatch try_catch;
10602 CompileRun("new fun()");
10603 CHECK(try_catch.HasCaught());
10604
10605 try_catch.Reset();
10606 fun->NewInstance();
10607 CHECK(try_catch.HasCaught());
10608}
10609
10610
10611THREADED_TEST(GetterSetterExceptions) {
10612 LocalContext context;
10613 v8::Isolate* isolate = context->GetIsolate();
10614 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010615 CompileRun(
10616 "function Foo() { };"
10617 "function Throw() { throw 5; };"
10618 "var x = { };"
10619 "x.__defineSetter__('set', Throw);"
10620 "x.__defineGetter__('get', Throw);");
10621 Local<v8::Object> x =
10622 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10623 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010624 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000010625 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010626 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000010627 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010628 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000010629 x->Get(v8_str("get"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010630 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000010631 x->Get(v8_str("get"));
10632}
10633
10634
10635THREADED_TEST(Constructor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010636 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010637 v8::Isolate* isolate = context->GetIsolate();
10638 v8::HandleScope handle_scope(isolate);
10639 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010640 templ->SetClassName(v8_str("Fun"));
10641 Local<Function> cons = templ->GetFunction();
10642 context->Global()->Set(v8_str("Fun"), cons);
10643 Local<v8::Object> inst = cons->NewInstance();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010644 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10645 CHECK(obj->IsJSObject());
Steve Blocka7e24c12009-10-30 11:49:00 +000010646 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10647 CHECK(value->BooleanValue());
10648}
10649
Ben Murdoch257744e2011-11-30 15:57:28 +000010650
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010651static void ConstructorCallback(
10652 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010653 ApiTestFuzzer::Fuzz();
10654 Local<Object> This;
10655
10656 if (args.IsConstructCall()) {
10657 Local<Object> Holder = args.Holder();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010658 This = Object::New(args.GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +000010659 Local<Value> proto = Holder->GetPrototype();
10660 if (proto->IsObject()) {
10661 This->SetPrototype(proto);
10662 }
10663 } else {
10664 This = args.This();
10665 }
10666
10667 This->Set(v8_str("a"), args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010668 args.GetReturnValue().Set(This);
Ben Murdoch257744e2011-11-30 15:57:28 +000010669}
10670
10671
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010672static void FakeConstructorCallback(
10673 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010674 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010675 args.GetReturnValue().Set(args[0]);
Ben Murdoch257744e2011-11-30 15:57:28 +000010676}
10677
10678
10679THREADED_TEST(ConstructorForObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010680 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010681 v8::Isolate* isolate = context->GetIsolate();
10682 v8::HandleScope handle_scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000010683
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010684 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000010685 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10686 Local<Object> instance = instance_template->NewInstance();
10687 context->Global()->Set(v8_str("obj"), instance);
10688 v8::TryCatch try_catch;
10689 Local<Value> value;
10690 CHECK(!try_catch.HasCaught());
10691
10692 // Call the Object's constructor with a 32-bit signed integer.
10693 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10694 CHECK(!try_catch.HasCaught());
10695 CHECK(value->IsInt32());
10696 CHECK_EQ(28, value->Int32Value());
10697
10698 Local<Value> args1[] = { v8_num(28) };
10699 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10700 CHECK(value_obj1->IsObject());
10701 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10702 value = object1->Get(v8_str("a"));
10703 CHECK(value->IsInt32());
10704 CHECK(!try_catch.HasCaught());
10705 CHECK_EQ(28, value->Int32Value());
10706
10707 // Call the Object's constructor with a String.
10708 value = CompileRun(
10709 "(function() { var o = new obj('tipli'); return o.a; })()");
10710 CHECK(!try_catch.HasCaught());
10711 CHECK(value->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010712 String::Utf8Value string_value1(value->ToString());
Ben Murdoch257744e2011-11-30 15:57:28 +000010713 CHECK_EQ("tipli", *string_value1);
10714
10715 Local<Value> args2[] = { v8_str("tipli") };
10716 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10717 CHECK(value_obj2->IsObject());
10718 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10719 value = object2->Get(v8_str("a"));
10720 CHECK(!try_catch.HasCaught());
10721 CHECK(value->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010722 String::Utf8Value string_value2(value->ToString());
Ben Murdoch257744e2011-11-30 15:57:28 +000010723 CHECK_EQ("tipli", *string_value2);
10724
10725 // Call the Object's constructor with a Boolean.
10726 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10727 CHECK(!try_catch.HasCaught());
10728 CHECK(value->IsBoolean());
10729 CHECK_EQ(true, value->BooleanValue());
10730
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010731 Handle<Value> args3[] = { v8::True(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000010732 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10733 CHECK(value_obj3->IsObject());
10734 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10735 value = object3->Get(v8_str("a"));
10736 CHECK(!try_catch.HasCaught());
10737 CHECK(value->IsBoolean());
10738 CHECK_EQ(true, value->BooleanValue());
10739
10740 // Call the Object's constructor with undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010741 Handle<Value> args4[] = { v8::Undefined(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000010742 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10743 CHECK(value_obj4->IsObject());
10744 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10745 value = object4->Get(v8_str("a"));
10746 CHECK(!try_catch.HasCaught());
10747 CHECK(value->IsUndefined());
10748
10749 // Call the Object's constructor with null.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010750 Handle<Value> args5[] = { v8::Null(isolate) };
Ben Murdoch257744e2011-11-30 15:57:28 +000010751 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10752 CHECK(value_obj5->IsObject());
10753 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10754 value = object5->Get(v8_str("a"));
10755 CHECK(!try_catch.HasCaught());
10756 CHECK(value->IsNull());
10757 }
10758
10759 // Check exception handling when there is no constructor set for the Object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010760 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000010761 Local<Object> instance = instance_template->NewInstance();
10762 context->Global()->Set(v8_str("obj2"), instance);
10763 v8::TryCatch try_catch;
10764 Local<Value> value;
10765 CHECK(!try_catch.HasCaught());
10766
10767 value = CompileRun("new obj2(28)");
10768 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010769 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000010770 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10771 try_catch.Reset();
10772
10773 Local<Value> args[] = { v8_num(29) };
10774 value = instance->CallAsConstructor(1, args);
10775 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010776 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000010777 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10778 try_catch.Reset();
10779 }
10780
10781 // Check the case when constructor throws exception.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010782 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000010783 instance_template->SetCallAsFunctionHandler(ThrowValue);
10784 Local<Object> instance = instance_template->NewInstance();
10785 context->Global()->Set(v8_str("obj3"), instance);
10786 v8::TryCatch try_catch;
10787 Local<Value> value;
10788 CHECK(!try_catch.HasCaught());
10789
10790 value = CompileRun("new obj3(22)");
10791 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010792 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000010793 CHECK_EQ("22", *exception_value1);
10794 try_catch.Reset();
10795
10796 Local<Value> args[] = { v8_num(23) };
10797 value = instance->CallAsConstructor(1, args);
10798 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010799 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000010800 CHECK_EQ("23", *exception_value2);
10801 try_catch.Reset();
10802 }
10803
10804 // Check whether constructor returns with an object or non-object.
10805 { Local<FunctionTemplate> function_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010806 FunctionTemplate::New(isolate, FakeConstructorCallback);
Ben Murdoch257744e2011-11-30 15:57:28 +000010807 Local<Function> function = function_template->GetFunction();
10808 Local<Object> instance1 = function;
10809 context->Global()->Set(v8_str("obj4"), instance1);
10810 v8::TryCatch try_catch;
10811 Local<Value> value;
10812 CHECK(!try_catch.HasCaught());
10813
10814 CHECK(instance1->IsObject());
10815 CHECK(instance1->IsFunction());
10816
10817 value = CompileRun("new obj4(28)");
10818 CHECK(!try_catch.HasCaught());
10819 CHECK(value->IsObject());
10820
10821 Local<Value> args1[] = { v8_num(28) };
10822 value = instance1->CallAsConstructor(1, args1);
10823 CHECK(!try_catch.HasCaught());
10824 CHECK(value->IsObject());
10825
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010826 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000010827 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10828 Local<Object> instance2 = instance_template->NewInstance();
10829 context->Global()->Set(v8_str("obj5"), instance2);
10830 CHECK(!try_catch.HasCaught());
10831
10832 CHECK(instance2->IsObject());
10833 CHECK(!instance2->IsFunction());
10834
10835 value = CompileRun("new obj5(28)");
10836 CHECK(!try_catch.HasCaught());
10837 CHECK(!value->IsObject());
10838
10839 Local<Value> args2[] = { v8_num(28) };
10840 value = instance2->CallAsConstructor(1, args2);
10841 CHECK(!try_catch.HasCaught());
10842 CHECK(!value->IsObject());
10843 }
10844}
10845
10846
Steve Blocka7e24c12009-10-30 11:49:00 +000010847THREADED_TEST(FunctionDescriptorException) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010848 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010849 v8::Isolate* isolate = context->GetIsolate();
10850 v8::HandleScope handle_scope(isolate);
10851 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010852 templ->SetClassName(v8_str("Fun"));
10853 Local<Function> cons = templ->GetFunction();
10854 context->Global()->Set(v8_str("Fun"), cons);
10855 Local<Value> value = CompileRun(
10856 "function test() {"
10857 " try {"
10858 " (new Fun()).blah()"
10859 " } catch (e) {"
10860 " var str = String(e);"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010861 // " if (str.indexOf('TypeError') == -1) return 1;"
10862 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10863 // " if (str.indexOf('#<Fun>') == -1) return 3;"
Steve Blocka7e24c12009-10-30 11:49:00 +000010864 " return 0;"
10865 " }"
10866 " return 4;"
10867 "}"
10868 "test();");
10869 CHECK_EQ(0, value->Int32Value());
10870}
10871
10872
10873THREADED_TEST(EvalAliasedDynamic) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010874 LocalContext current;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010875 v8::HandleScope scope(current->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000010876
10877 // Tests where aliased eval can only be resolved dynamically.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010878 Local<Script> script = v8_compile(
10879 "function f(x) { "
10880 " var foo = 2;"
10881 " with (x) { return eval('foo'); }"
10882 "}"
10883 "foo = 0;"
10884 "result1 = f(new Object());"
10885 "result2 = f(this);"
10886 "var x = new Object();"
10887 "x.eval = function(x) { return 1; };"
10888 "result3 = f(x);");
Steve Blocka7e24c12009-10-30 11:49:00 +000010889 script->Run();
10890 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10891 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10892 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10893
10894 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010895 script = v8_compile(
10896 "function f(x) { "
10897 " var bar = 2;"
10898 " with (x) { return eval('bar'); }"
10899 "}"
10900 "result4 = f(this)");
Steve Blocka7e24c12009-10-30 11:49:00 +000010901 script->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010902 CHECK(!try_catch.HasCaught());
10903 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10904
Steve Blocka7e24c12009-10-30 11:49:00 +000010905 try_catch.Reset();
10906}
10907
10908
10909THREADED_TEST(CrossEval) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010910 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000010911 LocalContext other;
10912 LocalContext current;
10913
10914 Local<String> token = v8_str("<security token>");
10915 other->SetSecurityToken(token);
10916 current->SetSecurityToken(token);
10917
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010918 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +000010919 current->Global()->Set(v8_str("other"), other->Global());
10920
10921 // Check that new variables are introduced in other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010922 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010923 script->Run();
10924 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10925 CHECK_EQ(1234, foo->Int32Value());
10926 CHECK(!current->Global()->Has(v8_str("foo")));
10927
10928 // Check that writing to non-existing properties introduces them in
10929 // the other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010930 script = v8_compile("other.eval('na = 1234')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010931 script->Run();
10932 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10933 CHECK(!current->Global()->Has(v8_str("na")));
10934
10935 // Check that global variables in current context are not visible in other
10936 // context.
10937 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010938 script = v8_compile("var bar = 42; other.eval('bar');");
Steve Blocka7e24c12009-10-30 11:49:00 +000010939 Local<Value> result = script->Run();
10940 CHECK(try_catch.HasCaught());
10941 try_catch.Reset();
10942
10943 // Check that local variables in current context are not visible in other
10944 // context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010945 script = v8_compile(
10946 "(function() { "
10947 " var baz = 87;"
10948 " return other.eval('baz');"
10949 "})();");
Steve Blocka7e24c12009-10-30 11:49:00 +000010950 result = script->Run();
10951 CHECK(try_catch.HasCaught());
10952 try_catch.Reset();
10953
10954 // Check that global variables in the other environment are visible
10955 // when evaluting code.
10956 other->Global()->Set(v8_str("bis"), v8_num(1234));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010957 script = v8_compile("other.eval('bis')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010958 CHECK_EQ(1234, script->Run()->Int32Value());
10959 CHECK(!try_catch.HasCaught());
10960
10961 // Check that the 'this' pointer points to the global object evaluating
10962 // code.
10963 other->Global()->Set(v8_str("t"), other->Global());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010964 script = v8_compile("other.eval('this == t')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010965 result = script->Run();
10966 CHECK(result->IsTrue());
10967 CHECK(!try_catch.HasCaught());
10968
10969 // Check that variables introduced in with-statement are not visible in
10970 // other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010971 script = v8_compile("with({x:2}){other.eval('x')}");
Steve Blocka7e24c12009-10-30 11:49:00 +000010972 result = script->Run();
10973 CHECK(try_catch.HasCaught());
10974 try_catch.Reset();
10975
10976 // Check that you cannot use 'eval.call' with another object than the
10977 // current global object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010978 script = v8_compile("other.y = 1; eval.call(other, 'y')");
Steve Blocka7e24c12009-10-30 11:49:00 +000010979 result = script->Run();
10980 CHECK(try_catch.HasCaught());
10981}
10982
10983
10984// Test that calling eval in a context which has been detached from
10985// its global throws an exception. This behavior is consistent with
10986// other JavaScript implementations.
10987THREADED_TEST(EvalInDetachedGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010988 v8::Isolate* isolate = CcTest::isolate();
10989 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010990
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010991 v8::Local<Context> context0 = Context::New(isolate);
10992 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010993
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010994 // Set up function in context0 that uses eval from context0.
Steve Blocka7e24c12009-10-30 11:49:00 +000010995 context0->Enter();
10996 v8::Handle<v8::Value> fun =
10997 CompileRun("var x = 42;"
10998 "(function() {"
10999 " var e = eval;"
11000 " return function(s) { return e(s); }"
11001 "})()");
11002 context0->Exit();
11003
11004 // Put the function into context1 and call it before and after
11005 // detaching the global. Before detaching, the call succeeds and
11006 // after detaching and exception is thrown.
11007 context1->Enter();
11008 context1->Global()->Set(v8_str("fun"), fun);
11009 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11010 CHECK_EQ(42, x_value->Int32Value());
11011 context0->DetachGlobal();
11012 v8::TryCatch catcher;
11013 x_value = CompileRun("fun('x')");
11014 CHECK(x_value.IsEmpty());
11015 CHECK(catcher.HasCaught());
11016 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000011017}
11018
11019
11020THREADED_TEST(CrossLazyLoad) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011021 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011022 LocalContext other;
11023 LocalContext current;
11024
11025 Local<String> token = v8_str("<security token>");
11026 other->SetSecurityToken(token);
11027 current->SetSecurityToken(token);
11028
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011029 // Set up reference from current to other.
Steve Blocka7e24c12009-10-30 11:49:00 +000011030 current->Global()->Set(v8_str("other"), other->Global());
11031
11032 // Trigger lazy loading in other context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011033 Local<Script> script = v8_compile("other.eval('new Date(42)')");
Steve Blocka7e24c12009-10-30 11:49:00 +000011034 Local<Value> value = script->Run();
11035 CHECK_EQ(42.0, value->NumberValue());
11036}
11037
11038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011039static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011040 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000011041 if (args.IsConstructCall()) {
11042 if (args[0]->IsInt32()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011043 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11044 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000011045 }
11046 }
11047
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011048 args.GetReturnValue().Set(args[0]);
11049}
11050
11051
11052static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11053 args.GetReturnValue().Set(args.This());
Steve Blocka7e24c12009-10-30 11:49:00 +000011054}
11055
11056
11057// Test that a call handler can be set for objects which will allow
11058// non-function objects created through the API to be called as
11059// functions.
11060THREADED_TEST(CallAsFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011061 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011062 v8::Isolate* isolate = context->GetIsolate();
11063 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011064
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011065 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011066 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11067 instance_template->SetCallAsFunctionHandler(call_as_function);
11068 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11069 context->Global()->Set(v8_str("obj"), instance);
11070 v8::TryCatch try_catch;
11071 Local<Value> value;
11072 CHECK(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +000011073
Ben Murdoch257744e2011-11-30 15:57:28 +000011074 value = CompileRun("obj(42)");
11075 CHECK(!try_catch.HasCaught());
11076 CHECK_EQ(42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011077
Ben Murdoch257744e2011-11-30 15:57:28 +000011078 value = CompileRun("(function(o){return o(49)})(obj)");
11079 CHECK(!try_catch.HasCaught());
11080 CHECK_EQ(49, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011081
Ben Murdoch257744e2011-11-30 15:57:28 +000011082 // test special case of call as function
11083 value = CompileRun("[obj]['0'](45)");
11084 CHECK(!try_catch.HasCaught());
11085 CHECK_EQ(45, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011086
Ben Murdoch257744e2011-11-30 15:57:28 +000011087 value = CompileRun("obj.call = Function.prototype.call;"
11088 "obj.call(null, 87)");
11089 CHECK(!try_catch.HasCaught());
11090 CHECK_EQ(87, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011091
Ben Murdoch257744e2011-11-30 15:57:28 +000011092 // Regression tests for bug #1116356: Calling call through call/apply
11093 // must work for non-function receivers.
11094 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11095 value = CompileRun(apply_99);
11096 CHECK(!try_catch.HasCaught());
11097 CHECK_EQ(99, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011098
Ben Murdoch257744e2011-11-30 15:57:28 +000011099 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11100 value = CompileRun(call_17);
11101 CHECK(!try_catch.HasCaught());
11102 CHECK_EQ(17, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011103
Ben Murdoch257744e2011-11-30 15:57:28 +000011104 // Check that the call-as-function handler can be called through
11105 // new.
11106 value = CompileRun("new obj(43)");
11107 CHECK(!try_catch.HasCaught());
11108 CHECK_EQ(-43, value->Int32Value());
11109
11110 // Check that the call-as-function handler can be called through
11111 // the API.
11112 v8::Handle<Value> args[] = { v8_num(28) };
11113 value = instance->CallAsFunction(instance, 1, args);
11114 CHECK(!try_catch.HasCaught());
11115 CHECK_EQ(28, value->Int32Value());
11116 }
11117
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011118 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011119 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11120 USE(instance_template);
Ben Murdoch257744e2011-11-30 15:57:28 +000011121 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11122 context->Global()->Set(v8_str("obj2"), instance);
11123 v8::TryCatch try_catch;
11124 Local<Value> value;
11125 CHECK(!try_catch.HasCaught());
11126
11127 // Call an object without call-as-function handler through the JS
11128 value = CompileRun("obj2(28)");
11129 CHECK(value.IsEmpty());
11130 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011131 String::Utf8Value exception_value1(try_catch.Exception());
11132 // TODO(verwaest): Better message
11133 CHECK_EQ("TypeError: object is not a function",
Ben Murdoch257744e2011-11-30 15:57:28 +000011134 *exception_value1);
11135 try_catch.Reset();
11136
11137 // Call an object without call-as-function handler through the API
11138 value = CompileRun("obj2(28)");
11139 v8::Handle<Value> args[] = { v8_num(28) };
11140 value = instance->CallAsFunction(instance, 1, args);
11141 CHECK(value.IsEmpty());
11142 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011143 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011144 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11145 try_catch.Reset();
11146 }
11147
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011148 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011149 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11150 instance_template->SetCallAsFunctionHandler(ThrowValue);
11151 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11152 context->Global()->Set(v8_str("obj3"), instance);
11153 v8::TryCatch try_catch;
11154 Local<Value> value;
11155 CHECK(!try_catch.HasCaught());
11156
11157 // Catch the exception which is thrown by call-as-function handler
11158 value = CompileRun("obj3(22)");
11159 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011160 String::Utf8Value exception_value1(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011161 CHECK_EQ("22", *exception_value1);
11162 try_catch.Reset();
11163
11164 v8::Handle<Value> args[] = { v8_num(23) };
11165 value = instance->CallAsFunction(instance, 1, args);
11166 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011167 String::Utf8Value exception_value2(try_catch.Exception());
Ben Murdoch257744e2011-11-30 15:57:28 +000011168 CHECK_EQ("23", *exception_value2);
11169 try_catch.Reset();
11170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011171
11172 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11173 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11174 instance_template->SetCallAsFunctionHandler(ReturnThis);
11175 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11176
11177 Local<v8::Value> a1 =
11178 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11179 CHECK(a1->StrictEquals(instance));
11180 Local<v8::Value> a2 =
11181 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11182 CHECK(a2->StrictEquals(instance));
11183 Local<v8::Value> a3 =
11184 instance->CallAsFunction(v8_num(42), 0, NULL);
11185 CHECK(a3->StrictEquals(instance));
11186 Local<v8::Value> a4 =
11187 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11188 CHECK(a4->StrictEquals(instance));
11189 Local<v8::Value> a5 =
11190 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11191 CHECK(a5->StrictEquals(instance));
11192 }
11193
11194 { CompileRun(
11195 "function ReturnThisSloppy() {"
11196 " return this;"
11197 "}"
11198 "function ReturnThisStrict() {"
11199 " 'use strict';"
11200 " return this;"
11201 "}");
11202 Local<Function> ReturnThisSloppy =
11203 Local<Function>::Cast(
11204 context->Global()->Get(v8_str("ReturnThisSloppy")));
11205 Local<Function> ReturnThisStrict =
11206 Local<Function>::Cast(
11207 context->Global()->Get(v8_str("ReturnThisStrict")));
11208
11209 Local<v8::Value> a1 =
11210 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11211 CHECK(a1->StrictEquals(context->Global()));
11212 Local<v8::Value> a2 =
11213 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11214 CHECK(a2->StrictEquals(context->Global()));
11215 Local<v8::Value> a3 =
11216 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11217 CHECK(a3->IsNumberObject());
11218 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11219 Local<v8::Value> a4 =
11220 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11221 CHECK(a4->IsStringObject());
11222 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11223 Local<v8::Value> a5 =
11224 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11225 CHECK(a5->IsBooleanObject());
11226 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11227
11228 Local<v8::Value> a6 =
11229 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11230 CHECK(a6->IsUndefined());
11231 Local<v8::Value> a7 =
11232 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11233 CHECK(a7->IsNull());
11234 Local<v8::Value> a8 =
11235 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11236 CHECK(a8->StrictEquals(v8_num(42)));
11237 Local<v8::Value> a9 =
11238 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11239 CHECK(a9->StrictEquals(v8_str("hello")));
11240 Local<v8::Value> a10 =
11241 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11242 CHECK(a10->StrictEquals(v8::True(isolate)));
11243 }
Ben Murdoch257744e2011-11-30 15:57:28 +000011244}
11245
11246
11247// Check whether a non-function object is callable.
11248THREADED_TEST(CallableObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000011249 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011250 v8::Isolate* isolate = context->GetIsolate();
11251 v8::HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011252
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011253 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011254 instance_template->SetCallAsFunctionHandler(call_as_function);
11255 Local<Object> instance = instance_template->NewInstance();
11256 v8::TryCatch try_catch;
11257
11258 CHECK(instance->IsCallable());
11259 CHECK(!try_catch.HasCaught());
11260 }
11261
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011262 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011263 Local<Object> instance = instance_template->NewInstance();
11264 v8::TryCatch try_catch;
11265
11266 CHECK(!instance->IsCallable());
11267 CHECK(!try_catch.HasCaught());
11268 }
11269
11270 { Local<FunctionTemplate> function_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011271 FunctionTemplate::New(isolate, call_as_function);
Ben Murdoch257744e2011-11-30 15:57:28 +000011272 Local<Function> function = function_template->GetFunction();
11273 Local<Object> instance = function;
11274 v8::TryCatch try_catch;
11275
11276 CHECK(instance->IsCallable());
11277 CHECK(!try_catch.HasCaught());
11278 }
11279
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011280 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000011281 Local<Function> function = function_template->GetFunction();
11282 Local<Object> instance = function;
11283 v8::TryCatch try_catch;
11284
11285 CHECK(instance->IsCallable());
11286 CHECK(!try_catch.HasCaught());
11287 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011288}
11289
11290
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011291static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11292 v8::HandleScope scope(isolate);
11293 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011294 for (int i = 0; i < iterations; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011295 Local<v8::Number> n(v8::Integer::New(isolate, 42));
Steve Blocka7e24c12009-10-30 11:49:00 +000011296 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011297 return Recurse(isolate, depth - 1, iterations);
Steve Blocka7e24c12009-10-30 11:49:00 +000011298}
11299
11300
11301THREADED_TEST(HandleIteration) {
11302 static const int kIterations = 500;
11303 static const int kNesting = 200;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011304 LocalContext context;
11305 v8::Isolate* isolate = context->GetIsolate();
11306 v8::HandleScope scope0(isolate);
11307 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011308 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011309 v8::HandleScope scope1(isolate);
11310 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011311 for (int i = 0; i < kIterations; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011312 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11313 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011314 }
11315
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011316 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011317 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011318 v8::HandleScope scope2(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000011319 for (int j = 0; j < kIterations; j++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011320 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11321 CHECK_EQ(j + 1 + kIterations,
11322 v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011323 }
11324 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011325 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000011326 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011327 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11328 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
Steve Blocka7e24c12009-10-30 11:49:00 +000011329}
11330
11331
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011332static void InterceptorHasOwnPropertyGetter(
Steve Blocka7e24c12009-10-30 11:49:00 +000011333 Local<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011334 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011335 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +000011336}
11337
11338
11339THREADED_TEST(InterceptorHasOwnProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011340 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011341 v8::Isolate* isolate = context->GetIsolate();
11342 v8::HandleScope scope(isolate);
11343 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011344 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11345 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11346 Local<Function> function = fun_templ->GetFunction();
11347 context->Global()->Set(v8_str("constructor"), function);
11348 v8::Handle<Value> value = CompileRun(
11349 "var o = new constructor();"
11350 "o.hasOwnProperty('ostehaps');");
11351 CHECK_EQ(false, value->BooleanValue());
11352 value = CompileRun(
11353 "o.ostehaps = 42;"
11354 "o.hasOwnProperty('ostehaps');");
11355 CHECK_EQ(true, value->BooleanValue());
11356 value = CompileRun(
11357 "var p = new constructor();"
11358 "p.hasOwnProperty('ostehaps');");
11359 CHECK_EQ(false, value->BooleanValue());
11360}
11361
11362
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011363static void InterceptorHasOwnPropertyGetterGC(
Steve Blocka7e24c12009-10-30 11:49:00 +000011364 Local<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011365 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011366 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011367 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000011368}
11369
11370
11371THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011372 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011373 v8::Isolate* isolate = context->GetIsolate();
11374 v8::HandleScope scope(isolate);
11375 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011376 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11377 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11378 Local<Function> function = fun_templ->GetFunction();
11379 context->Global()->Set(v8_str("constructor"), function);
11380 // Let's first make some stuff so we can be sure to get a good GC.
11381 CompileRun(
11382 "function makestr(size) {"
11383 " switch (size) {"
11384 " case 1: return 'f';"
11385 " case 2: return 'fo';"
11386 " case 3: return 'foo';"
11387 " }"
11388 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11389 "}"
11390 "var x = makestr(12345);"
11391 "x = makestr(31415);"
11392 "x = makestr(23456);");
11393 v8::Handle<Value> value = CompileRun(
11394 "var o = new constructor();"
11395 "o.__proto__ = new String(x);"
11396 "o.hasOwnProperty('ostehaps');");
11397 CHECK_EQ(false, value->BooleanValue());
11398}
11399
11400
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011401typedef void (*NamedPropertyGetter)(
11402 Local<String> property,
11403 const v8::PropertyCallbackInfo<v8::Value>& info);
Steve Blocka7e24c12009-10-30 11:49:00 +000011404
11405
11406static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11407 const char* source,
11408 int expected) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011409 v8::Isolate* isolate = CcTest::isolate();
11410 v8::HandleScope scope(isolate);
11411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011412 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +000011413 LocalContext context;
11414 context->Global()->Set(v8_str("o"), templ->NewInstance());
11415 v8::Handle<Value> value = CompileRun(source);
11416 CHECK_EQ(expected, value->Int32Value());
11417}
11418
11419
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011420static void InterceptorLoadICGetter(
11421 Local<String> name,
11422 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011423 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011424 v8::Isolate* isolate = CcTest::isolate();
11425 CHECK_EQ(isolate, info.GetIsolate());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011426 CHECK_EQ(v8_str("data"), info.Data());
11427 CHECK_EQ(v8_str("x"), name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011428 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
Steve Blocka7e24c12009-10-30 11:49:00 +000011429}
11430
11431
11432// This test should hit the load IC for the interceptor case.
11433THREADED_TEST(InterceptorLoadIC) {
11434 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11435 "var result = 0;"
11436 "for (var i = 0; i < 1000; i++) {"
11437 " result = o.x;"
11438 "}",
11439 42);
11440}
11441
11442
11443// Below go several tests which verify that JITing for various
11444// configurations of interceptor and explicit fields works fine
11445// (those cases are special cased to get better performance).
11446
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011447static void InterceptorLoadXICGetter(
11448 Local<String> name,
11449 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011450 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011451 info.GetReturnValue().Set(
11452 v8_str("x")->Equals(name) ?
11453 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11454 v8::Handle<v8::Value>());
Steve Blocka7e24c12009-10-30 11:49:00 +000011455}
11456
11457
11458THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11459 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11460 "var result = 0;"
11461 "o.y = 239;"
11462 "for (var i = 0; i < 1000; i++) {"
11463 " result = o.y;"
11464 "}",
11465 239);
11466}
11467
11468
11469THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11470 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11471 "var result = 0;"
11472 "o.__proto__ = { 'y': 239 };"
11473 "for (var i = 0; i < 1000; i++) {"
11474 " result = o.y + o.x;"
11475 "}",
11476 239 + 42);
11477}
11478
11479
11480THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11481 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11482 "var result = 0;"
11483 "o.__proto__.y = 239;"
11484 "for (var i = 0; i < 1000; i++) {"
11485 " result = o.y + o.x;"
11486 "}",
11487 239 + 42);
11488}
11489
11490
11491THREADED_TEST(InterceptorLoadICUndefined) {
11492 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11493 "var result = 0;"
11494 "for (var i = 0; i < 1000; i++) {"
11495 " result = (o.y == undefined) ? 239 : 42;"
11496 "}",
11497 239);
11498}
11499
11500
11501THREADED_TEST(InterceptorLoadICWithOverride) {
11502 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11503 "fst = new Object(); fst.__proto__ = o;"
11504 "snd = new Object(); snd.__proto__ = fst;"
11505 "var result1 = 0;"
11506 "for (var i = 0; i < 1000; i++) {"
11507 " result1 = snd.x;"
11508 "}"
11509 "fst.x = 239;"
11510 "var result = 0;"
11511 "for (var i = 0; i < 1000; i++) {"
11512 " result = snd.x;"
11513 "}"
11514 "result + result1",
11515 239 + 42);
11516}
11517
11518
11519// Test the case when we stored field into
11520// a stub, but interceptor produced value on its own.
11521THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11522 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11523 "proto = new Object();"
11524 "o.__proto__ = proto;"
11525 "proto.x = 239;"
11526 "for (var i = 0; i < 1000; i++) {"
11527 " o.x;"
11528 // Now it should be ICed and keep a reference to x defined on proto
11529 "}"
11530 "var result = 0;"
11531 "for (var i = 0; i < 1000; i++) {"
11532 " result += o.x;"
11533 "}"
11534 "result;",
11535 42 * 1000);
11536}
11537
11538
11539// Test the case when we stored field into
11540// a stub, but it got invalidated later on.
11541THREADED_TEST(InterceptorLoadICInvalidatedField) {
11542 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11543 "proto1 = new Object();"
11544 "proto2 = new Object();"
11545 "o.__proto__ = proto1;"
11546 "proto1.__proto__ = proto2;"
11547 "proto2.y = 239;"
11548 "for (var i = 0; i < 1000; i++) {"
11549 " o.y;"
11550 // Now it should be ICed and keep a reference to y defined on proto2
11551 "}"
11552 "proto1.y = 42;"
11553 "var result = 0;"
11554 "for (var i = 0; i < 1000; i++) {"
11555 " result += o.y;"
11556 "}"
11557 "result;",
11558 42 * 1000);
11559}
11560
11561
Steve Block6ded16b2010-05-10 14:33:55 +010011562static int interceptor_load_not_handled_calls = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011563static void InterceptorLoadNotHandled(
11564 Local<String> name,
11565 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Block6ded16b2010-05-10 14:33:55 +010011566 ++interceptor_load_not_handled_calls;
Steve Block6ded16b2010-05-10 14:33:55 +010011567}
11568
11569
11570// Test how post-interceptor lookups are done in the non-cacheable
11571// case: the interceptor should not be invoked during this lookup.
11572THREADED_TEST(InterceptorLoadICPostInterceptor) {
11573 interceptor_load_not_handled_calls = 0;
11574 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11575 "receiver = new Object();"
11576 "receiver.__proto__ = o;"
11577 "proto = new Object();"
11578 "/* Make proto a slow-case object. */"
11579 "for (var i = 0; i < 1000; i++) {"
11580 " proto[\"xxxxxxxx\" + i] = [];"
11581 "}"
11582 "proto.x = 17;"
11583 "o.__proto__ = proto;"
11584 "var result = 0;"
11585 "for (var i = 0; i < 1000; i++) {"
11586 " result += receiver.x;"
11587 "}"
11588 "result;",
11589 17 * 1000);
11590 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11591}
11592
11593
Steve Blocka7e24c12009-10-30 11:49:00 +000011594// Test the case when we stored field into
11595// a stub, but it got invalidated later on due to override on
11596// global object which is between interceptor and fields' holders.
11597THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11598 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11599 "o.__proto__ = this;" // set a global to be a proto of o.
11600 "this.__proto__.y = 239;"
11601 "for (var i = 0; i < 10; i++) {"
11602 " if (o.y != 239) throw 'oops: ' + o.y;"
11603 // Now it should be ICed and keep a reference to y defined on field_holder.
11604 "}"
11605 "this.y = 42;" // Assign on a global.
11606 "var result = 0;"
11607 "for (var i = 0; i < 10; i++) {"
11608 " result += o.y;"
11609 "}"
11610 "result;",
11611 42 * 10);
11612}
11613
11614
Steve Blocka7e24c12009-10-30 11:49:00 +000011615static void SetOnThis(Local<String> name,
11616 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011617 const v8::PropertyCallbackInfo<void>& info) {
11618 Local<Object>::Cast(info.This())->ForceSet(name, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011619}
11620
11621
11622THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011623 v8::Isolate* isolate = CcTest::isolate();
11624 v8::HandleScope scope(isolate);
11625 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011626 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011627 templ->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000011628 LocalContext context;
11629 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011630
11631 // Check the case when receiver and interceptor's holder
11632 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +000011633 v8::Handle<Value> value = CompileRun(
11634 "var result = 0;"
11635 "for (var i = 0; i < 7; i++) {"
11636 " result = o.y;"
11637 "}");
11638 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011639
11640 // Check the case when interceptor's holder is in proto chain
11641 // of receiver.
11642 value = CompileRun(
11643 "r = { __proto__: o };"
11644 "var result = 0;"
11645 "for (var i = 0; i < 7; i++) {"
11646 " result = r.y;"
11647 "}");
11648 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011649}
11650
11651
11652THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011653 v8::Isolate* isolate = CcTest::isolate();
11654 v8::HandleScope scope(isolate);
11655 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011656 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011657 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11658 templ_p->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000011659
11660 LocalContext context;
11661 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11662 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11663
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011664 // Check the case when receiver and interceptor's holder
11665 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +000011666 v8::Handle<Value> value = CompileRun(
11667 "o.__proto__ = p;"
11668 "var result = 0;"
11669 "for (var i = 0; i < 7; i++) {"
11670 " result = o.x + o.y;"
11671 "}");
11672 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011673
11674 // Check the case when interceptor's holder is in proto chain
11675 // of receiver.
11676 value = CompileRun(
11677 "r = { __proto__: o };"
11678 "var result = 0;"
11679 "for (var i = 0; i < 7; i++) {"
11680 " result = r.x + r.y;"
11681 "}");
11682 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011683}
11684
11685
11686THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011687 v8::Isolate* isolate = CcTest::isolate();
11688 v8::HandleScope scope(isolate);
11689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011690 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011691 templ->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000011692
11693 LocalContext context;
11694 context->Global()->Set(v8_str("o"), templ->NewInstance());
11695
11696 v8::Handle<Value> value = CompileRun(
11697 "fst = new Object(); fst.__proto__ = o;"
11698 "snd = new Object(); snd.__proto__ = fst;"
11699 "var result1 = 0;"
11700 "for (var i = 0; i < 7; i++) {"
11701 " result1 = snd.x;"
11702 "}"
11703 "fst.x = 239;"
11704 "var result = 0;"
11705 "for (var i = 0; i < 7; i++) {"
11706 " result = snd.x;"
11707 "}"
11708 "result + result1");
11709 CHECK_EQ(239 + 42, value->Int32Value());
11710}
11711
11712
11713// Test the case when we stored callback into
11714// a stub, but interceptor produced value on its own.
11715THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011716 v8::Isolate* isolate = CcTest::isolate();
11717 v8::HandleScope scope(isolate);
11718 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011719 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011720 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11721 templ_p->SetAccessor(v8_str("y"), Return239Callback);
Steve Blocka7e24c12009-10-30 11:49:00 +000011722
11723 LocalContext context;
11724 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11725 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11726
11727 v8::Handle<Value> value = CompileRun(
11728 "o.__proto__ = p;"
11729 "for (var i = 0; i < 7; i++) {"
11730 " o.x;"
11731 // Now it should be ICed and keep a reference to x defined on p
11732 "}"
11733 "var result = 0;"
11734 "for (var i = 0; i < 7; i++) {"
11735 " result += o.x;"
11736 "}"
11737 "result");
11738 CHECK_EQ(42 * 7, value->Int32Value());
11739}
11740
11741
11742// Test the case when we stored callback into
11743// a stub, but it got invalidated later on.
11744THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011745 v8::Isolate* isolate = CcTest::isolate();
11746 v8::HandleScope scope(isolate);
11747 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011748 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011749 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11750 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
Steve Blocka7e24c12009-10-30 11:49:00 +000011751
11752 LocalContext context;
11753 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11754 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11755
11756 v8::Handle<Value> value = CompileRun(
11757 "inbetween = new Object();"
11758 "o.__proto__ = inbetween;"
11759 "inbetween.__proto__ = p;"
11760 "for (var i = 0; i < 10; i++) {"
11761 " o.y;"
11762 // Now it should be ICed and keep a reference to y defined on p
11763 "}"
11764 "inbetween.y = 42;"
11765 "var result = 0;"
11766 "for (var i = 0; i < 10; i++) {"
11767 " result += o.y;"
11768 "}"
11769 "result");
11770 CHECK_EQ(42 * 10, value->Int32Value());
11771}
11772
11773
11774// Test the case when we stored callback into
11775// a stub, but it got invalidated later on due to override on
11776// global object which is between interceptor and callbacks' holders.
11777THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011778 v8::Isolate* isolate = CcTest::isolate();
11779 v8::HandleScope scope(isolate);
11780 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011781 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011782 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11783 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
Steve Blocka7e24c12009-10-30 11:49:00 +000011784
11785 LocalContext context;
11786 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11787 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11788
11789 v8::Handle<Value> value = CompileRun(
11790 "o.__proto__ = this;"
11791 "this.__proto__ = p;"
11792 "for (var i = 0; i < 10; i++) {"
11793 " if (o.y != 239) throw 'oops: ' + o.y;"
11794 // Now it should be ICed and keep a reference to y defined on p
11795 "}"
11796 "this.y = 42;"
11797 "var result = 0;"
11798 "for (var i = 0; i < 10; i++) {"
11799 " result += o.y;"
11800 "}"
11801 "result");
11802 CHECK_EQ(42 * 10, value->Int32Value());
11803}
11804
11805
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011806static void InterceptorLoadICGetter0(
11807 Local<String> name,
11808 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011809 ApiTestFuzzer::Fuzz();
11810 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011811 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
Steve Blocka7e24c12009-10-30 11:49:00 +000011812}
11813
11814
11815THREADED_TEST(InterceptorReturningZero) {
11816 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11817 "o.x == undefined ? 1 : 0",
11818 0);
11819}
11820
11821
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011822static void InterceptorStoreICSetter(
11823 Local<String> key,
11824 Local<Value> value,
11825 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011826 CHECK(v8_str("x")->Equals(key));
11827 CHECK_EQ(42, value->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011828 info.GetReturnValue().Set(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011829}
11830
11831
11832// This test should hit the store IC for the interceptor case.
11833THREADED_TEST(InterceptorStoreIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011834 v8::Isolate* isolate = CcTest::isolate();
11835 v8::HandleScope scope(isolate);
11836 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011837 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080011838 InterceptorStoreICSetter,
11839 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +000011840 LocalContext context;
11841 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011842 CompileRun(
11843 "for (var i = 0; i < 1000; i++) {"
11844 " o.x = 42;"
11845 "}");
Steve Blocka7e24c12009-10-30 11:49:00 +000011846}
11847
11848
11849THREADED_TEST(InterceptorStoreICWithNoSetter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011850 v8::Isolate* isolate = CcTest::isolate();
11851 v8::HandleScope scope(isolate);
11852 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011853 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11854 LocalContext context;
11855 context->Global()->Set(v8_str("o"), templ->NewInstance());
11856 v8::Handle<Value> value = CompileRun(
11857 "for (var i = 0; i < 1000; i++) {"
11858 " o.y = 239;"
11859 "}"
11860 "42 + o.y");
11861 CHECK_EQ(239 + 42, value->Int32Value());
11862}
11863
11864
11865
11866
11867v8::Handle<Value> call_ic_function;
11868v8::Handle<Value> call_ic_function2;
11869v8::Handle<Value> call_ic_function3;
11870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011871static void InterceptorCallICGetter(
11872 Local<String> name,
11873 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011874 ApiTestFuzzer::Fuzz();
11875 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011876 info.GetReturnValue().Set(call_ic_function);
Steve Blocka7e24c12009-10-30 11:49:00 +000011877}
11878
11879
11880// This test should hit the call IC for the interceptor case.
11881THREADED_TEST(InterceptorCallIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011882 v8::Isolate* isolate = CcTest::isolate();
11883 v8::HandleScope scope(isolate);
11884 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011885 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11886 LocalContext context;
11887 context->Global()->Set(v8_str("o"), templ->NewInstance());
11888 call_ic_function =
11889 v8_compile("function f(x) { return x + 1; }; f")->Run();
11890 v8::Handle<Value> value = CompileRun(
11891 "var result = 0;"
11892 "for (var i = 0; i < 1000; i++) {"
11893 " result = o.x(41);"
11894 "}");
11895 CHECK_EQ(42, value->Int32Value());
11896}
11897
11898
11899// This test checks that if interceptor doesn't provide
11900// a value, we can fetch regular value.
11901THREADED_TEST(InterceptorCallICSeesOthers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011902 v8::Isolate* isolate = CcTest::isolate();
11903 v8::HandleScope scope(isolate);
11904 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011905 templ->SetNamedPropertyHandler(NoBlockGetterX);
11906 LocalContext context;
11907 context->Global()->Set(v8_str("o"), templ->NewInstance());
11908 v8::Handle<Value> value = CompileRun(
11909 "o.x = function f(x) { return x + 1; };"
11910 "var result = 0;"
11911 "for (var i = 0; i < 7; i++) {"
11912 " result = o.x(41);"
11913 "}");
11914 CHECK_EQ(42, value->Int32Value());
11915}
11916
11917
11918static v8::Handle<Value> call_ic_function4;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011919static void InterceptorCallICGetter4(
11920 Local<String> name,
11921 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011922 ApiTestFuzzer::Fuzz();
11923 CHECK(v8_str("x")->Equals(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011924 info.GetReturnValue().Set(call_ic_function4);
Steve Blocka7e24c12009-10-30 11:49:00 +000011925}
11926
11927
11928// This test checks that if interceptor provides a function,
11929// even if we cached shadowed variant, interceptor's function
11930// is invoked
11931THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011932 v8::Isolate* isolate = CcTest::isolate();
11933 v8::HandleScope scope(isolate);
11934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011935 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11936 LocalContext context;
11937 context->Global()->Set(v8_str("o"), templ->NewInstance());
11938 call_ic_function4 =
11939 v8_compile("function f(x) { return x - 1; }; f")->Run();
11940 v8::Handle<Value> value = CompileRun(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011941 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
Steve Blocka7e24c12009-10-30 11:49:00 +000011942 "var result = 0;"
11943 "for (var i = 0; i < 1000; i++) {"
11944 " result = o.x(42);"
11945 "}");
11946 CHECK_EQ(41, value->Int32Value());
11947}
11948
11949
11950// Test the case when we stored cacheable lookup into
11951// a stub, but it got invalidated later on
11952THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011953 v8::Isolate* isolate = CcTest::isolate();
11954 v8::HandleScope scope(isolate);
11955 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011956 templ->SetNamedPropertyHandler(NoBlockGetterX);
11957 LocalContext context;
11958 context->Global()->Set(v8_str("o"), templ->NewInstance());
11959 v8::Handle<Value> value = CompileRun(
11960 "proto1 = new Object();"
11961 "proto2 = new Object();"
11962 "o.__proto__ = proto1;"
11963 "proto1.__proto__ = proto2;"
11964 "proto2.y = function(x) { return x + 1; };"
11965 // Invoke it many times to compile a stub
11966 "for (var i = 0; i < 7; i++) {"
11967 " o.y(42);"
11968 "}"
11969 "proto1.y = function(x) { return x - 1; };"
11970 "var result = 0;"
11971 "for (var i = 0; i < 7; i++) {"
11972 " result += o.y(42);"
11973 "}");
11974 CHECK_EQ(41 * 7, value->Int32Value());
11975}
11976
11977
Steve Blocka7e24c12009-10-30 11:49:00 +000011978// This test checks that if interceptor doesn't provide a function,
11979// cached constant function is used
11980THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011981 v8::Isolate* isolate = CcTest::isolate();
11982 v8::HandleScope scope(isolate);
11983 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011984 templ->SetNamedPropertyHandler(NoBlockGetterX);
11985 LocalContext context;
11986 context->Global()->Set(v8_str("o"), templ->NewInstance());
11987 v8::Handle<Value> value = CompileRun(
11988 "function inc(x) { return x + 1; };"
11989 "inc(1);"
11990 "o.x = inc;"
11991 "var result = 0;"
11992 "for (var i = 0; i < 1000; i++) {"
11993 " result = o.x(42);"
11994 "}");
11995 CHECK_EQ(43, value->Int32Value());
11996}
11997
11998
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011999static v8::Handle<Value> call_ic_function5;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012000static void InterceptorCallICGetter5(
12001 Local<String> name,
12002 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012003 ApiTestFuzzer::Fuzz();
12004 if (v8_str("x")->Equals(name))
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012005 info.GetReturnValue().Set(call_ic_function5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012006}
12007
12008
Steve Blocka7e24c12009-10-30 11:49:00 +000012009// This test checks that if interceptor provides a function,
12010// even if we cached constant function, interceptor's function
12011// is invoked
12012THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012013 v8::Isolate* isolate = CcTest::isolate();
12014 v8::HandleScope scope(isolate);
12015 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012016 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12017 LocalContext context;
12018 context->Global()->Set(v8_str("o"), templ->NewInstance());
12019 call_ic_function5 =
12020 v8_compile("function f(x) { return x - 1; }; f")->Run();
12021 v8::Handle<Value> value = CompileRun(
12022 "function inc(x) { return x + 1; };"
12023 "inc(1);"
12024 "o.x = inc;"
12025 "var result = 0;"
12026 "for (var i = 0; i < 1000; i++) {"
12027 " result = o.x(42);"
12028 "}");
12029 CHECK_EQ(41, value->Int32Value());
12030}
12031
12032
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012033static v8::Handle<Value> call_ic_function6;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012034static void InterceptorCallICGetter6(
12035 Local<String> name,
12036 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012037 ApiTestFuzzer::Fuzz();
12038 if (v8_str("x")->Equals(name))
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012039 info.GetReturnValue().Set(call_ic_function6);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012040}
12041
12042
12043// Same test as above, except the code is wrapped in a function
12044// to test the optimized compiler.
12045THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12046 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012047 v8::Isolate* isolate = CcTest::isolate();
12048 v8::HandleScope scope(isolate);
12049 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012050 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12051 LocalContext context;
12052 context->Global()->Set(v8_str("o"), templ->NewInstance());
12053 call_ic_function6 =
12054 v8_compile("function f(x) { return x - 1; }; f")->Run();
12055 v8::Handle<Value> value = CompileRun(
12056 "function inc(x) { return x + 1; };"
12057 "inc(1);"
12058 "o.x = inc;"
12059 "function test() {"
12060 " var result = 0;"
12061 " for (var i = 0; i < 1000; i++) {"
12062 " result = o.x(42);"
12063 " }"
12064 " return result;"
12065 "};"
12066 "test();"
12067 "test();"
12068 "test();"
12069 "%OptimizeFunctionOnNextCall(test);"
12070 "test()");
12071 CHECK_EQ(41, value->Int32Value());
12072}
12073
12074
Steve Blocka7e24c12009-10-30 11:49:00 +000012075// Test the case when we stored constant function into
12076// a stub, but it got invalidated later on
12077THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012078 v8::Isolate* isolate = CcTest::isolate();
12079 v8::HandleScope scope(isolate);
12080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012081 templ->SetNamedPropertyHandler(NoBlockGetterX);
12082 LocalContext context;
12083 context->Global()->Set(v8_str("o"), templ->NewInstance());
12084 v8::Handle<Value> value = CompileRun(
12085 "function inc(x) { return x + 1; };"
12086 "inc(1);"
12087 "proto1 = new Object();"
12088 "proto2 = new Object();"
12089 "o.__proto__ = proto1;"
12090 "proto1.__proto__ = proto2;"
12091 "proto2.y = inc;"
12092 // Invoke it many times to compile a stub
12093 "for (var i = 0; i < 7; i++) {"
12094 " o.y(42);"
12095 "}"
12096 "proto1.y = function(x) { return x - 1; };"
12097 "var result = 0;"
12098 "for (var i = 0; i < 7; i++) {"
12099 " result += o.y(42);"
12100 "}");
12101 CHECK_EQ(41 * 7, value->Int32Value());
12102}
12103
12104
12105// Test the case when we stored constant function into
12106// a stub, but it got invalidated later on due to override on
12107// global object which is between interceptor and constant function' holders.
12108THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012109 v8::Isolate* isolate = CcTest::isolate();
12110 v8::HandleScope scope(isolate);
12111 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012112 templ->SetNamedPropertyHandler(NoBlockGetterX);
12113 LocalContext context;
12114 context->Global()->Set(v8_str("o"), templ->NewInstance());
12115 v8::Handle<Value> value = CompileRun(
12116 "function inc(x) { return x + 1; };"
12117 "inc(1);"
12118 "o.__proto__ = this;"
12119 "this.__proto__.y = inc;"
12120 // Invoke it many times to compile a stub
12121 "for (var i = 0; i < 7; i++) {"
12122 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12123 "}"
12124 "this.y = function(x) { return x - 1; };"
12125 "var result = 0;"
12126 "for (var i = 0; i < 7; i++) {"
12127 " result += o.y(42);"
12128 "}");
12129 CHECK_EQ(41 * 7, value->Int32Value());
12130}
12131
12132
Leon Clarke4515c472010-02-03 11:58:03 +000012133// Test the case when actual function to call sits on global object.
12134THREADED_TEST(InterceptorCallICCachedFromGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012135 v8::Isolate* isolate = CcTest::isolate();
12136 v8::HandleScope scope(isolate);
12137 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Leon Clarke4515c472010-02-03 11:58:03 +000012138 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12139
12140 LocalContext context;
12141 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12142
12143 v8::Handle<Value> value = CompileRun(
12144 "try {"
12145 " o.__proto__ = this;"
12146 " for (var i = 0; i < 10; i++) {"
12147 " var v = o.parseFloat('239');"
12148 " if (v != 239) throw v;"
12149 // Now it should be ICed and keep a reference to parseFloat.
12150 " }"
12151 " var result = 0;"
12152 " for (var i = 0; i < 10; i++) {"
12153 " result += o.parseFloat('239');"
12154 " }"
12155 " result"
12156 "} catch(e) {"
12157 " e"
12158 "};");
12159 CHECK_EQ(239 * 10, value->Int32Value());
12160}
12161
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012162static void InterceptorCallICFastApi(
12163 Local<String> name,
12164 const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012165 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012166 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12167 int* call_count =
12168 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
Andrei Popescu402d9372010-02-26 13:31:12 +000012169 ++(*call_count);
12170 if ((*call_count) % 20 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012171 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Andrei Popescu402d9372010-02-26 13:31:12 +000012172 }
Andrei Popescu402d9372010-02-26 13:31:12 +000012173}
12174
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012175static void FastApiCallback_TrivialSignature(
12176 const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012177 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012178 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12179 v8::Isolate* isolate = CcTest::isolate();
12180 CHECK_EQ(isolate, args.GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +000012181 CHECK_EQ(args.This(), args.Holder());
12182 CHECK(args.Data()->Equals(v8_str("method_data")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012183 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +000012184}
12185
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012186static void FastApiCallback_SimpleSignature(
12187 const v8::FunctionCallbackInfo<v8::Value>& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012188 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012189 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12190 v8::Isolate* isolate = CcTest::isolate();
12191 CHECK_EQ(isolate, args.GetIsolate());
Andrei Popescu402d9372010-02-26 13:31:12 +000012192 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12193 CHECK(args.Data()->Equals(v8_str("method_data")));
12194 // Note, we're using HasRealNamedProperty instead of Has to avoid
12195 // invoking the interceptor again.
12196 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012197 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +000012198}
12199
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012200
Andrei Popescu402d9372010-02-26 13:31:12 +000012201// Helper to maximize the odds of object moving.
12202static void GenerateSomeGarbage() {
12203 CompileRun(
12204 "var garbage;"
12205 "for (var i = 0; i < 1000; i++) {"
12206 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12207 "}"
12208 "garbage = undefined;");
12209}
12210
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012211
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012212void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block1e0659c2011-05-24 12:43:12 +010012213 static int count = 0;
12214 if (count++ % 3 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012215 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12216 // This should move the stub
Steve Block1e0659c2011-05-24 12:43:12 +010012217 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12218 }
Steve Block1e0659c2011-05-24 12:43:12 +010012219}
12220
12221
12222THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
Steve Block1e0659c2011-05-24 12:43:12 +010012223 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012224 v8::Isolate* isolate = context->GetIsolate();
12225 v8::HandleScope scope(isolate);
12226 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12227 v8::ObjectTemplate::New(isolate);
12228 nativeobject_templ->Set(isolate, "callback",
12229 v8::FunctionTemplate::New(isolate,
12230 DirectApiCallback));
Steve Block1e0659c2011-05-24 12:43:12 +010012231 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12232 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12233 // call the api function multiple times to ensure direct call stub creation.
12234 CompileRun(
12235 "function f() {"
12236 " for (var i = 1; i <= 30; i++) {"
12237 " nativeobject.callback();"
12238 " }"
12239 "}"
12240 "f();");
12241}
12242
12243
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012244void ThrowingDirectApiCallback(
12245 const v8::FunctionCallbackInfo<v8::Value>& args) {
12246 args.GetIsolate()->ThrowException(v8_str("g"));
Steve Block1e0659c2011-05-24 12:43:12 +010012247}
12248
12249
12250THREADED_TEST(CallICFastApi_DirectCall_Throw) {
Steve Block1e0659c2011-05-24 12:43:12 +010012251 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012252 v8::Isolate* isolate = context->GetIsolate();
12253 v8::HandleScope scope(isolate);
12254 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12255 v8::ObjectTemplate::New(isolate);
12256 nativeobject_templ->Set(isolate, "callback",
12257 v8::FunctionTemplate::New(isolate,
12258 ThrowingDirectApiCallback));
Steve Block1e0659c2011-05-24 12:43:12 +010012259 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12260 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12261 // call the api function multiple times to ensure direct call stub creation.
12262 v8::Handle<Value> result = CompileRun(
12263 "var result = '';"
12264 "function f() {"
12265 " for (var i = 1; i <= 5; i++) {"
12266 " try { nativeobject.callback(); } catch (e) { result += e; }"
12267 " }"
12268 "}"
12269 "f(); result;");
12270 CHECK_EQ(v8_str("ggggg"), result);
12271}
12272
12273
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012274static Handle<Value> DoDirectGetter() {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012275 if (++p_getter_count % 3 == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012276 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012277 GenerateSomeGarbage();
12278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012279 return v8_str("Direct Getter Result");
12280}
12281
12282static void DirectGetterCallback(
12283 Local<String> name,
12284 const v8::PropertyCallbackInfo<v8::Value>& info) {
12285 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12286 info.GetReturnValue().Set(DoDirectGetter());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012287}
12288
12289
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012290template<typename Accessor>
12291static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012292 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012293 v8::Isolate* isolate = context->GetIsolate();
12294 v8::HandleScope scope(isolate);
12295 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12296 obj->SetAccessor(v8_str("p1"), accessor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012297 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12298 p_getter_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012299 v8::Handle<v8::Value> result = CompileRun(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012300 "function f() {"
12301 " for (var i = 0; i < 30; i++) o1.p1;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012302 " return o1.p1"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012303 "}"
12304 "f();");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012305 CHECK_EQ(v8_str("Direct Getter Result"), result);
12306 CHECK_EQ(31, p_getter_count);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012307}
12308
12309
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012310THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12311 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12312}
12313
12314
12315void ThrowingDirectGetterCallback(
12316 Local<String> name,
12317 const v8::PropertyCallbackInfo<v8::Value>& info) {
12318 info.GetIsolate()->ThrowException(v8_str("g"));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012319}
12320
12321
12322THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012323 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012324 v8::Isolate* isolate = context->GetIsolate();
12325 v8::HandleScope scope(isolate);
12326 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012327 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12328 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12329 v8::Handle<Value> result = CompileRun(
12330 "var result = '';"
12331 "for (var i = 0; i < 5; i++) {"
12332 " try { o1.p1; } catch (e) { result += e; }"
12333 "}"
12334 "result;");
12335 CHECK_EQ(v8_str("ggggg"), result);
12336}
12337
12338
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012339THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012340 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012341 v8::Isolate* isolate = CcTest::isolate();
12342 v8::HandleScope scope(isolate);
12343 v8::Handle<v8::FunctionTemplate> fun_templ =
12344 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000012345 v8::Handle<v8::FunctionTemplate> method_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012346 v8::FunctionTemplate::New(isolate,
12347 FastApiCallback_TrivialSignature,
Andrei Popescu402d9372010-02-26 13:31:12 +000012348 v8_str("method_data"),
12349 v8::Handle<v8::Signature>());
12350 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12351 proto_templ->Set(v8_str("method"), method_templ);
12352 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012353 templ->SetNamedPropertyHandler(
12354 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12355 v8::External::New(isolate, &interceptor_call_count));
Andrei Popescu402d9372010-02-26 13:31:12 +000012356 LocalContext context;
12357 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12358 GenerateSomeGarbage();
12359 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012360 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012361 "var result = 0;"
12362 "for (var i = 0; i < 100; i++) {"
12363 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012364 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012365 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12366 CHECK_EQ(100, interceptor_call_count);
12367}
12368
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012369
12370THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012371 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012372 v8::Isolate* isolate = CcTest::isolate();
12373 v8::HandleScope scope(isolate);
12374 v8::Handle<v8::FunctionTemplate> fun_templ =
12375 v8::FunctionTemplate::New(isolate);
12376 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12377 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12378 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012379 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12380 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012381 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000012382 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012383 templ->SetNamedPropertyHandler(
12384 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12385 v8::External::New(isolate, &interceptor_call_count));
Andrei Popescu402d9372010-02-26 13:31:12 +000012386 LocalContext context;
12387 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12388 GenerateSomeGarbage();
12389 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012390 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012391 "o.foo = 17;"
12392 "var receiver = {};"
12393 "receiver.__proto__ = o;"
12394 "var result = 0;"
12395 "for (var i = 0; i < 100; i++) {"
12396 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012397 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012398 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12399 CHECK_EQ(100, interceptor_call_count);
12400}
12401
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012402
12403THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012404 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012405 v8::Isolate* isolate = CcTest::isolate();
12406 v8::HandleScope scope(isolate);
12407 v8::Handle<v8::FunctionTemplate> fun_templ =
12408 v8::FunctionTemplate::New(isolate);
12409 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12410 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12411 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012412 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12413 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012414 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000012415 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012416 templ->SetNamedPropertyHandler(
12417 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12418 v8::External::New(isolate, &interceptor_call_count));
Andrei Popescu402d9372010-02-26 13:31:12 +000012419 LocalContext context;
12420 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12421 GenerateSomeGarbage();
12422 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012423 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012424 "o.foo = 17;"
12425 "var receiver = {};"
12426 "receiver.__proto__ = o;"
12427 "var result = 0;"
12428 "var saved_result = 0;"
12429 "for (var i = 0; i < 100; i++) {"
12430 " result = receiver.method(41);"
12431 " if (i == 50) {"
12432 " saved_result = result;"
12433 " receiver = {method: function(x) { return x - 1 }};"
12434 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012435 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012436 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12437 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12438 CHECK_GE(interceptor_call_count, 50);
12439}
12440
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012441
12442THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012443 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012444 v8::Isolate* isolate = CcTest::isolate();
12445 v8::HandleScope scope(isolate);
12446 v8::Handle<v8::FunctionTemplate> fun_templ =
12447 v8::FunctionTemplate::New(isolate);
12448 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12449 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12450 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012451 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12452 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012453 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000012454 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012455 templ->SetNamedPropertyHandler(
12456 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12457 v8::External::New(isolate, &interceptor_call_count));
Andrei Popescu402d9372010-02-26 13:31:12 +000012458 LocalContext context;
12459 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12460 GenerateSomeGarbage();
12461 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012462 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012463 "o.foo = 17;"
12464 "var receiver = {};"
12465 "receiver.__proto__ = o;"
12466 "var result = 0;"
12467 "var saved_result = 0;"
12468 "for (var i = 0; i < 100; i++) {"
12469 " result = receiver.method(41);"
12470 " if (i == 50) {"
12471 " saved_result = result;"
12472 " o.method = function(x) { return x - 1 };"
12473 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012474 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012475 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12476 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12477 CHECK_GE(interceptor_call_count, 50);
12478}
12479
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012480
12481THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
Steve Block6ded16b2010-05-10 14:33:55 +010012482 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012483 v8::Isolate* isolate = CcTest::isolate();
12484 v8::HandleScope scope(isolate);
12485 v8::Handle<v8::FunctionTemplate> fun_templ =
12486 v8::FunctionTemplate::New(isolate);
12487 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12488 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12489 v8::Signature::New(isolate, fun_templ));
Steve Block6ded16b2010-05-10 14:33:55 +010012490 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12491 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012492 fun_templ->SetHiddenPrototype(true);
Steve Block6ded16b2010-05-10 14:33:55 +010012493 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012494 templ->SetNamedPropertyHandler(
12495 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12496 v8::External::New(isolate, &interceptor_call_count));
Steve Block6ded16b2010-05-10 14:33:55 +010012497 LocalContext context;
12498 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12499 GenerateSomeGarbage();
12500 context->Global()->Set(v8_str("o"), fun->NewInstance());
12501 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012502 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +010012503 "o.foo = 17;"
12504 "var receiver = {};"
12505 "receiver.__proto__ = o;"
12506 "var result = 0;"
12507 "var saved_result = 0;"
12508 "for (var i = 0; i < 100; i++) {"
12509 " result = receiver.method(41);"
12510 " if (i == 50) {"
12511 " saved_result = result;"
12512 " receiver = 333;"
12513 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012514 "}");
Steve Block6ded16b2010-05-10 14:33:55 +010012515 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012516 // TODO(verwaest): Adjust message.
12517 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
Steve Block6ded16b2010-05-10 14:33:55 +010012518 try_catch.Exception()->ToString());
12519 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12520 CHECK_GE(interceptor_call_count, 50);
12521}
12522
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012523
12524THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012525 int interceptor_call_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012526 v8::Isolate* isolate = CcTest::isolate();
12527 v8::HandleScope scope(isolate);
12528 v8::Handle<v8::FunctionTemplate> fun_templ =
12529 v8::FunctionTemplate::New(isolate);
12530 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12531 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12532 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012533 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12534 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012535 fun_templ->SetHiddenPrototype(true);
Andrei Popescu402d9372010-02-26 13:31:12 +000012536 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012537 templ->SetNamedPropertyHandler(
12538 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12539 v8::External::New(isolate, &interceptor_call_count));
Andrei Popescu402d9372010-02-26 13:31:12 +000012540 LocalContext context;
12541 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12542 GenerateSomeGarbage();
12543 context->Global()->Set(v8_str("o"), fun->NewInstance());
12544 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012545 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012546 "o.foo = 17;"
12547 "var receiver = {};"
12548 "receiver.__proto__ = o;"
12549 "var result = 0;"
12550 "var saved_result = 0;"
12551 "for (var i = 0; i < 100; i++) {"
12552 " result = receiver.method(41);"
12553 " if (i == 50) {"
12554 " saved_result = result;"
12555 " receiver = {method: receiver.method};"
12556 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012557 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012558 CHECK(try_catch.HasCaught());
12559 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12560 try_catch.Exception()->ToString());
12561 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12562 CHECK_GE(interceptor_call_count, 50);
12563}
12564
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012565
12566THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12567 v8::Isolate* isolate = CcTest::isolate();
12568 v8::HandleScope scope(isolate);
12569 v8::Handle<v8::FunctionTemplate> fun_templ =
12570 v8::FunctionTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000012571 v8::Handle<v8::FunctionTemplate> method_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012572 v8::FunctionTemplate::New(isolate,
12573 FastApiCallback_TrivialSignature,
Andrei Popescu402d9372010-02-26 13:31:12 +000012574 v8_str("method_data"),
12575 v8::Handle<v8::Signature>());
12576 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12577 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012578 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12579 USE(templ);
Andrei Popescu402d9372010-02-26 13:31:12 +000012580 LocalContext context;
12581 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12582 GenerateSomeGarbage();
12583 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012584 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012585 "var result = 0;"
12586 "for (var i = 0; i < 100; i++) {"
12587 " result = o.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012588 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012589
12590 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12591}
12592
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012593
12594THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12595 v8::Isolate* isolate = CcTest::isolate();
12596 v8::HandleScope scope(isolate);
12597 v8::Handle<v8::FunctionTemplate> fun_templ =
12598 v8::FunctionTemplate::New(isolate);
12599 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12600 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12601 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012602 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12603 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012604 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012605 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12606 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +000012607 LocalContext context;
12608 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12609 GenerateSomeGarbage();
12610 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012611 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012612 "o.foo = 17;"
12613 "var receiver = {};"
12614 "receiver.__proto__ = o;"
12615 "var result = 0;"
12616 "for (var i = 0; i < 100; i++) {"
12617 " result = receiver.method(41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012618 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012619
12620 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12621}
12622
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012623
12624THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12625 v8::Isolate* isolate = CcTest::isolate();
12626 v8::HandleScope scope(isolate);
12627 v8::Handle<v8::FunctionTemplate> fun_templ =
12628 v8::FunctionTemplate::New(isolate);
12629 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12630 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12631 v8::Signature::New(isolate, fun_templ));
Andrei Popescu402d9372010-02-26 13:31:12 +000012632 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12633 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012634 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012635 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12636 CHECK(!templ.IsEmpty());
Andrei Popescu402d9372010-02-26 13:31:12 +000012637 LocalContext context;
12638 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12639 GenerateSomeGarbage();
12640 context->Global()->Set(v8_str("o"), fun->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012641 CompileRun(
Andrei Popescu402d9372010-02-26 13:31:12 +000012642 "o.foo = 17;"
12643 "var receiver = {};"
12644 "receiver.__proto__ = o;"
12645 "var result = 0;"
12646 "var saved_result = 0;"
12647 "for (var i = 0; i < 100; i++) {"
12648 " result = receiver.method(41);"
12649 " if (i == 50) {"
12650 " saved_result = result;"
12651 " receiver = {method: function(x) { return x - 1 }};"
12652 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012653 "}");
Andrei Popescu402d9372010-02-26 13:31:12 +000012654 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12655 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12656}
12657
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012658
12659THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12660 v8::Isolate* isolate = CcTest::isolate();
12661 v8::HandleScope scope(isolate);
12662 v8::Handle<v8::FunctionTemplate> fun_templ =
12663 v8::FunctionTemplate::New(isolate);
12664 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12665 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12666 v8::Signature::New(isolate, fun_templ));
Steve Block6ded16b2010-05-10 14:33:55 +010012667 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12668 proto_templ->Set(v8_str("method"), method_templ);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012669 fun_templ->SetHiddenPrototype(true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012670 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12671 CHECK(!templ.IsEmpty());
Steve Block6ded16b2010-05-10 14:33:55 +010012672 LocalContext context;
12673 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12674 GenerateSomeGarbage();
12675 context->Global()->Set(v8_str("o"), fun->NewInstance());
12676 v8::TryCatch try_catch;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012677 CompileRun(
Steve Block6ded16b2010-05-10 14:33:55 +010012678 "o.foo = 17;"
12679 "var receiver = {};"
12680 "receiver.__proto__ = o;"
12681 "var result = 0;"
12682 "var saved_result = 0;"
12683 "for (var i = 0; i < 100; i++) {"
12684 " result = receiver.method(41);"
12685 " if (i == 50) {"
12686 " saved_result = result;"
12687 " receiver = 333;"
12688 " }"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012689 "}");
Steve Block6ded16b2010-05-10 14:33:55 +010012690 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012691 // TODO(verwaest): Adjust message.
12692 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12693 try_catch.Exception()->ToString());
12694 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12695}
12696
12697
12698THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12699 v8::Isolate* isolate = CcTest::isolate();
12700 v8::HandleScope scope(isolate);
12701 v8::Handle<v8::FunctionTemplate> fun_templ =
12702 v8::FunctionTemplate::New(isolate);
12703 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12704 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12705 v8::Signature::New(isolate, fun_templ));
12706 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12707 proto_templ->Set(v8_str("method"), method_templ);
12708 fun_templ->SetHiddenPrototype(true);
12709 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12710 CHECK(!templ.IsEmpty());
12711 LocalContext context;
12712 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12713 GenerateSomeGarbage();
12714 context->Global()->Set(v8_str("o"), fun->NewInstance());
12715 v8::TryCatch try_catch;
12716 CompileRun(
12717 "o.foo = 17;"
12718 "var receiver = {};"
12719 "receiver.__proto__ = o;"
12720 "var result = 0;"
12721 "var saved_result = 0;"
12722 "for (var i = 0; i < 100; i++) {"
12723 " result = receiver.method(41);"
12724 " if (i == 50) {"
12725 " saved_result = result;"
12726 " receiver = Object.create(receiver);"
12727 " }"
12728 "}");
12729 CHECK(try_catch.HasCaught());
12730 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
Steve Block6ded16b2010-05-10 14:33:55 +010012731 try_catch.Exception()->ToString());
12732 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12733}
12734
Leon Clarke4515c472010-02-03 11:58:03 +000012735
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012736v8::Handle<Value> keyed_call_ic_function;
12737
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012738static void InterceptorKeyedCallICGetter(
12739 Local<String> name,
12740 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012741 ApiTestFuzzer::Fuzz();
12742 if (v8_str("x")->Equals(name)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012743 info.GetReturnValue().Set(keyed_call_ic_function);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012744 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012745}
12746
12747
12748// Test the case when we stored cacheable lookup into
12749// a stub, but the function name changed (to another cacheable function).
12750THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012751 v8::Isolate* isolate = CcTest::isolate();
12752 v8::HandleScope scope(isolate);
12753 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012754 templ->SetNamedPropertyHandler(NoBlockGetterX);
12755 LocalContext context;
12756 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012757 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012758 "proto = new Object();"
12759 "proto.y = function(x) { return x + 1; };"
12760 "proto.z = function(x) { return x - 1; };"
12761 "o.__proto__ = proto;"
12762 "var result = 0;"
12763 "var method = 'y';"
12764 "for (var i = 0; i < 10; i++) {"
12765 " if (i == 5) { method = 'z'; };"
12766 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012767 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012768 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12769}
12770
12771
12772// Test the case when we stored cacheable lookup into
12773// a stub, but the function name changed (and the new function is present
12774// both before and after the interceptor in the prototype chain).
12775THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012776 v8::Isolate* isolate = CcTest::isolate();
12777 v8::HandleScope scope(isolate);
12778 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012779 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12780 LocalContext context;
12781 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12782 keyed_call_ic_function =
12783 v8_compile("function f(x) { return x - 1; }; f")->Run();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012784 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012785 "o = new Object();"
12786 "proto2 = new Object();"
12787 "o.y = function(x) { return x + 1; };"
12788 "proto2.y = function(x) { return x + 2; };"
12789 "o.__proto__ = proto1;"
12790 "proto1.__proto__ = proto2;"
12791 "var result = 0;"
12792 "var method = 'x';"
12793 "for (var i = 0; i < 10; i++) {"
12794 " if (i == 5) { method = 'y'; };"
12795 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012796 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012797 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12798}
12799
12800
12801// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12802// on the global object.
12803THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012804 v8::Isolate* isolate = CcTest::isolate();
12805 v8::HandleScope scope(isolate);
12806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012807 templ->SetNamedPropertyHandler(NoBlockGetterX);
12808 LocalContext context;
12809 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012810 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012811 "function inc(x) { return x + 1; };"
12812 "inc(1);"
12813 "function dec(x) { return x - 1; };"
12814 "dec(1);"
12815 "o.__proto__ = this;"
12816 "this.__proto__.x = inc;"
12817 "this.__proto__.y = dec;"
12818 "var result = 0;"
12819 "var method = 'x';"
12820 "for (var i = 0; i < 10; i++) {"
12821 " if (i == 5) { method = 'y'; };"
12822 " result += o[method](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012823 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012824 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12825}
12826
12827
12828// Test the case when actual function to call sits on global object.
12829THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012830 v8::Isolate* isolate = CcTest::isolate();
12831 v8::HandleScope scope(isolate);
12832 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012833 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12834 LocalContext context;
12835 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12836
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012837 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012838 "function len(x) { return x.length; };"
12839 "o.__proto__ = this;"
12840 "var m = 'parseFloat';"
12841 "var result = 0;"
12842 "for (var i = 0; i < 10; i++) {"
12843 " if (i == 5) {"
12844 " m = 'len';"
12845 " saved_result = result;"
12846 " };"
12847 " result = o[m]('239');"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012848 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012849 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12850 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12851}
12852
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012853
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012854// Test the map transition before the interceptor.
12855THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012856 v8::Isolate* isolate = CcTest::isolate();
12857 v8::HandleScope scope(isolate);
12858 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012859 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12860 LocalContext context;
12861 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12862
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012863 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012864 "var o = new Object();"
12865 "o.__proto__ = proto;"
12866 "o.method = function(x) { return x + 1; };"
12867 "var m = 'method';"
12868 "var result = 0;"
12869 "for (var i = 0; i < 10; i++) {"
12870 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12871 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012872 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012873 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12874}
12875
12876
12877// Test the map transition after the interceptor.
12878THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012879 v8::Isolate* isolate = CcTest::isolate();
12880 v8::HandleScope scope(isolate);
12881 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012882 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12883 LocalContext context;
12884 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12885
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012886 CompileRun(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012887 "var proto = new Object();"
12888 "o.__proto__ = proto;"
12889 "proto.method = function(x) { return x + 1; };"
12890 "var m = 'method';"
12891 "var result = 0;"
12892 "for (var i = 0; i < 10; i++) {"
12893 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12894 " result += o[m](41);"
Ben Murdochc7cc0282012-03-05 14:35:55 +000012895 "}");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010012896 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12897}
12898
12899
Steve Blocka7e24c12009-10-30 11:49:00 +000012900static int interceptor_call_count = 0;
12901
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012902static void InterceptorICRefErrorGetter(
12903 Local<String> name,
12904 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012905 ApiTestFuzzer::Fuzz();
12906 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012907 info.GetReturnValue().Set(call_ic_function2);
Steve Blocka7e24c12009-10-30 11:49:00 +000012908 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012909}
12910
12911
12912// This test should hit load and call ICs for the interceptor case.
12913// Once in a while, the interceptor will reply that a property was not
12914// found in which case we should get a reference error.
12915THREADED_TEST(InterceptorICReferenceErrors) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012916 v8::Isolate* isolate = CcTest::isolate();
12917 v8::HandleScope scope(isolate);
12918 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012919 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12920 LocalContext context(0, templ, v8::Handle<Value>());
12921 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12922 v8::Handle<Value> value = CompileRun(
12923 "function f() {"
12924 " for (var i = 0; i < 1000; i++) {"
12925 " try { x; } catch(e) { return true; }"
12926 " }"
12927 " return false;"
12928 "};"
12929 "f();");
12930 CHECK_EQ(true, value->BooleanValue());
12931 interceptor_call_count = 0;
12932 value = CompileRun(
12933 "function g() {"
12934 " for (var i = 0; i < 1000; i++) {"
12935 " try { x(42); } catch(e) { return true; }"
12936 " }"
12937 " return false;"
12938 "};"
12939 "g();");
12940 CHECK_EQ(true, value->BooleanValue());
12941}
12942
12943
12944static int interceptor_ic_exception_get_count = 0;
12945
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012946static void InterceptorICExceptionGetter(
Steve Blocka7e24c12009-10-30 11:49:00 +000012947 Local<String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012948 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012949 ApiTestFuzzer::Fuzz();
12950 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012951 info.GetReturnValue().Set(call_ic_function3);
Steve Blocka7e24c12009-10-30 11:49:00 +000012952 }
12953 if (interceptor_ic_exception_get_count == 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012954 info.GetIsolate()->ThrowException(v8_num(42));
12955 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000012956 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012957}
12958
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012959
Steve Blocka7e24c12009-10-30 11:49:00 +000012960// Test interceptor load/call IC where the interceptor throws an
12961// exception once in a while.
12962THREADED_TEST(InterceptorICGetterExceptions) {
12963 interceptor_ic_exception_get_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012964 v8::Isolate* isolate = CcTest::isolate();
12965 v8::HandleScope scope(isolate);
12966 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012967 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12968 LocalContext context(0, templ, v8::Handle<Value>());
12969 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12970 v8::Handle<Value> value = CompileRun(
12971 "function f() {"
12972 " for (var i = 0; i < 100; i++) {"
12973 " try { x; } catch(e) { return true; }"
12974 " }"
12975 " return false;"
12976 "};"
12977 "f();");
12978 CHECK_EQ(true, value->BooleanValue());
12979 interceptor_ic_exception_get_count = 0;
12980 value = CompileRun(
12981 "function f() {"
12982 " for (var i = 0; i < 100; i++) {"
12983 " try { x(42); } catch(e) { return true; }"
12984 " }"
12985 " return false;"
12986 "};"
12987 "f();");
12988 CHECK_EQ(true, value->BooleanValue());
12989}
12990
12991
12992static int interceptor_ic_exception_set_count = 0;
12993
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012994static void InterceptorICExceptionSetter(
12995 Local<String> key,
12996 Local<Value> value,
12997 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012998 ApiTestFuzzer::Fuzz();
12999 if (++interceptor_ic_exception_set_count > 20) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013000 info.GetIsolate()->ThrowException(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013001 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013002}
13003
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013004
Steve Blocka7e24c12009-10-30 11:49:00 +000013005// Test interceptor store IC where the interceptor throws an exception
13006// once in a while.
13007THREADED_TEST(InterceptorICSetterExceptions) {
13008 interceptor_ic_exception_set_count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013009 v8::Isolate* isolate = CcTest::isolate();
13010 v8::HandleScope scope(isolate);
13011 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013012 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13013 LocalContext context(0, templ, v8::Handle<Value>());
13014 v8::Handle<Value> value = CompileRun(
13015 "function f() {"
13016 " for (var i = 0; i < 100; i++) {"
13017 " try { x = 42; } catch(e) { return true; }"
13018 " }"
13019 " return false;"
13020 "};"
13021 "f();");
13022 CHECK_EQ(true, value->BooleanValue());
13023}
13024
13025
13026// Test that we ignore null interceptors.
13027THREADED_TEST(NullNamedInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013028 v8::Isolate* isolate = CcTest::isolate();
13029 v8::HandleScope scope(isolate);
13030 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13031 templ->SetNamedPropertyHandler(
13032 static_cast<v8::NamedPropertyGetterCallback>(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000013033 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013034 templ->Set(CcTest::isolate(), "x", v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013035 v8::Handle<v8::Object> obj = templ->NewInstance();
13036 context->Global()->Set(v8_str("obj"), obj);
13037 v8::Handle<Value> value = CompileRun("obj.x");
13038 CHECK(value->IsInt32());
13039 CHECK_EQ(42, value->Int32Value());
13040}
13041
13042
13043// Test that we ignore null interceptors.
13044THREADED_TEST(NullIndexedInterceptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013045 v8::Isolate* isolate = CcTest::isolate();
13046 v8::HandleScope scope(isolate);
13047 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13048 templ->SetIndexedPropertyHandler(
13049 static_cast<v8::IndexedPropertyGetterCallback>(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000013050 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013051 templ->Set(CcTest::isolate(), "42", v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013052 v8::Handle<v8::Object> obj = templ->NewInstance();
13053 context->Global()->Set(v8_str("obj"), obj);
13054 v8::Handle<Value> value = CompileRun("obj[42]");
13055 CHECK(value->IsInt32());
13056 CHECK_EQ(42, value->Int32Value());
13057}
13058
13059
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013060THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013061 v8::Isolate* isolate = CcTest::isolate();
13062 v8::HandleScope scope(isolate);
13063 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010013064 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13065 LocalContext env;
13066 env->Global()->Set(v8_str("obj"),
13067 templ->GetFunction()->NewInstance());
13068 ExpectTrue("obj.x === 42");
13069 ExpectTrue("!obj.propertyIsEnumerable('x')");
13070}
13071
13072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013073static void ThrowingGetter(Local<String> name,
13074 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013075 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013076 info.GetIsolate()->ThrowException(Handle<Value>());
13077 info.GetReturnValue().SetUndefined();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013078}
13079
13080
13081THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013082 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013083 HandleScope scope(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013084
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013085 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013086 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13087 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13088
13089 Local<Object> instance = templ->GetFunction()->NewInstance();
13090
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013091 Local<Object> another = Object::New(context->GetIsolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013092 another->SetPrototype(instance);
13093
13094 Local<Object> with_js_getter = CompileRun(
13095 "o = {};\n"
13096 "o.__defineGetter__('f', function() { throw undefined; });\n"
13097 "o\n").As<Object>();
13098 CHECK(!with_js_getter.IsEmpty());
13099
13100 TryCatch try_catch;
13101
13102 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13103 CHECK(try_catch.HasCaught());
13104 try_catch.Reset();
13105 CHECK(result.IsEmpty());
13106
13107 result = another->GetRealNamedProperty(v8_str("f"));
13108 CHECK(try_catch.HasCaught());
13109 try_catch.Reset();
13110 CHECK(result.IsEmpty());
13111
13112 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13113 CHECK(try_catch.HasCaught());
13114 try_catch.Reset();
13115 CHECK(result.IsEmpty());
13116
13117 result = another->Get(v8_str("f"));
13118 CHECK(try_catch.HasCaught());
13119 try_catch.Reset();
13120 CHECK(result.IsEmpty());
13121
13122 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13123 CHECK(try_catch.HasCaught());
13124 try_catch.Reset();
13125 CHECK(result.IsEmpty());
13126
13127 result = with_js_getter->Get(v8_str("f"));
13128 CHECK(try_catch.HasCaught());
13129 try_catch.Reset();
13130 CHECK(result.IsEmpty());
13131}
13132
13133
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013134static void ThrowingCallbackWithTryCatch(
13135 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013136 TryCatch try_catch;
13137 // Verboseness is important: it triggers message delivery which can call into
13138 // external code.
13139 try_catch.SetVerbose(true);
13140 CompileRun("throw 'from JS';");
13141 CHECK(try_catch.HasCaught());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013142 CHECK(!CcTest::i_isolate()->has_pending_exception());
13143 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
Ben Murdoch8b112d22011-06-08 16:22:53 +010013144}
13145
13146
13147static int call_depth;
13148
13149
13150static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13151 TryCatch try_catch;
13152}
13153
13154
13155static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13156 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13157}
13158
13159
13160static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013161 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
Ben Murdoch8b112d22011-06-08 16:22:53 +010013162}
13163
13164
13165static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13166 Handle<String> errorMessageString = message->Get();
13167 CHECK(!errorMessageString.IsEmpty());
13168 message->GetStackTrace();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013169 message->GetScriptOrigin().ResourceName();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013170}
13171
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013172
Ben Murdoch8b112d22011-06-08 16:22:53 +010013173THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010013174 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013175 v8::Isolate* isolate = context->GetIsolate();
13176 HandleScope scope(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010013177
13178 Local<Function> func =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013179 FunctionTemplate::New(isolate,
13180 ThrowingCallbackWithTryCatch)->GetFunction();
Ben Murdoch8b112d22011-06-08 16:22:53 +010013181 context->Global()->Set(v8_str("func"), func);
13182
13183 MessageCallback callbacks[] =
13184 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13185 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13186 MessageCallback callback = callbacks[i];
13187 if (callback != NULL) {
13188 V8::AddMessageListener(callback);
13189 }
Ben Murdoch257744e2011-11-30 15:57:28 +000013190 // Some small number to control number of times message handler should
13191 // throw an exception.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013192 call_depth = 5;
13193 ExpectFalse(
13194 "var thrown = false;\n"
13195 "try { func(); } catch(e) { thrown = true; }\n"
13196 "thrown\n");
13197 if (callback != NULL) {
13198 V8::RemoveMessageListeners(callback);
13199 }
13200 }
13201}
13202
13203
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013204static void ParentGetter(Local<String> name,
13205 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013206 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013207 info.GetReturnValue().Set(v8_num(1));
Steve Blocka7e24c12009-10-30 11:49:00 +000013208}
13209
13210
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013211static void ChildGetter(Local<String> name,
13212 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013213 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013214 info.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000013215}
13216
13217
13218THREADED_TEST(Overriding) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013219 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013220 v8::Isolate* isolate = context->GetIsolate();
13221 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013222
13223 // Parent template.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013224 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013225 Local<ObjectTemplate> parent_instance_templ =
13226 parent_templ->InstanceTemplate();
13227 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13228
13229 // Template that inherits from the parent template.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013230 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013231 Local<ObjectTemplate> child_instance_templ =
13232 child_templ->InstanceTemplate();
13233 child_templ->Inherit(parent_templ);
13234 // Override 'f'. The child version of 'f' should get called for child
13235 // instances.
13236 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13237 // Add 'g' twice. The 'g' added last should get called for instances.
13238 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13239 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13240
13241 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13242 // so 'h' can be shadowed on the instance object.
13243 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13244 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13245 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13246
13247 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13248 // but the attribute does not have effect because it is duplicated with
13249 // NULL setter.
13250 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13251 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13252
13253
13254
13255 // Instantiate the child template.
13256 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13257
13258 // Check that the child function overrides the parent one.
13259 context->Global()->Set(v8_str("o"), instance);
13260 Local<Value> value = v8_compile("o.f")->Run();
13261 // Check that the 'g' that was added last is hit.
13262 CHECK_EQ(42, value->Int32Value());
13263 value = v8_compile("o.g")->Run();
13264 CHECK_EQ(42, value->Int32Value());
13265
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013266 // Check that 'h' cannot be shadowed.
Steve Blocka7e24c12009-10-30 11:49:00 +000013267 value = v8_compile("o.h = 3; o.h")->Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013268 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000013269
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013270 // Check that 'i' cannot be shadowed or changed.
Steve Blocka7e24c12009-10-30 11:49:00 +000013271 value = v8_compile("o.i = 3; o.i")->Run();
13272 CHECK_EQ(42, value->Int32Value());
13273}
13274
13275
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013276static void IsConstructHandler(
13277 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013278 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013279 args.GetReturnValue().Set(args.IsConstructCall());
Steve Blocka7e24c12009-10-30 11:49:00 +000013280}
13281
13282
13283THREADED_TEST(IsConstructCall) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013284 v8::Isolate* isolate = CcTest::isolate();
13285 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013286
13287 // Function template with call handler.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013288 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013289 templ->SetCallHandler(IsConstructHandler);
13290
13291 LocalContext context;
13292
13293 context->Global()->Set(v8_str("f"), templ->GetFunction());
13294 Local<Value> value = v8_compile("f()")->Run();
13295 CHECK(!value->BooleanValue());
13296 value = v8_compile("new f()")->Run();
13297 CHECK(value->BooleanValue());
13298}
13299
13300
13301THREADED_TEST(ObjectProtoToString) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013302 v8::Isolate* isolate = CcTest::isolate();
13303 v8::HandleScope scope(isolate);
13304 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013305 templ->SetClassName(v8_str("MyClass"));
13306
13307 LocalContext context;
13308
13309 Local<String> customized_tostring = v8_str("customized toString");
13310
13311 // Replace Object.prototype.toString
13312 v8_compile("Object.prototype.toString = function() {"
13313 " return 'customized toString';"
13314 "}")->Run();
13315
13316 // Normal ToString call should call replaced Object.prototype.toString
13317 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13318 Local<String> value = instance->ToString();
13319 CHECK(value->IsString() && value->Equals(customized_tostring));
13320
13321 // ObjectProtoToString should not call replace toString function.
13322 value = instance->ObjectProtoToString();
13323 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13324
13325 // Check global
13326 value = context->Global()->ObjectProtoToString();
13327 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13328
13329 // Check ordinary object
13330 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +010013331 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +000013332 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13333}
13334
13335
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080013336THREADED_TEST(ObjectGetConstructorName) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080013337 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013338 v8::HandleScope scope(context->GetIsolate());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080013339 v8_compile("function Parent() {};"
13340 "function Child() {};"
13341 "Child.prototype = new Parent();"
13342 "var outer = { inner: function() { } };"
13343 "var p = new Parent();"
13344 "var c = new Child();"
13345 "var x = new outer.inner();")->Run();
13346
13347 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13348 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13349 v8_str("Parent")));
13350
13351 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13352 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13353 v8_str("Child")));
13354
13355 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13356 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13357 v8_str("outer.inner")));
13358}
13359
13360
Steve Blocka7e24c12009-10-30 11:49:00 +000013361bool ApiTestFuzzer::fuzzing_ = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013362v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000013363int ApiTestFuzzer::active_tests_;
13364int ApiTestFuzzer::tests_being_run_;
13365int ApiTestFuzzer::current_;
13366
13367
13368// We are in a callback and want to switch to another thread (if we
13369// are currently running the thread fuzzing test).
13370void ApiTestFuzzer::Fuzz() {
13371 if (!fuzzing_) return;
13372 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13373 test->ContextSwitch();
13374}
13375
13376
13377// Let the next thread go. Since it is also waiting on the V8 lock it may
13378// not start immediately.
13379bool ApiTestFuzzer::NextThread() {
13380 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +000013381 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000013382 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +000013383 if (kLogThreading)
13384 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000013385 return false;
13386 }
Steve Blockd0582a62009-12-15 09:54:21 +000013387 if (kLogThreading) {
13388 printf("Switch from %s to %s\n",
13389 test_name,
13390 RegisterThreadedTest::nth(test_position)->name());
13391 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013392 current_ = test_position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013393 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +000013394 return true;
13395}
13396
13397
13398void ApiTestFuzzer::Run() {
13399 // When it is our turn...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013400 gate_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000013401 {
13402 // ... get the V8 lock and start running the test.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013403 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013404 CallTest();
13405 }
13406 // This test finished.
13407 active_ = false;
13408 active_tests_--;
13409 // If it was the last then signal that fact.
13410 if (active_tests_ == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013411 all_tests_done_.Signal();
Steve Blocka7e24c12009-10-30 11:49:00 +000013412 } else {
13413 // Otherwise select a new test and start that.
13414 NextThread();
13415 }
13416}
13417
13418
13419static unsigned linear_congruential_generator;
13420
13421
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013422void ApiTestFuzzer::SetUp(PartOfTest part) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013423 linear_congruential_generator = i::FLAG_testing_prng_seed;
13424 fuzzing_ = true;
Ben Murdoch257744e2011-11-30 15:57:28 +000013425 int count = RegisterThreadedTest::count();
13426 int start = count * part / (LAST_PART + 1);
13427 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13428 active_tests_ = tests_being_run_ = end - start + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +000013429 for (int i = 0; i < tests_being_run_; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013430 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
Steve Blocka7e24c12009-10-30 11:49:00 +000013431 }
13432 for (int i = 0; i < active_tests_; i++) {
13433 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13434 }
13435}
13436
13437
13438static void CallTestNumber(int test_number) {
13439 (RegisterThreadedTest::nth(test_number)->callback())();
13440}
13441
13442
13443void ApiTestFuzzer::RunAllTests() {
13444 // Set off the first test.
13445 current_ = -1;
13446 NextThread();
13447 // Wait till they are all done.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013448 all_tests_done_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000013449}
13450
13451
13452int ApiTestFuzzer::GetNextTestNumber() {
13453 int next_test;
13454 do {
13455 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13456 linear_congruential_generator *= 1664525u;
13457 linear_congruential_generator += 1013904223u;
13458 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13459 return next_test;
13460}
13461
13462
13463void ApiTestFuzzer::ContextSwitch() {
13464 // If the new thread is the same as the current thread there is nothing to do.
13465 if (NextThread()) {
13466 // Now it can start.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013467 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013468 // Wait till someone starts us again.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013469 gate_.Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +000013470 // And we're off.
13471 }
13472}
13473
13474
13475void ApiTestFuzzer::TearDown() {
13476 fuzzing_ = false;
13477 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13478 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13479 if (fuzzer != NULL) fuzzer->Join();
13480 }
13481}
13482
13483
13484// Lets not be needlessly self-referential.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013485TEST(Threading1) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013486 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000013487 ApiTestFuzzer::RunAllTests();
13488 ApiTestFuzzer::TearDown();
13489}
13490
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013491
Steve Blocka7e24c12009-10-30 11:49:00 +000013492TEST(Threading2) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013493 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
Steve Blocka7e24c12009-10-30 11:49:00 +000013494 ApiTestFuzzer::RunAllTests();
13495 ApiTestFuzzer::TearDown();
13496}
13497
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013498
Ben Murdoch257744e2011-11-30 15:57:28 +000013499TEST(Threading3) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013500 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000013501 ApiTestFuzzer::RunAllTests();
13502 ApiTestFuzzer::TearDown();
13503}
13504
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013505
Ben Murdoch257744e2011-11-30 15:57:28 +000013506TEST(Threading4) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013507 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
Ben Murdoch257744e2011-11-30 15:57:28 +000013508 ApiTestFuzzer::RunAllTests();
13509 ApiTestFuzzer::TearDown();
13510}
Steve Blocka7e24c12009-10-30 11:49:00 +000013511
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013512
Steve Blocka7e24c12009-10-30 11:49:00 +000013513void ApiTestFuzzer::CallTest() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013514 v8::Isolate::Scope scope(CcTest::isolate());
Steve Blockd0582a62009-12-15 09:54:21 +000013515 if (kLogThreading)
13516 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000013517 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +000013518 if (kLogThreading)
13519 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +000013520}
13521
13522
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013523static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13524 v8::Isolate* isolate = args.GetIsolate();
13525 CHECK(v8::Locker::IsLocked(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000013526 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013527 v8::Unlocker unlocker(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013528 const char* code = "throw 7;";
13529 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013530 v8::Locker nested_locker(isolate);
13531 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013532 v8::Handle<Value> exception;
13533 { v8::TryCatch try_catch;
13534 v8::Handle<Value> value = CompileRun(code);
13535 CHECK(value.IsEmpty());
13536 CHECK(try_catch.HasCaught());
13537 // Make sure to wrap the exception in a new handle because
13538 // the handle returned from the TryCatch is destroyed
13539 // when the TryCatch is destroyed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013540 exception = Local<Value>::New(isolate, try_catch.Exception());
Steve Blocka7e24c12009-10-30 11:49:00 +000013541 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013542 args.GetIsolate()->ThrowException(exception);
Steve Blocka7e24c12009-10-30 11:49:00 +000013543 }
13544}
13545
13546
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013547static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13548 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013549 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013550 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013551 const char* code = "throw 7;";
13552 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013553 v8::Locker nested_locker(CcTest::isolate());
13554 v8::HandleScope scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013555 v8::Handle<Value> value = CompileRun(code);
13556 CHECK(value.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013557 args.GetReturnValue().Set(v8_str("foo"));
Steve Blocka7e24c12009-10-30 11:49:00 +000013558 }
13559}
13560
13561
13562// These are locking tests that don't need to be run again
13563// as part of the locking aggregation tests.
13564TEST(NestedLockers) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013565 v8::Isolate* isolate = CcTest::isolate();
13566 v8::Locker locker(isolate);
13567 CHECK(v8::Locker::IsLocked(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000013568 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013569 v8::HandleScope scope(env->GetIsolate());
13570 Local<v8::FunctionTemplate> fun_templ =
13571 v8::FunctionTemplate::New(isolate, ThrowInJS);
Steve Blocka7e24c12009-10-30 11:49:00 +000013572 Local<Function> fun = fun_templ->GetFunction();
13573 env->Global()->Set(v8_str("throw_in_js"), fun);
13574 Local<Script> script = v8_compile("(function () {"
13575 " try {"
13576 " throw_in_js();"
13577 " return 42;"
13578 " } catch (e) {"
13579 " return e * 13;"
13580 " }"
13581 "})();");
13582 CHECK_EQ(91, script->Run()->Int32Value());
13583}
13584
13585
13586// These are locking tests that don't need to be run again
13587// as part of the locking aggregation tests.
13588TEST(NestedLockersNoTryCatch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013589 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013590 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013591 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013592 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013593 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
Steve Blocka7e24c12009-10-30 11:49:00 +000013594 Local<Function> fun = fun_templ->GetFunction();
13595 env->Global()->Set(v8_str("throw_in_js"), fun);
13596 Local<Script> script = v8_compile("(function () {"
13597 " try {"
13598 " throw_in_js();"
13599 " return 42;"
13600 " } catch (e) {"
13601 " return e * 13;"
13602 " }"
13603 "})();");
13604 CHECK_EQ(91, script->Run()->Int32Value());
13605}
13606
13607
13608THREADED_TEST(RecursiveLocking) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013609 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013610 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013611 v8::Locker locker2(CcTest::isolate());
13612 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013613 }
13614}
13615
13616
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013617static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013618 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013619 v8::Unlocker unlocker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013620}
13621
13622
13623THREADED_TEST(LockUnlockLock) {
13624 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013625 v8::Locker locker(CcTest::isolate());
13626 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013627 LocalContext env;
13628 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013629 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
Steve Blocka7e24c12009-10-30 11:49:00 +000013630 Local<Function> fun = fun_templ->GetFunction();
13631 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13632 Local<Script> script = v8_compile("(function () {"
13633 " unlock_for_a_moment();"
13634 " return 42;"
13635 "})();");
13636 CHECK_EQ(42, script->Run()->Int32Value());
13637 }
13638 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013639 v8::Locker locker(CcTest::isolate());
13640 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013641 LocalContext env;
13642 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013643 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
Steve Blocka7e24c12009-10-30 11:49:00 +000013644 Local<Function> fun = fun_templ->GetFunction();
13645 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13646 Local<Script> script = v8_compile("(function () {"
13647 " unlock_for_a_moment();"
13648 " return 42;"
13649 "})();");
13650 CHECK_EQ(42, script->Run()->Int32Value());
13651 }
13652}
13653
13654
Leon Clarked91b9f72010-01-27 17:25:45 +000013655static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +000013656 int count = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013657 i::HeapIterator it(CcTest::heap());
Leon Clarked91b9f72010-01-27 17:25:45 +000013658 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13659 if (object->IsJSGlobalObject()) count++;
13660 return count;
13661}
13662
13663
Ben Murdochf87a2032010-10-22 12:50:53 +010013664static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013665 // We need to collect all garbage twice to be sure that everything
13666 // has been collected. This is because inline caches are cleared in
13667 // the first garbage collection but some of the maps have already
13668 // been marked at that point. Therefore some of the maps are not
13669 // collected until the second garbage collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013670 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13671 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
Leon Clarked91b9f72010-01-27 17:25:45 +000013672 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000013673#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013674 if (count != expected) CcTest::heap()->TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +000013675#endif
Ben Murdochf87a2032010-10-22 12:50:53 +010013676 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +000013677}
13678
13679
13680TEST(DontLeakGlobalObjects) {
13681 // Regression test for issues 1139850 and 1174891.
13682
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013683 i::FLAG_expose_gc = true;
Steve Blocka7e24c12009-10-30 11:49:00 +000013684 v8::V8::Initialize();
13685
Steve Blocka7e24c12009-10-30 11:49:00 +000013686 for (int i = 0; i < 5; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013687 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013688 LocalContext context;
13689 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013690 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010013691 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000013692
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013693 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013694 LocalContext context;
13695 v8_compile("Date")->Run();
13696 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013697 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010013698 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000013699
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013700 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013701 LocalContext context;
13702 v8_compile("/aaa/")->Run();
13703 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013704 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010013705 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000013706
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013707 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013708 const char* extension_list[] = { "v8/gc" };
13709 v8::ExtensionConfiguration extensions(1, extension_list);
13710 LocalContext context(&extensions);
13711 v8_compile("gc();")->Run();
13712 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013713 CcTest::isolate()->ContextDisposedNotification();
Ben Murdochf87a2032010-10-22 12:50:53 +010013714 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +000013715 }
13716}
13717
13718
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013719TEST(CopyablePersistent) {
13720 LocalContext context;
13721 v8::Isolate* isolate = context->GetIsolate();
13722 i::GlobalHandles* globals =
13723 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13724 int initial_handles = globals->global_handles_count();
13725 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13726 CopyableObject;
13727 {
13728 CopyableObject handle1;
13729 {
13730 v8::HandleScope scope(isolate);
13731 handle1.Reset(isolate, v8::Object::New(isolate));
13732 }
13733 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13734 CopyableObject handle2;
13735 handle2 = handle1;
13736 CHECK(handle1 == handle2);
13737 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13738 CopyableObject handle3(handle2);
13739 CHECK(handle1 == handle3);
13740 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13741 }
13742 // Verify autodispose
13743 CHECK_EQ(initial_handles, globals->global_handles_count());
13744}
13745
13746
13747static void WeakApiCallback(
13748 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13749 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13750 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13751 data.GetParameter()->Reset();
13752 delete data.GetParameter();
13753}
13754
13755
13756TEST(WeakCallbackApi) {
13757 LocalContext context;
13758 v8::Isolate* isolate = context->GetIsolate();
13759 i::GlobalHandles* globals =
13760 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13761 int initial_handles = globals->global_handles_count();
13762 {
13763 v8::HandleScope scope(isolate);
13764 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13765 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13766 v8::Persistent<v8::Object>* handle =
13767 new v8::Persistent<v8::Object>(isolate, obj);
13768 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13769 WeakApiCallback);
13770 }
13771 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13772 CollectAllGarbage(i::Heap::kNoGCFlags);
13773 // Verify disposed.
13774 CHECK_EQ(initial_handles, globals->global_handles_count());
13775}
13776
13777
Steve Blocka7e24c12009-10-30 11:49:00 +000013778v8::Persistent<v8::Object> some_object;
13779v8::Persistent<v8::Object> bad_handle;
13780
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013781void NewPersistentHandleCallback(
13782 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13783 v8::HandleScope scope(data.GetIsolate());
13784 bad_handle.Reset(data.GetIsolate(), some_object);
13785 data.GetParameter()->Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +000013786}
13787
13788
13789THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13790 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013791 v8::Isolate* isolate = context->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000013792
13793 v8::Persistent<v8::Object> handle1, handle2;
13794 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013795 v8::HandleScope scope(isolate);
13796 some_object.Reset(isolate, v8::Object::New(isolate));
13797 handle1.Reset(isolate, v8::Object::New(isolate));
13798 handle2.Reset(isolate, v8::Object::New(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000013799 }
13800 // Note: order is implementation dependent alas: currently
13801 // global handle nodes are processed by PostGarbageCollectionProcessing
13802 // in reverse allocation order, so if second allocated handle is deleted,
13803 // weak callback of the first handle would be able to 'reallocate' it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013804 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13805 handle2.Reset();
13806 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blocka7e24c12009-10-30 11:49:00 +000013807}
13808
13809
13810v8::Persistent<v8::Object> to_be_disposed;
13811
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013812void DisposeAndForceGcCallback(
13813 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13814 to_be_disposed.Reset();
13815 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13816 data.GetParameter()->Reset();
Steve Blocka7e24c12009-10-30 11:49:00 +000013817}
13818
13819
13820THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13821 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013822 v8::Isolate* isolate = context->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000013823
13824 v8::Persistent<v8::Object> handle1, handle2;
13825 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013826 v8::HandleScope scope(isolate);
13827 handle1.Reset(isolate, v8::Object::New(isolate));
13828 handle2.Reset(isolate, v8::Object::New(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000013829 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013830 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13831 to_be_disposed.Reset(isolate, handle2);
13832 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blocka7e24c12009-10-30 11:49:00 +000013833}
13834
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013835void DisposingCallback(
13836 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13837 data.GetParameter()->Reset();
Steve Blockd0582a62009-12-15 09:54:21 +000013838}
13839
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013840void HandleCreatingCallback(
13841 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13842 v8::HandleScope scope(data.GetIsolate());
13843 v8::Persistent<v8::Object>(data.GetIsolate(),
13844 v8::Object::New(data.GetIsolate()));
13845 data.GetParameter()->Reset();
Steve Blockd0582a62009-12-15 09:54:21 +000013846}
13847
13848
13849THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13850 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013851 v8::Isolate* isolate = context->GetIsolate();
Steve Blockd0582a62009-12-15 09:54:21 +000013852
13853 v8::Persistent<v8::Object> handle1, handle2, handle3;
13854 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013855 v8::HandleScope scope(isolate);
13856 handle3.Reset(isolate, v8::Object::New(isolate));
13857 handle2.Reset(isolate, v8::Object::New(isolate));
13858 handle1.Reset(isolate, v8::Object::New(isolate));
Steve Blockd0582a62009-12-15 09:54:21 +000013859 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013860 handle2.SetWeak(&handle2, DisposingCallback);
13861 handle3.SetWeak(&handle3, HandleCreatingCallback);
13862 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
Steve Blockd0582a62009-12-15 09:54:21 +000013863}
13864
Steve Blocka7e24c12009-10-30 11:49:00 +000013865
13866THREADED_TEST(CheckForCrossContextObjectLiterals) {
13867 v8::V8::Initialize();
13868
13869 const int nof = 2;
13870 const char* sources[nof] = {
13871 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13872 "Object()"
13873 };
13874
13875 for (int i = 0; i < nof; i++) {
13876 const char* source = sources[i];
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013877 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013878 LocalContext context;
13879 CompileRun(source);
13880 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013881 { v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013882 LocalContext context;
13883 CompileRun(source);
13884 }
13885 }
13886}
13887
13888
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013889static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13890 v8::EscapableHandleScope inner(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000013891 env->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013892 v8::Local<Value> three = v8_num(3);
13893 v8::Local<Value> value = inner.Escape(three);
Steve Blocka7e24c12009-10-30 11:49:00 +000013894 env->Exit();
13895 return value;
13896}
13897
13898
13899THREADED_TEST(NestedHandleScopeAndContexts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013900 v8::Isolate* isolate = CcTest::isolate();
13901 v8::HandleScope outer(isolate);
13902 v8::Local<Context> env = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013903 env->Enter();
13904 v8::Handle<Value> value = NestedScope(env);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013905 v8::Handle<String> str(value->ToString());
13906 CHECK(!str.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000013907 env->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013908}
13909
13910
13911static bool MatchPointers(void* key1, void* key2) {
13912 return key1 == key2;
13913}
13914
13915
13916struct SymbolInfo {
13917 size_t id;
13918 size_t size;
13919 std::string name;
13920};
13921
13922
13923class SetFunctionEntryHookTest {
13924 public:
13925 SetFunctionEntryHookTest() {
13926 CHECK(instance_ == NULL);
13927 instance_ = this;
13928 }
13929 ~SetFunctionEntryHookTest() {
13930 CHECK(instance_ == this);
13931 instance_ = NULL;
13932 }
13933 void Reset() {
13934 symbols_.clear();
13935 symbol_locations_.clear();
13936 invocations_.clear();
13937 }
13938 void RunTest();
13939 void OnJitEvent(const v8::JitCodeEvent* event);
13940 static void JitEvent(const v8::JitCodeEvent* event) {
13941 CHECK(instance_ != NULL);
13942 instance_->OnJitEvent(event);
13943 }
13944
13945 void OnEntryHook(uintptr_t function,
13946 uintptr_t return_addr_location);
13947 static void EntryHook(uintptr_t function,
13948 uintptr_t return_addr_location) {
13949 CHECK(instance_ != NULL);
13950 instance_->OnEntryHook(function, return_addr_location);
13951 }
13952
13953 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13954 CHECK(instance_ != NULL);
13955 args.GetReturnValue().Set(v8_num(42));
13956 }
13957 void RunLoopInNewEnv(v8::Isolate* isolate);
13958
13959 // Records addr as location of symbol.
13960 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13961
13962 // Finds the symbol containing addr
13963 SymbolInfo* FindSymbolForAddr(i::Address addr);
13964 // Returns the number of invocations where the caller name contains
13965 // \p caller_name and the function name contains \p function_name.
13966 int CountInvocations(const char* caller_name,
13967 const char* function_name);
13968
13969 i::Handle<i::JSFunction> foo_func_;
13970 i::Handle<i::JSFunction> bar_func_;
13971
13972 typedef std::map<size_t, SymbolInfo> SymbolMap;
13973 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13974 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13975 SymbolMap symbols_;
13976 SymbolLocationMap symbol_locations_;
13977 InvocationMap invocations_;
13978
13979 static SetFunctionEntryHookTest* instance_;
13980};
13981SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13982
13983
13984// Returns true if addr is in the range [start, start+len).
13985static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13986 if (start <= addr && start + len > addr)
13987 return true;
13988
13989 return false;
13990}
13991
13992void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13993 SymbolInfo* symbol) {
13994 // Insert the symbol at the new location.
13995 SymbolLocationMap::iterator it =
13996 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13997 // Now erase symbols to the left and right that overlap this one.
13998 while (it != symbol_locations_.begin()) {
13999 SymbolLocationMap::iterator left = it;
14000 --left;
14001 if (!Overlaps(left->first, left->second->size, addr))
14002 break;
14003 symbol_locations_.erase(left);
14004 }
14005
14006 // Now erase symbols to the left and right that overlap this one.
14007 while (true) {
14008 SymbolLocationMap::iterator right = it;
14009 ++right;
14010 if (right == symbol_locations_.end())
14011 break;
14012 if (!Overlaps(addr, symbol->size, right->first))
14013 break;
14014 symbol_locations_.erase(right);
14015 }
14016}
14017
14018
14019void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14020 switch (event->type) {
14021 case v8::JitCodeEvent::CODE_ADDED: {
14022 CHECK(event->code_start != NULL);
14023 CHECK_NE(0, static_cast<int>(event->code_len));
14024 CHECK(event->name.str != NULL);
14025 size_t symbol_id = symbols_.size();
14026
14027 // Record the new symbol.
14028 SymbolInfo& info = symbols_[symbol_id];
14029 info.id = symbol_id;
14030 info.size = event->code_len;
14031 info.name.assign(event->name.str, event->name.str + event->name.len);
14032
14033 // And record it's location.
14034 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14035 }
14036 break;
14037
14038 case v8::JitCodeEvent::CODE_MOVED: {
14039 // We would like to never see code move that we haven't seen before,
14040 // but the code creation event does not happen until the line endings
14041 // have been calculated (this is so that we can report the line in the
14042 // script at which the function source is found, see
14043 // Compiler::RecordFunctionCompilation) and the line endings
14044 // calculations can cause a GC, which can move the newly created code
14045 // before its existence can be logged.
14046 SymbolLocationMap::iterator it(
14047 symbol_locations_.find(
14048 reinterpret_cast<i::Address>(event->code_start)));
14049 if (it != symbol_locations_.end()) {
14050 // Found a symbol at this location, move it.
14051 SymbolInfo* info = it->second;
14052 symbol_locations_.erase(it);
14053 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14054 info);
14055 }
14056 }
14057 default:
14058 break;
14059 }
14060}
14061
14062void SetFunctionEntryHookTest::OnEntryHook(
14063 uintptr_t function, uintptr_t return_addr_location) {
14064 // Get the function's code object.
14065 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14066 reinterpret_cast<i::Address>(function));
14067 CHECK(function_code != NULL);
14068
14069 // Then try and look up the caller's code object.
14070 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14071
14072 // Count the invocation.
14073 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14074 SymbolInfo* function_symbol =
14075 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14076 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14077
14078 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14079 // Check that we have a symbol for the "bar" function at the right location.
14080 SymbolLocationMap::iterator it(
14081 symbol_locations_.find(function_code->instruction_start()));
14082 CHECK(it != symbol_locations_.end());
14083 }
14084
14085 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14086 // Check that we have a symbol for "foo" at the right location.
14087 SymbolLocationMap::iterator it(
14088 symbol_locations_.find(function_code->instruction_start()));
14089 CHECK(it != symbol_locations_.end());
14090 }
14091}
14092
14093
14094SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14095 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14096 // Do we have a direct hit on a symbol?
14097 if (it != symbol_locations_.end()) {
14098 if (it->first == addr)
14099 return it->second;
14100 }
14101
14102 // If not a direct hit, it'll have to be the previous symbol.
14103 if (it == symbol_locations_.begin())
14104 return NULL;
14105
14106 --it;
14107 size_t offs = addr - it->first;
14108 if (offs < it->second->size)
14109 return it->second;
14110
14111 return NULL;
14112}
14113
14114
14115int SetFunctionEntryHookTest::CountInvocations(
14116 const char* caller_name, const char* function_name) {
14117 InvocationMap::iterator it(invocations_.begin());
14118 int invocations = 0;
14119 for (; it != invocations_.end(); ++it) {
14120 SymbolInfo* caller = it->first.first;
14121 SymbolInfo* function = it->first.second;
14122
14123 // Filter out non-matching functions.
14124 if (function_name != NULL) {
14125 if (function->name.find(function_name) == std::string::npos)
14126 continue;
14127 }
14128
14129 // Filter out non-matching callers.
14130 if (caller_name != NULL) {
14131 if (caller == NULL)
14132 continue;
14133 if (caller->name.find(caller_name) == std::string::npos)
14134 continue;
14135 }
14136
14137 // It matches add the invocation count to the tally.
14138 invocations += it->second;
14139 }
14140
14141 return invocations;
14142}
14143
14144
14145void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14146 v8::HandleScope outer(isolate);
14147 v8::Local<Context> env = Context::New(isolate);
14148 env->Enter();
14149
14150 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14151 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14152 env->Global()->Set(v8_str("obj"), t->NewInstance());
14153
14154 const char* script =
14155 "function bar() {\n"
14156 " var sum = 0;\n"
14157 " for (i = 0; i < 100; ++i)\n"
14158 " sum = foo(i);\n"
14159 " return sum;\n"
14160 "}\n"
14161 "function foo(i) { return i * i; }\n"
14162 "// Invoke on the runtime function.\n"
14163 "obj.asdf()";
14164 CompileRun(script);
14165 bar_func_ = i::Handle<i::JSFunction>::cast(
14166 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14167 DCHECK(!bar_func_.is_null());
14168
14169 foo_func_ =
14170 i::Handle<i::JSFunction>::cast(
14171 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14172 DCHECK(!foo_func_.is_null());
14173
14174 v8::Handle<v8::Value> value = CompileRun("bar();");
14175 CHECK(value->IsNumber());
14176 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14177
14178 // Test the optimized codegen path.
14179 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14180 "bar();");
14181 CHECK(value->IsNumber());
14182 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14183
14184 env->Exit();
14185}
14186
14187
14188void SetFunctionEntryHookTest::RunTest() {
14189 // Work in a new isolate throughout.
14190 v8::Isolate::CreateParams create_params;
14191 create_params.entry_hook = EntryHook;
14192 create_params.code_event_handler = JitEvent;
14193 v8::Isolate* isolate = v8::Isolate::New(create_params);
14194
14195 {
14196 v8::Isolate::Scope scope(isolate);
14197
14198 RunLoopInNewEnv(isolate);
14199
14200 // Check the exepected invocation counts.
14201 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14202 CHECK_EQ(200, CountInvocations("bar", "foo"));
14203 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14204
14205 // Verify that we have an entry hook on some specific stubs.
14206 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14207 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14208 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14209 }
14210 isolate->Dispose();
14211
14212 Reset();
14213
14214 // Make sure a second isolate is unaffected by the previous entry hook.
14215 isolate = v8::Isolate::New();
14216 {
14217 v8::Isolate::Scope scope(isolate);
14218
14219 // Reset the entry count to zero and set the entry hook.
14220 RunLoopInNewEnv(isolate);
14221
14222 // We should record no invocations in this isolate.
14223 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14224 }
14225
14226 isolate->Dispose();
14227}
14228
14229
14230TEST(SetFunctionEntryHook) {
14231 // FunctionEntryHook does not work well with experimental natives.
14232 // Experimental natives are compiled during snapshot deserialization.
14233 // This test breaks because InstallGetter (function from snapshot that
14234 // only gets called from experimental natives) is compiled with entry hooks.
14235 i::FLAG_allow_natives_syntax = true;
14236 i::FLAG_use_inlining = false;
14237
14238 SetFunctionEntryHookTest test;
14239 test.RunTest();
14240}
14241
14242
14243static i::HashMap* code_map = NULL;
14244static i::HashMap* jitcode_line_info = NULL;
14245static int saw_bar = 0;
14246static int move_events = 0;
14247
14248
14249static bool FunctionNameIs(const char* expected,
14250 const v8::JitCodeEvent* event) {
14251 // Log lines for functions are of the general form:
14252 // "LazyCompile:<type><function_name>", where the type is one of
14253 // "*", "~" or "".
14254 static const char kPreamble[] = "LazyCompile:";
14255 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14256
14257 if (event->name.len < sizeof(kPreamble) - 1 ||
14258 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14259 return false;
14260 }
14261
14262 const char* tail = event->name.str + kPreambleLen;
14263 size_t tail_len = event->name.len - kPreambleLen;
14264 size_t expected_len = strlen(expected);
14265 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14266 --tail_len;
14267 ++tail;
14268 }
14269
14270 // Check for tails like 'bar :1'.
14271 if (tail_len > expected_len + 2 &&
14272 tail[expected_len] == ' ' &&
14273 tail[expected_len + 1] == ':' &&
14274 tail[expected_len + 2] &&
14275 !strncmp(tail, expected, expected_len)) {
14276 return true;
14277 }
14278
14279 if (tail_len != expected_len)
14280 return false;
14281
14282 return strncmp(tail, expected, expected_len) == 0;
14283}
14284
14285
14286static void event_handler(const v8::JitCodeEvent* event) {
14287 CHECK(event != NULL);
14288 CHECK(code_map != NULL);
14289 CHECK(jitcode_line_info != NULL);
14290
14291 class DummyJitCodeLineInfo {
14292 };
14293
14294 switch (event->type) {
14295 case v8::JitCodeEvent::CODE_ADDED: {
14296 CHECK(event->code_start != NULL);
14297 CHECK_NE(0, static_cast<int>(event->code_len));
14298 CHECK(event->name.str != NULL);
14299 i::HashMap::Entry* entry =
14300 code_map->Lookup(event->code_start,
14301 i::ComputePointerHash(event->code_start),
14302 true);
14303 entry->value = reinterpret_cast<void*>(event->code_len);
14304
14305 if (FunctionNameIs("bar", event)) {
14306 ++saw_bar;
14307 }
14308 }
14309 break;
14310
14311 case v8::JitCodeEvent::CODE_MOVED: {
14312 uint32_t hash = i::ComputePointerHash(event->code_start);
14313 // We would like to never see code move that we haven't seen before,
14314 // but the code creation event does not happen until the line endings
14315 // have been calculated (this is so that we can report the line in the
14316 // script at which the function source is found, see
14317 // Compiler::RecordFunctionCompilation) and the line endings
14318 // calculations can cause a GC, which can move the newly created code
14319 // before its existence can be logged.
14320 i::HashMap::Entry* entry =
14321 code_map->Lookup(event->code_start, hash, false);
14322 if (entry != NULL) {
14323 ++move_events;
14324
14325 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14326 code_map->Remove(event->code_start, hash);
14327
14328 entry = code_map->Lookup(event->new_code_start,
14329 i::ComputePointerHash(event->new_code_start),
14330 true);
14331 CHECK(entry != NULL);
14332 entry->value = reinterpret_cast<void*>(event->code_len);
14333 }
14334 }
14335 break;
14336
14337 case v8::JitCodeEvent::CODE_REMOVED:
14338 // Object/code removal events are currently not dispatched from the GC.
14339 CHECK(false);
14340 break;
14341
14342 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14343 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14344 // record it in jitcode_line_info.
14345 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14346 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14347 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14348 temp_event->user_data = line_info;
14349 i::HashMap::Entry* entry =
14350 jitcode_line_info->Lookup(line_info,
14351 i::ComputePointerHash(line_info),
14352 true);
14353 entry->value = reinterpret_cast<void*>(line_info);
14354 }
14355 break;
14356 // For these two events, we will check whether the event->user_data
14357 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14358 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14359 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14360 CHECK(event->user_data != NULL);
14361 uint32_t hash = i::ComputePointerHash(event->user_data);
14362 i::HashMap::Entry* entry =
14363 jitcode_line_info->Lookup(event->user_data, hash, false);
14364 CHECK(entry != NULL);
14365 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14366 }
14367 break;
14368
14369 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14370 CHECK(event->user_data != NULL);
14371 uint32_t hash = i::ComputePointerHash(event->user_data);
14372 i::HashMap::Entry* entry =
14373 jitcode_line_info->Lookup(event->user_data, hash, false);
14374 CHECK(entry != NULL);
14375 }
14376 break;
14377
14378 default:
14379 // Impossible event.
14380 CHECK(false);
14381 break;
14382 }
14383}
14384
14385
14386UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14387 i::FLAG_stress_compaction = true;
14388 i::FLAG_incremental_marking = false;
14389 if (i::FLAG_never_compact) return;
14390 const char* script =
14391 "function bar() {"
14392 " var sum = 0;"
14393 " for (i = 0; i < 100; ++i)"
14394 " sum = foo(i);"
14395 " return sum;"
14396 "}"
14397 "function foo(i) { return i * i; };"
14398 "bar();";
14399
14400 // Run this test in a new isolate to make sure we don't
14401 // have remnants of state from other code.
14402 v8::Isolate* isolate = v8::Isolate::New();
14403 isolate->Enter();
14404 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14405 i::Heap* heap = i_isolate->heap();
14406
14407 {
14408 v8::HandleScope scope(isolate);
14409 i::HashMap code(MatchPointers);
14410 code_map = &code;
14411
14412 i::HashMap lineinfo(MatchPointers);
14413 jitcode_line_info = &lineinfo;
14414
14415 saw_bar = 0;
14416 move_events = 0;
14417
14418 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14419
14420 // Generate new code objects sparsely distributed across several
14421 // different fragmented code-space pages.
14422 const int kIterations = 10;
14423 for (int i = 0; i < kIterations; ++i) {
14424 LocalContext env(isolate);
14425 i::AlwaysAllocateScope always_allocate(i_isolate);
14426 SimulateFullSpace(heap->code_space());
14427 CompileRun(script);
14428
14429 // Keep a strong reference to the code object in the handle scope.
14430 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14431 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14432 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14433 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14434
14435 // Clear the compilation cache to get more wastage.
14436 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14437 }
14438
14439 // Force code movement.
14440 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14441
14442 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14443
14444 CHECK_LE(kIterations, saw_bar);
14445 CHECK_LT(0, move_events);
14446
14447 code_map = NULL;
14448 jitcode_line_info = NULL;
14449 }
14450
14451 isolate->Exit();
14452 isolate->Dispose();
14453
14454 // Do this in a new isolate.
14455 isolate = v8::Isolate::New();
14456 isolate->Enter();
14457
14458 // Verify that we get callbacks for existing code objects when we
14459 // request enumeration of existing code.
14460 {
14461 v8::HandleScope scope(isolate);
14462 LocalContext env(isolate);
14463 CompileRun(script);
14464
14465 // Now get code through initial iteration.
14466 i::HashMap code(MatchPointers);
14467 code_map = &code;
14468
14469 i::HashMap lineinfo(MatchPointers);
14470 jitcode_line_info = &lineinfo;
14471
14472 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14473 event_handler);
14474 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14475
14476 jitcode_line_info = NULL;
14477 // We expect that we got some events. Note that if we could get code removal
14478 // notifications, we could compare two collections, one created by listening
14479 // from the time of creation of an isolate, and the other by subscribing
14480 // with EnumExisting.
14481 CHECK_LT(0, code.occupancy());
14482
14483 code_map = NULL;
14484 }
14485
14486 isolate->Exit();
14487 isolate->Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +000014488}
14489
14490
14491THREADED_TEST(ExternalAllocatedMemory) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014492 v8::Isolate* isolate = CcTest::isolate();
14493 v8::HandleScope outer(isolate);
14494 v8::Local<Context> env(Context::New(isolate));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014495 CHECK(!env.IsEmpty());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014496 const int64_t kSize = 1024*1024;
14497 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14498 CHECK_EQ(baseline + kSize,
14499 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14500 CHECK_EQ(baseline,
14501 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000014502}
14503
14504
14505// Regression test for issue 54, object templates with internal fields
14506// but no accessors or interceptors did not get their internal field
14507// count set on instances.
14508THREADED_TEST(Regress54) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014509 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014510 v8::Isolate* isolate = context->GetIsolate();
14511 v8::HandleScope outer(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014512 static v8::Persistent<v8::ObjectTemplate> templ;
14513 if (templ.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014514 v8::EscapableHandleScope inner(isolate);
14515 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014516 local->SetInternalFieldCount(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014517 templ.Reset(isolate, inner.Escape(local));
Steve Blocka7e24c12009-10-30 11:49:00 +000014518 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014519 v8::Handle<v8::Object> result =
14520 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
Steve Blocka7e24c12009-10-30 11:49:00 +000014521 CHECK_EQ(1, result->InternalFieldCount());
14522}
14523
14524
14525// If part of the threaded tests, this test makes ThreadingTest fail
14526// on mac.
14527TEST(CatchStackOverflow) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014528 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014529 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014530 v8::TryCatch try_catch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014531 v8::Handle<v8::Value> result = CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +000014532 "function f() {"
14533 " return f();"
14534 "}"
14535 ""
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014536 "f();");
Steve Blocka7e24c12009-10-30 11:49:00 +000014537 CHECK(result.IsEmpty());
14538}
14539
14540
14541static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14542 const char* resource_name,
14543 int line_offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014544 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014545 v8::TryCatch try_catch;
14546 v8::Handle<v8::Value> result = script->Run();
14547 CHECK(result.IsEmpty());
14548 CHECK(try_catch.HasCaught());
14549 v8::Handle<v8::Message> message = try_catch.Message();
14550 CHECK(!message.IsEmpty());
14551 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14552 CHECK_EQ(91, message->GetStartPosition());
14553 CHECK_EQ(92, message->GetEndPosition());
14554 CHECK_EQ(2, message->GetStartColumn());
14555 CHECK_EQ(3, message->GetEndColumn());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014556 v8::String::Utf8Value line(message->GetSourceLine());
Steve Blocka7e24c12009-10-30 11:49:00 +000014557 CHECK_EQ(" throw 'nirk';", *line);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014558 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +000014559 CHECK_EQ(resource_name, *name);
14560}
14561
14562
14563THREADED_TEST(TryCatchSourceInfo) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014564 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014565 v8::HandleScope scope(context->GetIsolate());
14566 v8::Local<v8::String> source = v8_str(
Steve Blocka7e24c12009-10-30 11:49:00 +000014567 "function Foo() {\n"
14568 " return Bar();\n"
14569 "}\n"
14570 "\n"
14571 "function Bar() {\n"
14572 " return Baz();\n"
14573 "}\n"
14574 "\n"
14575 "function Baz() {\n"
14576 " throw 'nirk';\n"
14577 "}\n"
14578 "\n"
14579 "Foo();\n");
14580
14581 const char* resource_name;
14582 v8::Handle<v8::Script> script;
14583 resource_name = "test.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014584 script = CompileWithOrigin(source, resource_name);
Steve Blocka7e24c12009-10-30 11:49:00 +000014585 CheckTryCatchSourceInfo(script, resource_name, 0);
14586
14587 resource_name = "test1.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014588 v8::ScriptOrigin origin1(
14589 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
Steve Blocka7e24c12009-10-30 11:49:00 +000014590 script = v8::Script::Compile(source, &origin1);
14591 CheckTryCatchSourceInfo(script, resource_name, 0);
14592
14593 resource_name = "test2.js";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014594 v8::ScriptOrigin origin2(
14595 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14596 v8::Integer::New(context->GetIsolate(), 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000014597 script = v8::Script::Compile(source, &origin2);
14598 CheckTryCatchSourceInfo(script, resource_name, 7);
14599}
14600
14601
14602THREADED_TEST(CompilationCache) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014603 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014604 v8::HandleScope scope(context->GetIsolate());
14605 v8::Handle<v8::String> source0 =
14606 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14607 v8::Handle<v8::String> source1 =
14608 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14609 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14610 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
Steve Blocka7e24c12009-10-30 11:49:00 +000014611 v8::Handle<v8::Script> script2 =
14612 v8::Script::Compile(source0); // different origin
14613 CHECK_EQ(1234, script0->Run()->Int32Value());
14614 CHECK_EQ(1234, script1->Run()->Int32Value());
14615 CHECK_EQ(1234, script2->Run()->Int32Value());
14616}
14617
14618
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014619static void FunctionNameCallback(
14620 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014621 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014622 args.GetReturnValue().Set(v8_num(42));
Steve Blocka7e24c12009-10-30 11:49:00 +000014623}
14624
14625
14626THREADED_TEST(CallbackFunctionName) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014627 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014628 v8::Isolate* isolate = context->GetIsolate();
14629 v8::HandleScope scope(isolate);
14630 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14631 t->Set(v8_str("asdf"),
14632 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
Steve Blocka7e24c12009-10-30 11:49:00 +000014633 context->Global()->Set(v8_str("obj"), t->NewInstance());
14634 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14635 CHECK(value->IsString());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014636 v8::String::Utf8Value name(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014637 CHECK_EQ("asdf", *name);
14638}
14639
14640
14641THREADED_TEST(DateAccess) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014642 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014643 v8::HandleScope scope(context->GetIsolate());
14644 v8::Handle<v8::Value> date =
14645 v8::Date::New(context->GetIsolate(), 1224744689038.0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014646 CHECK(date->IsDate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014647 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
Steve Blocka7e24c12009-10-30 11:49:00 +000014648}
14649
14650
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014651void CheckProperties(v8::Isolate* isolate,
14652 v8::Handle<v8::Value> val,
14653 int elmc,
14654 const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +010014655 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000014656 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14657 CHECK_EQ(elmc, props->Length());
14658 for (int i = 0; i < elmc; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014659 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
Steve Blocka7e24c12009-10-30 11:49:00 +000014660 CHECK_EQ(elmv[i], *elm);
14661 }
14662}
14663
14664
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014665void CheckOwnProperties(v8::Isolate* isolate,
14666 v8::Handle<v8::Value> val,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014667 int elmc,
14668 const char* elmv[]) {
14669 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14670 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14671 CHECK_EQ(elmc, props->Length());
14672 for (int i = 0; i < elmc; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014673 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014674 CHECK_EQ(elmv[i], *elm);
14675 }
14676}
14677
14678
Steve Blocka7e24c12009-10-30 11:49:00 +000014679THREADED_TEST(PropertyEnumeration) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014680 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014681 v8::Isolate* isolate = context->GetIsolate();
14682 v8::HandleScope scope(isolate);
14683 v8::Handle<v8::Value> obj = CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +000014684 "var result = [];"
14685 "result[0] = {};"
14686 "result[1] = {a: 1, b: 2};"
14687 "result[2] = [1, 2, 3];"
14688 "var proto = {x: 1, y: 2, z: 3};"
14689 "var x = { __proto__: proto, w: 0, z: 1 };"
14690 "result[3] = x;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014691 "result;");
Steve Block6ded16b2010-05-10 14:33:55 +010014692 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +000014693 CHECK_EQ(4, elms->Length());
14694 int elmc0 = 0;
14695 const char** elmv0 = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014696 CheckProperties(
14697 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14698 CheckOwnProperties(
14699 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014700 int elmc1 = 2;
14701 const char* elmv1[] = {"a", "b"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014702 CheckProperties(
14703 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14704 CheckOwnProperties(
14705 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
Steve Blocka7e24c12009-10-30 11:49:00 +000014706 int elmc2 = 3;
14707 const char* elmv2[] = {"0", "1", "2"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014708 CheckProperties(
14709 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14710 CheckOwnProperties(
14711 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
Steve Blocka7e24c12009-10-30 11:49:00 +000014712 int elmc3 = 4;
14713 const char* elmv3[] = {"w", "z", "x", "y"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014714 CheckProperties(
14715 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014716 int elmc4 = 2;
14717 const char* elmv4[] = {"w", "z"};
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014718 CheckOwnProperties(
14719 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
Steve Blocka7e24c12009-10-30 11:49:00 +000014720}
14721
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014722
Steve Block44f0eee2011-05-26 01:26:41 +010014723THREADED_TEST(PropertyEnumeration2) {
Steve Block44f0eee2011-05-26 01:26:41 +010014724 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014725 v8::Isolate* isolate = context->GetIsolate();
14726 v8::HandleScope scope(isolate);
14727 v8::Handle<v8::Value> obj = CompileRun(
Steve Block44f0eee2011-05-26 01:26:41 +010014728 "var result = [];"
14729 "result[0] = {};"
14730 "result[1] = {a: 1, b: 2};"
14731 "result[2] = [1, 2, 3];"
14732 "var proto = {x: 1, y: 2, z: 3};"
14733 "var x = { __proto__: proto, w: 0, z: 1 };"
14734 "result[3] = x;"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014735 "result;");
Steve Block44f0eee2011-05-26 01:26:41 +010014736 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14737 CHECK_EQ(4, elms->Length());
14738 int elmc0 = 0;
14739 const char** elmv0 = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014740 CheckProperties(isolate,
14741 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
Steve Block44f0eee2011-05-26 01:26:41 +010014742
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014743 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
Steve Block44f0eee2011-05-26 01:26:41 +010014744 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14745 CHECK_EQ(0, props->Length());
14746 for (uint32_t i = 0; i < props->Length(); i++) {
14747 printf("p[%d]\n", i);
14748 }
14749}
Steve Blocka7e24c12009-10-30 11:49:00 +000014750
Steve Blocka7e24c12009-10-30 11:49:00 +000014751static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14752 Local<Value> name,
14753 v8::AccessType type,
14754 Local<Value> data) {
14755 return type != v8::ACCESS_SET;
14756}
14757
14758
14759static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14760 uint32_t key,
14761 v8::AccessType type,
14762 Local<Value> data) {
14763 return type != v8::ACCESS_SET;
14764}
14765
14766
14767THREADED_TEST(DisableAccessChecksWhileConfiguring) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014768 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014769 v8::Isolate* isolate = context->GetIsolate();
14770 v8::HandleScope scope(isolate);
14771 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014772 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14773 IndexedSetAccessBlocker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014774 templ->Set(v8_str("x"), v8::True(isolate));
Steve Blocka7e24c12009-10-30 11:49:00 +000014775 Local<v8::Object> instance = templ->NewInstance();
14776 context->Global()->Set(v8_str("obj"), instance);
14777 Local<Value> value = CompileRun("obj.x");
14778 CHECK(value->BooleanValue());
14779}
14780
14781
14782static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14783 Local<Value> name,
14784 v8::AccessType type,
14785 Local<Value> data) {
14786 return false;
14787}
14788
14789
14790static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14791 uint32_t key,
14792 v8::AccessType type,
14793 Local<Value> data) {
14794 return false;
14795}
14796
14797
14798
14799THREADED_TEST(AccessChecksReenabledCorrectly) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014800 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014801 v8::Isolate* isolate = context->GetIsolate();
14802 v8::HandleScope scope(isolate);
14803 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014804 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14805 IndexedGetAccessBlocker);
14806 templ->Set(v8_str("a"), v8_str("a"));
14807 // Add more than 8 (see kMaxFastProperties) properties
14808 // so that the constructor will force copying map.
14809 // Cannot sprintf, gcc complains unsafety.
14810 char buf[4];
14811 for (char i = '0'; i <= '9' ; i++) {
14812 buf[0] = i;
14813 for (char j = '0'; j <= '9'; j++) {
14814 buf[1] = j;
14815 for (char k = '0'; k <= '9'; k++) {
14816 buf[2] = k;
14817 buf[3] = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014818 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
Steve Blocka7e24c12009-10-30 11:49:00 +000014819 }
14820 }
14821 }
14822
14823 Local<v8::Object> instance_1 = templ->NewInstance();
14824 context->Global()->Set(v8_str("obj_1"), instance_1);
14825
14826 Local<Value> value_1 = CompileRun("obj_1.a");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014827 CHECK(value_1.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000014828
14829 Local<v8::Object> instance_2 = templ->NewInstance();
14830 context->Global()->Set(v8_str("obj_2"), instance_2);
14831
14832 Local<Value> value_2 = CompileRun("obj_2.a");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014833 CHECK(value_2.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000014834}
14835
14836
14837// This tests that access check information remains on the global
14838// object template when creating contexts.
14839THREADED_TEST(AccessControlRepeatedContextCreation) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014840 v8::Isolate* isolate = CcTest::isolate();
14841 v8::HandleScope handle_scope(isolate);
14842 v8::Handle<v8::ObjectTemplate> global_template =
14843 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014844 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14845 IndexedSetAccessBlocker);
14846 i::Handle<i::ObjectTemplateInfo> internal_template =
14847 v8::Utils::OpenHandle(*global_template);
14848 CHECK(!internal_template->constructor()->IsUndefined());
14849 i::Handle<i::FunctionTemplateInfo> constructor(
14850 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14851 CHECK(!constructor->access_check_info()->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014852 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014853 CHECK(!context0.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000014854 CHECK(!constructor->access_check_info()->IsUndefined());
14855}
14856
14857
14858THREADED_TEST(TurnOnAccessCheck) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014859 v8::Isolate* isolate = CcTest::isolate();
14860 v8::HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014861
14862 // Create an environment with access check to the global object disabled by
14863 // default.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014864 v8::Handle<v8::ObjectTemplate> global_template =
14865 v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014866 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14867 IndexedGetAccessBlocker,
14868 v8::Handle<v8::Value>(),
14869 false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014870 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +000014871 Context::Scope context_scope(context);
14872
14873 // Set up a property and a number of functions.
14874 context->Global()->Set(v8_str("a"), v8_num(1));
14875 CompileRun("function f1() {return a;}"
14876 "function f2() {return a;}"
14877 "function g1() {return h();}"
14878 "function g2() {return h();}"
14879 "function h() {return 1;}");
14880 Local<Function> f1 =
14881 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14882 Local<Function> f2 =
14883 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14884 Local<Function> g1 =
14885 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14886 Local<Function> g2 =
14887 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14888 Local<Function> h =
14889 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14890
14891 // Get the global object.
14892 v8::Handle<v8::Object> global = context->Global();
14893
14894 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14895 // uses the runtime system to retreive property a whereas f2 uses global load
14896 // inline cache.
14897 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14898 for (int i = 0; i < 4; i++) {
14899 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14900 }
14901
14902 // Same for g1 and g2.
14903 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14904 for (int i = 0; i < 4; i++) {
14905 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14906 }
14907
14908 // Detach the global and turn on access check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014909 Local<Object> hidden_global = Local<Object>::Cast(
14910 context->Global()->GetPrototype());
Steve Blocka7e24c12009-10-30 11:49:00 +000014911 context->DetachGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014912 hidden_global->TurnOnAccessCheck();
Steve Blocka7e24c12009-10-30 11:49:00 +000014913
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014914 // Failing access check results in exception.
14915 CHECK(f1->Call(global, 0, NULL).IsEmpty());
14916 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000014917 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14918 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14919
14920 // No failing access check when just returning a constant.
14921 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14922}
14923
14924
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014925static const char* kPropertyA = "a";
14926static const char* kPropertyH = "h";
Ben Murdochb0fe1622011-05-05 13:52:32 +010014927
14928static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14929 Local<Value> name,
14930 v8::AccessType type,
14931 Local<Value> data) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014932 if (!name->IsString()) return false;
14933 i::Handle<i::String> name_handle =
14934 v8::Utils::OpenHandle(String::Cast(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014935 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14936 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
Ben Murdochb0fe1622011-05-05 13:52:32 +010014937}
14938
14939
14940THREADED_TEST(TurnOnAccessCheckAndRecompile) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014941 v8::Isolate* isolate = CcTest::isolate();
14942 v8::HandleScope handle_scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014943
14944 // Create an environment with access check to the global object disabled by
14945 // default. When the registered access checker will block access to properties
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014946 // a and h.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014947 v8::Handle<v8::ObjectTemplate> global_template =
14948 v8::ObjectTemplate::New(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014949 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14950 IndexedGetAccessBlocker,
14951 v8::Handle<v8::Value>(),
14952 false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014953 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014954 Context::Scope context_scope(context);
14955
14956 // Set up a property and a number of functions.
14957 context->Global()->Set(v8_str("a"), v8_num(1));
14958 static const char* source = "function f1() {return a;}"
14959 "function f2() {return a;}"
14960 "function g1() {return h();}"
14961 "function g2() {return h();}"
14962 "function h() {return 1;}";
14963
14964 CompileRun(source);
14965 Local<Function> f1;
14966 Local<Function> f2;
14967 Local<Function> g1;
14968 Local<Function> g2;
14969 Local<Function> h;
14970 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14971 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14972 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14973 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14974 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14975
14976 // Get the global object.
14977 v8::Handle<v8::Object> global = context->Global();
14978
14979 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14980 // uses the runtime system to retreive property a whereas f2 uses global load
14981 // inline cache.
14982 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14983 for (int i = 0; i < 4; i++) {
14984 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14985 }
14986
14987 // Same for g1 and g2.
14988 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14989 for (int i = 0; i < 4; i++) {
14990 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14991 }
14992
14993 // Detach the global and turn on access check now blocking access to property
14994 // a and function h.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014995 Local<Object> hidden_global = Local<Object>::Cast(
14996 context->Global()->GetPrototype());
Ben Murdochb0fe1622011-05-05 13:52:32 +010014997 context->DetachGlobal();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014998 hidden_global->TurnOnAccessCheck();
Ben Murdochb0fe1622011-05-05 13:52:32 +010014999
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015000 // Failing access check results in exception.
15001 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15002 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015003 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15004 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15005
15006 // No failing access check when just returning a constant.
15007 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15008
15009 // Now compile the source again. And get the newly compiled functions, except
15010 // for h for which access is blocked.
15011 CompileRun(source);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015012 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15013 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15014 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15015 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15016 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015018 // Failing access check results in exception.
15019 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15020 CHECK(result.IsEmpty());
15021 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15022 CHECK(f2->Call(global, 0, NULL).IsEmpty());
Ben Murdochb0fe1622011-05-05 13:52:32 +010015023 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15024 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15025}
15026
15027
Leon Clarkef7060e22010-06-03 12:02:55 +010015028// Tests that ScriptData can be serialized and deserialized.
15029TEST(PreCompileSerialization) {
15030 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015031 LocalContext env;
15032 v8::Isolate* isolate = env->GetIsolate();
15033 HandleScope handle_scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010015034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015035 i::FLAG_min_preparse_length = 0;
15036 const char* script = "function foo(a) { return a+1; }";
15037 v8::ScriptCompiler::Source source(v8_str(script));
15038 v8::ScriptCompiler::Compile(isolate, &source,
15039 v8::ScriptCompiler::kProduceParserCache);
Leon Clarkef7060e22010-06-03 12:02:55 +010015040 // Serialize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015041 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15042 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15043 i::MemCopy(serialized_data, cd->data, cd->length);
Leon Clarkef7060e22010-06-03 12:02:55 +010015044
15045 // Deserialize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015046 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
Leon Clarkef7060e22010-06-03 12:02:55 +010015047
15048 // Verify that the original is the same as the deserialized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015049 CHECK_EQ(cd->length, deserialized->length());
15050 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
Leon Clarkef7060e22010-06-03 12:02:55 +010015051
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015052 delete deserialized;
15053 i::DeleteArray(serialized_data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010015054}
15055
15056
Steve Blocka7e24c12009-10-30 11:49:00 +000015057// This tests that we do not allow dictionary load/call inline caches
15058// to use functions that have not yet been compiled. The potential
15059// problem of loading a function that has not yet been compiled can
15060// arise because we share code between contexts via the compilation
15061// cache.
15062THREADED_TEST(DictionaryICLoadedFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015063 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015064 // Test LoadIC.
15065 for (int i = 0; i < 2; i++) {
15066 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015067 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015068 context->Global()->Delete(v8_str("tmp"));
15069 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15070 }
15071 // Test CallIC.
15072 for (int i = 0; i < 2; i++) {
15073 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015074 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015075 context->Global()->Delete(v8_str("tmp"));
15076 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15077 }
15078}
15079
15080
15081// Test that cross-context new calls use the context of the callee to
15082// create the new JavaScript object.
15083THREADED_TEST(CrossContextNew) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015084 v8::Isolate* isolate = CcTest::isolate();
15085 v8::HandleScope scope(isolate);
15086 v8::Local<Context> context0 = Context::New(isolate);
15087 v8::Local<Context> context1 = Context::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015088
15089 // Allow cross-domain access.
15090 Local<String> token = v8_str("<security token>");
15091 context0->SetSecurityToken(token);
15092 context1->SetSecurityToken(token);
15093
15094 // Set an 'x' property on the Object prototype and define a
15095 // constructor function in context0.
15096 context0->Enter();
15097 CompileRun("Object.prototype.x = 42; function C() {};");
15098 context0->Exit();
15099
15100 // Call the constructor function from context0 and check that the
15101 // result has the 'x' property.
15102 context1->Enter();
15103 context1->Global()->Set(v8_str("other"), context0->Global());
15104 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15105 CHECK(value->IsInt32());
15106 CHECK_EQ(42, value->Int32Value());
15107 context1->Exit();
Steve Blocka7e24c12009-10-30 11:49:00 +000015108}
15109
15110
15111// Verify that we can clone an object
15112TEST(ObjectClone) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015113 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015114 v8::Isolate* isolate = env->GetIsolate();
15115 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015116
15117 const char* sample =
15118 "var rv = {};" \
15119 "rv.alpha = 'hello';" \
15120 "rv.beta = 123;" \
15121 "rv;";
15122
15123 // Create an object, verify basics.
15124 Local<Value> val = CompileRun(sample);
15125 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +010015126 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015127 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15128
15129 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015130 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015131 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15132
15133 // Clone it.
15134 Local<v8::Object> clone = obj->Clone();
15135 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015136 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015137 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15138
15139 // Set a property on the clone, verify each object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015140 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15141 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15142 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
Steve Blocka7e24c12009-10-30 11:49:00 +000015143}
15144
15145
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015146class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
Steve Blocka7e24c12009-10-30 11:49:00 +000015147 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015148 explicit OneByteVectorResource(i::Vector<const char> vector)
Steve Blocka7e24c12009-10-30 11:49:00 +000015149 : data_(vector) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015150 virtual ~OneByteVectorResource() {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015151 virtual size_t length() const { return data_.length(); }
15152 virtual const char* data() const { return data_.start(); }
15153 private:
15154 i::Vector<const char> data_;
15155};
15156
15157
15158class UC16VectorResource : public v8::String::ExternalStringResource {
15159 public:
15160 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15161 : data_(vector) {}
15162 virtual ~UC16VectorResource() {}
15163 virtual size_t length() const { return data_.length(); }
15164 virtual const i::uc16* data() const { return data_.start(); }
15165 private:
15166 i::Vector<const i::uc16> data_;
15167};
15168
15169
15170static void MorphAString(i::String* string,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015171 OneByteVectorResource* one_byte_resource,
Steve Blocka7e24c12009-10-30 11:49:00 +000015172 UC16VectorResource* uc16_resource) {
15173 CHECK(i::StringShape(string).IsExternal());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015174 if (string->IsOneByteRepresentation()) {
15175 // Check old map is not internalized or long.
15176 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000015177 // Morph external string to be TwoByte string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015178 string->set_map(CcTest::heap()->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +000015179 i::ExternalTwoByteString* morphed =
15180 i::ExternalTwoByteString::cast(string);
15181 morphed->set_resource(uc16_resource);
15182 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015183 // Check old map is not internalized or long.
15184 CHECK(string->map() == CcTest::heap()->external_string_map());
15185 // Morph external string to be one-byte string.
15186 string->set_map(CcTest::heap()->external_one_byte_string_map());
15187 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15188 morphed->set_resource(one_byte_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000015189 }
15190}
15191
15192
15193// Test that we can still flatten a string if the components it is built up
15194// from have been turned into 16 bit strings in the mean time.
15195THREADED_TEST(MorphCompositeStringTest) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015196 char utf_buffer[129];
Steve Blocka7e24c12009-10-30 11:49:00 +000015197 const char* c_string = "Now is the time for all good men"
15198 " to come to the aid of the party";
15199 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15200 {
Steve Blocka7e24c12009-10-30 11:49:00 +000015201 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015202 i::Factory* factory = CcTest::i_isolate()->factory();
15203 v8::HandleScope scope(env->GetIsolate());
15204 OneByteVectorResource one_byte_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000015205 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015206 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +000015207 i::Vector<const uint16_t>(two_byte_string,
15208 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015209
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015210 Local<String> lhs(
15211 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15212 &one_byte_resource).ToHandleChecked()));
15213 Local<String> rhs(
15214 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15215 &one_byte_resource).ToHandleChecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015216
15217 env->Global()->Set(v8_str("lhs"), lhs);
15218 env->Global()->Set(v8_str("rhs"), rhs);
15219
15220 CompileRun(
15221 "var cons = lhs + rhs;"
15222 "var slice = lhs.substring(1, lhs.length - 1);"
15223 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15224
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015225 CHECK(lhs->IsOneByte());
15226 CHECK(rhs->IsOneByte());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015227
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015228 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15229 &uc16_resource);
15230 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15231 &uc16_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000015232
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015233 // This should UTF-8 without flattening, since everything is ASCII.
15234 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15235 CHECK_EQ(128, cons->Utf8Length());
15236 int nchars = -1;
15237 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15238 CHECK_EQ(128, nchars);
15239 CHECK_EQ(0, strcmp(
15240 utf_buffer,
15241 "Now is the time for all good men to come to the aid of the party"
15242 "Now is the time for all good men to come to the aid of the party"));
15243
Steve Blocka7e24c12009-10-30 11:49:00 +000015244 // Now do some stuff to make sure the strings are flattened, etc.
15245 CompileRun(
15246 "/[^a-z]/.test(cons);"
15247 "/[^a-z]/.test(slice);"
15248 "/[^a-z]/.test(slice_on_cons);");
15249 const char* expected_cons =
15250 "Now is the time for all good men to come to the aid of the party"
15251 "Now is the time for all good men to come to the aid of the party";
15252 const char* expected_slice =
15253 "ow is the time for all good men to come to the aid of the part";
15254 const char* expected_slice_on_cons =
15255 "ow is the time for all good men to come to the aid of the party"
15256 "Now is the time for all good men to come to the aid of the part";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015257 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
Steve Blocka7e24c12009-10-30 11:49:00 +000015258 env->Global()->Get(v8_str("cons")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015259 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
Steve Blocka7e24c12009-10-30 11:49:00 +000015260 env->Global()->Get(v8_str("slice")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015261 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
Steve Blocka7e24c12009-10-30 11:49:00 +000015262 env->Global()->Get(v8_str("slice_on_cons")));
15263 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +010015264 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +000015265}
15266
15267
15268TEST(CompileExternalTwoByteSource) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015269 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015270 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015271
15272 // This is a very short list of sources, which currently is to check for a
15273 // regression caused by r2703.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015274 const char* one_byte_sources[] = {
15275 "0.5",
15276 "-0.5", // This mainly testes PushBack in the Scanner.
15277 "--0.5", // This mainly testes PushBack in the Scanner.
15278 NULL};
Steve Blocka7e24c12009-10-30 11:49:00 +000015279
15280 // Compile the sources as external two byte strings.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015281 for (int i = 0; one_byte_sources[i] != NULL; i++) {
15282 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15283 TestResource* uc16_resource = new TestResource(two_byte_string);
15284 v8::Local<v8::String> source =
15285 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000015286 v8::Script::Compile(source);
15287 }
15288}
15289
15290
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015291#ifndef V8_INTERPRETED_REGEXP
15292
15293struct RegExpInterruptionData {
15294 int loop_count;
15295 UC16VectorResource* string_resource;
15296 v8::Persistent<v8::String> string;
15297} regexp_interruption_data;
15298
15299
15300class RegExpInterruptionThread : public v8::base::Thread {
Steve Blocka7e24c12009-10-30 11:49:00 +000015301 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015302 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15303 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +000015304
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015305 virtual void Run() {
15306 for (regexp_interruption_data.loop_count = 0;
15307 regexp_interruption_data.loop_count < 7;
15308 regexp_interruption_data.loop_count++) {
15309 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
15310 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
Steve Blocka7e24c12009-10-30 11:49:00 +000015311 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015312 v8::base::OS::Sleep(50); // Wait a bit before terminating.
15313 v8::V8::TerminateExecution(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +000015314 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015315
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015316 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015317 v8::Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +000015318};
15319
15320
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015321void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15322 if (regexp_interruption_data.loop_count != 2) return;
15323 v8::HandleScope scope(CcTest::isolate());
15324 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15325 CcTest::isolate(), regexp_interruption_data.string);
15326 string->MakeExternal(regexp_interruption_data.string_resource);
Steve Blocka7e24c12009-10-30 11:49:00 +000015327}
15328
15329
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015330// Test that RegExp execution can be interrupted. Specifically, we test
15331// * interrupting with GC
15332// * turn the subject string from one-byte internal to two-byte external string
15333// * force termination
15334TEST(RegExpInterruption) {
15335 v8::HandleScope scope(CcTest::isolate());
15336 LocalContext env;
15337
15338 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15339
15340 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15341 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15342 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15343 v8::Local<v8::String> string = v8_str(one_byte_content);
15344
15345 CcTest::global()->Set(v8_str("a"), string);
15346 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15347 regexp_interruption_data.string_resource = new UC16VectorResource(
15348 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15349
15350 v8::TryCatch try_catch;
15351 timeout_thread.Start();
15352
15353 CompileRun("/((a*)*)*b/.exec(a)");
15354 CHECK(try_catch.HasTerminated());
15355
15356 timeout_thread.Join();
15357
15358 regexp_interruption_data.string.Reset();
15359 i::DeleteArray(uc16_content);
15360}
15361
15362#endif // V8_INTERPRETED_REGEXP
15363
15364
15365// Test that we cannot set a property on the global object if there
Steve Blocka7e24c12009-10-30 11:49:00 +000015366// is a read-only property in the prototype chain.
15367TEST(ReadOnlyPropertyInGlobalProto) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015368 v8::Isolate* isolate = CcTest::isolate();
15369 v8::HandleScope scope(isolate);
15370 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015371 LocalContext context(0, templ);
15372 v8::Handle<v8::Object> global = context->Global();
15373 v8::Handle<v8::Object> global_proto =
15374 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015375 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15376 v8::ReadOnly);
15377 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15378 v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +000015379 // Check without 'eval' or 'with'.
15380 v8::Handle<v8::Value> res =
15381 CompileRun("function f() { x = 42; return x; }; f()");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015382 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000015383 // Check with 'eval'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015384 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15385 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000015386 // Check with 'with'.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015387 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15388 CHECK_EQ(v8::Integer::New(isolate, 0), res);
Steve Blocka7e24c12009-10-30 11:49:00 +000015389}
15390
15391static int force_set_set_count = 0;
15392static int force_set_get_count = 0;
15393bool pass_on_get = false;
15394
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015395static void ForceSetGetter(v8::Local<v8::String> name,
15396 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015397 force_set_get_count++;
15398 if (pass_on_get) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015399 return;
Steve Blocka7e24c12009-10-30 11:49:00 +000015400 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015401 info.GetReturnValue().Set(3);
Steve Blocka7e24c12009-10-30 11:49:00 +000015402}
15403
15404static void ForceSetSetter(v8::Local<v8::String> name,
15405 v8::Local<v8::Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015406 const v8::PropertyCallbackInfo<void>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015407 force_set_set_count++;
15408}
15409
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015410static void ForceSetInterceptSetter(
Steve Blocka7e24c12009-10-30 11:49:00 +000015411 v8::Local<v8::String> name,
15412 v8::Local<v8::Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015413 const v8::PropertyCallbackInfo<v8::Value>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015414 force_set_set_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015415 info.GetReturnValue().SetUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000015416}
15417
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015418
Steve Blocka7e24c12009-10-30 11:49:00 +000015419TEST(ForceSet) {
15420 force_set_get_count = 0;
15421 force_set_set_count = 0;
15422 pass_on_get = false;
15423
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015424 v8::Isolate* isolate = CcTest::isolate();
15425 v8::HandleScope scope(isolate);
15426 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15427 v8::Handle<v8::String> access_property =
15428 v8::String::NewFromUtf8(isolate, "a");
Steve Blocka7e24c12009-10-30 11:49:00 +000015429 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15430 LocalContext context(NULL, templ);
15431 v8::Handle<v8::Object> global = context->Global();
15432
15433 // Ordinary properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015434 v8::Handle<v8::String> simple_property =
15435 v8::String::NewFromUtf8(isolate, "p");
15436 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
Steve Blocka7e24c12009-10-30 11:49:00 +000015437 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15438 // This should fail because the property is read-only
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015439 global->Set(simple_property, v8::Int32::New(isolate, 5));
Steve Blocka7e24c12009-10-30 11:49:00 +000015440 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15441 // This should succeed even though the property is read-only
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015442 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
Steve Blocka7e24c12009-10-30 11:49:00 +000015443 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15444
15445 // Accessors
15446 CHECK_EQ(0, force_set_set_count);
15447 CHECK_EQ(0, force_set_get_count);
15448 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15449 // CHECK_EQ the property shouldn't override it, just call the setter
15450 // which in this case does nothing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015451 global->Set(access_property, v8::Int32::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000015452 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15453 CHECK_EQ(1, force_set_set_count);
15454 CHECK_EQ(2, force_set_get_count);
15455 // Forcing the property to be set should override the accessor without
15456 // calling it
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015457 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000015458 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15459 CHECK_EQ(1, force_set_set_count);
15460 CHECK_EQ(2, force_set_get_count);
15461}
15462
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015463
Steve Blocka7e24c12009-10-30 11:49:00 +000015464TEST(ForceSetWithInterceptor) {
15465 force_set_get_count = 0;
15466 force_set_set_count = 0;
15467 pass_on_get = false;
15468
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015469 v8::Isolate* isolate = CcTest::isolate();
15470 v8::HandleScope scope(isolate);
15471 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015472 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15473 LocalContext context(NULL, templ);
15474 v8::Handle<v8::Object> global = context->Global();
15475
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015476 v8::Handle<v8::String> some_property =
15477 v8::String::NewFromUtf8(isolate, "a");
Steve Blocka7e24c12009-10-30 11:49:00 +000015478 CHECK_EQ(0, force_set_set_count);
15479 CHECK_EQ(0, force_set_get_count);
15480 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15481 // Setting the property shouldn't override it, just call the setter
15482 // which in this case does nothing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015483 global->Set(some_property, v8::Int32::New(isolate, 7));
Steve Blocka7e24c12009-10-30 11:49:00 +000015484 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15485 CHECK_EQ(1, force_set_set_count);
15486 CHECK_EQ(2, force_set_get_count);
15487 // Getting the property when the interceptor returns an empty handle
15488 // should yield undefined, since the property isn't present on the
15489 // object itself yet.
15490 pass_on_get = true;
15491 CHECK(global->Get(some_property)->IsUndefined());
15492 CHECK_EQ(1, force_set_set_count);
15493 CHECK_EQ(3, force_set_get_count);
15494 // Forcing the property to be set should cause the value to be
15495 // set locally without calling the interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015496 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
Steve Blocka7e24c12009-10-30 11:49:00 +000015497 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15498 CHECK_EQ(1, force_set_set_count);
15499 CHECK_EQ(4, force_set_get_count);
15500 // Reenabling the interceptor should cause it to take precedence over
15501 // the property
15502 pass_on_get = false;
15503 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15504 CHECK_EQ(1, force_set_set_count);
15505 CHECK_EQ(5, force_set_get_count);
15506 // The interceptor should also work for other properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015507 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15508 ->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000015509 CHECK_EQ(1, force_set_set_count);
15510 CHECK_EQ(6, force_set_get_count);
15511}
15512
15513
15514THREADED_TEST(ForceDelete) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015515 v8::Isolate* isolate = CcTest::isolate();
15516 v8::HandleScope scope(isolate);
15517 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015518 LocalContext context(NULL, templ);
15519 v8::Handle<v8::Object> global = context->Global();
15520
15521 // Ordinary properties
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015522 v8::Handle<v8::String> simple_property =
15523 v8::String::NewFromUtf8(isolate, "p");
15524 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +000015525 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15526 // This should fail because the property is dont-delete.
15527 CHECK(!global->Delete(simple_property));
15528 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15529 // This should succeed even though the property is dont-delete.
15530 CHECK(global->ForceDelete(simple_property));
15531 CHECK(global->Get(simple_property)->IsUndefined());
15532}
15533
15534
15535static int force_delete_interceptor_count = 0;
15536static bool pass_on_delete = false;
15537
15538
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015539static void ForceDeleteDeleter(
Steve Blocka7e24c12009-10-30 11:49:00 +000015540 v8::Local<v8::String> name,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015541 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015542 force_delete_interceptor_count++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015543 if (pass_on_delete) return;
15544 info.GetReturnValue().Set(true);
Steve Blocka7e24c12009-10-30 11:49:00 +000015545}
15546
15547
15548THREADED_TEST(ForceDeleteWithInterceptor) {
15549 force_delete_interceptor_count = 0;
15550 pass_on_delete = false;
15551
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015552 v8::Isolate* isolate = CcTest::isolate();
15553 v8::HandleScope scope(isolate);
15554 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015555 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15556 LocalContext context(NULL, templ);
15557 v8::Handle<v8::Object> global = context->Global();
15558
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015559 v8::Handle<v8::String> some_property =
15560 v8::String::NewFromUtf8(isolate, "a");
15561 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15562 v8::DontDelete);
Steve Blocka7e24c12009-10-30 11:49:00 +000015563
15564 // Deleting a property should get intercepted and nothing should
15565 // happen.
15566 CHECK_EQ(0, force_delete_interceptor_count);
15567 CHECK(global->Delete(some_property));
15568 CHECK_EQ(1, force_delete_interceptor_count);
15569 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15570 // Deleting the property when the interceptor returns an empty
15571 // handle should not delete the property since it is DontDelete.
15572 pass_on_delete = true;
15573 CHECK(!global->Delete(some_property));
15574 CHECK_EQ(2, force_delete_interceptor_count);
15575 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15576 // Forcing the property to be deleted should delete the value
15577 // without calling the interceptor.
15578 CHECK(global->ForceDelete(some_property));
15579 CHECK(global->Get(some_property)->IsUndefined());
15580 CHECK_EQ(2, force_delete_interceptor_count);
15581}
15582
15583
15584// Make sure that forcing a delete invalidates any IC stubs, so we
15585// don't read the hole value.
15586THREADED_TEST(ForceDeleteIC) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015587 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015588 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015589 // Create a DontDelete variable on the global object.
15590 CompileRun("this.__proto__ = { foo: 'horse' };"
15591 "var foo = 'fish';"
15592 "function f() { return foo.length; }");
15593 // Initialize the IC for foo in f.
15594 CompileRun("for (var i = 0; i < 4; i++) f();");
15595 // Make sure the value of foo is correct before the deletion.
15596 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15597 // Force the deletion of foo.
15598 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15599 // Make sure the value for foo is read from the prototype, and that
15600 // we don't get in trouble with reading the deleted cell value
15601 // sentinel.
15602 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15603}
15604
15605
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015606TEST(InlinedFunctionAcrossContexts) {
15607 i::FLAG_allow_natives_syntax = true;
15608 v8::Isolate* isolate = CcTest::isolate();
15609 v8::HandleScope outer_scope(isolate);
15610 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15611 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15612 ctx1->Enter();
15613
15614 {
15615 v8::HandleScope inner_scope(CcTest::isolate());
15616 CompileRun("var G = 42; function foo() { return G; }");
15617 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15618 ctx2->Enter();
15619 ctx2->Global()->Set(v8_str("o"), foo);
15620 v8::Local<v8::Value> res = CompileRun(
15621 "function f() { return o(); }"
15622 "for (var i = 0; i < 10; ++i) f();"
15623 "%OptimizeFunctionOnNextCall(f);"
15624 "f();");
15625 CHECK_EQ(42, res->Int32Value());
15626 ctx2->Exit();
15627 v8::Handle<v8::String> G_property =
15628 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15629 CHECK(ctx1->Global()->ForceDelete(G_property));
15630 ctx2->Enter();
15631 ExpectString(
15632 "(function() {"
15633 " try {"
15634 " return f();"
15635 " } catch(e) {"
15636 " return e.toString();"
15637 " }"
15638 " })()",
15639 "ReferenceError: G is not defined");
15640 ctx2->Exit();
15641 ctx1->Exit();
15642 }
15643}
15644
15645
15646static v8::Local<Context> calling_context0;
15647static v8::Local<Context> calling_context1;
15648static v8::Local<Context> calling_context2;
Steve Blocka7e24c12009-10-30 11:49:00 +000015649
15650
15651// Check that the call to the callback is initiated in
15652// calling_context2, the directly calling context is calling_context1
15653// and the callback itself is in calling_context0.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015654static void GetCallingContextCallback(
15655 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015656 ApiTestFuzzer::Fuzz();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015657 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15658 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15659 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15660 args.GetReturnValue().Set(42);
15661}
15662
15663
15664THREADED_TEST(GetCurrentContextWhenNotInContext) {
15665 i::Isolate* isolate = CcTest::i_isolate();
15666 CHECK(isolate != NULL);
15667 CHECK(isolate->context() == NULL);
15668 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15669 v8::HandleScope scope(v8_isolate);
15670 // The following should not crash, but return an empty handle.
15671 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15672 CHECK(current.IsEmpty());
Steve Blocka7e24c12009-10-30 11:49:00 +000015673}
15674
15675
15676THREADED_TEST(GetCallingContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015677 v8::Isolate* isolate = CcTest::isolate();
15678 v8::HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015679
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015680 Local<Context> calling_context0(Context::New(isolate));
15681 Local<Context> calling_context1(Context::New(isolate));
15682 Local<Context> calling_context2(Context::New(isolate));
15683 ::calling_context0 = calling_context0;
15684 ::calling_context1 = calling_context1;
15685 ::calling_context2 = calling_context2;
Steve Blocka7e24c12009-10-30 11:49:00 +000015686
15687 // Allow cross-domain access.
15688 Local<String> token = v8_str("<security token>");
15689 calling_context0->SetSecurityToken(token);
15690 calling_context1->SetSecurityToken(token);
15691 calling_context2->SetSecurityToken(token);
15692
15693 // Create an object with a C++ callback in context0.
15694 calling_context0->Enter();
15695 Local<v8::FunctionTemplate> callback_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015696 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000015697 calling_context0->Global()->Set(v8_str("callback"),
15698 callback_templ->GetFunction());
15699 calling_context0->Exit();
15700
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015701 // Expose context0 in context1 and set up a function that calls the
Steve Blocka7e24c12009-10-30 11:49:00 +000015702 // callback function.
15703 calling_context1->Enter();
15704 calling_context1->Global()->Set(v8_str("context0"),
15705 calling_context0->Global());
15706 CompileRun("function f() { context0.callback() }");
15707 calling_context1->Exit();
15708
15709 // Expose context1 in context2 and call the callback function in
15710 // context0 indirectly through f in context1.
15711 calling_context2->Enter();
15712 calling_context2->Global()->Set(v8_str("context1"),
15713 calling_context1->Global());
15714 CompileRun("context1.f()");
15715 calling_context2->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015716 ::calling_context0.Clear();
15717 ::calling_context1.Clear();
15718 ::calling_context2.Clear();
Steve Blocka7e24c12009-10-30 11:49:00 +000015719}
15720
15721
15722// Check that a variable declaration with no explicit initialization
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015723// value does shadow an existing property in the prototype chain.
Steve Blocka7e24c12009-10-30 11:49:00 +000015724THREADED_TEST(InitGlobalVarInProtoChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015725 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015726 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015727 // Introduce a variable in the prototype chain.
15728 CompileRun("__proto__.x = 42");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015729 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
Steve Blocka7e24c12009-10-30 11:49:00 +000015730 CHECK(!result->IsUndefined());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015731 CHECK_EQ(43, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +000015732}
15733
15734
15735// Regression test for issue 398.
15736// If a function is added to an object, creating a constant function
15737// field, and the result is cloned, replacing the constant function on the
15738// original should not affect the clone.
15739// See http://code.google.com/p/v8/issues/detail?id=398
15740THREADED_TEST(ReplaceConstantFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015741 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015742 v8::Isolate* isolate = context->GetIsolate();
15743 v8::HandleScope scope(isolate);
15744 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15745 v8::Handle<v8::FunctionTemplate> func_templ =
15746 v8::FunctionTemplate::New(isolate);
15747 v8::Handle<v8::String> foo_string =
15748 v8::String::NewFromUtf8(isolate, "foo");
Steve Blocka7e24c12009-10-30 11:49:00 +000015749 obj->Set(foo_string, func_templ->GetFunction());
15750 v8::Handle<v8::Object> obj_clone = obj->Clone();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015751 obj_clone->Set(foo_string,
15752 v8::String::NewFromUtf8(isolate, "Hello"));
Steve Blocka7e24c12009-10-30 11:49:00 +000015753 CHECK(!obj->Get(foo_string)->IsUndefined());
15754}
15755
15756
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015757static void CheckElementValue(i::Isolate* isolate,
15758 int expected,
15759 i::Handle<i::Object> obj,
15760 int offset) {
15761 i::Object* element =
15762 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15763 CHECK_EQ(expected, i::Smi::cast(element)->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000015764}
15765
15766
15767THREADED_TEST(PixelArray) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015768 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015769 i::Isolate* isolate = CcTest::i_isolate();
15770 i::Factory* factory = isolate->factory();
15771 v8::HandleScope scope(context->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000015772 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000015773 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015774 i::Handle<i::ExternalUint8ClampedArray> pixels =
15775 i::Handle<i::ExternalUint8ClampedArray>::cast(
15776 factory->NewExternalArray(kElementCount,
15777 v8::kExternalUint8ClampedArray,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015778 pixel_data));
15779 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015780 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000015781 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000015782 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000015783 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015784 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015785 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000015786 for (int i = 0; i < kElementCount; i++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015787 CHECK_EQ(i % 256, pixels->get_scalar(i));
Steve Blockd0582a62009-12-15 09:54:21 +000015788 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000015789 }
15790
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015791 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015792 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15793 // Set the elements to be the pixels.
15794 // jsobj->set_elements(*pixels);
15795 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015796 CheckElementValue(isolate, 1, jsobj, 1);
15797 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
Steve Blocka7e24c12009-10-30 11:49:00 +000015798 context->Global()->Set(v8_str("pixels"), obj);
15799 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15800 CHECK_EQ(1503, result->Int32Value());
15801 result = CompileRun("pixels[1]");
15802 CHECK_EQ(1, result->Int32Value());
15803
15804 result = CompileRun("var sum = 0;"
15805 "for (var i = 0; i < 8; i++) {"
15806 " sum += pixels[i] = pixels[i] = -i;"
15807 "}"
15808 "sum;");
15809 CHECK_EQ(-28, result->Int32Value());
15810
15811 result = CompileRun("var sum = 0;"
15812 "for (var i = 0; i < 8; i++) {"
15813 " sum += pixels[i] = pixels[i] = 0;"
15814 "}"
15815 "sum;");
15816 CHECK_EQ(0, result->Int32Value());
15817
15818 result = CompileRun("var sum = 0;"
15819 "for (var i = 0; i < 8; i++) {"
15820 " sum += pixels[i] = pixels[i] = 255;"
15821 "}"
15822 "sum;");
15823 CHECK_EQ(8 * 255, result->Int32Value());
15824
15825 result = CompileRun("var sum = 0;"
15826 "for (var i = 0; i < 8; i++) {"
15827 " sum += pixels[i] = pixels[i] = 256 + i;"
15828 "}"
15829 "sum;");
15830 CHECK_EQ(2076, result->Int32Value());
15831
15832 result = CompileRun("var sum = 0;"
15833 "for (var i = 0; i < 8; i++) {"
15834 " sum += pixels[i] = pixels[i] = i;"
15835 "}"
15836 "sum;");
15837 CHECK_EQ(28, result->Int32Value());
15838
15839 result = CompileRun("var sum = 0;"
15840 "for (var i = 0; i < 8; i++) {"
15841 " sum += pixels[i];"
15842 "}"
15843 "sum;");
15844 CHECK_EQ(28, result->Int32Value());
15845
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015846 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15847 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
Ben Murdoch589d6972011-11-30 16:04:58 +000015848 i::Handle<i::Object> no_failure;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015849 no_failure = i::JSObject::SetElement(
15850 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15851 DCHECK(!no_failure.is_null());
15852 USE(no_failure);
15853 CheckElementValue(isolate, 2, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015854 *value.location() = i::Smi::FromInt(256);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015855 no_failure = i::JSObject::SetElement(
15856 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15857 DCHECK(!no_failure.is_null());
15858 USE(no_failure);
15859 CheckElementValue(isolate, 255, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015860 *value.location() = i::Smi::FromInt(-1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015861 no_failure = i::JSObject::SetElement(
15862 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15863 DCHECK(!no_failure.is_null());
15864 USE(no_failure);
15865 CheckElementValue(isolate, 0, jsobj, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015866
15867 result = CompileRun("for (var i = 0; i < 8; i++) {"
15868 " pixels[i] = (i * 65) - 109;"
15869 "}"
15870 "pixels[1] + pixels[6];");
15871 CHECK_EQ(255, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015872 CheckElementValue(isolate, 0, jsobj, 0);
15873 CheckElementValue(isolate, 0, jsobj, 1);
15874 CheckElementValue(isolate, 21, jsobj, 2);
15875 CheckElementValue(isolate, 86, jsobj, 3);
15876 CheckElementValue(isolate, 151, jsobj, 4);
15877 CheckElementValue(isolate, 216, jsobj, 5);
15878 CheckElementValue(isolate, 255, jsobj, 6);
15879 CheckElementValue(isolate, 255, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000015880 result = CompileRun("var sum = 0;"
15881 "for (var i = 0; i < 8; i++) {"
15882 " sum += pixels[i];"
15883 "}"
15884 "sum;");
15885 CHECK_EQ(984, result->Int32Value());
15886
15887 result = CompileRun("for (var i = 0; i < 8; i++) {"
15888 " pixels[i] = (i * 1.1);"
15889 "}"
15890 "pixels[1] + pixels[6];");
15891 CHECK_EQ(8, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015892 CheckElementValue(isolate, 0, jsobj, 0);
15893 CheckElementValue(isolate, 1, jsobj, 1);
15894 CheckElementValue(isolate, 2, jsobj, 2);
15895 CheckElementValue(isolate, 3, jsobj, 3);
15896 CheckElementValue(isolate, 4, jsobj, 4);
15897 CheckElementValue(isolate, 6, jsobj, 5);
15898 CheckElementValue(isolate, 7, jsobj, 6);
15899 CheckElementValue(isolate, 8, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000015900
15901 result = CompileRun("for (var i = 0; i < 8; i++) {"
15902 " pixels[7] = undefined;"
15903 "}"
15904 "pixels[7];");
15905 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015906 CheckElementValue(isolate, 0, jsobj, 7);
Steve Blocka7e24c12009-10-30 11:49:00 +000015907
15908 result = CompileRun("for (var i = 0; i < 8; i++) {"
15909 " pixels[6] = '2.3';"
15910 "}"
15911 "pixels[6];");
15912 CHECK_EQ(2, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015913 CheckElementValue(isolate, 2, jsobj, 6);
Steve Blocka7e24c12009-10-30 11:49:00 +000015914
15915 result = CompileRun("for (var i = 0; i < 8; i++) {"
15916 " pixels[5] = NaN;"
15917 "}"
15918 "pixels[5];");
15919 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015920 CheckElementValue(isolate, 0, jsobj, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +000015921
15922 result = CompileRun("for (var i = 0; i < 8; i++) {"
15923 " pixels[8] = Infinity;"
15924 "}"
15925 "pixels[8];");
15926 CHECK_EQ(255, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015927 CheckElementValue(isolate, 255, jsobj, 8);
Steve Blocka7e24c12009-10-30 11:49:00 +000015928
15929 result = CompileRun("for (var i = 0; i < 8; i++) {"
15930 " pixels[9] = -Infinity;"
15931 "}"
15932 "pixels[9];");
15933 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015934 CheckElementValue(isolate, 0, jsobj, 9);
Steve Blocka7e24c12009-10-30 11:49:00 +000015935
15936 result = CompileRun("pixels[3] = 33;"
15937 "delete pixels[3];"
15938 "pixels[3];");
15939 CHECK_EQ(33, result->Int32Value());
15940
15941 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15942 "pixels[2] = 12; pixels[3] = 13;"
15943 "pixels.__defineGetter__('2',"
15944 "function() { return 120; });"
15945 "pixels[2];");
15946 CHECK_EQ(12, result->Int32Value());
15947
15948 result = CompileRun("var js_array = new Array(40);"
15949 "js_array[0] = 77;"
15950 "js_array;");
15951 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15952
15953 result = CompileRun("pixels[1] = 23;"
15954 "pixels.__proto__ = [];"
15955 "js_array.__proto__ = pixels;"
15956 "js_array.concat(pixels);");
15957 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15958 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15959
15960 result = CompileRun("pixels[1] = 23;");
15961 CHECK_EQ(23, result->Int32Value());
15962
Steve Blockd0582a62009-12-15 09:54:21 +000015963 // Test for index greater than 255. Regression test for:
15964 // http://code.google.com/p/chromium/issues/detail?id=26337.
15965 result = CompileRun("pixels[256] = 255;");
15966 CHECK_EQ(255, result->Int32Value());
15967 result = CompileRun("var i = 0;"
15968 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15969 "i");
15970 CHECK_EQ(255, result->Int32Value());
15971
Steve Block1e0659c2011-05-24 12:43:12 +010015972 // Make sure that pixel array ICs recognize when a non-pixel array
15973 // is passed to it.
15974 result = CompileRun("function pa_load(p) {"
15975 " var sum = 0;"
15976 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15977 " return sum;"
15978 "}"
15979 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15980 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15981 "just_ints = new Object();"
15982 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15983 "for (var i = 0; i < 10; ++i) {"
15984 " result = pa_load(just_ints);"
15985 "}"
15986 "result");
15987 CHECK_EQ(32640, result->Int32Value());
15988
15989 // Make sure that pixel array ICs recognize out-of-bound accesses.
15990 result = CompileRun("function pa_load(p, start) {"
15991 " var sum = 0;"
15992 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15993 " return sum;"
15994 "}"
15995 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15996 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15997 "for (var i = 0; i < 10; ++i) {"
15998 " result = pa_load(pixels,-10);"
15999 "}"
16000 "result");
16001 CHECK_EQ(0, result->Int32Value());
16002
16003 // Make sure that generic ICs properly handles a pixel array.
16004 result = CompileRun("function pa_load(p) {"
16005 " var sum = 0;"
16006 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16007 " return sum;"
16008 "}"
16009 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16010 "just_ints = new Object();"
16011 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16012 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16013 "for (var i = 0; i < 10; ++i) {"
16014 " result = pa_load(pixels);"
16015 "}"
16016 "result");
16017 CHECK_EQ(32640, result->Int32Value());
16018
16019 // Make sure that generic load ICs recognize out-of-bound accesses in
16020 // pixel arrays.
16021 result = CompileRun("function pa_load(p, start) {"
16022 " var sum = 0;"
16023 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16024 " return sum;"
16025 "}"
16026 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16027 "just_ints = new Object();"
16028 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16029 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16030 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16031 "for (var i = 0; i < 10; ++i) {"
16032 " result = pa_load(pixels,-10);"
16033 "}"
16034 "result");
16035 CHECK_EQ(0, result->Int32Value());
16036
16037 // Make sure that generic ICs properly handles other types than pixel
16038 // arrays (that the inlined fast pixel array test leaves the right information
16039 // in the right registers).
16040 result = CompileRun("function pa_load(p) {"
16041 " var sum = 0;"
16042 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16043 " return sum;"
16044 "}"
16045 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16046 "just_ints = new Object();"
16047 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16048 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16049 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16050 "sparse_array = new Object();"
16051 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16052 "sparse_array[1000000] = 3;"
16053 "for (var i = 0; i < 10; ++i) {"
16054 " result = pa_load(sparse_array);"
16055 "}"
16056 "result");
16057 CHECK_EQ(32640, result->Int32Value());
16058
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016059 // Make sure that pixel array store ICs clamp values correctly.
16060 result = CompileRun("function pa_store(p) {"
16061 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16062 "}"
16063 "pa_store(pixels);"
16064 "var sum = 0;"
16065 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16066 "sum");
16067 CHECK_EQ(48896, result->Int32Value());
16068
16069 // Make sure that pixel array stores correctly handle accesses outside
16070 // of the pixel array..
16071 result = CompileRun("function pa_store(p,start) {"
16072 " for (var j = 0; j < 256; j++) {"
16073 " p[j+start] = j * 2;"
16074 " }"
16075 "}"
16076 "pa_store(pixels,0);"
16077 "pa_store(pixels,-128);"
16078 "var sum = 0;"
16079 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16080 "sum");
16081 CHECK_EQ(65280, result->Int32Value());
16082
16083 // Make sure that the generic store stub correctly handle accesses outside
16084 // of the pixel array..
16085 result = CompileRun("function pa_store(p,start) {"
16086 " for (var j = 0; j < 256; j++) {"
16087 " p[j+start] = j * 2;"
16088 " }"
16089 "}"
16090 "pa_store(pixels,0);"
16091 "just_ints = new Object();"
16092 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16093 "pa_store(just_ints, 0);"
16094 "pa_store(pixels,-128);"
16095 "var sum = 0;"
16096 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16097 "sum");
16098 CHECK_EQ(65280, result->Int32Value());
16099
16100 // Make sure that the generic keyed store stub clamps pixel array values
16101 // correctly.
16102 result = CompileRun("function pa_store(p) {"
16103 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16104 "}"
16105 "pa_store(pixels);"
16106 "just_ints = new Object();"
16107 "pa_store(just_ints);"
16108 "pa_store(pixels);"
16109 "var sum = 0;"
16110 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16111 "sum");
16112 CHECK_EQ(48896, result->Int32Value());
16113
16114 // Make sure that pixel array loads are optimized by crankshaft.
Steve Block1e0659c2011-05-24 12:43:12 +010016115 result = CompileRun("function pa_load(p) {"
16116 " var sum = 0;"
16117 " for (var i=0; i<256; ++i) {"
16118 " sum += p[i];"
16119 " }"
16120 " return sum; "
16121 "}"
16122 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
Steve Block44f0eee2011-05-26 01:26:41 +010016123 "for (var i = 0; i < 5000; ++i) {"
Steve Block1e0659c2011-05-24 12:43:12 +010016124 " result = pa_load(pixels);"
16125 "}"
16126 "result");
16127 CHECK_EQ(32640, result->Int32Value());
16128
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016129 // Make sure that pixel array stores are optimized by crankshaft.
16130 result = CompileRun("function pa_init(p) {"
16131 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16132 "}"
16133 "function pa_load(p) {"
16134 " var sum = 0;"
16135 " for (var i=0; i<256; ++i) {"
16136 " sum += p[i];"
16137 " }"
16138 " return sum; "
16139 "}"
Steve Block44f0eee2011-05-26 01:26:41 +010016140 "for (var i = 0; i < 5000; ++i) {"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016141 " pa_init(pixels);"
16142 "}"
16143 "result = pa_load(pixels);"
16144 "result");
16145 CHECK_EQ(32640, result->Int32Value());
16146
Steve Blocka7e24c12009-10-30 11:49:00 +000016147 free(pixel_data);
16148}
16149
16150
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016151THREADED_TEST(PixelArrayInfo) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016152 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016153 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016154 for (int size = 0; size < 100; size += 10) {
16155 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016156 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016157 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16158 CHECK(obj->HasIndexedPropertiesInPixelData());
16159 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16160 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16161 free(pixel_data);
16162 }
16163}
16164
16165
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016166static void NotHandledIndexedPropertyGetter(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016167 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016168 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016169 ApiTestFuzzer::Fuzz();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016170}
16171
16172
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016173static void NotHandledIndexedPropertySetter(
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016174 uint32_t index,
16175 Local<Value> value,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016176 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016177 ApiTestFuzzer::Fuzz();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016178}
16179
16180
16181THREADED_TEST(PixelArrayWithInterceptor) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016182 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016183 i::Factory* factory = CcTest::i_isolate()->factory();
16184 v8::Isolate* isolate = context->GetIsolate();
16185 v8::HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016186 const int kElementCount = 260;
16187 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016188 i::Handle<i::ExternalUint8ClampedArray> pixels =
16189 i::Handle<i::ExternalUint8ClampedArray>::cast(
16190 factory->NewExternalArray(kElementCount,
16191 v8::kExternalUint8ClampedArray,
Steve Block44f0eee2011-05-26 01:26:41 +010016192 pixel_data));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016193 for (int i = 0; i < kElementCount; i++) {
16194 pixels->set(i, i % 256);
16195 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016196 v8::Handle<v8::ObjectTemplate> templ =
16197 v8::ObjectTemplate::New(context->GetIsolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010016198 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16199 NotHandledIndexedPropertySetter);
16200 v8::Handle<v8::Object> obj = templ->NewInstance();
16201 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16202 context->Global()->Set(v8_str("pixels"), obj);
16203 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16204 CHECK_EQ(1, result->Int32Value());
16205 result = CompileRun("var sum = 0;"
16206 "for (var i = 0; i < 8; i++) {"
16207 " sum += pixels[i] = pixels[i] = -i;"
16208 "}"
16209 "sum;");
16210 CHECK_EQ(-28, result->Int32Value());
16211 result = CompileRun("pixels.hasOwnProperty('1')");
16212 CHECK(result->BooleanValue());
16213 free(pixel_data);
16214}
16215
16216
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016217static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16218 switch (array_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016219 case v8::kExternalInt8Array:
16220 case v8::kExternalUint8Array:
16221 case v8::kExternalUint8ClampedArray:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016222 return 1;
16223 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016224 case v8::kExternalInt16Array:
16225 case v8::kExternalUint16Array:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016226 return 2;
16227 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016228 case v8::kExternalInt32Array:
16229 case v8::kExternalUint32Array:
16230 case v8::kExternalFloat32Array:
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016231 return 4;
16232 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016233 case v8::kExternalFloat64Array:
Ben Murdoch257744e2011-11-30 15:57:28 +000016234 return 8;
16235 break;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016236 default:
16237 UNREACHABLE();
16238 return -1;
16239 }
16240 UNREACHABLE();
16241 return -1;
16242}
16243
16244
Steve Block3ce2e202009-11-05 08:53:23 +000016245template <class ExternalArrayClass, class ElementType>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016246static void ObjectWithExternalArrayTestHelper(
16247 Handle<Context> context,
16248 v8::Handle<Object> obj,
16249 int element_count,
16250 v8::ExternalArrayType array_type,
16251 int64_t low, int64_t high) {
Steve Block3ce2e202009-11-05 08:53:23 +000016252 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016253 i::Isolate* isolate = jsobj->GetIsolate();
16254 obj->Set(v8_str("field"),
16255 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
Steve Block3ce2e202009-11-05 08:53:23 +000016256 context->Global()->Set(v8_str("ext_array"), obj);
16257 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16258 CHECK_EQ(1503, result->Int32Value());
16259 result = CompileRun("ext_array[1]");
16260 CHECK_EQ(1, result->Int32Value());
16261
Steve Block3ce2e202009-11-05 08:53:23 +000016262 // Check assigned smis
16263 result = CompileRun("for (var i = 0; i < 8; i++) {"
16264 " ext_array[i] = i;"
16265 "}"
16266 "var sum = 0;"
16267 "for (var i = 0; i < 8; i++) {"
16268 " sum += ext_array[i];"
16269 "}"
16270 "sum;");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016271
Steve Block3ce2e202009-11-05 08:53:23 +000016272 CHECK_EQ(28, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016273 // Check pass through of assigned smis
16274 result = CompileRun("var sum = 0;"
16275 "for (var i = 0; i < 8; i++) {"
16276 " sum += ext_array[i] = ext_array[i] = -i;"
16277 "}"
16278 "sum;");
16279 CHECK_EQ(-28, result->Int32Value());
16280
Steve Block3ce2e202009-11-05 08:53:23 +000016281
16282 // Check assigned smis in reverse order
16283 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16284 " ext_array[i] = i;"
16285 "}"
16286 "var sum = 0;"
16287 "for (var i = 0; i < 8; i++) {"
16288 " sum += ext_array[i];"
16289 "}"
16290 "sum;");
16291 CHECK_EQ(28, result->Int32Value());
16292
16293 // Check pass through of assigned HeapNumbers
16294 result = CompileRun("var sum = 0;"
16295 "for (var i = 0; i < 16; i+=2) {"
16296 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16297 "}"
16298 "sum;");
16299 CHECK_EQ(-28, result->Int32Value());
16300
16301 // Check assigned HeapNumbers
16302 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16303 " ext_array[i] = (i * 0.5);"
16304 "}"
16305 "var sum = 0;"
16306 "for (var i = 0; i < 16; i+=2) {"
16307 " sum += ext_array[i];"
16308 "}"
16309 "sum;");
16310 CHECK_EQ(28, result->Int32Value());
16311
16312 // Check assigned HeapNumbers in reverse order
16313 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16314 " ext_array[i] = (i * 0.5);"
16315 "}"
16316 "var sum = 0;"
16317 "for (var i = 0; i < 16; i+=2) {"
16318 " sum += ext_array[i];"
16319 "}"
16320 "sum;");
16321 CHECK_EQ(28, result->Int32Value());
16322
16323 i::ScopedVector<char> test_buf(1024);
16324
16325 // Check legal boundary conditions.
16326 // The repeated loads and stores ensure the ICs are exercised.
16327 const char* boundary_program =
16328 "var res = 0;"
16329 "for (var i = 0; i < 16; i++) {"
16330 " ext_array[i] = %lld;"
16331 " if (i > 8) {"
16332 " res = ext_array[i];"
16333 " }"
16334 "}"
16335 "res;";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016336 i::SNPrintF(test_buf,
16337 boundary_program,
16338 low);
Steve Block3ce2e202009-11-05 08:53:23 +000016339 result = CompileRun(test_buf.start());
16340 CHECK_EQ(low, result->IntegerValue());
16341
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016342 i::SNPrintF(test_buf,
16343 boundary_program,
16344 high);
Steve Block3ce2e202009-11-05 08:53:23 +000016345 result = CompileRun(test_buf.start());
16346 CHECK_EQ(high, result->IntegerValue());
16347
16348 // Check misprediction of type in IC.
16349 result = CompileRun("var tmp_array = ext_array;"
16350 "var sum = 0;"
16351 "for (var i = 0; i < 8; i++) {"
16352 " tmp_array[i] = i;"
16353 " sum += tmp_array[i];"
16354 " if (i == 4) {"
16355 " tmp_array = {};"
16356 " }"
16357 "}"
16358 "sum;");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016359 // Force GC to trigger verification.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016360 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block3ce2e202009-11-05 08:53:23 +000016361 CHECK_EQ(28, result->Int32Value());
16362
16363 // Make sure out-of-range loads do not throw.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016364 i::SNPrintF(test_buf,
16365 "var caught_exception = false;"
16366 "try {"
16367 " ext_array[%d];"
16368 "} catch (e) {"
16369 " caught_exception = true;"
16370 "}"
16371 "caught_exception;",
16372 element_count);
Steve Block3ce2e202009-11-05 08:53:23 +000016373 result = CompileRun(test_buf.start());
16374 CHECK_EQ(false, result->BooleanValue());
16375
16376 // Make sure out-of-range stores do not throw.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016377 i::SNPrintF(test_buf,
16378 "var caught_exception = false;"
16379 "try {"
16380 " ext_array[%d] = 1;"
16381 "} catch (e) {"
16382 " caught_exception = true;"
16383 "}"
16384 "caught_exception;",
16385 element_count);
Steve Block3ce2e202009-11-05 08:53:23 +000016386 result = CompileRun(test_buf.start());
16387 CHECK_EQ(false, result->BooleanValue());
16388
16389 // Check other boundary conditions, values and operations.
16390 result = CompileRun("for (var i = 0; i < 8; i++) {"
16391 " ext_array[7] = undefined;"
16392 "}"
16393 "ext_array[7];");
16394 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016395 if (array_type == v8::kExternalFloat64Array ||
16396 array_type == v8::kExternalFloat32Array) {
16397 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16398 static_cast<int>(
16399 i::Object::GetElement(
16400 isolate, jsobj, 7).ToHandleChecked()->Number()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016401 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016402 CheckElementValue(isolate, 0, jsobj, 7);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016403 }
Steve Block3ce2e202009-11-05 08:53:23 +000016404
16405 result = CompileRun("for (var i = 0; i < 8; i++) {"
16406 " ext_array[6] = '2.3';"
16407 "}"
16408 "ext_array[6];");
16409 CHECK_EQ(2, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016410 CHECK_EQ(2,
16411 static_cast<int>(
16412 i::Object::GetElement(
16413 isolate, jsobj, 6).ToHandleChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000016414
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016415 if (array_type != v8::kExternalFloat32Array &&
16416 array_type != v8::kExternalFloat64Array) {
Steve Block3ce2e202009-11-05 08:53:23 +000016417 // Though the specification doesn't state it, be explicit about
16418 // converting NaNs and +/-Infinity to zero.
16419 result = CompileRun("for (var i = 0; i < 8; i++) {"
16420 " ext_array[i] = 5;"
16421 "}"
16422 "for (var i = 0; i < 8; i++) {"
16423 " ext_array[i] = NaN;"
16424 "}"
16425 "ext_array[5];");
16426 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016427 CheckElementValue(isolate, 0, jsobj, 5);
Steve Block3ce2e202009-11-05 08:53:23 +000016428
16429 result = CompileRun("for (var i = 0; i < 8; i++) {"
16430 " ext_array[i] = 5;"
16431 "}"
16432 "for (var i = 0; i < 8; i++) {"
16433 " ext_array[i] = Infinity;"
16434 "}"
16435 "ext_array[5];");
Steve Block44f0eee2011-05-26 01:26:41 +010016436 int expected_value =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016437 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
Steve Block44f0eee2011-05-26 01:26:41 +010016438 CHECK_EQ(expected_value, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016439 CheckElementValue(isolate, expected_value, jsobj, 5);
Steve Block3ce2e202009-11-05 08:53:23 +000016440
16441 result = CompileRun("for (var i = 0; i < 8; i++) {"
16442 " ext_array[i] = 5;"
16443 "}"
16444 "for (var i = 0; i < 8; i++) {"
16445 " ext_array[i] = -Infinity;"
16446 "}"
16447 "ext_array[5];");
16448 CHECK_EQ(0, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016449 CheckElementValue(isolate, 0, jsobj, 5);
Steve Block1e0659c2011-05-24 12:43:12 +010016450
16451 // Check truncation behavior of integral arrays.
16452 const char* unsigned_data =
16453 "var source_data = [0.6, 10.6];"
16454 "var expected_results = [0, 10];";
16455 const char* signed_data =
16456 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16457 "var expected_results = [0, 10, 0, -10];";
Steve Block44f0eee2011-05-26 01:26:41 +010016458 const char* pixel_data =
16459 "var source_data = [0.6, 10.6];"
16460 "var expected_results = [1, 11];";
Steve Block1e0659c2011-05-24 12:43:12 +010016461 bool is_unsigned =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016462 (array_type == v8::kExternalUint8Array ||
16463 array_type == v8::kExternalUint16Array ||
16464 array_type == v8::kExternalUint32Array);
16465 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
Steve Block1e0659c2011-05-24 12:43:12 +010016466
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016467 i::SNPrintF(test_buf,
16468 "%s"
16469 "var all_passed = true;"
16470 "for (var i = 0; i < source_data.length; i++) {"
16471 " for (var j = 0; j < 8; j++) {"
16472 " ext_array[j] = source_data[i];"
16473 " }"
16474 " all_passed = all_passed &&"
16475 " (ext_array[5] == expected_results[i]);"
16476 "}"
16477 "all_passed;",
16478 (is_unsigned ?
16479 unsigned_data :
16480 (is_pixel_data ? pixel_data : signed_data)));
Steve Block1e0659c2011-05-24 12:43:12 +010016481 result = CompileRun(test_buf.start());
16482 CHECK_EQ(true, result->BooleanValue());
Steve Block3ce2e202009-11-05 08:53:23 +000016483 }
16484
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016485 i::Handle<ExternalArrayClass> array(
16486 ExternalArrayClass::cast(jsobj->elements()));
16487 for (int i = 0; i < element_count; i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010016488 array->set(i, static_cast<ElementType>(i));
16489 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016490
Ben Murdoch8b112d22011-06-08 16:22:53 +010016491 // Test complex assignments
16492 result = CompileRun("function ee_op_test_complex_func(sum) {"
16493 " for (var i = 0; i < 40; ++i) {"
16494 " sum += (ext_array[i] += 1);"
16495 " sum += (ext_array[i] -= 1);"
16496 " } "
16497 " return sum;"
16498 "}"
16499 "sum=0;"
16500 "for (var i=0;i<10000;++i) {"
16501 " sum=ee_op_test_complex_func(sum);"
16502 "}"
16503 "sum;");
16504 CHECK_EQ(16000000, result->Int32Value());
16505
16506 // Test count operations
16507 result = CompileRun("function ee_op_test_count_func(sum) {"
16508 " for (var i = 0; i < 40; ++i) {"
16509 " sum += (++ext_array[i]);"
16510 " sum += (--ext_array[i]);"
16511 " } "
16512 " return sum;"
16513 "}"
16514 "sum=0;"
16515 "for (var i=0;i<10000;++i) {"
16516 " sum=ee_op_test_count_func(sum);"
16517 "}"
16518 "sum;");
16519 CHECK_EQ(16000000, result->Int32Value());
16520
Steve Block3ce2e202009-11-05 08:53:23 +000016521 result = CompileRun("ext_array[3] = 33;"
16522 "delete ext_array[3];"
16523 "ext_array[3];");
16524 CHECK_EQ(33, result->Int32Value());
16525
16526 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16527 "ext_array[2] = 12; ext_array[3] = 13;"
16528 "ext_array.__defineGetter__('2',"
16529 "function() { return 120; });"
16530 "ext_array[2];");
16531 CHECK_EQ(12, result->Int32Value());
16532
16533 result = CompileRun("var js_array = new Array(40);"
16534 "js_array[0] = 77;"
16535 "js_array;");
16536 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16537
16538 result = CompileRun("ext_array[1] = 23;"
16539 "ext_array.__proto__ = [];"
16540 "js_array.__proto__ = ext_array;"
16541 "js_array.concat(ext_array);");
16542 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16543 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16544
16545 result = CompileRun("ext_array[1] = 23;");
16546 CHECK_EQ(23, result->Int32Value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016547}
16548
16549
16550template <class FixedTypedArrayClass,
16551 i::ElementsKind elements_kind,
16552 class ElementType>
16553static void FixedTypedArrayTestHelper(
16554 v8::ExternalArrayType array_type,
16555 ElementType low,
16556 ElementType high) {
16557 i::FLAG_allow_natives_syntax = true;
16558 LocalContext context;
16559 i::Isolate* isolate = CcTest::i_isolate();
16560 i::Factory* factory = isolate->factory();
16561 v8::HandleScope scope(context->GetIsolate());
16562 const int kElementCount = 260;
16563 i::Handle<FixedTypedArrayClass> fixed_array =
16564 i::Handle<FixedTypedArrayClass>::cast(
16565 factory->NewFixedTypedArray(kElementCount, array_type));
16566 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16567 fixed_array->map()->instance_type());
16568 CHECK_EQ(kElementCount, fixed_array->length());
16569 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16570 for (int i = 0; i < kElementCount; i++) {
16571 fixed_array->set(i, static_cast<ElementType>(i));
16572 }
16573 // Force GC to trigger verification.
16574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16575 for (int i = 0; i < kElementCount; i++) {
16576 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16577 static_cast<int64_t>(fixed_array->get_scalar(i)));
16578 }
16579 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16580 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16581 i::Handle<i::Map> fixed_array_map =
16582 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16583 jsobj->set_map(*fixed_array_map);
16584 jsobj->set_elements(*fixed_array);
16585
16586 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16587 context.local(), obj, kElementCount, array_type,
16588 static_cast<int64_t>(low),
16589 static_cast<int64_t>(high));
16590}
16591
16592
16593THREADED_TEST(FixedUint8Array) {
16594 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16595 v8::kExternalUint8Array,
16596 0x0, 0xFF);
16597}
16598
16599
16600THREADED_TEST(FixedUint8ClampedArray) {
16601 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16602 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16603 v8::kExternalUint8ClampedArray,
16604 0x0, 0xFF);
16605}
16606
16607
16608THREADED_TEST(FixedInt8Array) {
16609 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16610 v8::kExternalInt8Array,
16611 -0x80, 0x7F);
16612}
16613
16614
16615THREADED_TEST(FixedUint16Array) {
16616 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16617 v8::kExternalUint16Array,
16618 0x0, 0xFFFF);
16619}
16620
16621
16622THREADED_TEST(FixedInt16Array) {
16623 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16624 v8::kExternalInt16Array,
16625 -0x8000, 0x7FFF);
16626}
16627
16628
16629THREADED_TEST(FixedUint32Array) {
16630 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16631 v8::kExternalUint32Array,
16632 0x0, UINT_MAX);
16633}
16634
16635
16636THREADED_TEST(FixedInt32Array) {
16637 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16638 v8::kExternalInt32Array,
16639 INT_MIN, INT_MAX);
16640}
16641
16642
16643THREADED_TEST(FixedFloat32Array) {
16644 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16645 v8::kExternalFloat32Array,
16646 -500, 500);
16647}
16648
16649
16650THREADED_TEST(FixedFloat64Array) {
16651 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16652 v8::kExternalFloat64Array,
16653 -500, 500);
16654}
16655
16656
16657template <class ExternalArrayClass, class ElementType>
16658static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16659 int64_t low,
16660 int64_t high) {
16661 LocalContext context;
16662 i::Isolate* isolate = CcTest::i_isolate();
16663 i::Factory* factory = isolate->factory();
16664 v8::HandleScope scope(context->GetIsolate());
16665 const int kElementCount = 40;
16666 int element_size = ExternalArrayElementSize(array_type);
16667 ElementType* array_data =
16668 static_cast<ElementType*>(malloc(kElementCount * element_size));
16669 i::Handle<ExternalArrayClass> array =
16670 i::Handle<ExternalArrayClass>::cast(
16671 factory->NewExternalArray(kElementCount, array_type, array_data));
16672 // Force GC to trigger verification.
16673 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16674 for (int i = 0; i < kElementCount; i++) {
16675 array->set(i, static_cast<ElementType>(i));
16676 }
16677 // Force GC to trigger verification.
16678 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16679 for (int i = 0; i < kElementCount; i++) {
16680 CHECK_EQ(static_cast<int64_t>(i),
16681 static_cast<int64_t>(array->get_scalar(i)));
16682 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16683 }
16684
16685 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16686 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16687 // Set the elements to be the external array.
16688 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16689 array_type,
16690 kElementCount);
16691 CHECK_EQ(1,
16692 static_cast<int>(
16693 i::Object::GetElement(
16694 isolate, jsobj, 1).ToHandleChecked()->Number()));
16695
16696 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16697 context.local(), obj, kElementCount, array_type, low, high);
16698
16699 v8::Handle<v8::Value> result;
Steve Block3ce2e202009-11-05 08:53:23 +000016700
Steve Blockd0582a62009-12-15 09:54:21 +000016701 // Test more complex manipulations which cause eax to contain values
16702 // that won't be completely overwritten by loads from the arrays.
16703 // This catches bugs in the instructions used for the KeyedLoadIC
16704 // for byte and word types.
16705 {
16706 const int kXSize = 300;
16707 const int kYSize = 300;
16708 const int kLargeElementCount = kXSize * kYSize * 4;
16709 ElementType* large_array_data =
16710 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016711 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000016712 // Set the elements to be the external array.
16713 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16714 array_type,
16715 kLargeElementCount);
16716 context->Global()->Set(v8_str("large_array"), large_obj);
16717 // Initialize contents of a few rows.
16718 for (int x = 0; x < 300; x++) {
16719 int row = 0;
16720 int offset = row * 300 * 4;
16721 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16722 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16723 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16724 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16725 row = 150;
16726 offset = row * 300 * 4;
16727 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16728 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16729 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16730 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16731 row = 298;
16732 offset = row * 300 * 4;
16733 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16734 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16735 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16736 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16737 }
16738 // The goal of the code below is to make "offset" large enough
16739 // that the computation of the index (which goes into eax) has
16740 // high bits set which will not be overwritten by a byte or short
16741 // load.
16742 result = CompileRun("var failed = false;"
16743 "var offset = 0;"
16744 "for (var i = 0; i < 300; i++) {"
16745 " if (large_array[4 * i] != 127 ||"
16746 " large_array[4 * i + 1] != 0 ||"
16747 " large_array[4 * i + 2] != 0 ||"
16748 " large_array[4 * i + 3] != 127) {"
16749 " failed = true;"
16750 " }"
16751 "}"
16752 "offset = 150 * 300 * 4;"
16753 "for (var i = 0; i < 300; i++) {"
16754 " if (large_array[offset + 4 * i] != 127 ||"
16755 " large_array[offset + 4 * i + 1] != 0 ||"
16756 " large_array[offset + 4 * i + 2] != 0 ||"
16757 " large_array[offset + 4 * i + 3] != 127) {"
16758 " failed = true;"
16759 " }"
16760 "}"
16761 "offset = 298 * 300 * 4;"
16762 "for (var i = 0; i < 300; i++) {"
16763 " if (large_array[offset + 4 * i] != 127 ||"
16764 " large_array[offset + 4 * i + 1] != 0 ||"
16765 " large_array[offset + 4 * i + 2] != 0 ||"
16766 " large_array[offset + 4 * i + 3] != 127) {"
16767 " failed = true;"
16768 " }"
16769 "}"
16770 "!failed;");
16771 CHECK_EQ(true, result->BooleanValue());
16772 free(large_array_data);
16773 }
16774
Steve Block44f0eee2011-05-26 01:26:41 +010016775 // The "" property descriptor is overloaded to store information about
16776 // the external array. Ensure that setting and accessing the "" property
16777 // works (it should overwrite the information cached about the external
16778 // array in the DescriptorArray) in various situations.
16779 result = CompileRun("ext_array[''] = 23; ext_array['']");
16780 CHECK_EQ(23, result->Int32Value());
16781
16782 // Property "" set after the external array is associated with the object.
16783 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016784 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16785 obj2->Set(v8_str("ee_test_field"),
16786 v8::Int32::New(context->GetIsolate(), 256));
16787 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
Steve Block44f0eee2011-05-26 01:26:41 +010016788 // Set the elements to be the external array.
16789 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16790 array_type,
16791 kElementCount);
16792 context->Global()->Set(v8_str("ext_array"), obj2);
16793 result = CompileRun("ext_array['']");
16794 CHECK_EQ(1503, result->Int32Value());
16795 }
16796
16797 // Property "" set after the external array is associated with the object.
16798 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016799 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16800 obj2->Set(v8_str("ee_test_field_2"),
16801 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016802 // Set the elements to be the external array.
16803 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16804 array_type,
16805 kElementCount);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016806 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
Steve Block44f0eee2011-05-26 01:26:41 +010016807 context->Global()->Set(v8_str("ext_array"), obj2);
16808 result = CompileRun("ext_array['']");
16809 CHECK_EQ(1503, result->Int32Value());
16810 }
16811
16812 // Should reuse the map from previous test.
16813 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016814 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16815 obj2->Set(v8_str("ee_test_field_2"),
16816 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016817 // Set the elements to be the external array. Should re-use the map
16818 // from previous test.
16819 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16820 array_type,
16821 kElementCount);
16822 context->Global()->Set(v8_str("ext_array"), obj2);
16823 result = CompileRun("ext_array['']");
16824 }
16825
16826 // Property "" is a constant function that shouldn't not be interfered with
16827 // when an external array is set.
16828 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016829 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
Steve Block44f0eee2011-05-26 01:26:41 +010016830 // Start
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016831 obj2->Set(v8_str("ee_test_field3"),
16832 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016833
16834 // Add a constant function to an object.
16835 context->Global()->Set(v8_str("ext_array"), obj2);
16836 result = CompileRun("ext_array[''] = function() {return 1503;};"
16837 "ext_array['']();");
16838
16839 // Add an external array transition to the same map that
16840 // has the constant transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016841 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16842 obj3->Set(v8_str("ee_test_field3"),
16843 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016844 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16845 array_type,
16846 kElementCount);
16847 context->Global()->Set(v8_str("ext_array"), obj3);
16848 }
16849
16850 // If a external array transition is in the map, it should get clobbered
16851 // by a constant function.
16852 {
16853 // Add an external array transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016854 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16855 obj3->Set(v8_str("ee_test_field4"),
16856 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016857 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16858 array_type,
16859 kElementCount);
16860
16861 // Add a constant function to the same map that just got an external array
16862 // transition.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016863 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16864 obj2->Set(v8_str("ee_test_field4"),
16865 v8::Int32::New(context->GetIsolate(), 256));
Steve Block44f0eee2011-05-26 01:26:41 +010016866 context->Global()->Set(v8_str("ext_array"), obj2);
16867 result = CompileRun("ext_array[''] = function() {return 1503;};"
16868 "ext_array['']();");
16869 }
16870
Steve Block3ce2e202009-11-05 08:53:23 +000016871 free(array_data);
16872}
16873
16874
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016875THREADED_TEST(ExternalInt8Array) {
16876 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16877 v8::kExternalInt8Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016878 -128,
16879 127);
16880}
16881
16882
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016883THREADED_TEST(ExternalUint8Array) {
16884 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16885 v8::kExternalUint8Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016886 0,
16887 255);
16888}
16889
16890
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016891THREADED_TEST(ExternalUint8ClampedArray) {
16892 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16893 v8::kExternalUint8ClampedArray,
Steve Block44f0eee2011-05-26 01:26:41 +010016894 0,
16895 255);
16896}
16897
16898
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016899THREADED_TEST(ExternalInt16Array) {
16900 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16901 v8::kExternalInt16Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016902 -32768,
16903 32767);
16904}
16905
16906
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016907THREADED_TEST(ExternalUint16Array) {
16908 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16909 v8::kExternalUint16Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016910 0,
16911 65535);
16912}
16913
16914
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016915THREADED_TEST(ExternalInt32Array) {
16916 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16917 v8::kExternalInt32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016918 INT_MIN, // -2147483648
16919 INT_MAX); // 2147483647
16920}
16921
16922
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016923THREADED_TEST(ExternalUint32Array) {
16924 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16925 v8::kExternalUint32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016926 0,
16927 UINT_MAX); // 4294967295
16928}
16929
16930
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016931THREADED_TEST(ExternalFloat32Array) {
16932 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16933 v8::kExternalFloat32Array,
Steve Block3ce2e202009-11-05 08:53:23 +000016934 -500,
16935 500);
16936}
16937
16938
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016939THREADED_TEST(ExternalFloat64Array) {
16940 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16941 v8::kExternalFloat64Array,
Ben Murdoch257744e2011-11-30 15:57:28 +000016942 -500,
16943 500);
16944}
16945
16946
Steve Block3ce2e202009-11-05 08:53:23 +000016947THREADED_TEST(ExternalArrays) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016948 TestExternalInt8Array();
16949 TestExternalUint8Array();
16950 TestExternalInt16Array();
16951 TestExternalUint16Array();
16952 TestExternalInt32Array();
16953 TestExternalUint32Array();
16954 TestExternalFloat32Array();
Steve Block3ce2e202009-11-05 08:53:23 +000016955}
16956
16957
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016958void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016959 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016960 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016961 for (int size = 0; size < 100; size += 10) {
16962 int element_size = ExternalArrayElementSize(array_type);
16963 void* external_data = malloc(size * element_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016964 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016965 obj->SetIndexedPropertiesToExternalArrayData(
16966 external_data, array_type, size);
16967 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16968 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16969 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16970 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16971 free(external_data);
16972 }
16973}
16974
16975
16976THREADED_TEST(ExternalArrayInfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016977 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16978 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16979 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16980 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16981 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16982 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16983 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16984 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16985 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010016986}
16987
16988
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016989void ExtArrayLimitsHelper(v8::Isolate* isolate,
16990 v8::ExternalArrayType array_type,
16991 int size) {
16992 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16993 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16994 last_location = last_message = NULL;
16995 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16996 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16997 CHECK_NE(NULL, last_location);
16998 CHECK_NE(NULL, last_message);
16999}
17000
17001
17002TEST(ExternalArrayLimits) {
17003 LocalContext context;
17004 v8::Isolate* isolate = context->GetIsolate();
17005 v8::HandleScope scope(isolate);
17006 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17007 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17008 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17009 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17010 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17011 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17012 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17013 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17014 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17015 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17016 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17017 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17018 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17019 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17020 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17021 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17022 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17023 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17024}
17025
17026
17027template <typename ElementType, typename TypedArray,
17028 class ExternalArrayClass>
17029void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17030 int64_t low, int64_t high) {
17031 const int kElementCount = 50;
17032
17033 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17034
17035 LocalContext env;
17036 v8::Isolate* isolate = env->GetIsolate();
17037 v8::HandleScope handle_scope(isolate);
17038
17039 Local<v8::ArrayBuffer> ab =
17040 v8::ArrayBuffer::New(isolate, backing_store.start(),
17041 (kElementCount + 2) * sizeof(ElementType));
17042 Local<TypedArray> ta =
17043 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17044 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17045 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17046 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17047 CHECK_EQ(kElementCount*sizeof(ElementType),
17048 static_cast<int>(ta->ByteLength()));
17049 CHECK_EQ(ab, ta->Buffer());
17050
17051 ElementType* data = backing_store.start() + 2;
17052 for (int i = 0; i < kElementCount; i++) {
17053 data[i] = static_cast<ElementType>(i);
17054 }
17055
17056 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17057 env.local(), ta, kElementCount, array_type, low, high);
17058}
17059
17060
17061THREADED_TEST(Uint8Array) {
17062 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17063 v8::kExternalUint8Array, 0, 0xFF);
17064}
17065
17066
17067THREADED_TEST(Int8Array) {
17068 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17069 v8::kExternalInt8Array, -0x80, 0x7F);
17070}
17071
17072
17073THREADED_TEST(Uint16Array) {
17074 TypedArrayTestHelper<uint16_t,
17075 v8::Uint16Array,
17076 i::ExternalUint16Array>(
17077 v8::kExternalUint16Array, 0, 0xFFFF);
17078}
17079
17080
17081THREADED_TEST(Int16Array) {
17082 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17083 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17084}
17085
17086
17087THREADED_TEST(Uint32Array) {
17088 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17089 v8::kExternalUint32Array, 0, UINT_MAX);
17090}
17091
17092
17093THREADED_TEST(Int32Array) {
17094 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17095 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17096}
17097
17098
17099THREADED_TEST(Float32Array) {
17100 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17101 v8::kExternalFloat32Array, -500, 500);
17102}
17103
17104
17105THREADED_TEST(Float64Array) {
17106 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17107 v8::kExternalFloat64Array, -500, 500);
17108}
17109
17110
17111THREADED_TEST(Uint8ClampedArray) {
17112 TypedArrayTestHelper<uint8_t,
17113 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17114 v8::kExternalUint8ClampedArray, 0, 0xFF);
17115}
17116
17117
17118THREADED_TEST(DataView) {
17119 const int kSize = 50;
17120
17121 i::ScopedVector<uint8_t> backing_store(kSize+2);
17122
17123 LocalContext env;
17124 v8::Isolate* isolate = env->GetIsolate();
17125 v8::HandleScope handle_scope(isolate);
17126
17127 Local<v8::ArrayBuffer> ab =
17128 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17129 Local<v8::DataView> dv =
17130 v8::DataView::New(ab, 2, kSize);
17131 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17132 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17133 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17134 CHECK_EQ(ab, dv->Buffer());
17135}
17136
17137
17138#define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17139 THREADED_TEST(Is##View) { \
17140 LocalContext env; \
17141 v8::Isolate* isolate = env->GetIsolate(); \
17142 v8::HandleScope handle_scope(isolate); \
17143 \
17144 Handle<Value> result = CompileRun( \
17145 "var ab = new ArrayBuffer(128);" \
17146 "new " #View "(ab)"); \
17147 CHECK(result->IsArrayBufferView()); \
17148 CHECK(result->Is##View()); \
17149 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17150 }
17151
17152IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17153IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17154IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17155IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17156IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17157IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17158IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17159IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17160IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17161IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17162
17163#undef IS_ARRAY_BUFFER_VIEW_TEST
17164
17165
17166
Steve Blocka7e24c12009-10-30 11:49:00 +000017167THREADED_TEST(ScriptContextDependence) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017168 LocalContext c1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017169 v8::HandleScope scope(c1->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017170 const char *source = "foo";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017171 v8::Handle<v8::Script> dep = v8_compile(source);
17172 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17173 c1->GetIsolate(), source));
17174 v8::Handle<v8::UnboundScript> indep =
17175 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17176 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17177 v8::Integer::New(c1->GetIsolate(), 100));
Steve Blocka7e24c12009-10-30 11:49:00 +000017178 CHECK_EQ(dep->Run()->Int32Value(), 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017179 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
Steve Blocka7e24c12009-10-30 11:49:00 +000017180 LocalContext c2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017181 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17182 v8::Integer::New(c2->GetIsolate(), 101));
Steve Blocka7e24c12009-10-30 11:49:00 +000017183 CHECK_EQ(dep->Run()->Int32Value(), 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017184 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
Steve Blocka7e24c12009-10-30 11:49:00 +000017185}
17186
17187
17188THREADED_TEST(StackTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017189 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017190 v8::HandleScope scope(context->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017191 v8::TryCatch try_catch;
17192 const char *source = "function foo() { FAIL.FAIL; }; foo();";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017193 v8::Handle<v8::String> src =
17194 v8::String::NewFromUtf8(context->GetIsolate(), source);
17195 v8::Handle<v8::String> origin =
17196 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17197 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17198 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17199 ->BindToCurrentContext()
17200 ->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +000017201 CHECK(try_catch.HasCaught());
17202 v8::String::Utf8Value stack(try_catch.StackTrace());
17203 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17204}
17205
17206
Kristian Monsen25f61362010-05-21 11:50:48 +010017207// Checks that a StackFrame has certain expected values.
17208void checkStackFrame(const char* expected_script_name,
17209 const char* expected_func_name, int expected_line_number,
17210 int expected_column, bool is_eval, bool is_constructor,
17211 v8::Handle<v8::StackFrame> frame) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017212 v8::HandleScope scope(CcTest::isolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010017213 v8::String::Utf8Value func_name(frame->GetFunctionName());
17214 v8::String::Utf8Value script_name(frame->GetScriptName());
17215 if (*script_name == NULL) {
17216 // The situation where there is no associated script, like for evals.
17217 CHECK(expected_script_name == NULL);
17218 } else {
17219 CHECK(strstr(*script_name, expected_script_name) != NULL);
17220 }
17221 CHECK(strstr(*func_name, expected_func_name) != NULL);
17222 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17223 CHECK_EQ(expected_column, frame->GetColumn());
17224 CHECK_EQ(is_eval, frame->IsEval());
17225 CHECK_EQ(is_constructor, frame->IsConstructor());
17226}
17227
17228
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017229void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17230 v8::HandleScope scope(args.GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010017231 const char* origin = "capture-stack-trace-test";
17232 const int kOverviewTest = 1;
17233 const int kDetailedTest = 2;
17234
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017235 DCHECK(args.Length() == 1);
Kristian Monsen25f61362010-05-21 11:50:48 +010017236
17237 int testGroup = args[0]->Int32Value();
17238 if (testGroup == kOverviewTest) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017239 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17240 args.GetIsolate(), 10, v8::StackTrace::kOverview);
Kristian Monsen25f61362010-05-21 11:50:48 +010017241 CHECK_EQ(4, stackTrace->GetFrameCount());
17242 checkStackFrame(origin, "bar", 2, 10, false, false,
17243 stackTrace->GetFrame(0));
17244 checkStackFrame(origin, "foo", 6, 3, false, false,
17245 stackTrace->GetFrame(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017246 // This is the source string inside the eval which has the call to foo.
17247 checkStackFrame(NULL, "", 1, 5, false, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010017248 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017249 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010017250 checkStackFrame(origin, "", 8, 7, false, false,
17251 stackTrace->GetFrame(3));
17252
17253 CHECK(stackTrace->AsArray()->IsArray());
17254 } else if (testGroup == kDetailedTest) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017255 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17256 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
Kristian Monsen25f61362010-05-21 11:50:48 +010017257 CHECK_EQ(4, stackTrace->GetFrameCount());
17258 checkStackFrame(origin, "bat", 4, 22, false, false,
17259 stackTrace->GetFrame(0));
17260 checkStackFrame(origin, "baz", 8, 3, false, true,
17261 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010017262 bool is_eval = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017263 // This is the source string inside the eval which has the call to baz.
17264 checkStackFrame(NULL, "", 1, 5, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010017265 stackTrace->GetFrame(2));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017266 // The last frame is an anonymous function which has the initial eval call.
Kristian Monsen25f61362010-05-21 11:50:48 +010017267 checkStackFrame(origin, "", 10, 1, false, false,
17268 stackTrace->GetFrame(3));
17269
17270 CHECK(stackTrace->AsArray()->IsArray());
17271 }
Kristian Monsen25f61362010-05-21 11:50:48 +010017272}
17273
17274
17275// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010017276// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17277// THREADED_TEST(CaptureStackTrace) {
17278TEST(CaptureStackTrace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017279 v8::Isolate* isolate = CcTest::isolate();
17280 v8::HandleScope scope(isolate);
17281 v8::Handle<v8::String> origin =
17282 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17283 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Kristian Monsen25f61362010-05-21 11:50:48 +010017284 templ->Set(v8_str("AnalyzeStackInNativeCode"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017285 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
Kristian Monsen25f61362010-05-21 11:50:48 +010017286 LocalContext context(0, templ);
17287
17288 // Test getting OVERVIEW information. Should ignore information that is not
17289 // script name, function name, line number, and column offset.
17290 const char *overview_source =
17291 "function bar() {\n"
17292 " var y; AnalyzeStackInNativeCode(1);\n"
17293 "}\n"
17294 "function foo() {\n"
17295 "\n"
17296 " bar();\n"
17297 "}\n"
17298 "var x;eval('new foo();');";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017299 v8::Handle<v8::String> overview_src =
17300 v8::String::NewFromUtf8(isolate, overview_source);
17301 v8::ScriptCompiler::Source script_source(overview_src,
17302 v8::ScriptOrigin(origin));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017303 v8::Handle<Value> overview_result(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017304 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17305 ->BindToCurrentContext()
17306 ->Run());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017307 CHECK(!overview_result.IsEmpty());
17308 CHECK(overview_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010017309
17310 // Test getting DETAILED information.
17311 const char *detailed_source =
17312 "function bat() {AnalyzeStackInNativeCode(2);\n"
17313 "}\n"
17314 "\n"
17315 "function baz() {\n"
17316 " bat();\n"
17317 "}\n"
17318 "eval('new baz();');";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017319 v8::Handle<v8::String> detailed_src =
17320 v8::String::NewFromUtf8(isolate, detailed_source);
Kristian Monsen25f61362010-05-21 11:50:48 +010017321 // Make the script using a non-zero line and column offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017322 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17323 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
Kristian Monsen25f61362010-05-21 11:50:48 +010017324 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017325 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17326 v8::Handle<v8::UnboundScript> detailed_script(
17327 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17328 v8::Handle<Value> detailed_result(
17329 detailed_script->BindToCurrentContext()->Run());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017330 CHECK(!detailed_result.IsEmpty());
17331 CHECK(detailed_result->IsObject());
Kristian Monsen25f61362010-05-21 11:50:48 +010017332}
17333
17334
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017335static void StackTraceForUncaughtExceptionListener(
17336 v8::Handle<v8::Message> message,
17337 v8::Handle<Value>) {
17338 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17339 CHECK_EQ(2, stack_trace->GetFrameCount());
17340 checkStackFrame("origin", "foo", 2, 3, false, false,
17341 stack_trace->GetFrame(0));
17342 checkStackFrame("origin", "bar", 5, 3, false, false,
17343 stack_trace->GetFrame(1));
17344}
17345
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017346
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017347TEST(CaptureStackTraceForUncaughtException) {
17348 report_count = 0;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017349 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017350 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017351 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17352 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17353
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017354 CompileRunWithOrigin(
17355 "function foo() {\n"
17356 " throw 1;\n"
17357 "};\n"
17358 "function bar() {\n"
17359 " foo();\n"
17360 "};",
17361 "origin");
Ben Murdoch3bec4d22010-07-22 14:51:16 +010017362 v8::Local<v8::Object> global = env->Global();
17363 Local<Value> trouble = global->Get(v8_str("bar"));
17364 CHECK(trouble->IsFunction());
17365 Function::Cast(*trouble)->Call(global, 0, NULL);
17366 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17367 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17368}
17369
17370
Steve Block1e0659c2011-05-24 12:43:12 +010017371TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
Steve Block1e0659c2011-05-24 12:43:12 +010017372 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017373 v8::HandleScope scope(env->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010017374 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17375 1024,
17376 v8::StackTrace::kDetailed);
17377
17378 CompileRun(
17379 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17380 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17381 " 'isConstructor'];\n"
17382 "for (var i = 0; i < setters.length; i++) {\n"
17383 " var prop = setters[i];\n"
17384 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17385 "}\n");
17386 CompileRun("throw 'exception';");
17387 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17388}
17389
17390
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017391static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17392 v8::Handle<v8::Value> data) {
17393 // Use the frame where JavaScript is called from.
17394 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17395 CHECK(!stack_trace.IsEmpty());
17396 int frame_count = stack_trace->GetFrameCount();
17397 CHECK_EQ(3, frame_count);
17398 int line_number[] = {1, 2, 5};
17399 for (int i = 0; i < frame_count; i++) {
17400 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17401 }
17402}
17403
17404
17405// Test that we only return the stack trace at the site where the exception
17406// is first thrown (not where it is rethrown).
17407TEST(RethrowStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017408 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017409 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017410 // We make sure that
17411 // - the stack trace of the ReferenceError in g() is reported.
17412 // - the stack trace is not overwritten when e1 is rethrown by t().
17413 // - the stack trace of e2 does not overwrite that of e1.
17414 const char* source =
17415 "function g() { error; } \n"
17416 "function f() { g(); } \n"
17417 "function t(e) { throw e; } \n"
17418 "try { \n"
17419 " f(); \n"
17420 "} catch (e1) { \n"
17421 " try { \n"
17422 " error; \n"
17423 " } catch (e2) { \n"
17424 " t(e1); \n"
17425 " } \n"
17426 "} \n";
17427 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17428 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17429 CompileRun(source);
17430 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17431 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17432}
17433
17434
17435static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17436 v8::Handle<v8::Value> data) {
17437 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17438 CHECK(!stack_trace.IsEmpty());
17439 int frame_count = stack_trace->GetFrameCount();
17440 CHECK_EQ(2, frame_count);
17441 int line_number[] = {3, 7};
17442 for (int i = 0; i < frame_count; i++) {
17443 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17444 }
17445}
17446
17447
17448// Test that we do not recognize identity for primitive exceptions.
17449TEST(RethrowPrimitiveStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017450 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017451 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017452 // We do not capture stack trace for non Error objects on creation time.
17453 // Instead, we capture the stack trace on last throw.
17454 const char* source =
17455 "function g() { throw 404; } \n"
17456 "function f() { g(); } \n"
17457 "function t(e) { throw e; } \n"
17458 "try { \n"
17459 " f(); \n"
17460 "} catch (e1) { \n"
17461 " t(e1) \n"
17462 "} \n";
17463 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17464 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17465 CompileRun(source);
17466 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17467 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17468}
17469
17470
17471static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17472 v8::Handle<v8::Value> data) {
17473 // Use the frame where JavaScript is called from.
17474 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17475 CHECK(!stack_trace.IsEmpty());
17476 CHECK_EQ(1, stack_trace->GetFrameCount());
17477 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17478}
17479
17480
17481// Test that the stack trace is captured when the error object is created and
17482// not where it is thrown.
17483TEST(RethrowExistingStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017484 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017485 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017486 const char* source =
17487 "var e = new Error(); \n"
17488 "throw e; \n";
17489 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17490 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17491 CompileRun(source);
17492 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17493 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17494}
17495
17496
17497static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17498 v8::Handle<v8::Value> data) {
17499 // Use the frame where JavaScript is called from.
17500 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17501 CHECK(!stack_trace.IsEmpty());
17502 CHECK_EQ(1, stack_trace->GetFrameCount());
17503 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17504}
17505
17506
17507// Test that the stack trace is captured where the bogus Error object is thrown.
17508TEST(RethrowBogusErrorStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017509 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017510 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017511 const char* source =
17512 "var e = {__proto__: new Error()} \n"
17513 "throw e; \n";
17514 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17515 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17516 CompileRun(source);
17517 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17518 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17519}
17520
17521
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017522void AnalyzeStackOfEvalWithSourceURL(
17523 const v8::FunctionCallbackInfo<v8::Value>& args) {
17524 v8::HandleScope scope(args.GetIsolate());
17525 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17526 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
Ben Murdochf87a2032010-10-22 12:50:53 +010017527 CHECK_EQ(5, stackTrace->GetFrameCount());
17528 v8::Handle<v8::String> url = v8_str("eval_url");
17529 for (int i = 0; i < 3; i++) {
17530 v8::Handle<v8::String> name =
17531 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17532 CHECK(!name.IsEmpty());
17533 CHECK_EQ(url, name);
17534 }
Ben Murdochf87a2032010-10-22 12:50:53 +010017535}
17536
17537
17538TEST(SourceURLInStackTrace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017539 v8::Isolate* isolate = CcTest::isolate();
17540 v8::HandleScope scope(isolate);
17541 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +010017542 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017543 v8::FunctionTemplate::New(isolate,
17544 AnalyzeStackOfEvalWithSourceURL));
Ben Murdochf87a2032010-10-22 12:50:53 +010017545 LocalContext context(0, templ);
17546
17547 const char *source =
17548 "function outer() {\n"
17549 "function bar() {\n"
17550 " AnalyzeStackOfEvalWithSourceURL();\n"
17551 "}\n"
17552 "function foo() {\n"
17553 "\n"
17554 " bar();\n"
17555 "}\n"
17556 "foo();\n"
17557 "}\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017558 "eval('(' + outer +')()%s');";
17559
17560 i::ScopedVector<char> code(1024);
17561 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17562 CHECK(CompileRun(code.start())->IsUndefined());
17563 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17564 CHECK(CompileRun(code.start())->IsUndefined());
17565}
17566
17567
17568static int scriptIdInStack[2];
17569
17570void AnalyzeScriptIdInStack(
17571 const v8::FunctionCallbackInfo<v8::Value>& args) {
17572 v8::HandleScope scope(args.GetIsolate());
17573 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17574 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17575 CHECK_EQ(2, stackTrace->GetFrameCount());
17576 for (int i = 0; i < 2; i++) {
17577 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17578 }
17579}
17580
17581
17582TEST(ScriptIdInStackTrace) {
17583 v8::Isolate* isolate = CcTest::isolate();
17584 v8::HandleScope scope(isolate);
17585 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17586 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17587 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17588 LocalContext context(0, templ);
17589
17590 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17591 isolate,
17592 "function foo() {\n"
17593 " AnalyzeScriptIdInStack();"
17594 "}\n"
17595 "foo();\n");
17596 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17597 script->Run();
17598 for (int i = 0; i < 2; i++) {
17599 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17600 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17601 }
17602}
17603
17604
17605void AnalyzeStackOfInlineScriptWithSourceURL(
17606 const v8::FunctionCallbackInfo<v8::Value>& args) {
17607 v8::HandleScope scope(args.GetIsolate());
17608 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17609 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17610 CHECK_EQ(4, stackTrace->GetFrameCount());
17611 v8::Handle<v8::String> url = v8_str("url");
17612 for (int i = 0; i < 3; i++) {
17613 v8::Handle<v8::String> name =
17614 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17615 CHECK(!name.IsEmpty());
17616 CHECK_EQ(url, name);
17617 }
17618}
17619
17620
17621TEST(InlineScriptWithSourceURLInStackTrace) {
17622 v8::Isolate* isolate = CcTest::isolate();
17623 v8::HandleScope scope(isolate);
17624 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17625 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17626 v8::FunctionTemplate::New(
17627 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17628 LocalContext context(0, templ);
17629
17630 const char *source =
17631 "function outer() {\n"
17632 "function bar() {\n"
17633 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17634 "}\n"
17635 "function foo() {\n"
17636 "\n"
17637 " bar();\n"
17638 "}\n"
17639 "foo();\n"
17640 "}\n"
17641 "outer()\n%s";
17642
17643 i::ScopedVector<char> code(1024);
17644 i::SNPrintF(code, source, "//# sourceURL=source_url");
17645 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17646 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17647 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17648}
17649
17650
17651void AnalyzeStackOfDynamicScriptWithSourceURL(
17652 const v8::FunctionCallbackInfo<v8::Value>& args) {
17653 v8::HandleScope scope(args.GetIsolate());
17654 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17655 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17656 CHECK_EQ(4, stackTrace->GetFrameCount());
17657 v8::Handle<v8::String> url = v8_str("source_url");
17658 for (int i = 0; i < 3; i++) {
17659 v8::Handle<v8::String> name =
17660 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17661 CHECK(!name.IsEmpty());
17662 CHECK_EQ(url, name);
17663 }
17664}
17665
17666
17667TEST(DynamicWithSourceURLInStackTrace) {
17668 v8::Isolate* isolate = CcTest::isolate();
17669 v8::HandleScope scope(isolate);
17670 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17671 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17672 v8::FunctionTemplate::New(
17673 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17674 LocalContext context(0, templ);
17675
17676 const char *source =
17677 "function outer() {\n"
17678 "function bar() {\n"
17679 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17680 "}\n"
17681 "function foo() {\n"
17682 "\n"
17683 " bar();\n"
17684 "}\n"
17685 "foo();\n"
17686 "}\n"
17687 "outer()\n%s";
17688
17689 i::ScopedVector<char> code(1024);
17690 i::SNPrintF(code, source, "//# sourceURL=source_url");
17691 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17692 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17693 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17694}
17695
17696
17697TEST(DynamicWithSourceURLInStackTraceString) {
17698 LocalContext context;
17699 v8::HandleScope scope(context->GetIsolate());
17700
17701 const char *source =
17702 "function outer() {\n"
17703 " function foo() {\n"
17704 " FAIL.FAIL;\n"
17705 " }\n"
17706 " foo();\n"
17707 "}\n"
17708 "outer()\n%s";
17709
17710 i::ScopedVector<char> code(1024);
17711 i::SNPrintF(code, source, "//# sourceURL=source_url");
17712 v8::TryCatch try_catch;
17713 CompileRunWithOrigin(code.start(), "", 0, 0);
17714 CHECK(try_catch.HasCaught());
17715 v8::String::Utf8Value stack(try_catch.StackTrace());
17716 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17717}
17718
17719
17720TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17721 LocalContext context;
17722 v8::HandleScope scope(context->GetIsolate());
17723
17724 const char *source =
17725 "function outer() {\n"
17726 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17727 " //# sourceURL=source_url\";\n"
17728 " eval(scriptContents);\n"
17729 " foo(); }\n"
17730 "outer();\n"
17731 "//# sourceURL=outer_url";
17732
17733 v8::TryCatch try_catch;
17734 CompileRun(source);
17735 CHECK(try_catch.HasCaught());
17736
17737 Local<v8::Message> message = try_catch.Message();
17738 Handle<Value> sourceURL =
17739 message->GetScriptOrigin().ResourceName();
17740 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17741}
17742
17743
17744TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17745 LocalContext context;
17746 v8::HandleScope scope(context->GetIsolate());
17747
17748 const char *source =
17749 "function outer() {\n"
17750 " var scriptContents = \"function boo(){ boo(); }\\\n"
17751 " //# sourceURL=source_url\";\n"
17752 " eval(scriptContents);\n"
17753 " boo(); }\n"
17754 "outer();\n"
17755 "//# sourceURL=outer_url";
17756
17757 v8::TryCatch try_catch;
17758 CompileRun(source);
17759 CHECK(try_catch.HasCaught());
17760
17761 Local<v8::Message> message = try_catch.Message();
17762 Handle<Value> sourceURL =
17763 message->GetScriptOrigin().ResourceName();
17764 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17765}
17766
17767
17768static void CreateGarbageInOldSpace() {
17769 i::Factory* factory = CcTest::i_isolate()->factory();
17770 v8::HandleScope scope(CcTest::isolate());
17771 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17772 for (int i = 0; i < 1000; i++) {
17773 factory->NewFixedArray(1000, i::TENURED);
17774 }
Ben Murdochf87a2032010-10-22 12:50:53 +010017775}
17776
17777
Steve Block3ce2e202009-11-05 08:53:23 +000017778// Test that idle notification can be handled and eventually returns true.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017779TEST(IdleNotification) {
17780 const intptr_t MB = 1024 * 1024;
17781 const int IdlePauseInMs = 1000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017782 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017783 v8::HandleScope scope(env->GetIsolate());
17784 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17785 CreateGarbageInOldSpace();
17786 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17787 CHECK_GT(size_with_garbage, initial_size + MB);
17788 bool finished = false;
17789 for (int i = 0; i < 200 && !finished; i++) {
17790 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Steve Block3ce2e202009-11-05 08:53:23 +000017791 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017792 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17793 CHECK(finished);
17794 CHECK_LT(final_size, initial_size + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017795}
17796
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017797
17798// Test that idle notification can be handled and eventually collects garbage.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017799TEST(IdleNotificationWithSmallHint) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017800 const intptr_t MB = 1024 * 1024;
17801 const int IdlePauseInMs = 900;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017802 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017803 v8::HandleScope scope(env->GetIsolate());
17804 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17805 CreateGarbageInOldSpace();
17806 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17807 CHECK_GT(size_with_garbage, initial_size + MB);
17808 bool finished = false;
17809 for (int i = 0; i < 200 && !finished; i++) {
17810 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017811 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017812 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17813 CHECK(finished);
17814 CHECK_LT(final_size, initial_size + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017815}
17816
17817
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017818// Test that idle notification can be handled and eventually collects garbage.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017819TEST(IdleNotificationWithLargeHint) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017820 const intptr_t MB = 1024 * 1024;
17821 const int IdlePauseInMs = 900;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017822 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017823 v8::HandleScope scope(env->GetIsolate());
17824 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17825 CreateGarbageInOldSpace();
17826 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17827 CHECK_GT(size_with_garbage, initial_size + MB);
17828 bool finished = false;
17829 for (int i = 0; i < 200 && !finished; i++) {
17830 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017831 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017832 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17833 CHECK(finished);
17834 CHECK_LT(final_size, initial_size + 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +000017835}
17836
Steve Blocka7e24c12009-10-30 11:49:00 +000017837
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017838TEST(Regress2107) {
17839 const intptr_t MB = 1024 * 1024;
17840 const int kIdlePauseInMs = 1000;
17841 LocalContext env;
17842 v8::Isolate* isolate = env->GetIsolate();
17843 v8::HandleScope scope(env->GetIsolate());
17844 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17845 // Send idle notification to start a round of incremental GCs.
17846 env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17847 // Emulate 7 page reloads.
17848 for (int i = 0; i < 7; i++) {
17849 {
17850 v8::HandleScope inner_scope(env->GetIsolate());
17851 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17852 ctx->Enter();
17853 CreateGarbageInOldSpace();
17854 ctx->Exit();
17855 }
17856 env->GetIsolate()->ContextDisposedNotification();
17857 env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17858 }
17859 // Create garbage and check that idle notification still collects it.
17860 CreateGarbageInOldSpace();
17861 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17862 CHECK_GT(size_with_garbage, initial_size + MB);
17863 bool finished = false;
17864 for (int i = 0; i < 200 && !finished; i++) {
17865 finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17866 }
17867 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17868 CHECK_LT(final_size, initial_size + 1);
17869}
17870
17871
17872TEST(Regress2333) {
17873 LocalContext env;
17874 for (int i = 0; i < 3; i++) {
17875 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17876 }
17877}
17878
Steve Blocka7e24c12009-10-30 11:49:00 +000017879static uint32_t* stack_limit;
17880
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017881static void GetStackLimitCallback(
17882 const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Block44f0eee2011-05-26 01:26:41 +010017883 stack_limit = reinterpret_cast<uint32_t*>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017884 CcTest::i_isolate()->stack_guard()->real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000017885}
17886
17887
17888// Uses the address of a local variable to determine the stack top now.
17889// Given a size, returns an address that is that far from the current
17890// top of stack.
17891static uint32_t* ComputeStackLimit(uint32_t size) {
17892 uint32_t* answer = &size - (size / sizeof(size));
17893 // If the size is very large and the stack is very near the bottom of
17894 // memory then the calculation above may wrap around and give an address
17895 // that is above the (downwards-growing) stack. In that case we return
17896 // a very low address.
17897 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17898 return answer;
17899}
17900
17901
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017902// We need at least 165kB for an x64 debug build with clang and ASAN.
17903static const int stack_breathing_room = 256 * i::KB;
17904
17905
17906TEST(SetStackLimit) {
17907 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
Steve Blocka7e24c12009-10-30 11:49:00 +000017908
17909 // Set stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017910 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +000017911
17912 // Execute a script.
Steve Blocka7e24c12009-10-30 11:49:00 +000017913 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017914 v8::HandleScope scope(env->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017915 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017916 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000017917 Local<Function> fun = fun_templ->GetFunction();
17918 env->Global()->Set(v8_str("get_stack_limit"), fun);
17919 CompileRun("get_stack_limit();");
17920
17921 CHECK(stack_limit == set_limit);
17922}
17923
17924
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017925TEST(SetStackLimitInThread) {
Steve Blocka7e24c12009-10-30 11:49:00 +000017926 uint32_t* set_limit;
17927 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017928 v8::Locker locker(CcTest::isolate());
17929 set_limit = ComputeStackLimit(stack_breathing_room);
Steve Blocka7e24c12009-10-30 11:49:00 +000017930
17931 // Set stack limit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017932 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +000017933
17934 // Execute a script.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017935 v8::HandleScope scope(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017936 LocalContext env;
17937 Local<v8::FunctionTemplate> fun_templ =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017938 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
Steve Blocka7e24c12009-10-30 11:49:00 +000017939 Local<Function> fun = fun_templ->GetFunction();
17940 env->Global()->Set(v8_str("get_stack_limit"), fun);
17941 CompileRun("get_stack_limit();");
17942
17943 CHECK(stack_limit == set_limit);
17944 }
17945 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017946 v8::Locker locker(CcTest::isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000017947 CHECK(stack_limit == set_limit);
17948 }
17949}
Steve Block3ce2e202009-11-05 08:53:23 +000017950
17951
17952THREADED_TEST(GetHeapStatistics) {
Steve Block3ce2e202009-11-05 08:53:23 +000017953 LocalContext c1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017954 v8::HandleScope scope(c1->GetIsolate());
Steve Block3ce2e202009-11-05 08:53:23 +000017955 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000017956 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17957 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017958 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000017959 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17960 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17961}
17962
17963
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017964class VisitorImpl : public v8::ExternalResourceVisitor {
17965 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017966 explicit VisitorImpl(TestResource** resource) {
17967 for (int i = 0; i < 4; i++) {
17968 resource_[i] = resource[i];
17969 found_resource_[i] = false;
17970 }
17971 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017972 virtual ~VisitorImpl() {}
17973 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17974 if (!string->IsExternal()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017975 CHECK(string->IsExternalOneByte());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017976 return;
17977 }
17978 v8::String::ExternalStringResource* resource =
17979 string->GetExternalStringResource();
17980 CHECK(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017981 for (int i = 0; i < 4; i++) {
17982 if (resource_[i] == resource) {
17983 CHECK(!found_resource_[i]);
17984 found_resource_[i] = true;
17985 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017986 }
17987 }
17988 void CheckVisitedResources() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017989 for (int i = 0; i < 4; i++) {
17990 CHECK(found_resource_[i]);
17991 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017992 }
17993
17994 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017995 v8::String::ExternalStringResource* resource_[4];
17996 bool found_resource_[4];
Ben Murdoch3ef787d2012-04-12 10:51:47 +010017997};
17998
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017999
18000TEST(ExternalizeOldSpaceTwoByteCons) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018001 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018002 v8::HandleScope scope(env->GetIsolate());
18003 v8::Local<v8::String> cons =
18004 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18005 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18006 CcTest::heap()->CollectAllAvailableGarbage();
18007 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18008 *v8::Utils::OpenHandle(*cons)));
18009
18010 TestResource* resource = new TestResource(
18011 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18012 cons->MakeExternal(resource);
18013
18014 CHECK(cons->IsExternal());
18015 CHECK_EQ(resource, cons->GetExternalStringResource());
18016 String::Encoding encoding;
18017 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18018 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18019}
18020
18021
18022TEST(ExternalizeOldSpaceOneByteCons) {
18023 LocalContext env;
18024 v8::HandleScope scope(env->GetIsolate());
18025 v8::Local<v8::String> cons =
18026 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18027 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18028 CcTest::heap()->CollectAllAvailableGarbage();
18029 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18030 *v8::Utils::OpenHandle(*cons)));
18031
18032 TestOneByteResource* resource =
18033 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18034 cons->MakeExternal(resource);
18035
18036 CHECK(cons->IsExternalOneByte());
18037 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18038 String::Encoding encoding;
18039 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18040 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18041}
18042
18043
18044TEST(VisitExternalStrings) {
18045 LocalContext env;
18046 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018047 const char* string = "Some string";
18048 uint16_t* two_byte_string = AsciiToTwoByteString(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018049 TestResource* resource[4];
18050 resource[0] = new TestResource(two_byte_string);
18051 v8::Local<v8::String> string0 =
18052 v8::String::NewExternal(env->GetIsolate(), resource[0]);
18053 resource[1] = new TestResource(two_byte_string, NULL, false);
18054 v8::Local<v8::String> string1 =
18055 v8::String::NewExternal(env->GetIsolate(), resource[1]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018056
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018057 // Externalized symbol.
18058 resource[2] = new TestResource(two_byte_string, NULL, false);
18059 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18060 env->GetIsolate(), string, v8::String::kInternalizedString);
18061 CHECK(string2->MakeExternal(resource[2]));
18062
18063 // Symbolized External.
18064 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18065 v8::Local<v8::String> string3 =
18066 v8::String::NewExternal(env->GetIsolate(), resource[3]);
18067 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
18068 // Turn into a symbol.
18069 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18070 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18071 string3_i).is_null());
18072 CHECK(string3_i->IsInternalizedString());
18073
18074 // We need to add usages for string* to avoid warnings in GCC 4.7
18075 CHECK(string0->IsExternal());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018076 CHECK(string1->IsExternal());
18077 CHECK(string2->IsExternal());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018078 CHECK(string3->IsExternal());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018079
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018080 VisitorImpl visitor(resource);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018081 v8::V8::VisitExternalResources(&visitor);
18082 visitor.CheckVisitedResources();
18083}
18084
18085
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018086TEST(ExternalStringCollectedAtTearDown) {
18087 int destroyed = 0;
18088 v8::Isolate* isolate = v8::Isolate::New();
18089 { v8::Isolate::Scope isolate_scope(isolate);
18090 v8::HandleScope handle_scope(isolate);
18091 const char* s = "One string to test them all, one string to find them.";
18092 TestOneByteResource* inscription =
18093 new TestOneByteResource(i::StrDup(s), &destroyed);
18094 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18095 // Ring is still alive. Orcs are roaming freely across our lands.
18096 CHECK_EQ(0, destroyed);
18097 USE(ring);
18098 }
18099
18100 isolate->Dispose();
18101 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18102 CHECK_EQ(1, destroyed);
18103}
18104
18105
18106TEST(ExternalInternalizedStringCollectedAtTearDown) {
18107 int destroyed = 0;
18108 v8::Isolate* isolate = v8::Isolate::New();
18109 { v8::Isolate::Scope isolate_scope(isolate);
18110 LocalContext env(isolate);
18111 v8::HandleScope handle_scope(isolate);
18112 CompileRun("var ring = 'One string to test them all';");
18113 const char* s = "One string to test them all";
18114 TestOneByteResource* inscription =
18115 new TestOneByteResource(i::StrDup(s), &destroyed);
18116 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18117 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18118 ring->MakeExternal(inscription);
18119 // Ring is still alive. Orcs are roaming freely across our lands.
18120 CHECK_EQ(0, destroyed);
18121 USE(ring);
18122 }
18123
18124 isolate->Dispose();
18125 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18126 CHECK_EQ(1, destroyed);
18127}
18128
18129
18130TEST(ExternalInternalizedStringCollectedAtGC) {
18131 int destroyed = 0;
18132 { LocalContext env;
18133 v8::HandleScope handle_scope(env->GetIsolate());
18134 CompileRun("var ring = 'One string to test them all';");
18135 const char* s = "One string to test them all";
18136 TestOneByteResource* inscription =
18137 new TestOneByteResource(i::StrDup(s), &destroyed);
18138 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18139 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18140 ring->MakeExternal(inscription);
18141 // Ring is still alive. Orcs are roaming freely across our lands.
18142 CHECK_EQ(0, destroyed);
18143 USE(ring);
18144 }
18145
18146 // Garbage collector deals swift blows to evil.
18147 CcTest::i_isolate()->compilation_cache()->Clear();
18148 CcTest::heap()->CollectAllAvailableGarbage();
18149
18150 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18151 CHECK_EQ(1, destroyed);
18152}
18153
18154
Steve Blockd0582a62009-12-15 09:54:21 +000018155static double DoubleFromBits(uint64_t value) {
18156 double target;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018157 i::MemCopy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000018158 return target;
18159}
18160
18161
18162static uint64_t DoubleToBits(double value) {
18163 uint64_t target;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018164 i::MemCopy(&target, &value, sizeof(target));
Steve Blockd0582a62009-12-15 09:54:21 +000018165 return target;
18166}
18167
18168
18169static double DoubleToDateTime(double input) {
18170 double date_limit = 864e13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018171 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18172 return v8::base::OS::nan_value();
Steve Blockd0582a62009-12-15 09:54:21 +000018173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018174 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
Steve Blockd0582a62009-12-15 09:54:21 +000018175}
18176
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018177
Steve Blockd0582a62009-12-15 09:54:21 +000018178// We don't have a consistent way to write 64-bit constants syntactically, so we
18179// split them into two 32-bit constants and combine them programmatically.
18180static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18181 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18182}
18183
18184
18185THREADED_TEST(QuietSignalingNaNs) {
Steve Blockd0582a62009-12-15 09:54:21 +000018186 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018187 v8::Isolate* isolate = context->GetIsolate();
18188 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018189 v8::TryCatch try_catch;
18190
18191 // Special double values.
18192 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18193 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18194 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18195 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18196 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18197 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18198 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18199
18200 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18201 // on either side of the epoch.
18202 double date_limit = 864e13;
18203
18204 double test_values[] = {
18205 snan,
18206 qnan,
18207 infinity,
18208 max_normal,
18209 date_limit + 1,
18210 date_limit,
18211 min_normal,
18212 max_denormal,
18213 min_denormal,
18214 0,
18215 -0,
18216 -min_denormal,
18217 -max_denormal,
18218 -min_normal,
18219 -date_limit,
18220 -date_limit - 1,
18221 -max_normal,
18222 -infinity,
18223 -qnan,
18224 -snan
18225 };
18226 int num_test_values = 20;
18227
18228 for (int i = 0; i < num_test_values; i++) {
18229 double test_value = test_values[i];
18230
18231 // Check that Number::New preserves non-NaNs and quiets SNaNs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018232 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
Steve Blockd0582a62009-12-15 09:54:21 +000018233 double stored_number = number->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018234 if (!std::isnan(test_value)) {
Steve Blockd0582a62009-12-15 09:54:21 +000018235 CHECK_EQ(test_value, stored_number);
18236 } else {
18237 uint64_t stored_bits = DoubleToBits(stored_number);
18238 // Check if quiet nan (bits 51..62 all set).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018239#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18240 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018241 // Most significant fraction bit for quiet nan is set to 0
18242 // on MIPS architecture. Allowed by IEEE-754.
18243 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18244#else
Steve Blockd0582a62009-12-15 09:54:21 +000018245 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018246#endif
Steve Blockd0582a62009-12-15 09:54:21 +000018247 }
18248
18249 // Check that Date::New preserves non-NaNs in the date range and
18250 // quiets SNaNs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018251 v8::Handle<v8::Value> date =
18252 v8::Date::New(isolate, test_value);
Steve Blockd0582a62009-12-15 09:54:21 +000018253 double expected_stored_date = DoubleToDateTime(test_value);
18254 double stored_date = date->NumberValue();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018255 if (!std::isnan(expected_stored_date)) {
Steve Blockd0582a62009-12-15 09:54:21 +000018256 CHECK_EQ(expected_stored_date, stored_date);
18257 } else {
18258 uint64_t stored_bits = DoubleToBits(stored_date);
18259 // Check if quiet nan (bits 51..62 all set).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018260#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18261 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018262 // Most significant fraction bit for quiet nan is set to 0
18263 // on MIPS architecture. Allowed by IEEE-754.
18264 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18265#else
Steve Blockd0582a62009-12-15 09:54:21 +000018266 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018267#endif
Steve Blockd0582a62009-12-15 09:54:21 +000018268 }
18269 }
18270}
18271
18272
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018273static void SpaghettiIncident(
18274 const v8::FunctionCallbackInfo<v8::Value>& args) {
18275 v8::HandleScope scope(args.GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000018276 v8::TryCatch tc;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018277 v8::Handle<v8::String> str(args[0]->ToString());
18278 USE(str);
Steve Blockd0582a62009-12-15 09:54:21 +000018279 if (tc.HasCaught())
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018280 tc.ReThrow();
Steve Blockd0582a62009-12-15 09:54:21 +000018281}
18282
18283
18284// Test that an exception can be propagated down through a spaghetti
18285// stack using ReThrow.
18286THREADED_TEST(SpaghettiStackReThrow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018287 v8::Isolate* isolate = CcTest::isolate();
18288 v8::HandleScope scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018289 LocalContext context;
18290 context->Global()->Set(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018291 v8::String::NewFromUtf8(isolate, "s"),
18292 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
Steve Blockd0582a62009-12-15 09:54:21 +000018293 v8::TryCatch try_catch;
18294 CompileRun(
18295 "var i = 0;"
18296 "var o = {"
18297 " toString: function () {"
18298 " if (i == 10) {"
18299 " throw 'Hey!';"
18300 " } else {"
18301 " i++;"
18302 " return s(o);"
18303 " }"
18304 " }"
18305 "};"
18306 "s(o);");
18307 CHECK(try_catch.HasCaught());
18308 v8::String::Utf8Value value(try_catch.Exception());
18309 CHECK_EQ(0, strcmp(*value, "Hey!"));
18310}
18311
18312
Steve Blockd0582a62009-12-15 09:54:21 +000018313TEST(Regress528) {
18314 v8::V8::Initialize();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018315 v8::Isolate* isolate = CcTest::isolate();
18316 v8::HandleScope scope(isolate);
18317 v8::Local<Context> other_context;
Steve Blockd0582a62009-12-15 09:54:21 +000018318 int gc_count;
18319
18320 // Create a context used to keep the code from aging in the compilation
18321 // cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018322 other_context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018323
18324 // Context-dependent context data creates reference from the compilation
18325 // cache to the global object.
18326 const char* source_simple = "1";
Steve Blockd0582a62009-12-15 09:54:21 +000018327 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018328 v8::HandleScope scope(isolate);
18329 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018330
18331 context->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018332 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18333 context->SetEmbedderData(0, obj);
Steve Blockd0582a62009-12-15 09:54:21 +000018334 CompileRun(source_simple);
18335 context->Exit();
18336 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018337 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000018338 for (gc_count = 1; gc_count < 10; gc_count++) {
18339 other_context->Enter();
18340 CompileRun(source_simple);
18341 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018342 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000018343 if (GetGlobalObjectsCount() == 1) break;
18344 }
18345 CHECK_GE(2, gc_count);
18346 CHECK_EQ(1, GetGlobalObjectsCount());
18347
18348 // Eval in a function creates reference from the compilation cache to the
18349 // global object.
18350 const char* source_eval = "function f(){eval('1')}; f()";
Steve Blockd0582a62009-12-15 09:54:21 +000018351 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018352 v8::HandleScope scope(isolate);
18353 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018354
18355 context->Enter();
18356 CompileRun(source_eval);
18357 context->Exit();
18358 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018359 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000018360 for (gc_count = 1; gc_count < 10; gc_count++) {
18361 other_context->Enter();
18362 CompileRun(source_eval);
18363 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018364 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000018365 if (GetGlobalObjectsCount() == 1) break;
18366 }
18367 CHECK_GE(2, gc_count);
18368 CHECK_EQ(1, GetGlobalObjectsCount());
18369
18370 // Looking up the line number for an exception creates reference from the
18371 // compilation cache to the global object.
18372 const char* source_exception = "function f(){throw 1;} f()";
Steve Blockd0582a62009-12-15 09:54:21 +000018373 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018374 v8::HandleScope scope(isolate);
18375 v8::Local<Context> context = Context::New(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000018376
18377 context->Enter();
18378 v8::TryCatch try_catch;
18379 CompileRun(source_exception);
18380 CHECK(try_catch.HasCaught());
18381 v8::Handle<v8::Message> message = try_catch.Message();
18382 CHECK(!message.IsEmpty());
18383 CHECK_EQ(1, message->GetLineNumber());
18384 context->Exit();
18385 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018386 isolate->ContextDisposedNotification();
Steve Blockd0582a62009-12-15 09:54:21 +000018387 for (gc_count = 1; gc_count < 10; gc_count++) {
18388 other_context->Enter();
18389 CompileRun(source_exception);
18390 other_context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018391 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Blockd0582a62009-12-15 09:54:21 +000018392 if (GetGlobalObjectsCount() == 1) break;
18393 }
18394 CHECK_GE(2, gc_count);
18395 CHECK_EQ(1, GetGlobalObjectsCount());
18396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018397 isolate->ContextDisposedNotification();
Steve Block3ce2e202009-11-05 08:53:23 +000018398}
Andrei Popescu402d9372010-02-26 13:31:12 +000018399
18400
18401THREADED_TEST(ScriptOrigin) {
Andrei Popescu402d9372010-02-26 13:31:12 +000018402 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018403 v8::HandleScope scope(env->GetIsolate());
18404 v8::ScriptOrigin origin =
18405 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18406 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18407 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
Andrei Popescu402d9372010-02-26 13:31:12 +000018408 v8::Script::Compile(script, &origin)->Run();
18409 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018410 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
Andrei Popescu402d9372010-02-26 13:31:12 +000018411 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018412 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
Andrei Popescu402d9372010-02-26 13:31:12 +000018413
18414 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018415 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
Andrei Popescu402d9372010-02-26 13:31:12 +000018416 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18417
18418 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018419 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
Andrei Popescu402d9372010-02-26 13:31:12 +000018420 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18421}
18422
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018423
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018424THREADED_TEST(FunctionGetInferredName) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018425 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018426 v8::HandleScope scope(env->GetIsolate());
18427 v8::ScriptOrigin origin =
18428 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18429 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18430 env->GetIsolate(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018431 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18432 v8::Script::Compile(script, &origin)->Run();
18433 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018434 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18435 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018436}
Andrei Popescu402d9372010-02-26 13:31:12 +000018437
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018438
18439THREADED_TEST(FunctionGetDisplayName) {
Andrei Popescu402d9372010-02-26 13:31:12 +000018440 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018441 v8::HandleScope scope(env->GetIsolate());
18442 const char* code = "var error = false;"
18443 "function a() { this.x = 1; };"
18444 "a.displayName = 'display_a';"
18445 "var b = (function() {"
18446 " var f = function() { this.x = 2; };"
18447 " f.displayName = 'display_b';"
18448 " return f;"
18449 "})();"
18450 "var c = function() {};"
18451 "c.__defineGetter__('displayName', function() {"
18452 " error = true;"
18453 " throw new Error();"
18454 "});"
18455 "function d() {};"
18456 "d.__defineGetter__('displayName', function() {"
18457 " error = true;"
18458 " return 'wrong_display_name';"
18459 "});"
18460 "function e() {};"
18461 "e.displayName = 'wrong_display_name';"
18462 "e.__defineSetter__('displayName', function() {"
18463 " error = true;"
18464 " throw new Error();"
18465 "});"
18466 "function f() {};"
18467 "f.displayName = { 'foo': 6, toString: function() {"
18468 " error = true;"
18469 " return 'wrong_display_name';"
18470 "}};"
18471 "var g = function() {"
18472 " arguments.callee.displayName = 'set_in_runtime';"
18473 "}; g();"
18474 ;
18475 v8::ScriptOrigin origin =
18476 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18477 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18478 ->Run();
18479 v8::Local<v8::Value> error =
18480 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18481 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18482 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18483 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18484 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18485 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18486 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18487 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18488 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18489 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18490 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18491 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18492 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18493 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18494 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18495 CHECK_EQ(false, error->BooleanValue());
18496 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18497 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18498 CHECK(c->GetDisplayName()->IsUndefined());
18499 CHECK(d->GetDisplayName()->IsUndefined());
18500 CHECK(e->GetDisplayName()->IsUndefined());
18501 CHECK(f->GetDisplayName()->IsUndefined());
18502 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18503}
18504
18505
18506THREADED_TEST(ScriptLineNumber) {
18507 LocalContext env;
18508 v8::HandleScope scope(env->GetIsolate());
18509 v8::ScriptOrigin origin =
18510 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18511 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18512 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
Andrei Popescu402d9372010-02-26 13:31:12 +000018513 v8::Script::Compile(script, &origin)->Run();
18514 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018515 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
Andrei Popescu402d9372010-02-26 13:31:12 +000018516 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018517 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
Andrei Popescu402d9372010-02-26 13:31:12 +000018518 CHECK_EQ(0, f->GetScriptLineNumber());
18519 CHECK_EQ(2, g->GetScriptLineNumber());
18520}
18521
18522
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018523THREADED_TEST(ScriptColumnNumber) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018524 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018525 v8::Isolate* isolate = env->GetIsolate();
18526 v8::HandleScope scope(isolate);
18527 v8::ScriptOrigin origin =
18528 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18529 v8::Integer::New(isolate, 3),
18530 v8::Integer::New(isolate, 2));
18531 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18532 isolate, "function foo() {}\n\n function bar() {}");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018533 v8::Script::Compile(script, &origin)->Run();
18534 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018535 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018536 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018537 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018538 CHECK_EQ(14, foo->GetScriptColumnNumber());
18539 CHECK_EQ(17, bar->GetScriptColumnNumber());
18540}
18541
18542
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018543THREADED_TEST(FunctionIsBuiltin) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018544 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018545 v8::Isolate* isolate = env->GetIsolate();
18546 v8::HandleScope scope(isolate);
18547 v8::Local<v8::Function> f;
18548 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18549 CHECK(f->IsBuiltin());
18550 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18551 CHECK(f->IsBuiltin());
18552 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18553 CHECK(f->IsBuiltin());
18554 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18555 CHECK(f->IsBuiltin());
18556 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18557 CHECK(!f->IsBuiltin());
18558}
18559
18560
18561THREADED_TEST(FunctionGetScriptId) {
18562 LocalContext env;
18563 v8::Isolate* isolate = env->GetIsolate();
18564 v8::HandleScope scope(isolate);
18565 v8::ScriptOrigin origin =
18566 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18567 v8::Integer::New(isolate, 3),
18568 v8::Integer::New(isolate, 2));
18569 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18570 isolate, "function foo() {}\n\n function bar() {}");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018571 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18572 script->Run();
18573 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018574 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018575 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018576 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18577 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18578 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010018579}
18580
18581
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018582THREADED_TEST(FunctionGetBoundFunction) {
18583 LocalContext env;
18584 v8::HandleScope scope(env->GetIsolate());
18585 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18586 env->GetIsolate(), "test"));
18587 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18588 env->GetIsolate(),
18589 "var a = new Object();\n"
18590 "a.x = 1;\n"
18591 "function f () { return this.x };\n"
18592 "var g = f.bind(a);\n"
18593 "var b = g();");
18594 v8::Script::Compile(script, &origin)->Run();
18595 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18596 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18597 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18598 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18599 CHECK(g->GetBoundFunction()->IsFunction());
18600 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18601 g->GetBoundFunction());
18602 CHECK_EQ(f->GetName(), original_function->GetName());
18603 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18604 CHECK_EQ(f->GetScriptColumnNumber(),
18605 original_function->GetScriptColumnNumber());
Andrei Popescu402d9372010-02-26 13:31:12 +000018606}
18607
18608
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018609static void GetterWhichReturns42(
18610 Local<String> name,
18611 const v8::PropertyCallbackInfo<v8::Value>& info) {
18612 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18613 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18614 info.GetReturnValue().Set(v8_num(42));
18615}
18616
18617
18618static void SetterWhichSetsYOnThisTo23(
18619 Local<String> name,
18620 Local<Value> value,
18621 const v8::PropertyCallbackInfo<void>& info) {
18622 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18623 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18624 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18625}
18626
18627
18628void FooGetInterceptor(Local<String> name,
18629 const v8::PropertyCallbackInfo<v8::Value>& info) {
18630 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18631 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18632 if (!name->Equals(v8_str("foo"))) return;
18633 info.GetReturnValue().Set(v8_num(42));
18634}
18635
18636
18637void FooSetInterceptor(Local<String> name,
18638 Local<Value> value,
18639 const v8::PropertyCallbackInfo<v8::Value>& info) {
18640 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18641 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18642 if (!name->Equals(v8_str("foo"))) return;
18643 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18644 info.GetReturnValue().Set(v8_num(23));
Andrei Popescu402d9372010-02-26 13:31:12 +000018645}
18646
18647
Steve Block6ded16b2010-05-10 14:33:55 +010018648TEST(SetterOnConstructorPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018649 v8::Isolate* isolate = CcTest::isolate();
18650 v8::HandleScope scope(isolate);
18651 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18652 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
Andrei Popescu402d9372010-02-26 13:31:12 +000018653 SetterWhichSetsYOnThisTo23);
18654 LocalContext context;
18655 context->Global()->Set(v8_str("P"), templ->NewInstance());
18656 CompileRun("function C1() {"
18657 " this.x = 23;"
18658 "};"
18659 "C1.prototype = P;"
18660 "function C2() {"
18661 " this.x = 23"
18662 "};"
18663 "C2.prototype = { };"
18664 "C2.prototype.__proto__ = P;");
18665
18666 v8::Local<v8::Script> script;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018667 script = v8_compile("new C1();");
Andrei Popescu402d9372010-02-26 13:31:12 +000018668 for (int i = 0; i < 10; i++) {
18669 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18670 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18671 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18672 }
18673
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018674script = v8_compile("new C2();");
Andrei Popescu402d9372010-02-26 13:31:12 +000018675 for (int i = 0; i < 10; i++) {
18676 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18677 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18678 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18679 }
18680}
18681
18682
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018683static void NamedPropertyGetterWhichReturns42(
18684 Local<String> name,
18685 const v8::PropertyCallbackInfo<v8::Value>& info) {
18686 info.GetReturnValue().Set(v8_num(42));
Andrei Popescu402d9372010-02-26 13:31:12 +000018687}
18688
18689
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018690static void NamedPropertySetterWhichSetsYOnThisTo23(
18691 Local<String> name,
18692 Local<Value> value,
18693 const v8::PropertyCallbackInfo<v8::Value>& info) {
Andrei Popescu402d9372010-02-26 13:31:12 +000018694 if (name->Equals(v8_str("x"))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018695 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
Andrei Popescu402d9372010-02-26 13:31:12 +000018696 }
Andrei Popescu402d9372010-02-26 13:31:12 +000018697}
18698
18699
18700THREADED_TEST(InterceptorOnConstructorPrototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018701 v8::Isolate* isolate = CcTest::isolate();
18702 v8::HandleScope scope(isolate);
18703 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +000018704 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18705 NamedPropertySetterWhichSetsYOnThisTo23);
18706 LocalContext context;
18707 context->Global()->Set(v8_str("P"), templ->NewInstance());
18708 CompileRun("function C1() {"
18709 " this.x = 23;"
18710 "};"
18711 "C1.prototype = P;"
18712 "function C2() {"
18713 " this.x = 23"
18714 "};"
18715 "C2.prototype = { };"
18716 "C2.prototype.__proto__ = P;");
18717
18718 v8::Local<v8::Script> script;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018719 script = v8_compile("new C1();");
Andrei Popescu402d9372010-02-26 13:31:12 +000018720 for (int i = 0; i < 10; i++) {
18721 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18722 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18723 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18724 }
18725
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018726 script = v8_compile("new C2();");
Andrei Popescu402d9372010-02-26 13:31:12 +000018727 for (int i = 0; i < 10; i++) {
18728 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18729 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18730 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18731 }
18732}
Steve Block6ded16b2010-05-10 14:33:55 +010018733
18734
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018735TEST(Regress618) {
Steve Block6ded16b2010-05-10 14:33:55 +010018736 const char* source = "function C1() {"
18737 " this.x = 23;"
18738 "};"
18739 "C1.prototype = P;";
18740
Steve Block6ded16b2010-05-10 14:33:55 +010018741 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018742 v8::Isolate* isolate = context->GetIsolate();
18743 v8::HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010018744 v8::Local<v8::Script> script;
18745
18746 // Use a simple object as prototype.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018747 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010018748 prototype->Set(v8_str("y"), v8_num(42));
18749 context->Global()->Set(v8_str("P"), prototype);
18750
18751 // This compile will add the code to the compilation cache.
18752 CompileRun(source);
18753
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018754 script = v8_compile("new C1();");
Kristian Monsen0d5e1162010-09-30 15:31:59 +010018755 // Allow enough iterations for the inobject slack tracking logic
18756 // to finalize instance size and install the fast construct stub.
18757 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010018758 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18759 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18760 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18761 }
18762
18763 // Use an API object with accessors as prototype.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18765 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
Steve Block6ded16b2010-05-10 14:33:55 +010018766 SetterWhichSetsYOnThisTo23);
18767 context->Global()->Set(v8_str("P"), templ->NewInstance());
18768
18769 // This compile will get the code from the compilation cache.
18770 CompileRun(source);
18771
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018772 script = v8_compile("new C1();");
Steve Block6ded16b2010-05-10 14:33:55 +010018773 for (int i = 0; i < 10; i++) {
18774 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18775 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18776 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18777 }
18778}
18779
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018780v8::Isolate* gc_callbacks_isolate = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +010018781int prologue_call_count = 0;
18782int epilogue_call_count = 0;
18783int prologue_call_count_second = 0;
18784int epilogue_call_count_second = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018785int prologue_call_count_alloc = 0;
18786int epilogue_call_count_alloc = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010018787
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018788void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18789 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018790 ++prologue_call_count;
18791}
18792
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018793
18794void PrologueCallback(v8::Isolate* isolate,
18795 v8::GCType,
18796 v8::GCCallbackFlags flags) {
18797 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18798 CHECK_EQ(gc_callbacks_isolate, isolate);
18799 ++prologue_call_count;
18800}
18801
18802
18803void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18804 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018805 ++epilogue_call_count;
18806}
18807
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018808
18809void EpilogueCallback(v8::Isolate* isolate,
18810 v8::GCType,
18811 v8::GCCallbackFlags flags) {
18812 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18813 CHECK_EQ(gc_callbacks_isolate, isolate);
18814 ++epilogue_call_count;
18815}
18816
18817
18818void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18819 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018820 ++prologue_call_count_second;
18821}
18822
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018823
18824void PrologueCallbackSecond(v8::Isolate* isolate,
18825 v8::GCType,
18826 v8::GCCallbackFlags flags) {
18827 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18828 CHECK_EQ(gc_callbacks_isolate, isolate);
18829 ++prologue_call_count_second;
18830}
18831
18832
18833void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18834 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018835 ++epilogue_call_count_second;
18836}
18837
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018838
18839void EpilogueCallbackSecond(v8::Isolate* isolate,
18840 v8::GCType,
18841 v8::GCCallbackFlags flags) {
18842 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18843 CHECK_EQ(gc_callbacks_isolate, isolate);
18844 ++epilogue_call_count_second;
18845}
18846
18847
18848void PrologueCallbackAlloc(v8::Isolate* isolate,
18849 v8::GCType,
18850 v8::GCCallbackFlags flags) {
18851 v8::HandleScope scope(isolate);
18852
18853 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18854 CHECK_EQ(gc_callbacks_isolate, isolate);
18855 ++prologue_call_count_alloc;
18856
18857 // Simulate full heap to see if we will reenter this callback
18858 SimulateFullSpace(CcTest::heap()->new_space());
18859
18860 Local<Object> obj = Object::New(isolate);
18861 CHECK(!obj.IsEmpty());
18862
18863 CcTest::heap()->CollectAllGarbage(
18864 i::Heap::kAbortIncrementalMarkingMask);
18865}
18866
18867
18868void EpilogueCallbackAlloc(v8::Isolate* isolate,
18869 v8::GCType,
18870 v8::GCCallbackFlags flags) {
18871 v8::HandleScope scope(isolate);
18872
18873 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18874 CHECK_EQ(gc_callbacks_isolate, isolate);
18875 ++epilogue_call_count_alloc;
18876
18877 // Simulate full heap to see if we will reenter this callback
18878 SimulateFullSpace(CcTest::heap()->new_space());
18879
18880 Local<Object> obj = Object::New(isolate);
18881 CHECK(!obj.IsEmpty());
18882
18883 CcTest::heap()->CollectAllGarbage(
18884 i::Heap::kAbortIncrementalMarkingMask);
18885}
18886
18887
18888TEST(GCCallbacksOld) {
Steve Block6ded16b2010-05-10 14:33:55 +010018889 LocalContext context;
18890
18891 v8::V8::AddGCPrologueCallback(PrologueCallback);
18892 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18893 CHECK_EQ(0, prologue_call_count);
18894 CHECK_EQ(0, epilogue_call_count);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018895 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018896 CHECK_EQ(1, prologue_call_count);
18897 CHECK_EQ(1, epilogue_call_count);
18898 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18899 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018900 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018901 CHECK_EQ(2, prologue_call_count);
18902 CHECK_EQ(2, epilogue_call_count);
18903 CHECK_EQ(1, prologue_call_count_second);
18904 CHECK_EQ(1, epilogue_call_count_second);
18905 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18906 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018907 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018908 CHECK_EQ(2, prologue_call_count);
18909 CHECK_EQ(2, epilogue_call_count);
18910 CHECK_EQ(2, prologue_call_count_second);
18911 CHECK_EQ(2, epilogue_call_count_second);
18912 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18913 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018914 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Steve Block6ded16b2010-05-10 14:33:55 +010018915 CHECK_EQ(2, prologue_call_count);
18916 CHECK_EQ(2, epilogue_call_count);
18917 CHECK_EQ(2, prologue_call_count_second);
18918 CHECK_EQ(2, epilogue_call_count_second);
18919}
Kristian Monsen25f61362010-05-21 11:50:48 +010018920
18921
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018922TEST(GCCallbacks) {
18923 LocalContext context;
18924 v8::Isolate* isolate = context->GetIsolate();
18925 gc_callbacks_isolate = isolate;
18926 isolate->AddGCPrologueCallback(PrologueCallback);
18927 isolate->AddGCEpilogueCallback(EpilogueCallback);
18928 CHECK_EQ(0, prologue_call_count);
18929 CHECK_EQ(0, epilogue_call_count);
18930 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18931 CHECK_EQ(1, prologue_call_count);
18932 CHECK_EQ(1, epilogue_call_count);
18933 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18934 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18935 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18936 CHECK_EQ(2, prologue_call_count);
18937 CHECK_EQ(2, epilogue_call_count);
18938 CHECK_EQ(1, prologue_call_count_second);
18939 CHECK_EQ(1, epilogue_call_count_second);
18940 isolate->RemoveGCPrologueCallback(PrologueCallback);
18941 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18942 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18943 CHECK_EQ(2, prologue_call_count);
18944 CHECK_EQ(2, epilogue_call_count);
18945 CHECK_EQ(2, prologue_call_count_second);
18946 CHECK_EQ(2, epilogue_call_count_second);
18947 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18948 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18949 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18950 CHECK_EQ(2, prologue_call_count);
18951 CHECK_EQ(2, epilogue_call_count);
18952 CHECK_EQ(2, prologue_call_count_second);
18953 CHECK_EQ(2, epilogue_call_count_second);
18954
18955 CHECK_EQ(0, prologue_call_count_alloc);
18956 CHECK_EQ(0, epilogue_call_count_alloc);
18957 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18958 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18959 CcTest::heap()->CollectAllGarbage(
18960 i::Heap::kAbortIncrementalMarkingMask);
18961 CHECK_EQ(1, prologue_call_count_alloc);
18962 CHECK_EQ(1, epilogue_call_count_alloc);
18963 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18964 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18965}
18966
18967
Kristian Monsen25f61362010-05-21 11:50:48 +010018968THREADED_TEST(AddToJSFunctionResultCache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018969 i::FLAG_stress_compaction = false;
Kristian Monsen25f61362010-05-21 11:50:48 +010018970 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018971 v8::HandleScope scope(CcTest::isolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010018972
18973 LocalContext context;
18974
18975 const char* code =
18976 "(function() {"
18977 " var key0 = 'a';"
18978 " var key1 = 'b';"
18979 " var r0 = %_GetFromCache(0, key0);"
18980 " var r1 = %_GetFromCache(0, key1);"
18981 " var r0_ = %_GetFromCache(0, key0);"
18982 " if (r0 !== r0_)"
18983 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18984 " var r1_ = %_GetFromCache(0, key1);"
18985 " if (r1 !== r1_)"
18986 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18987 " return 'PASSED';"
18988 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018989 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010018990 ExpectString(code, "PASSED");
18991}
18992
18993
Kristian Monsen25f61362010-05-21 11:50:48 +010018994THREADED_TEST(FillJSFunctionResultCache) {
18995 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010018996 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018997 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010018998
18999 const char* code =
19000 "(function() {"
19001 " var k = 'a';"
19002 " var r = %_GetFromCache(0, k);"
19003 " for (var i = 0; i < 16; i++) {"
19004 " %_GetFromCache(0, 'a' + i);"
19005 " };"
19006 " if (r === %_GetFromCache(0, k))"
19007 " return 'FAILED: k0CacheSize is too small';"
19008 " return 'PASSED';"
19009 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019010 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010019011 ExpectString(code, "PASSED");
19012}
19013
19014
19015THREADED_TEST(RoundRobinGetFromCache) {
19016 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010019017 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019018 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010019019
19020 const char* code =
19021 "(function() {"
19022 " var keys = [];"
19023 " for (var i = 0; i < 16; i++) keys.push(i);"
19024 " var values = [];"
19025 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19026 " for (var i = 0; i < 16; i++) {"
19027 " var v = %_GetFromCache(0, keys[i]);"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019028 " if (v.toString() !== values[i].toString())"
Kristian Monsen25f61362010-05-21 11:50:48 +010019029 " return 'Wrong value for ' + "
19030 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19031 " };"
19032 " return 'PASSED';"
19033 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019034 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010019035 ExpectString(code, "PASSED");
19036}
19037
19038
19039THREADED_TEST(ReverseGetFromCache) {
19040 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010019041 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019042 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010019043
19044 const char* code =
19045 "(function() {"
19046 " var keys = [];"
19047 " for (var i = 0; i < 16; i++) keys.push(i);"
19048 " var values = [];"
19049 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19050 " for (var i = 15; i >= 16; i--) {"
19051 " var v = %_GetFromCache(0, keys[i]);"
19052 " if (v !== values[i])"
19053 " return 'Wrong value for ' + "
19054 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19055 " };"
19056 " return 'PASSED';"
19057 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019058 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010019059 ExpectString(code, "PASSED");
19060}
19061
19062
19063THREADED_TEST(TestEviction) {
19064 i::FLAG_allow_natives_syntax = true;
Kristian Monsen25f61362010-05-21 11:50:48 +010019065 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019066 v8::HandleScope scope(context->GetIsolate());
Kristian Monsen25f61362010-05-21 11:50:48 +010019067
19068 const char* code =
19069 "(function() {"
19070 " for (var i = 0; i < 2*16; i++) {"
19071 " %_GetFromCache(0, 'a' + i);"
19072 " };"
19073 " return 'PASSED';"
19074 "})()";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019075 CcTest::heap()->ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010019076 ExpectString(code, "PASSED");
19077}
Steve Block8defd9f2010-07-08 12:39:36 +010019078
19079
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019080THREADED_TEST(TwoByteStringInOneByteCons) {
Steve Block8defd9f2010-07-08 12:39:36 +010019081 // See Chromium issue 47824.
Steve Block8defd9f2010-07-08 12:39:36 +010019082 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019083 v8::HandleScope scope(context->GetIsolate());
19084
Steve Block8defd9f2010-07-08 12:39:36 +010019085 const char* init_code =
19086 "var str1 = 'abelspendabel';"
19087 "var str2 = str1 + str1 + str1;"
19088 "str2;";
19089 Local<Value> result = CompileRun(init_code);
19090
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019091 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19092 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19093
Steve Block8defd9f2010-07-08 12:39:36 +010019094 CHECK(result->IsString());
19095 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19096 int length = string->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019097 CHECK(string->IsOneByteRepresentation());
Steve Block8defd9f2010-07-08 12:39:36 +010019098
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019099 i::Handle<i::String> flat_string = i::String::Flatten(string);
Steve Block8defd9f2010-07-08 12:39:36 +010019100
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019101 CHECK(string->IsOneByteRepresentation());
19102 CHECK(flat_string->IsOneByteRepresentation());
Steve Block8defd9f2010-07-08 12:39:36 +010019103
19104 // Create external resource.
19105 uint16_t* uc16_buffer = new uint16_t[length + 1];
19106
19107 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19108 uc16_buffer[length] = 0;
19109
19110 TestResource resource(uc16_buffer);
19111
19112 flat_string->MakeExternal(&resource);
19113
19114 CHECK(flat_string->IsTwoByteRepresentation());
19115
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019116 // If the cons string has been short-circuited, skip the following checks.
19117 if (!string.is_identical_to(flat_string)) {
19118 // At this point, we should have a Cons string which is flat and one-byte,
19119 // with a first half that is a two-byte string (although it only contains
19120 // one-byte characters). This is a valid sequence of steps, and it can
19121 // happen in real pages.
19122 CHECK(string->IsOneByteRepresentation());
19123 i::ConsString* cons = i::ConsString::cast(*string);
19124 CHECK_EQ(0, cons->second()->length());
19125 CHECK(cons->first()->IsTwoByteRepresentation());
19126 }
Steve Block8defd9f2010-07-08 12:39:36 +010019127
19128 // Check that some string operations work.
19129
19130 // Atom RegExp.
19131 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19132 CHECK_EQ(6, reresult->Int32Value());
19133
19134 // Nonatom RegExp.
19135 reresult = CompileRun("str2.match(/abe./g).length;");
19136 CHECK_EQ(6, reresult->Int32Value());
19137
19138 reresult = CompileRun("str2.search(/bel/g);");
19139 CHECK_EQ(1, reresult->Int32Value());
19140
19141 reresult = CompileRun("str2.search(/be./g);");
19142 CHECK_EQ(1, reresult->Int32Value());
19143
19144 ExpectTrue("/bel/g.test(str2);");
19145
19146 ExpectTrue("/be./g.test(str2);");
19147
19148 reresult = CompileRun("/bel/g.exec(str2);");
19149 CHECK(!reresult->IsNull());
19150
19151 reresult = CompileRun("/be./g.exec(str2);");
19152 CHECK(!reresult->IsNull());
19153
19154 ExpectString("str2.substring(2, 10);", "elspenda");
19155
19156 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19157
19158 ExpectString("str2.charAt(2);", "e");
19159
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019160 ExpectObject("str2.indexOf('els');", indexof);
19161
19162 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19163
Steve Block8defd9f2010-07-08 12:39:36 +010019164 reresult = CompileRun("str2.charCodeAt(2);");
19165 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19166}
Iain Merrick75681382010-08-19 15:07:18 +010019167
19168
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019169TEST(ContainsOnlyOneByte) {
19170 v8::V8::Initialize();
19171 v8::Isolate* isolate = CcTest::isolate();
19172 v8::HandleScope scope(isolate);
19173 // Make a buffer long enough that it won't automatically be converted.
19174 const int length = 512;
19175 // Ensure word aligned assignment.
19176 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19177 i::SmartArrayPointer<uintptr_t>
19178 aligned_contents(new uintptr_t[aligned_length]);
19179 uint16_t* string_contents =
19180 reinterpret_cast<uint16_t*>(aligned_contents.get());
19181 // Set to contain only one byte.
19182 for (int i = 0; i < length-1; i++) {
19183 string_contents[i] = 0x41;
19184 }
19185 string_contents[length-1] = 0;
19186 // Simple case.
19187 Handle<String> string =
19188 String::NewExternal(isolate,
19189 new TestResource(string_contents, NULL, false));
19190 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19191 // Counter example.
19192 string = String::NewFromTwoByte(isolate, string_contents);
19193 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19194 // Test left right and balanced cons strings.
19195 Handle<String> base = String::NewFromUtf8(isolate, "a");
19196 Handle<String> left = base;
19197 Handle<String> right = base;
19198 for (int i = 0; i < 1000; i++) {
19199 left = String::Concat(base, left);
19200 right = String::Concat(right, base);
19201 }
19202 Handle<String> balanced = String::Concat(left, base);
19203 balanced = String::Concat(balanced, right);
19204 Handle<String> cons_strings[] = {left, balanced, right};
19205 Handle<String> two_byte =
19206 String::NewExternal(isolate,
19207 new TestResource(string_contents, NULL, false));
19208 USE(two_byte); USE(cons_strings);
19209 for (size_t i = 0; i < arraysize(cons_strings); i++) {
19210 // Base assumptions.
19211 string = cons_strings[i];
19212 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19213 // Test left and right concatentation.
19214 string = String::Concat(two_byte, cons_strings[i]);
19215 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19216 string = String::Concat(cons_strings[i], two_byte);
19217 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19218 }
19219 // Set bits in different positions
19220 // for strings of different lengths and alignments.
19221 for (int alignment = 0; alignment < 7; alignment++) {
19222 for (int size = 2; alignment + size < length; size *= 2) {
19223 int zero_offset = size + alignment;
19224 string_contents[zero_offset] = 0;
19225 for (int i = 0; i < size; i++) {
19226 int shift = 8 + (i % 7);
19227 string_contents[alignment + i] = 1 << shift;
19228 string = String::NewExternal(
19229 isolate,
19230 new TestResource(string_contents + alignment, NULL, false));
19231 CHECK_EQ(size, string->Length());
19232 CHECK(!string->ContainsOnlyOneByte());
19233 string_contents[alignment + i] = 0x41;
19234 }
19235 string_contents[zero_offset] = 0x41;
19236 }
19237 }
19238}
19239
19240
Iain Merrick75681382010-08-19 15:07:18 +010019241// Failed access check callback that performs a GC on each invocation.
19242void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19243 v8::AccessType type,
19244 Local<v8::Value> data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019245 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Iain Merrick75681382010-08-19 15:07:18 +010019246}
19247
19248
19249TEST(GCInFailedAccessCheckCallback) {
19250 // Install a failed access check callback that performs a GC on each
19251 // invocation. Then force the callback to be called from va
19252
19253 v8::V8::Initialize();
19254 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19255
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019256 v8::Isolate* isolate = CcTest::isolate();
19257 v8::HandleScope scope(isolate);
Iain Merrick75681382010-08-19 15:07:18 +010019258
19259 // Create an ObjectTemplate for global objects and install access
19260 // check callbacks that will block access.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019261 v8::Handle<v8::ObjectTemplate> global_template =
19262 v8::ObjectTemplate::New(isolate);
Iain Merrick75681382010-08-19 15:07:18 +010019263 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19264 IndexedGetAccessBlocker,
19265 v8::Handle<v8::Value>(),
19266 false);
19267
19268 // Create a context and set an x property on it's global object.
19269 LocalContext context0(NULL, global_template);
19270 context0->Global()->Set(v8_str("x"), v8_num(42));
19271 v8::Handle<v8::Object> global0 = context0->Global();
19272
19273 // Create a context with a different security token so that the
19274 // failed access check callback will be called on each access.
19275 LocalContext context1(NULL, global_template);
19276 context1->Global()->Set(v8_str("other"), global0);
19277
19278 // Get property with failed access check.
19279 ExpectUndefined("other.x");
19280
19281 // Get element with failed access check.
19282 ExpectUndefined("other[0]");
19283
19284 // Set property with failed access check.
19285 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19286 CHECK(result->IsObject());
19287
19288 // Set element with failed access check.
19289 result = CompileRun("other[0] = new Object()");
19290 CHECK(result->IsObject());
19291
19292 // Get property attribute with failed access check.
19293 ExpectFalse("\'x\' in other");
19294
19295 // Get property attribute for element with failed access check.
19296 ExpectFalse("0 in other");
19297
19298 // Delete property.
19299 ExpectFalse("delete other.x");
19300
19301 // Delete element.
19302 CHECK_EQ(false, global0->Delete(0));
19303
19304 // DefineAccessor.
19305 CHECK_EQ(false,
19306 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19307
19308 // Define JavaScript accessor.
19309 ExpectUndefined("Object.prototype.__defineGetter__.call("
19310 " other, \'x\', function() { return 42; })");
19311
19312 // LookupAccessor.
19313 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19314 " other, \'x\')");
19315
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019316 // HasOwnElement.
Iain Merrick75681382010-08-19 15:07:18 +010019317 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19318
19319 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19320 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19321 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19322
19323 // Reset the failed access check callback so it does not influence
19324 // the other tests.
19325 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19326}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019327
Steve Block44f0eee2011-05-26 01:26:41 +010019328
19329TEST(IsolateNewDispose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019330 v8::Isolate* current_isolate = CcTest::isolate();
Steve Block44f0eee2011-05-26 01:26:41 +010019331 v8::Isolate* isolate = v8::Isolate::New();
19332 CHECK(isolate != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010019333 CHECK(current_isolate != isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019334 CHECK(current_isolate == CcTest::isolate());
Steve Block44f0eee2011-05-26 01:26:41 +010019335
19336 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19337 last_location = last_message = NULL;
19338 isolate->Dispose();
19339 CHECK_EQ(last_location, NULL);
19340 CHECK_EQ(last_message, NULL);
19341}
19342
Steve Block44f0eee2011-05-26 01:26:41 +010019343
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019344UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
Steve Block44f0eee2011-05-26 01:26:41 +010019345 v8::Isolate* isolate = v8::Isolate::New();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019346 {
19347 v8::Isolate::Scope i_scope(isolate);
19348 v8::HandleScope scope(isolate);
19349 LocalContext context(isolate);
19350 // Run something in this isolate.
19351 ExpectTrue("true");
19352 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19353 last_location = last_message = NULL;
19354 // Still entered, should fail.
19355 isolate->Dispose();
19356 CHECK_NE(last_location, NULL);
19357 CHECK_NE(last_message, NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010019358 }
Steve Block44f0eee2011-05-26 01:26:41 +010019359 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010019360}
19361
Steve Block44f0eee2011-05-26 01:26:41 +010019362
19363TEST(RunTwoIsolatesOnSingleThread) {
19364 // Run isolate 1.
19365 v8::Isolate* isolate1 = v8::Isolate::New();
19366 isolate1->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019367 v8::Persistent<v8::Context> context1;
19368 {
19369 v8::HandleScope scope(isolate1);
19370 context1.Reset(isolate1, Context::New(isolate1));
19371 }
Steve Block44f0eee2011-05-26 01:26:41 +010019372
19373 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019374 v8::HandleScope scope(isolate1);
19375 v8::Local<v8::Context> context =
19376 v8::Local<v8::Context>::New(isolate1, context1);
19377 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019378 // Run something in new isolate.
19379 CompileRun("var foo = 'isolate 1';");
19380 ExpectString("function f() { return foo; }; f()", "isolate 1");
19381 }
19382
19383 // Run isolate 2.
19384 v8::Isolate* isolate2 = v8::Isolate::New();
19385 v8::Persistent<v8::Context> context2;
19386
19387 {
19388 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019389 v8::HandleScope scope(isolate2);
19390 context2.Reset(isolate2, Context::New(isolate2));
19391 v8::Local<v8::Context> context =
19392 v8::Local<v8::Context>::New(isolate2, context2);
19393 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019394
19395 // Run something in new isolate.
19396 CompileRun("var foo = 'isolate 2';");
19397 ExpectString("function f() { return foo; }; f()", "isolate 2");
19398 }
19399
19400 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019401 v8::HandleScope scope(isolate1);
19402 v8::Local<v8::Context> context =
19403 v8::Local<v8::Context>::New(isolate1, context1);
19404 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019405 // Now again in isolate 1
19406 ExpectString("function f() { return foo; }; f()", "isolate 1");
19407 }
19408
19409 isolate1->Exit();
19410
19411 // Run some stuff in default isolate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019412 v8::Persistent<v8::Context> context_default;
19413 {
19414 v8::Isolate* isolate = CcTest::isolate();
19415 v8::Isolate::Scope iscope(isolate);
19416 v8::HandleScope scope(isolate);
19417 context_default.Reset(isolate, Context::New(isolate));
19418 }
Steve Block44f0eee2011-05-26 01:26:41 +010019419
19420 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019421 v8::HandleScope scope(CcTest::isolate());
19422 v8::Local<v8::Context> context =
19423 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19424 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019425 // Variables in other isolates should be not available, verify there
19426 // is an exception.
19427 ExpectTrue("function f() {"
19428 " try {"
19429 " foo;"
19430 " return false;"
19431 " } catch(e) {"
19432 " return true;"
19433 " }"
19434 "};"
19435 "var isDefaultIsolate = true;"
19436 "f()");
19437 }
19438
19439 isolate1->Enter();
19440
19441 {
19442 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019443 v8::HandleScope scope(isolate2);
19444 v8::Local<v8::Context> context =
19445 v8::Local<v8::Context>::New(isolate2, context2);
19446 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019447 ExpectString("function f() { return foo; }; f()", "isolate 2");
19448 }
19449
19450 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019451 v8::HandleScope scope(v8::Isolate::GetCurrent());
19452 v8::Local<v8::Context> context =
19453 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19454 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019455 ExpectString("function f() { return foo; }; f()", "isolate 1");
19456 }
19457
19458 {
19459 v8::Isolate::Scope iscope(isolate2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019460 context2.Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010019461 }
19462
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019463 context1.Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010019464 isolate1->Exit();
19465
19466 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19467 last_location = last_message = NULL;
19468
19469 isolate1->Dispose();
19470 CHECK_EQ(last_location, NULL);
19471 CHECK_EQ(last_message, NULL);
19472
19473 isolate2->Dispose();
19474 CHECK_EQ(last_location, NULL);
19475 CHECK_EQ(last_message, NULL);
19476
19477 // Check that default isolate still runs.
19478 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019479 v8::HandleScope scope(CcTest::isolate());
19480 v8::Local<v8::Context> context =
19481 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19482 v8::Context::Scope context_scope(context);
Steve Block44f0eee2011-05-26 01:26:41 +010019483 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19484 }
19485}
19486
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019487
Steve Block44f0eee2011-05-26 01:26:41 +010019488static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19489 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019490 v8::HandleScope scope(isolate);
19491 LocalContext context(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +010019492 i::ScopedVector<char> code(1024);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019493 i::SNPrintF(code, "function fib(n) {"
19494 " if (n <= 2) return 1;"
19495 " return fib(n-1) + fib(n-2);"
19496 "}"
19497 "fib(%d)", limit);
Steve Block44f0eee2011-05-26 01:26:41 +010019498 Local<Value> value = CompileRun(code.start());
19499 CHECK(value->IsNumber());
19500 return static_cast<int>(value->NumberValue());
19501}
19502
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019503class IsolateThread : public v8::base::Thread {
Steve Block44f0eee2011-05-26 01:26:41 +010019504 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019505 explicit IsolateThread(int fib_limit)
19506 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
Steve Block44f0eee2011-05-26 01:26:41 +010019507
19508 void Run() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019509 v8::Isolate* isolate = v8::Isolate::New();
19510 result_ = CalcFibonacci(isolate, fib_limit_);
19511 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010019512 }
19513
19514 int result() { return result_; }
19515
19516 private:
Steve Block44f0eee2011-05-26 01:26:41 +010019517 int fib_limit_;
19518 int result_;
19519};
19520
Steve Block44f0eee2011-05-26 01:26:41 +010019521
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019522TEST(MultipleIsolatesOnIndividualThreads) {
19523 IsolateThread thread1(21);
19524 IsolateThread thread2(12);
Steve Block44f0eee2011-05-26 01:26:41 +010019525
19526 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19527 thread1.Start();
19528 thread2.Start();
19529
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019530 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19531 int result2 = CalcFibonacci(CcTest::isolate(), 12);
Steve Block44f0eee2011-05-26 01:26:41 +010019532
19533 thread1.Join();
19534 thread2.Join();
19535
19536 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19537 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19538 CHECK_EQ(result1, 10946);
19539 CHECK_EQ(result2, 144);
19540 CHECK_EQ(result1, thread1.result());
19541 CHECK_EQ(result2, thread2.result());
Steve Block44f0eee2011-05-26 01:26:41 +010019542}
19543
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019544
Ben Murdoch257744e2011-11-30 15:57:28 +000019545TEST(IsolateDifferentContexts) {
19546 v8::Isolate* isolate = v8::Isolate::New();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019547 Local<v8::Context> context;
Ben Murdoch257744e2011-11-30 15:57:28 +000019548 {
19549 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019550 v8::HandleScope handle_scope(isolate);
19551 context = v8::Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000019552 v8::Context::Scope context_scope(context);
19553 Local<Value> v = CompileRun("2");
19554 CHECK(v->IsNumber());
19555 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19556 }
19557 {
19558 v8::Isolate::Scope isolate_scope(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019559 v8::HandleScope handle_scope(isolate);
19560 context = v8::Context::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000019561 v8::Context::Scope context_scope(context);
19562 Local<Value> v = CompileRun("22");
19563 CHECK(v->IsNumber());
19564 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19565 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019566 isolate->Dispose();
Ben Murdoch257744e2011-11-30 15:57:28 +000019567}
Steve Block44f0eee2011-05-26 01:26:41 +010019568
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019569class InitDefaultIsolateThread : public v8::base::Thread {
Steve Block44f0eee2011-05-26 01:26:41 +010019570 public:
19571 enum TestCase {
Steve Block44f0eee2011-05-26 01:26:41 +010019572 SetResourceConstraints,
19573 SetFatalHandler,
19574 SetCounterFunction,
19575 SetCreateHistogramFunction,
19576 SetAddHistogramSampleFunction
19577 };
19578
19579 explicit InitDefaultIsolateThread(TestCase testCase)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019580 : Thread(Options("InitDefaultIsolateThread")),
Steve Block44f0eee2011-05-26 01:26:41 +010019581 testCase_(testCase),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019582 result_(false) {}
Steve Block44f0eee2011-05-26 01:26:41 +010019583
19584 void Run() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019585 v8::Isolate::CreateParams create_params;
Steve Block44f0eee2011-05-26 01:26:41 +010019586 switch (testCase_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019587 case SetResourceConstraints: {
19588 create_params.constraints.set_max_semi_space_size(1);
19589 create_params.constraints.set_max_old_space_size(4);
19590 break;
19591 }
19592 default:
19593 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019594 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019595 v8::Isolate* isolate = v8::Isolate::New(create_params);
19596 isolate->Enter();
19597 switch (testCase_) {
19598 case SetResourceConstraints:
19599 // Already handled in pre-Isolate-creation block.
19600 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019601
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019602 case SetFatalHandler:
19603 v8::V8::SetFatalErrorHandler(NULL);
19604 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019605
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019606 case SetCounterFunction:
19607 CcTest::isolate()->SetCounterFunction(NULL);
19608 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019609
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019610 case SetCreateHistogramFunction:
19611 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19612 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019613
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019614 case SetAddHistogramSampleFunction:
19615 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19616 break;
Steve Block44f0eee2011-05-26 01:26:41 +010019617 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019618 isolate->Exit();
19619 isolate->Dispose();
Steve Block44f0eee2011-05-26 01:26:41 +010019620 result_ = true;
19621 }
19622
19623 bool result() { return result_; }
19624
19625 private:
19626 TestCase testCase_;
19627 bool result_;
19628};
19629
19630
19631static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19632 InitDefaultIsolateThread thread(testCase);
19633 thread.Start();
19634 thread.Join();
19635 CHECK_EQ(thread.result(), true);
19636}
19637
Steve Block44f0eee2011-05-26 01:26:41 +010019638
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019639TEST(InitializeDefaultIsolateOnSecondaryThread1) {
Steve Block44f0eee2011-05-26 01:26:41 +010019640 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19641}
19642
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019643
19644TEST(InitializeDefaultIsolateOnSecondaryThread2) {
Steve Block44f0eee2011-05-26 01:26:41 +010019645 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19646}
19647
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019648
19649TEST(InitializeDefaultIsolateOnSecondaryThread3) {
Steve Block44f0eee2011-05-26 01:26:41 +010019650 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19651}
19652
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019653
19654TEST(InitializeDefaultIsolateOnSecondaryThread4) {
Steve Block44f0eee2011-05-26 01:26:41 +010019655 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19656}
19657
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019658
19659TEST(InitializeDefaultIsolateOnSecondaryThread5) {
Steve Block44f0eee2011-05-26 01:26:41 +010019660 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19661}
19662
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019663
19664TEST(StringCheckMultipleContexts) {
19665 const char* code =
19666 "(function() { return \"a\".charAt(0); })()";
19667
19668 {
19669 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019670 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019671 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019672 ExpectString(code, "a");
19673 ExpectString(code, "a");
19674 }
19675
19676 {
19677 // Change the String.prototype in the second context and check
19678 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019679 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019680 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019681 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19682 ExpectString(code, "not a");
19683 }
19684}
19685
19686
19687TEST(NumberCheckMultipleContexts) {
19688 const char* code =
19689 "(function() { return (42).toString(); })()";
19690
19691 {
19692 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019693 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019694 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019695 ExpectString(code, "42");
19696 ExpectString(code, "42");
19697 }
19698
19699 {
19700 // Change the Number.prototype in the second context and check
19701 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019702 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019703 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019704 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19705 ExpectString(code, "not 42");
19706 }
19707}
19708
19709
19710TEST(BooleanCheckMultipleContexts) {
19711 const char* code =
19712 "(function() { return true.toString(); })()";
19713
19714 {
19715 // Run the code twice in the first context to initialize the call IC.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019716 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019717 v8::HandleScope scope(context1->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019718 ExpectString(code, "true");
19719 ExpectString(code, "true");
19720 }
19721
19722 {
19723 // Change the Boolean.prototype in the second context and check
19724 // that the right function gets called.
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019725 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019726 v8::HandleScope scope(context2->GetIsolate());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010019727 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19728 ExpectString(code, "");
19729 }
19730}
Ben Murdochf87a2032010-10-22 12:50:53 +010019731
19732
19733TEST(DontDeleteCellLoadIC) {
19734 const char* function_code =
19735 "function readCell() { while (true) { return cell; } }";
19736
19737 {
19738 // Run the code twice in the first context to initialize the load
19739 // IC for a don't delete cell.
Ben Murdochf87a2032010-10-22 12:50:53 +010019740 LocalContext context1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019741 v8::HandleScope scope(context1->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010019742 CompileRun("var cell = \"first\";");
19743 ExpectBoolean("delete cell", false);
19744 CompileRun(function_code);
19745 ExpectString("readCell()", "first");
19746 ExpectString("readCell()", "first");
19747 }
19748
19749 {
19750 // Use a deletable cell in the second context.
Ben Murdochf87a2032010-10-22 12:50:53 +010019751 LocalContext context2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019752 v8::HandleScope scope(context2->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010019753 CompileRun("cell = \"second\";");
19754 CompileRun(function_code);
19755 ExpectString("readCell()", "second");
19756 ExpectBoolean("delete cell", true);
19757 ExpectString("(function() {"
19758 " try {"
19759 " return readCell();"
19760 " } catch(e) {"
19761 " return e.toString();"
19762 " }"
19763 "})()",
19764 "ReferenceError: cell is not defined");
19765 CompileRun("cell = \"new_second\";");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019766 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
Ben Murdochf87a2032010-10-22 12:50:53 +010019767 ExpectString("readCell()", "new_second");
19768 ExpectString("readCell()", "new_second");
19769 }
19770}
19771
19772
19773TEST(DontDeleteCellLoadICForceDelete) {
19774 const char* function_code =
19775 "function readCell() { while (true) { return cell; } }";
19776
19777 // Run the code twice to initialize the load IC for a don't delete
19778 // cell.
Ben Murdochf87a2032010-10-22 12:50:53 +010019779 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019780 v8::HandleScope scope(context->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010019781 CompileRun("var cell = \"value\";");
19782 ExpectBoolean("delete cell", false);
19783 CompileRun(function_code);
19784 ExpectString("readCell()", "value");
19785 ExpectString("readCell()", "value");
19786
19787 // Delete the cell using the API and check the inlined code works
19788 // correctly.
19789 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19790 ExpectString("(function() {"
19791 " try {"
19792 " return readCell();"
19793 " } catch(e) {"
19794 " return e.toString();"
19795 " }"
19796 "})()",
19797 "ReferenceError: cell is not defined");
19798}
19799
19800
19801TEST(DontDeleteCellLoadICAPI) {
19802 const char* function_code =
19803 "function readCell() { while (true) { return cell; } }";
19804
19805 // Run the code twice to initialize the load IC for a don't delete
19806 // cell created using the API.
Ben Murdochf87a2032010-10-22 12:50:53 +010019807 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019808 v8::HandleScope scope(context->GetIsolate());
19809 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
Ben Murdochf87a2032010-10-22 12:50:53 +010019810 ExpectBoolean("delete cell", false);
19811 CompileRun(function_code);
19812 ExpectString("readCell()", "value");
19813 ExpectString("readCell()", "value");
19814
19815 // Delete the cell using the API and check the inlined code works
19816 // correctly.
19817 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19818 ExpectString("(function() {"
19819 " try {"
19820 " return readCell();"
19821 " } catch(e) {"
19822 " return e.toString();"
19823 " }"
19824 "})()",
19825 "ReferenceError: cell is not defined");
19826}
19827
19828
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019829class Visitor42 : public v8::PersistentHandleVisitor {
19830 public:
19831 explicit Visitor42(v8::Persistent<v8::Object>* object)
19832 : counter_(0), object_(object) { }
19833
19834 virtual void VisitPersistentHandle(Persistent<Value>* value,
19835 uint16_t class_id) {
19836 if (class_id != 42) return;
19837 CHECK_EQ(42, value->WrapperClassId());
19838 v8::Isolate* isolate = CcTest::isolate();
19839 v8::HandleScope handle_scope(isolate);
19840 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19841 v8::Handle<v8::Value> object =
19842 v8::Local<v8::Object>::New(isolate, *object_);
19843 CHECK(handle->IsObject());
19844 CHECK_EQ(Handle<Object>::Cast(handle), object);
19845 ++counter_;
19846 }
19847
19848 int counter_;
19849 v8::Persistent<v8::Object>* object_;
19850};
19851
19852
19853TEST(PersistentHandleVisitor) {
Ben Murdochf87a2032010-10-22 12:50:53 +010019854 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019855 v8::Isolate* isolate = context->GetIsolate();
19856 v8::HandleScope scope(isolate);
19857 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19858 CHECK_EQ(0, object.WrapperClassId());
19859 object.SetWrapperClassId(42);
19860 CHECK_EQ(42, object.WrapperClassId());
19861
19862 Visitor42 visitor(&object);
19863 v8::V8::VisitHandlesWithClassIds(&visitor);
19864 CHECK_EQ(1, visitor.counter_);
19865
19866 object.Reset();
19867}
19868
19869
19870TEST(WrapperClassId) {
19871 LocalContext context;
19872 v8::Isolate* isolate = context->GetIsolate();
19873 v8::HandleScope scope(isolate);
19874 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19875 CHECK_EQ(0, object.WrapperClassId());
19876 object.SetWrapperClassId(65535);
19877 CHECK_EQ(65535, object.WrapperClassId());
19878 object.Reset();
19879}
19880
19881
19882TEST(PersistentHandleInNewSpaceVisitor) {
19883 LocalContext context;
19884 v8::Isolate* isolate = context->GetIsolate();
19885 v8::HandleScope scope(isolate);
19886 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19887 CHECK_EQ(0, object1.WrapperClassId());
19888 object1.SetWrapperClassId(42);
19889 CHECK_EQ(42, object1.WrapperClassId());
19890
19891 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19892 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19893
19894 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19895 CHECK_EQ(0, object2.WrapperClassId());
19896 object2.SetWrapperClassId(42);
19897 CHECK_EQ(42, object2.WrapperClassId());
19898
19899 Visitor42 visitor(&object2);
19900 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19901 CHECK_EQ(1, visitor.counter_);
19902
19903 object1.Reset();
19904 object2.Reset();
19905}
19906
19907
19908TEST(RegExp) {
19909 LocalContext context;
19910 v8::HandleScope scope(context->GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010019911
19912 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19913 CHECK(re->IsRegExp());
19914 CHECK(re->GetSource()->Equals(v8_str("foo")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019915 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010019916
19917 re = v8::RegExp::New(v8_str("bar"),
19918 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19919 v8::RegExp::kGlobal));
19920 CHECK(re->IsRegExp());
19921 CHECK(re->GetSource()->Equals(v8_str("bar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019922 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19923 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010019924
19925 re = v8::RegExp::New(v8_str("baz"),
19926 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19927 v8::RegExp::kMultiline));
19928 CHECK(re->IsRegExp());
19929 CHECK(re->GetSource()->Equals(v8_str("baz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019930 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19931 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010019932
19933 re = CompileRun("/quux/").As<v8::RegExp>();
19934 CHECK(re->IsRegExp());
19935 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019936 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010019937
19938 re = CompileRun("/quux/gm").As<v8::RegExp>();
19939 CHECK(re->IsRegExp());
19940 CHECK(re->GetSource()->Equals(v8_str("quux")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019941 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19942 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010019943
19944 // Override the RegExp constructor and check the API constructor
19945 // still works.
19946 CompileRun("RegExp = function() {}");
19947
19948 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19949 CHECK(re->IsRegExp());
19950 CHECK(re->GetSource()->Equals(v8_str("foobar")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019951 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
Ben Murdochf87a2032010-10-22 12:50:53 +010019952
19953 re = v8::RegExp::New(v8_str("foobarbaz"),
19954 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19955 v8::RegExp::kMultiline));
19956 CHECK(re->IsRegExp());
19957 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000019958 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19959 static_cast<int>(re->GetFlags()));
Ben Murdochf87a2032010-10-22 12:50:53 +010019960
19961 context->Global()->Set(v8_str("re"), re);
19962 ExpectTrue("re.test('FoobarbaZ')");
19963
Ben Murdoch257744e2011-11-30 15:57:28 +000019964 // RegExps are objects on which you can set properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019965 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010019966 v8::Handle<v8::Value> value(CompileRun("re.property"));
19967 CHECK_EQ(32, value->Int32Value());
Ben Murdoch257744e2011-11-30 15:57:28 +000019968
Ben Murdochf87a2032010-10-22 12:50:53 +010019969 v8::TryCatch try_catch;
19970 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19971 CHECK(re.IsEmpty());
19972 CHECK(try_catch.HasCaught());
19973 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19974 ExpectTrue("ex instanceof SyntaxError");
19975}
19976
19977
Steve Block1e0659c2011-05-24 12:43:12 +010019978THREADED_TEST(Equals) {
Steve Block1e0659c2011-05-24 12:43:12 +010019979 LocalContext localContext;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019980 v8::HandleScope handleScope(localContext->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010019981
19982 v8::Handle<v8::Object> globalProxy = localContext->Global();
19983 v8::Handle<Value> global = globalProxy->GetPrototype();
19984
19985 CHECK(global->StrictEquals(global));
19986 CHECK(!global->StrictEquals(globalProxy));
19987 CHECK(!globalProxy->StrictEquals(global));
19988 CHECK(globalProxy->StrictEquals(globalProxy));
19989
19990 CHECK(global->Equals(global));
19991 CHECK(!global->Equals(globalProxy));
19992 CHECK(!globalProxy->Equals(global));
19993 CHECK(globalProxy->Equals(globalProxy));
19994}
19995
19996
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019997static void Getter(v8::Local<v8::String> property,
19998 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19999 info.GetReturnValue().Set(v8_str("42!"));
Ben Murdochf87a2032010-10-22 12:50:53 +010020000}
20001
20002
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020003static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20004 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
Ben Murdochf87a2032010-10-22 12:50:53 +010020005 result->Set(0, v8_str("universalAnswer"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020006 info.GetReturnValue().Set(result);
Ben Murdochf87a2032010-10-22 12:50:53 +010020007}
20008
20009
20010TEST(NamedEnumeratorAndForIn) {
Ben Murdochf87a2032010-10-22 12:50:53 +010020011 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020012 v8::Isolate* isolate = context->GetIsolate();
20013 v8::HandleScope handle_scope(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +010020014 v8::Context::Scope context_scope(context.local());
20015
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020016 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
Ben Murdochf87a2032010-10-22 12:50:53 +010020017 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20018 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20019 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20020 "var result = []; for (var k in o) result.push(k); result"));
20021 CHECK_EQ(1, result->Length());
20022 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20023}
Steve Block1e0659c2011-05-24 12:43:12 +010020024
20025
20026TEST(DefinePropertyPostDetach) {
Steve Block1e0659c2011-05-24 12:43:12 +010020027 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020028 v8::HandleScope scope(context->GetIsolate());
Steve Block1e0659c2011-05-24 12:43:12 +010020029 v8::Handle<v8::Object> proxy = context->Global();
20030 v8::Handle<v8::Function> define_property =
20031 CompileRun("(function() {"
20032 " Object.defineProperty("
20033 " this,"
20034 " 1,"
20035 " { configurable: true, enumerable: true, value: 3 });"
20036 "})").As<Function>();
20037 context->DetachGlobal();
20038 define_property->Call(proxy, 0, NULL);
20039}
Ben Murdoch8b112d22011-06-08 16:22:53 +010020040
20041
20042static void InstallContextId(v8::Handle<Context> context, int id) {
20043 Context::Scope scope(context);
20044 CompileRun("Object.prototype").As<Object>()->
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020045 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
Ben Murdoch8b112d22011-06-08 16:22:53 +010020046}
20047
20048
20049static void CheckContextId(v8::Handle<Object> object, int expected) {
20050 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20051}
20052
20053
20054THREADED_TEST(CreationContext) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020055 v8::Isolate* isolate = CcTest::isolate();
20056 HandleScope handle_scope(isolate);
20057 Handle<Context> context1 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020058 InstallContextId(context1, 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020059 Handle<Context> context2 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020060 InstallContextId(context2, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020061 Handle<Context> context3 = Context::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020062 InstallContextId(context3, 3);
20063
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020064 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020065
20066 Local<Object> object1;
20067 Local<Function> func1;
20068 {
20069 Context::Scope scope(context1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020070 object1 = Object::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020071 func1 = tmpl->GetFunction();
20072 }
20073
20074 Local<Object> object2;
20075 Local<Function> func2;
20076 {
20077 Context::Scope scope(context2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020078 object2 = Object::New(isolate);
Ben Murdoch8b112d22011-06-08 16:22:53 +010020079 func2 = tmpl->GetFunction();
20080 }
20081
20082 Local<Object> instance1;
20083 Local<Object> instance2;
20084
20085 {
20086 Context::Scope scope(context3);
20087 instance1 = func1->NewInstance();
20088 instance2 = func2->NewInstance();
20089 }
20090
20091 CHECK(object1->CreationContext() == context1);
20092 CheckContextId(object1, 1);
20093 CHECK(func1->CreationContext() == context1);
20094 CheckContextId(func1, 1);
20095 CHECK(instance1->CreationContext() == context1);
20096 CheckContextId(instance1, 1);
20097 CHECK(object2->CreationContext() == context2);
20098 CheckContextId(object2, 2);
20099 CHECK(func2->CreationContext() == context2);
20100 CheckContextId(func2, 2);
20101 CHECK(instance2->CreationContext() == context2);
20102 CheckContextId(instance2, 2);
20103
20104 {
20105 Context::Scope scope(context1);
20106 CHECK(object1->CreationContext() == context1);
20107 CheckContextId(object1, 1);
20108 CHECK(func1->CreationContext() == context1);
20109 CheckContextId(func1, 1);
20110 CHECK(instance1->CreationContext() == context1);
20111 CheckContextId(instance1, 1);
20112 CHECK(object2->CreationContext() == context2);
20113 CheckContextId(object2, 2);
20114 CHECK(func2->CreationContext() == context2);
20115 CheckContextId(func2, 2);
20116 CHECK(instance2->CreationContext() == context2);
20117 CheckContextId(instance2, 2);
20118 }
20119
20120 {
20121 Context::Scope scope(context2);
20122 CHECK(object1->CreationContext() == context1);
20123 CheckContextId(object1, 1);
20124 CHECK(func1->CreationContext() == context1);
20125 CheckContextId(func1, 1);
20126 CHECK(instance1->CreationContext() == context1);
20127 CheckContextId(instance1, 1);
20128 CHECK(object2->CreationContext() == context2);
20129 CheckContextId(object2, 2);
20130 CHECK(func2->CreationContext() == context2);
20131 CheckContextId(func2, 2);
20132 CHECK(instance2->CreationContext() == context2);
20133 CheckContextId(instance2, 2);
20134 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010020135}
Ben Murdoch257744e2011-11-30 15:57:28 +000020136
20137
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020138THREADED_TEST(CreationContextOfJsFunction) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020139 HandleScope handle_scope(CcTest::isolate());
20140 Handle<Context> context = Context::New(CcTest::isolate());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020141 InstallContextId(context, 1);
20142
20143 Local<Object> function;
20144 {
20145 Context::Scope scope(context);
20146 function = CompileRun("function foo() {}; foo").As<Object>();
20147 }
20148
20149 CHECK(function->CreationContext() == context);
20150 CheckContextId(function, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020151}
20152
20153
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020154void HasOwnPropertyIndexedPropertyGetter(
20155 uint32_t index,
20156 const v8::PropertyCallbackInfo<v8::Value>& info) {
20157 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000020158}
20159
20160
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020161void HasOwnPropertyNamedPropertyGetter(
20162 Local<String> property,
20163 const v8::PropertyCallbackInfo<v8::Value>& info) {
20164 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000020165}
20166
20167
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020168void HasOwnPropertyIndexedPropertyQuery(
20169 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20170 if (index == 42) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000020171}
20172
20173
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020174void HasOwnPropertyNamedPropertyQuery(
20175 Local<String> property,
20176 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20177 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000020178}
20179
20180
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020181void HasOwnPropertyNamedPropertyQuery2(
20182 Local<String> property,
20183 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20184 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
Ben Murdoch257744e2011-11-30 15:57:28 +000020185}
20186
20187
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020188void HasOwnPropertyAccessorGetter(
20189 Local<String> property,
20190 const v8::PropertyCallbackInfo<v8::Value>& info) {
20191 info.GetReturnValue().Set(v8_str("yes"));
Ben Murdoch257744e2011-11-30 15:57:28 +000020192}
20193
20194
20195TEST(HasOwnProperty) {
Ben Murdoch257744e2011-11-30 15:57:28 +000020196 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020197 v8::Isolate* isolate = env->GetIsolate();
20198 v8::HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020199 { // Check normal properties and defined getters.
20200 Handle<Value> value = CompileRun(
20201 "function Foo() {"
20202 " this.foo = 11;"
20203 " this.__defineGetter__('baz', function() { return 1; });"
20204 "};"
20205 "function Bar() { "
20206 " this.bar = 13;"
20207 " this.__defineGetter__('bla', function() { return 2; });"
20208 "};"
20209 "Bar.prototype = new Foo();"
20210 "new Bar();");
20211 CHECK(value->IsObject());
20212 Handle<Object> object = value->ToObject();
20213 CHECK(object->Has(v8_str("foo")));
20214 CHECK(!object->HasOwnProperty(v8_str("foo")));
20215 CHECK(object->HasOwnProperty(v8_str("bar")));
20216 CHECK(object->Has(v8_str("baz")));
20217 CHECK(!object->HasOwnProperty(v8_str("baz")));
20218 CHECK(object->HasOwnProperty(v8_str("bla")));
20219 }
20220 { // Check named getter interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020221 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020222 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20223 Handle<Object> instance = templ->NewInstance();
20224 CHECK(!instance->HasOwnProperty(v8_str("42")));
20225 CHECK(instance->HasOwnProperty(v8_str("foo")));
20226 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20227 }
20228 { // Check indexed getter interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020229 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020230 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20231 Handle<Object> instance = templ->NewInstance();
20232 CHECK(instance->HasOwnProperty(v8_str("42")));
20233 CHECK(!instance->HasOwnProperty(v8_str("43")));
20234 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20235 }
20236 { // Check named query interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020237 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020238 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20239 Handle<Object> instance = templ->NewInstance();
20240 CHECK(instance->HasOwnProperty(v8_str("foo")));
20241 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20242 }
20243 { // Check indexed query interceptors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020244 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020245 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20246 Handle<Object> instance = templ->NewInstance();
20247 CHECK(instance->HasOwnProperty(v8_str("42")));
20248 CHECK(!instance->HasOwnProperty(v8_str("41")));
20249 }
20250 { // Check callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020251 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020252 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20253 Handle<Object> instance = templ->NewInstance();
20254 CHECK(instance->HasOwnProperty(v8_str("foo")));
20255 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20256 }
20257 { // Check that query wins on disagreement.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020258 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +000020259 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20260 0,
20261 HasOwnPropertyNamedPropertyQuery2);
20262 Handle<Object> instance = templ->NewInstance();
20263 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20264 CHECK(instance->HasOwnProperty(v8_str("bar")));
20265 }
20266}
20267
20268
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020269TEST(IndexedInterceptorWithStringProto) {
20270 v8::Isolate* isolate = CcTest::isolate();
20271 v8::HandleScope scope(isolate);
20272 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20273 templ->SetIndexedPropertyHandler(NULL,
20274 NULL,
20275 HasOwnPropertyIndexedPropertyQuery);
20276 LocalContext context;
20277 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20278 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20279 // These should be intercepted.
20280 CHECK(CompileRun("42 in obj")->BooleanValue());
20281 CHECK(CompileRun("'42' in obj")->BooleanValue());
20282 // These should fall through to the String prototype.
20283 CHECK(CompileRun("0 in obj")->BooleanValue());
20284 CHECK(CompileRun("'0' in obj")->BooleanValue());
20285 // And these should both fail.
20286 CHECK(!CompileRun("32 in obj")->BooleanValue());
20287 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20288}
20289
20290
Ben Murdoch257744e2011-11-30 15:57:28 +000020291void CheckCodeGenerationAllowed() {
20292 Handle<Value> result = CompileRun("eval('42')");
20293 CHECK_EQ(42, result->Int32Value());
20294 result = CompileRun("(function(e) { return e('42'); })(eval)");
20295 CHECK_EQ(42, result->Int32Value());
20296 result = CompileRun("var f = new Function('return 42'); f()");
20297 CHECK_EQ(42, result->Int32Value());
20298}
20299
20300
20301void CheckCodeGenerationDisallowed() {
20302 TryCatch try_catch;
20303
20304 Handle<Value> result = CompileRun("eval('42')");
20305 CHECK(result.IsEmpty());
20306 CHECK(try_catch.HasCaught());
20307 try_catch.Reset();
20308
20309 result = CompileRun("(function(e) { return e('42'); })(eval)");
20310 CHECK(result.IsEmpty());
20311 CHECK(try_catch.HasCaught());
20312 try_catch.Reset();
20313
20314 result = CompileRun("var f = new Function('return 42'); f()");
20315 CHECK(result.IsEmpty());
20316 CHECK(try_catch.HasCaught());
20317}
20318
20319
20320bool CodeGenerationAllowed(Local<Context> context) {
20321 ApiTestFuzzer::Fuzz();
20322 return true;
20323}
20324
20325
20326bool CodeGenerationDisallowed(Local<Context> context) {
20327 ApiTestFuzzer::Fuzz();
20328 return false;
20329}
20330
20331
20332THREADED_TEST(AllowCodeGenFromStrings) {
Ben Murdoch257744e2011-11-30 15:57:28 +000020333 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020334 v8::HandleScope scope(context->GetIsolate());
Ben Murdoch257744e2011-11-30 15:57:28 +000020335
20336 // eval and the Function constructor allowed by default.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020337 CHECK(context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000020338 CheckCodeGenerationAllowed();
20339
20340 // Disallow eval and the Function constructor.
20341 context->AllowCodeGenerationFromStrings(false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020342 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000020343 CheckCodeGenerationDisallowed();
20344
20345 // Allow again.
20346 context->AllowCodeGenerationFromStrings(true);
20347 CheckCodeGenerationAllowed();
20348
20349 // Disallow but setting a global callback that will allow the calls.
20350 context->AllowCodeGenerationFromStrings(false);
20351 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020352 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000020353 CheckCodeGenerationAllowed();
20354
20355 // Set a callback that disallows the code generation.
20356 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020357 CHECK(!context->IsCodeGenerationFromStringsAllowed());
Ben Murdoch257744e2011-11-30 15:57:28 +000020358 CheckCodeGenerationDisallowed();
20359}
20360
20361
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020362TEST(SetErrorMessageForCodeGenFromStrings) {
20363 LocalContext context;
20364 v8::HandleScope scope(context->GetIsolate());
20365 TryCatch try_catch;
20366
20367 Handle<String> message = v8_str("Message") ;
20368 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20369 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20370 context->AllowCodeGenerationFromStrings(false);
20371 context->SetErrorMessageForCodeGenerationFromStrings(message);
20372 Handle<Value> result = CompileRun("eval('42')");
20373 CHECK(result.IsEmpty());
20374 CHECK(try_catch.HasCaught());
20375 Handle<String> actual_message = try_catch.Message()->Get();
20376 CHECK(expected_message->Equals(actual_message));
20377}
20378
20379
20380static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch257744e2011-11-30 15:57:28 +000020381}
20382
20383
20384THREADED_TEST(CallAPIFunctionOnNonObject) {
Ben Murdoch257744e2011-11-30 15:57:28 +000020385 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020386 v8::Isolate* isolate = context->GetIsolate();
20387 v8::HandleScope scope(isolate);
20388 Handle<FunctionTemplate> templ =
20389 v8::FunctionTemplate::New(isolate, NonObjectThis);
Ben Murdoch257744e2011-11-30 15:57:28 +000020390 Handle<Function> function = templ->GetFunction();
20391 context->Global()->Set(v8_str("f"), function);
20392 TryCatch try_catch;
20393 CompileRun("f.call(2)");
20394}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020395
20396
20397// Regression test for issue 1470.
20398THREADED_TEST(ReadOnlyIndexedProperties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020399 v8::Isolate* isolate = CcTest::isolate();
20400 v8::HandleScope scope(isolate);
20401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020402
20403 LocalContext context;
20404 Local<v8::Object> obj = templ->NewInstance();
20405 context->Global()->Set(v8_str("obj"), obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020406 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020407 obj->Set(v8_str("1"), v8_str("foobar"));
20408 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020409 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020410 obj->Set(v8_num(2), v8_str("foobar"));
20411 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20412
20413 // Test non-smi case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020414 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020415 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20416 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20417}
20418
20419
20420THREADED_TEST(Regress1516) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020421 LocalContext context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020422 v8::HandleScope scope(context->GetIsolate());
20423
20424 { v8::HandleScope temp_scope(context->GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020425 CompileRun("({'a': 0})");
20426 }
20427
20428 int elements;
20429 { i::MapCache* map_cache =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020430 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020431 elements = map_cache->NumberOfElements();
20432 CHECK_LE(1, elements);
20433 }
20434
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020435 CcTest::heap()->CollectAllGarbage(
20436 i::Heap::kAbortIncrementalMarkingMask);
20437 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20438 if (raw_map_cache != CcTest::heap()->undefined_value()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020439 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20440 CHECK_GT(elements, map_cache->NumberOfElements());
20441 }
20442 }
20443}
20444
20445
20446static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20447 Local<Value> name,
20448 v8::AccessType type,
20449 Local<Value> data) {
20450 // Only block read access to __proto__.
20451 if (type == v8::ACCESS_GET &&
20452 name->IsString() &&
20453 name->ToString()->Length() == 9 &&
20454 name->ToString()->Utf8Length() == 9) {
20455 char buffer[10];
20456 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20457 return strncmp(buffer, "__proto__", 9) != 0;
20458 }
20459
20460 return true;
20461}
20462
20463
20464THREADED_TEST(Regress93759) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020465 v8::Isolate* isolate = CcTest::isolate();
20466 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020467
20468 // Template for object with security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020469 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020470 // We don't do indexing, so any callback can be used for that.
20471 no_proto_template->SetAccessCheckCallbacks(
20472 BlockProtoNamedSecurityTestCallback,
20473 IndexedSecurityTestCallback);
20474
20475 // Templates for objects with hidden prototypes and possibly security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020476 Local<FunctionTemplate> hidden_proto_template =
20477 v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020478 hidden_proto_template->SetHiddenPrototype(true);
20479
20480 Local<FunctionTemplate> protected_hidden_proto_template =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020481 v8::FunctionTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020482 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20483 BlockProtoNamedSecurityTestCallback,
20484 IndexedSecurityTestCallback);
20485 protected_hidden_proto_template->SetHiddenPrototype(true);
20486
20487 // Context for "foreign" objects used in test.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020488 Local<Context> context = v8::Context::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020489 context->Enter();
20490
20491 // Plain object, no security check.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020492 Local<Object> simple_object = Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020493
20494 // Object with explicit security check.
20495 Local<Object> protected_object =
20496 no_proto_template->NewInstance();
20497
20498 // JSGlobalProxy object, always have security check.
20499 Local<Object> proxy_object =
20500 context->Global();
20501
20502 // Global object, the prototype of proxy_object. No security checks.
20503 Local<Object> global_object =
20504 proxy_object->GetPrototype()->ToObject();
20505
20506 // Hidden prototype without security check.
20507 Local<Object> hidden_prototype =
20508 hidden_proto_template->GetFunction()->NewInstance();
20509 Local<Object> object_with_hidden =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020510 Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020511 object_with_hidden->SetPrototype(hidden_prototype);
20512
20513 // Hidden prototype with security check on the hidden prototype.
20514 Local<Object> protected_hidden_prototype =
20515 protected_hidden_proto_template->GetFunction()->NewInstance();
20516 Local<Object> object_with_protected_hidden =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020517 Object::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020518 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20519
20520 context->Exit();
20521
20522 // Template for object for second context. Values to test are put on it as
20523 // properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020524 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020525 global_template->Set(v8_str("simple"), simple_object);
20526 global_template->Set(v8_str("protected"), protected_object);
20527 global_template->Set(v8_str("global"), global_object);
20528 global_template->Set(v8_str("proxy"), proxy_object);
20529 global_template->Set(v8_str("hidden"), object_with_hidden);
20530 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20531
20532 LocalContext context2(NULL, global_template);
20533
20534 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20535 CHECK(result1->Equals(simple_object->GetPrototype()));
20536
20537 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020538 CHECK(result2.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020539
20540 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20541 CHECK(result3->Equals(global_object->GetPrototype()));
20542
20543 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020544 CHECK(result4.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020545
20546 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20547 CHECK(result5->Equals(
20548 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20549
20550 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020551 CHECK(result6.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000020552}
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020553
20554
Ben Murdoch5710cea2012-05-21 14:52:42 +010020555THREADED_TEST(Regress125988) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020556 v8::HandleScope scope(CcTest::isolate());
20557 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
Ben Murdoch5710cea2012-05-21 14:52:42 +010020558 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20559 LocalContext env;
20560 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20561 CompileRun("var a = new Object();"
20562 "var b = new Intercept();"
20563 "var c = new Object();"
20564 "c.__proto__ = b;"
20565 "b.__proto__ = a;"
20566 "a.x = 23;"
20567 "for (var i = 0; i < 3; i++) c.x;");
20568 ExpectBoolean("c.hasOwnProperty('x')", false);
20569 ExpectInt32("c.x", 23);
20570 CompileRun("a.y = 42;"
20571 "for (var i = 0; i < 3; i++) c.x;");
20572 ExpectBoolean("c.hasOwnProperty('x')", false);
20573 ExpectInt32("c.x", 23);
20574 ExpectBoolean("c.hasOwnProperty('y')", false);
20575 ExpectInt32("c.y", 42);
20576}
20577
20578
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020579static void TestReceiver(Local<Value> expected_result,
20580 Local<Value> expected_receiver,
20581 const char* code) {
20582 Local<Value> result = CompileRun(code);
20583 CHECK(result->IsObject());
20584 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20585 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20586}
20587
20588
20589THREADED_TEST(ForeignFunctionReceiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020590 v8::Isolate* isolate = CcTest::isolate();
20591 HandleScope scope(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020592
20593 // Create two contexts with different "id" properties ('i' and 'o').
20594 // Call a function both from its own context and from a the foreign
20595 // context, and see what "this" is bound to (returning both "this"
20596 // and "this.id" for comparison).
20597
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020598 Local<Context> foreign_context = v8::Context::New(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020599 foreign_context->Enter();
20600 Local<Value> foreign_function =
20601 CompileRun("function func() { return { 0: this.id, "
20602 " 1: this, "
20603 " toString: function() { "
20604 " return this[0];"
20605 " }"
20606 " };"
20607 "}"
20608 "var id = 'i';"
20609 "func;");
20610 CHECK(foreign_function->IsFunction());
20611 foreign_context->Exit();
20612
20613 LocalContext context;
20614
20615 Local<String> password = v8_str("Password");
20616 // Don't get hit by security checks when accessing foreign_context's
20617 // global receiver (aka. global proxy).
20618 context->SetSecurityToken(password);
20619 foreign_context->SetSecurityToken(password);
20620
20621 Local<String> i = v8_str("i");
20622 Local<String> o = v8_str("o");
20623 Local<String> id = v8_str("id");
20624
20625 CompileRun("function ownfunc() { return { 0: this.id, "
20626 " 1: this, "
20627 " toString: function() { "
20628 " return this[0];"
20629 " }"
20630 " };"
20631 "}"
20632 "var id = 'o';"
20633 "ownfunc");
20634 context->Global()->Set(v8_str("func"), foreign_function);
20635
20636 // Sanity check the contexts.
20637 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20638 CHECK(o->Equals(context->Global()->Get(id)));
20639
20640 // Checking local function's receiver.
20641 // Calling function using its call/apply methods.
20642 TestReceiver(o, context->Global(), "ownfunc.call()");
20643 TestReceiver(o, context->Global(), "ownfunc.apply()");
20644 // Making calls through built-in functions.
20645 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20646 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20647 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20648 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20649 // Calling with environment record as base.
20650 TestReceiver(o, context->Global(), "ownfunc()");
20651 // Calling with no base.
20652 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20653
20654 // Checking foreign function return value.
20655 // Calling function using its call/apply methods.
20656 TestReceiver(i, foreign_context->Global(), "func.call()");
20657 TestReceiver(i, foreign_context->Global(), "func.apply()");
20658 // Calling function using another context's call/apply methods.
20659 TestReceiver(i, foreign_context->Global(),
20660 "Function.prototype.call.call(func)");
20661 TestReceiver(i, foreign_context->Global(),
20662 "Function.prototype.call.apply(func)");
20663 TestReceiver(i, foreign_context->Global(),
20664 "Function.prototype.apply.call(func)");
20665 TestReceiver(i, foreign_context->Global(),
20666 "Function.prototype.apply.apply(func)");
20667 // Making calls through built-in functions.
20668 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20669 // ToString(func()) is func()[0], i.e., the returned this.id.
20670 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20671 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20672 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20673
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020674 // Calling with environment record as base.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020675 TestReceiver(i, foreign_context->Global(), "func()");
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020676 // Calling with no base.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020677 TestReceiver(i, foreign_context->Global(), "(1,func)()");
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020678}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020679
20680
20681uint8_t callback_fired = 0;
20682
20683
20684void CallCompletedCallback1() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020685 v8::base::OS::Print("Firing callback 1.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020686 callback_fired ^= 1; // Toggle first bit.
20687}
20688
20689
20690void CallCompletedCallback2() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020691 v8::base::OS::Print("Firing callback 2.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020692 callback_fired ^= 2; // Toggle second bit.
20693}
20694
20695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020696void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020697 int32_t level = args[0]->Int32Value();
20698 if (level < 3) {
20699 level++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020700 v8::base::OS::Print("Entering recursion level %d.\n", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020701 char script[64];
20702 i::Vector<char> script_vector(script, sizeof(script));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020703 i::SNPrintF(script_vector, "recursion(%d)", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020704 CompileRun(script_vector.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020705 v8::base::OS::Print("Leaving recursion level %d.\n", level);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020706 CHECK_EQ(0, callback_fired);
20707 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020708 v8::base::OS::Print("Recursion ends.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020709 CHECK_EQ(0, callback_fired);
20710 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020711}
20712
20713
20714TEST(CallCompletedCallback) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020715 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020716 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020717 v8::Handle<v8::FunctionTemplate> recursive_runtime =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020718 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020719 env->Global()->Set(v8_str("recursion"),
20720 recursive_runtime->GetFunction());
20721 // Adding the same callback a second time has no effect.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020722 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20723 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20724 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20725 v8::base::OS::Print("--- Script (1) ---\n");
20726 Local<Script> script = v8::Script::Compile(
20727 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020728 script->Run();
20729 CHECK_EQ(3, callback_fired);
20730
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020731 v8::base::OS::Print("\n--- Script (2) ---\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020732 callback_fired = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020733 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020734 script->Run();
20735 CHECK_EQ(2, callback_fired);
20736
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020737 v8::base::OS::Print("\n--- Function ---\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020738 callback_fired = 0;
20739 Local<Function> recursive_function =
20740 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20741 v8::Handle<Value> args[] = { v8_num(0) };
20742 recursive_function->Call(env->Global(), 1, args);
20743 CHECK_EQ(2, callback_fired);
20744}
20745
20746
20747void CallCompletedCallbackNoException() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020748 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020749 CompileRun("1+1;");
20750}
20751
20752
20753void CallCompletedCallbackException() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020754 v8::HandleScope scope(CcTest::isolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020755 CompileRun("throw 'second exception';");
20756}
20757
20758
20759TEST(CallCompletedCallbackOneException) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020760 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020761 v8::HandleScope scope(env->GetIsolate());
20762 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020763 CompileRun("throw 'exception';");
20764}
20765
20766
20767TEST(CallCompletedCallbackTwoExceptions) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020768 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020769 v8::HandleScope scope(env->GetIsolate());
20770 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020771 CompileRun("throw 'first exception';");
20772}
20773
20774
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020775static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20776 v8::HandleScope scope(info.GetIsolate());
20777 CompileRun("ext1Calls++;");
20778}
20779
20780
20781static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20782 v8::HandleScope scope(info.GetIsolate());
20783 CompileRun("ext2Calls++;");
20784}
20785
20786
20787void* g_passed_to_three = NULL;
20788
20789
20790static void MicrotaskThree(void* data) {
20791 g_passed_to_three = data;
20792}
20793
20794
20795TEST(EnqueueMicrotask) {
20796 LocalContext env;
20797 v8::HandleScope scope(env->GetIsolate());
20798 CompileRun(
20799 "var ext1Calls = 0;"
20800 "var ext2Calls = 0;");
20801 CompileRun("1+1;");
20802 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20803 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20804
20805 env->GetIsolate()->EnqueueMicrotask(
20806 Function::New(env->GetIsolate(), MicrotaskOne));
20807 CompileRun("1+1;");
20808 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20809 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20810
20811 env->GetIsolate()->EnqueueMicrotask(
20812 Function::New(env->GetIsolate(), MicrotaskOne));
20813 env->GetIsolate()->EnqueueMicrotask(
20814 Function::New(env->GetIsolate(), MicrotaskTwo));
20815 CompileRun("1+1;");
20816 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20817 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20818
20819 env->GetIsolate()->EnqueueMicrotask(
20820 Function::New(env->GetIsolate(), MicrotaskTwo));
20821 CompileRun("1+1;");
20822 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20823 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20824
20825 CompileRun("1+1;");
20826 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20827 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20828
20829 g_passed_to_three = NULL;
20830 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20831 CompileRun("1+1;");
20832 CHECK_EQ(NULL, g_passed_to_three);
20833 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20834 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20835
20836 int dummy;
20837 env->GetIsolate()->EnqueueMicrotask(
20838 Function::New(env->GetIsolate(), MicrotaskOne));
20839 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20840 env->GetIsolate()->EnqueueMicrotask(
20841 Function::New(env->GetIsolate(), MicrotaskTwo));
20842 CompileRun("1+1;");
20843 CHECK_EQ(&dummy, g_passed_to_three);
20844 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20845 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20846 g_passed_to_three = NULL;
20847}
20848
20849
20850static void MicrotaskExceptionOne(
20851 const v8::FunctionCallbackInfo<Value>& info) {
20852 v8::HandleScope scope(info.GetIsolate());
20853 CompileRun("exception1Calls++;");
20854 info.GetIsolate()->ThrowException(
20855 v8::Exception::Error(v8_str("first")));
20856}
20857
20858
20859static void MicrotaskExceptionTwo(
20860 const v8::FunctionCallbackInfo<Value>& info) {
20861 v8::HandleScope scope(info.GetIsolate());
20862 CompileRun("exception2Calls++;");
20863 info.GetIsolate()->ThrowException(
20864 v8::Exception::Error(v8_str("second")));
20865}
20866
20867
20868TEST(RunMicrotasksIgnoresThrownExceptions) {
20869 LocalContext env;
20870 v8::Isolate* isolate = env->GetIsolate();
20871 v8::HandleScope scope(isolate);
20872 CompileRun(
20873 "var exception1Calls = 0;"
20874 "var exception2Calls = 0;");
20875 isolate->EnqueueMicrotask(
20876 Function::New(isolate, MicrotaskExceptionOne));
20877 isolate->EnqueueMicrotask(
20878 Function::New(isolate, MicrotaskExceptionTwo));
20879 TryCatch try_catch;
20880 CompileRun("1+1;");
20881 CHECK(!try_catch.HasCaught());
20882 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20883 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20884}
20885
20886
20887TEST(SetAutorunMicrotasks) {
20888 LocalContext env;
20889 v8::HandleScope scope(env->GetIsolate());
20890 CompileRun(
20891 "var ext1Calls = 0;"
20892 "var ext2Calls = 0;");
20893 CompileRun("1+1;");
20894 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20895 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20896
20897 env->GetIsolate()->EnqueueMicrotask(
20898 Function::New(env->GetIsolate(), MicrotaskOne));
20899 CompileRun("1+1;");
20900 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20901 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20902
20903 env->GetIsolate()->SetAutorunMicrotasks(false);
20904 env->GetIsolate()->EnqueueMicrotask(
20905 Function::New(env->GetIsolate(), MicrotaskOne));
20906 env->GetIsolate()->EnqueueMicrotask(
20907 Function::New(env->GetIsolate(), MicrotaskTwo));
20908 CompileRun("1+1;");
20909 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20910 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20911
20912 env->GetIsolate()->RunMicrotasks();
20913 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20914 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20915
20916 env->GetIsolate()->EnqueueMicrotask(
20917 Function::New(env->GetIsolate(), MicrotaskTwo));
20918 CompileRun("1+1;");
20919 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20920 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20921
20922 env->GetIsolate()->RunMicrotasks();
20923 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20924 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20925
20926 env->GetIsolate()->SetAutorunMicrotasks(true);
20927 env->GetIsolate()->EnqueueMicrotask(
20928 Function::New(env->GetIsolate(), MicrotaskTwo));
20929 CompileRun("1+1;");
20930 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20931 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20932
20933 env->GetIsolate()->EnqueueMicrotask(
20934 Function::New(env->GetIsolate(), MicrotaskTwo));
20935 {
20936 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20937 CompileRun("1+1;");
20938 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20939 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20940 }
20941
20942 CompileRun("1+1;");
20943 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20944 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20945}
20946
20947
20948TEST(RunMicrotasksWithoutEnteringContext) {
20949 v8::Isolate* isolate = CcTest::isolate();
20950 HandleScope handle_scope(isolate);
20951 isolate->SetAutorunMicrotasks(false);
20952 Handle<Context> context = Context::New(isolate);
20953 {
20954 Context::Scope context_scope(context);
20955 CompileRun("var ext1Calls = 0;");
20956 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20957 }
20958 isolate->RunMicrotasks();
20959 {
20960 Context::Scope context_scope(context);
20961 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20962 }
20963 isolate->SetAutorunMicrotasks(true);
20964}
20965
20966
20967static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
20968 v8::DebugEvent event = event_details.GetEvent();
20969 if (event != v8::Break) return;
20970 Handle<Object> exec_state = event_details.GetExecutionState();
20971 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
20972 CompileRun("function f(id) { new FrameDetails(id, 0); }");
20973 Handle<Function> fun = Handle<Function>::Cast(
20974 CcTest::global()->Get(v8_str("f"))->ToObject());
20975 fun->Call(CcTest::global(), 1, &break_id);
20976}
20977
20978
20979TEST(Regress385349) {
20980 i::FLAG_allow_natives_syntax = true;
20981 v8::Isolate* isolate = CcTest::isolate();
20982 HandleScope handle_scope(isolate);
20983 isolate->SetAutorunMicrotasks(false);
20984 Handle<Context> context = Context::New(isolate);
20985 v8::Debug::SetDebugEventListener(DebugEventInObserver);
20986 {
20987 Context::Scope context_scope(context);
20988 CompileRun("var obj = {};"
20989 "Object.observe(obj, function(changes) { debugger; });"
20990 "obj.a = 0;");
20991 }
20992 isolate->RunMicrotasks();
20993 isolate->SetAutorunMicrotasks(true);
20994 v8::Debug::SetDebugEventListener(NULL);
20995}
20996
20997
20998#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +010020999static int probes_counter = 0;
21000static int misses_counter = 0;
21001static int updates_counter = 0;
21002
21003
21004static int* LookupCounter(const char* name) {
21005 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21006 return &probes_counter;
21007 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21008 return &misses_counter;
21009 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21010 return &updates_counter;
21011 }
21012 return NULL;
21013}
21014
21015
21016static const char* kMegamorphicTestProgram =
21017 "function ClassA() { };"
21018 "function ClassB() { };"
21019 "ClassA.prototype.foo = function() { };"
21020 "ClassB.prototype.foo = function() { };"
21021 "function fooify(obj) { obj.foo(); };"
21022 "var a = new ClassA();"
21023 "var b = new ClassB();"
21024 "for (var i = 0; i < 10000; i++) {"
21025 " fooify(a);"
21026 " fooify(b);"
21027 "}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021028#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021029
21030
21031static void StubCacheHelper(bool primary) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021032#ifdef DEBUG
21033 i::FLAG_native_code_counters = true;
21034 if (primary) {
21035 i::FLAG_test_primary_stub_cache = true;
21036 } else {
21037 i::FLAG_test_secondary_stub_cache = true;
21038 }
21039 i::FLAG_crankshaft = false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021040 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021041 env->GetIsolate()->SetCounterFunction(LookupCounter);
21042 v8::HandleScope scope(env->GetIsolate());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021043 int initial_probes = probes_counter;
21044 int initial_misses = misses_counter;
21045 int initial_updates = updates_counter;
21046 CompileRun(kMegamorphicTestProgram);
21047 int probes = probes_counter - initial_probes;
21048 int misses = misses_counter - initial_misses;
21049 int updates = updates_counter - initial_updates;
21050 CHECK_LT(updates, 10);
21051 CHECK_LT(misses, 10);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021052 // TODO(verwaest): Update this test to overflow the degree of polymorphism
21053 // before megamorphism. The number of probes will only work once we teach the
21054 // serializer to embed references to counters in the stubs, given that the
21055 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21056 CHECK_GE(probes, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010021057#endif
21058}
21059
21060
21061TEST(SecondaryStubCache) {
21062 StubCacheHelper(true);
21063}
21064
21065
21066TEST(PrimaryStubCache) {
21067 StubCacheHelper(false);
21068}
21069
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021070
21071#ifdef DEBUG
21072static int cow_arrays_created_runtime = 0;
21073
21074
21075static int* LookupCounterCOWArrays(const char* name) {
21076 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21077 return &cow_arrays_created_runtime;
21078 }
21079 return NULL;
21080}
21081#endif
21082
21083
21084TEST(CheckCOWArraysCreatedRuntimeCounter) {
21085#ifdef DEBUG
21086 i::FLAG_native_code_counters = true;
21087 LocalContext env;
21088 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21089 v8::HandleScope scope(env->GetIsolate());
21090 int initial_cow_arrays = cow_arrays_created_runtime;
21091 CompileRun("var o = [1, 2, 3];");
21092 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21093 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21094 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21095 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21096 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21097#endif
21098}
21099
21100
21101TEST(StaticGetters) {
21102 LocalContext context;
21103 i::Factory* factory = CcTest::i_isolate()->factory();
21104 v8::Isolate* isolate = CcTest::isolate();
21105 v8::HandleScope scope(isolate);
21106 i::Handle<i::Object> undefined_value = factory->undefined_value();
21107 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21108 i::Handle<i::Object> null_value = factory->null_value();
21109 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21110 i::Handle<i::Object> true_value = factory->true_value();
21111 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21112 i::Handle<i::Object> false_value = factory->false_value();
21113 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21114}
21115
21116
21117UNINITIALIZED_TEST(IsolateEmbedderData) {
21118 CcTest::DisableAutomaticDispose();
21119 v8::Isolate* isolate = v8::Isolate::New();
21120 isolate->Enter();
21121 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21122 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21123 CHECK_EQ(NULL, isolate->GetData(slot));
21124 CHECK_EQ(NULL, i_isolate->GetData(slot));
21125 }
21126 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21127 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21128 isolate->SetData(slot, data);
21129 }
21130 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21131 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21132 CHECK_EQ(data, isolate->GetData(slot));
21133 CHECK_EQ(data, i_isolate->GetData(slot));
21134 }
21135 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21136 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21137 isolate->SetData(slot, data);
21138 }
21139 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21140 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21141 CHECK_EQ(data, isolate->GetData(slot));
21142 CHECK_EQ(data, i_isolate->GetData(slot));
21143 }
21144 isolate->Exit();
21145 isolate->Dispose();
21146}
21147
21148
21149TEST(StringEmpty) {
21150 LocalContext context;
21151 i::Factory* factory = CcTest::i_isolate()->factory();
21152 v8::Isolate* isolate = CcTest::isolate();
21153 v8::HandleScope scope(isolate);
21154 i::Handle<i::Object> empty_string = factory->empty_string();
21155 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21156}
21157
21158
21159static int instance_checked_getter_count = 0;
21160static void InstanceCheckedGetter(
21161 Local<String> name,
21162 const v8::PropertyCallbackInfo<v8::Value>& info) {
21163 CHECK_EQ(name, v8_str("foo"));
21164 instance_checked_getter_count++;
21165 info.GetReturnValue().Set(v8_num(11));
21166}
21167
21168
21169static int instance_checked_setter_count = 0;
21170static void InstanceCheckedSetter(Local<String> name,
21171 Local<Value> value,
21172 const v8::PropertyCallbackInfo<void>& info) {
21173 CHECK_EQ(name, v8_str("foo"));
21174 CHECK_EQ(value, v8_num(23));
21175 instance_checked_setter_count++;
21176}
21177
21178
21179static void CheckInstanceCheckedResult(int getters, int setters,
21180 bool expects_callbacks,
21181 TryCatch* try_catch) {
21182 if (expects_callbacks) {
21183 CHECK(!try_catch->HasCaught());
21184 CHECK_EQ(getters, instance_checked_getter_count);
21185 CHECK_EQ(setters, instance_checked_setter_count);
21186 } else {
21187 CHECK(try_catch->HasCaught());
21188 CHECK_EQ(0, instance_checked_getter_count);
21189 CHECK_EQ(0, instance_checked_setter_count);
21190 }
21191 try_catch->Reset();
21192}
21193
21194
21195static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21196 instance_checked_getter_count = 0;
21197 instance_checked_setter_count = 0;
21198 TryCatch try_catch;
21199
21200 // Test path through generic runtime code.
21201 CompileRun("obj.foo");
21202 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21203 CompileRun("obj.foo = 23");
21204 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21205
21206 // Test path through generated LoadIC and StoredIC.
21207 CompileRun("function test_get(o) { o.foo; }"
21208 "test_get(obj);");
21209 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21210 CompileRun("test_get(obj);");
21211 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21212 CompileRun("test_get(obj);");
21213 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21214 CompileRun("function test_set(o) { o.foo = 23; }"
21215 "test_set(obj);");
21216 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21217 CompileRun("test_set(obj);");
21218 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21219 CompileRun("test_set(obj);");
21220 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21221
21222 // Test path through optimized code.
21223 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21224 "test_get(obj);");
21225 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21226 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21227 "test_set(obj);");
21228 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21229
21230 // Cleanup so that closures start out fresh in next check.
21231 CompileRun("%DeoptimizeFunction(test_get);"
21232 "%ClearFunctionTypeFeedback(test_get);"
21233 "%DeoptimizeFunction(test_set);"
21234 "%ClearFunctionTypeFeedback(test_set);");
21235}
21236
21237
21238THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21239 v8::internal::FLAG_allow_natives_syntax = true;
21240 LocalContext context;
21241 v8::HandleScope scope(context->GetIsolate());
21242
21243 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21244 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21245 inst->SetAccessor(v8_str("foo"),
21246 InstanceCheckedGetter, InstanceCheckedSetter,
21247 Handle<Value>(),
21248 v8::DEFAULT,
21249 v8::None,
21250 v8::AccessorSignature::New(context->GetIsolate(), templ));
21251 context->Global()->Set(v8_str("f"), templ->GetFunction());
21252
21253 printf("Testing positive ...\n");
21254 CompileRun("var obj = new f();");
21255 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21256 CheckInstanceCheckedAccessors(true);
21257
21258 printf("Testing negative ...\n");
21259 CompileRun("var obj = {};"
21260 "obj.__proto__ = new f();");
21261 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21262 CheckInstanceCheckedAccessors(false);
21263}
21264
21265
21266THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21267 v8::internal::FLAG_allow_natives_syntax = true;
21268 LocalContext context;
21269 v8::HandleScope scope(context->GetIsolate());
21270
21271 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21272 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21273 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21274 inst->SetAccessor(v8_str("foo"),
21275 InstanceCheckedGetter, InstanceCheckedSetter,
21276 Handle<Value>(),
21277 v8::DEFAULT,
21278 v8::None,
21279 v8::AccessorSignature::New(context->GetIsolate(), templ));
21280 context->Global()->Set(v8_str("f"), templ->GetFunction());
21281
21282 printf("Testing positive ...\n");
21283 CompileRun("var obj = new f();");
21284 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21285 CheckInstanceCheckedAccessors(true);
21286
21287 printf("Testing negative ...\n");
21288 CompileRun("var obj = {};"
21289 "obj.__proto__ = new f();");
21290 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21291 CheckInstanceCheckedAccessors(false);
21292}
21293
21294
21295THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21296 v8::internal::FLAG_allow_natives_syntax = true;
21297 LocalContext context;
21298 v8::HandleScope scope(context->GetIsolate());
21299
21300 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21301 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21302 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21303 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21304 v8::None,
21305 v8::AccessorSignature::New(context->GetIsolate(), templ));
21306 context->Global()->Set(v8_str("f"), templ->GetFunction());
21307
21308 printf("Testing positive ...\n");
21309 CompileRun("var obj = new f();");
21310 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21311 CheckInstanceCheckedAccessors(true);
21312
21313 printf("Testing negative ...\n");
21314 CompileRun("var obj = {};"
21315 "obj.__proto__ = new f();");
21316 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21317 CheckInstanceCheckedAccessors(false);
21318
21319 printf("Testing positive with modified prototype chain ...\n");
21320 CompileRun("var obj = new f();"
21321 "var pro = {};"
21322 "pro.__proto__ = obj.__proto__;"
21323 "obj.__proto__ = pro;");
21324 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21325 CheckInstanceCheckedAccessors(true);
21326}
21327
21328
21329TEST(TryFinallyMessage) {
21330 LocalContext context;
21331 v8::HandleScope scope(context->GetIsolate());
21332 {
21333 // Test that the original error message is not lost if there is a
21334 // recursive call into Javascript is done in the finally block, e.g. to
21335 // initialize an IC. (crbug.com/129171)
21336 TryCatch try_catch;
21337 const char* trigger_ic =
21338 "try { \n"
21339 " throw new Error('test'); \n"
21340 "} finally { \n"
21341 " var x = 0; \n"
21342 " x++; \n" // Trigger an IC initialization here.
21343 "} \n";
21344 CompileRun(trigger_ic);
21345 CHECK(try_catch.HasCaught());
21346 Local<Message> message = try_catch.Message();
21347 CHECK(!message.IsEmpty());
21348 CHECK_EQ(2, message->GetLineNumber());
21349 }
21350
21351 {
21352 // Test that the original exception message is indeed overwritten if
21353 // a new error is thrown in the finally block.
21354 TryCatch try_catch;
21355 const char* throw_again =
21356 "try { \n"
21357 " throw new Error('test'); \n"
21358 "} finally { \n"
21359 " var x = 0; \n"
21360 " x++; \n"
21361 " throw new Error('again'); \n" // This is the new uncaught error.
21362 "} \n";
21363 CompileRun(throw_again);
21364 CHECK(try_catch.HasCaught());
21365 Local<Message> message = try_catch.Message();
21366 CHECK(!message.IsEmpty());
21367 CHECK_EQ(6, message->GetLineNumber());
21368 }
21369}
21370
21371
21372static void Helper137002(bool do_store,
21373 bool polymorphic,
21374 bool remove_accessor,
21375 bool interceptor) {
21376 LocalContext context;
21377 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21378 if (interceptor) {
21379 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21380 } else {
21381 templ->SetAccessor(v8_str("foo"),
21382 GetterWhichReturns42,
21383 SetterWhichSetsYOnThisTo23);
21384 }
21385 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21386
21387 // Turn monomorphic on slow object with native accessor, then turn
21388 // polymorphic, finally optimize to create negative lookup and fail.
21389 CompileRun(do_store ?
21390 "function f(x) { x.foo = void 0; }" :
21391 "function f(x) { return x.foo; }");
21392 CompileRun("obj.y = void 0;");
21393 if (!interceptor) {
21394 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21395 }
21396 CompileRun("obj.__proto__ = null;"
21397 "f(obj); f(obj); f(obj);");
21398 if (polymorphic) {
21399 CompileRun("f({});");
21400 }
21401 CompileRun("obj.y = void 0;"
21402 "%OptimizeFunctionOnNextCall(f);");
21403 if (remove_accessor) {
21404 CompileRun("delete obj.foo;");
21405 }
21406 CompileRun("var result = f(obj);");
21407 if (do_store) {
21408 CompileRun("result = obj.y;");
21409 }
21410 if (remove_accessor && !interceptor) {
21411 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21412 } else {
21413 CHECK_EQ(do_store ? 23 : 42,
21414 context->Global()->Get(v8_str("result"))->Int32Value());
21415 }
21416}
21417
21418
21419THREADED_TEST(Regress137002a) {
21420 i::FLAG_allow_natives_syntax = true;
21421 i::FLAG_compilation_cache = false;
21422 v8::HandleScope scope(CcTest::isolate());
21423 for (int i = 0; i < 16; i++) {
21424 Helper137002(i & 8, i & 4, i & 2, i & 1);
21425 }
21426}
21427
21428
21429THREADED_TEST(Regress137002b) {
21430 i::FLAG_allow_natives_syntax = true;
21431 LocalContext context;
21432 v8::Isolate* isolate = context->GetIsolate();
21433 v8::HandleScope scope(isolate);
21434 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21435 templ->SetAccessor(v8_str("foo"),
21436 GetterWhichReturns42,
21437 SetterWhichSetsYOnThisTo23);
21438 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21439
21440 // Turn monomorphic on slow object with native accessor, then just
21441 // delete the property and fail.
21442 CompileRun("function load(x) { return x.foo; }"
21443 "function store(x) { x.foo = void 0; }"
21444 "function keyed_load(x, key) { return x[key]; }"
21445 // Second version of function has a different source (add void 0)
21446 // so that it does not share code with the first version. This
21447 // ensures that the ICs are monomorphic.
21448 "function load2(x) { void 0; return x.foo; }"
21449 "function store2(x) { void 0; x.foo = void 0; }"
21450 "function keyed_load2(x, key) { void 0; return x[key]; }"
21451
21452 "obj.y = void 0;"
21453 "obj.__proto__ = null;"
21454 "var subobj = {};"
21455 "subobj.y = void 0;"
21456 "subobj.__proto__ = obj;"
21457 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21458
21459 // Make the ICs monomorphic.
21460 "load(obj); load(obj);"
21461 "load2(subobj); load2(subobj);"
21462 "store(obj); store(obj);"
21463 "store2(subobj); store2(subobj);"
21464 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21465 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21466
21467 // Actually test the shiny new ICs and better not crash. This
21468 // serves as a regression test for issue 142088 as well.
21469 "load(obj);"
21470 "load2(subobj);"
21471 "store(obj);"
21472 "store2(subobj);"
21473 "keyed_load(obj, 'foo');"
21474 "keyed_load2(subobj, 'foo');"
21475
21476 // Delete the accessor. It better not be called any more now.
21477 "delete obj.foo;"
21478 "obj.y = void 0;"
21479 "subobj.y = void 0;"
21480
21481 "var load_result = load(obj);"
21482 "var load_result2 = load2(subobj);"
21483 "var keyed_load_result = keyed_load(obj, 'foo');"
21484 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21485 "store(obj);"
21486 "store2(subobj);"
21487 "var y_from_obj = obj.y;"
21488 "var y_from_subobj = subobj.y;");
21489 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21490 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21491 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21492 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21493 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21494 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21495}
21496
21497
21498THREADED_TEST(Regress142088) {
21499 i::FLAG_allow_natives_syntax = true;
21500 LocalContext context;
21501 v8::Isolate* isolate = context->GetIsolate();
21502 v8::HandleScope scope(isolate);
21503 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21504 templ->SetAccessor(v8_str("foo"),
21505 GetterWhichReturns42,
21506 SetterWhichSetsYOnThisTo23);
21507 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21508
21509 CompileRun("function load(x) { return x.foo; }"
21510 "var o = Object.create(obj);"
21511 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21512 "load(o); load(o); load(o); load(o);");
21513}
21514
21515
21516THREADED_TEST(Regress3337) {
21517 LocalContext context;
21518 v8::Isolate* isolate = context->GetIsolate();
21519 v8::HandleScope scope(isolate);
21520 Local<v8::Object> o1 = Object::New(isolate);
21521 Local<v8::Object> o2 = Object::New(isolate);
21522 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21523 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21524 CHECK(io1->map() == io2->map());
21525 o1->SetIndexedPropertiesToExternalArrayData(
21526 NULL, v8::kExternalUint32Array, 0);
21527 o2->SetIndexedPropertiesToExternalArrayData(
21528 NULL, v8::kExternalUint32Array, 0);
21529 CHECK(io1->map() == io2->map());
21530}
21531
21532
21533THREADED_TEST(Regress137496) {
21534 i::FLAG_expose_gc = true;
21535 LocalContext context;
21536 v8::HandleScope scope(context->GetIsolate());
21537
21538 // Compile a try-finally clause where the finally block causes a GC
21539 // while there still is a message pending for external reporting.
21540 TryCatch try_catch;
21541 try_catch.SetVerbose(true);
21542 CompileRun("try { throw new Error(); } finally { gc(); }");
21543 CHECK(try_catch.HasCaught());
21544}
21545
21546
21547THREADED_TEST(Regress149912) {
21548 LocalContext context;
21549 v8::HandleScope scope(context->GetIsolate());
21550 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21551 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21552 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21553 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21554}
21555
21556
21557THREADED_TEST(Regress157124) {
21558 LocalContext context;
21559 v8::Isolate* isolate = context->GetIsolate();
21560 v8::HandleScope scope(isolate);
21561 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21562 Local<Object> obj = templ->NewInstance();
21563 obj->GetIdentityHash();
21564 obj->DeleteHiddenValue(v8_str("Bug"));
21565}
21566
21567
21568THREADED_TEST(Regress2535) {
21569 LocalContext context;
21570 v8::HandleScope scope(context->GetIsolate());
21571 Local<Value> set_value = CompileRun("new Set();");
21572 Local<Object> set_object(Local<Object>::Cast(set_value));
21573 CHECK_EQ(0, set_object->InternalFieldCount());
21574 Local<Value> map_value = CompileRun("new Map();");
21575 Local<Object> map_object(Local<Object>::Cast(map_value));
21576 CHECK_EQ(0, map_object->InternalFieldCount());
21577}
21578
21579
21580THREADED_TEST(Regress2746) {
21581 LocalContext context;
21582 v8::Isolate* isolate = context->GetIsolate();
21583 v8::HandleScope scope(isolate);
21584 Local<Object> obj = Object::New(isolate);
21585 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21586 obj->SetHiddenValue(key, v8::Undefined(isolate));
21587 Local<Value> value = obj->GetHiddenValue(key);
21588 CHECK(!value.IsEmpty());
21589 CHECK(value->IsUndefined());
21590}
21591
21592
21593THREADED_TEST(Regress260106) {
21594 LocalContext context;
21595 v8::Isolate* isolate = context->GetIsolate();
21596 v8::HandleScope scope(isolate);
21597 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21598 DummyCallHandler);
21599 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21600 Local<Function> function = templ->GetFunction();
21601 CHECK(!function.IsEmpty());
21602 CHECK(function->IsFunction());
21603}
21604
21605
21606THREADED_TEST(JSONParseObject) {
21607 LocalContext context;
21608 HandleScope scope(context->GetIsolate());
21609 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21610 Handle<Object> global = context->Global();
21611 global->Set(v8_str("obj"), obj);
21612 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21613}
21614
21615
21616THREADED_TEST(JSONParseNumber) {
21617 LocalContext context;
21618 HandleScope scope(context->GetIsolate());
21619 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21620 Handle<Object> global = context->Global();
21621 global->Set(v8_str("obj"), obj);
21622 ExpectString("JSON.stringify(obj)", "42");
21623}
21624
21625
21626#if V8_OS_POSIX && !V8_OS_NACL
21627class ThreadInterruptTest {
21628 public:
21629 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21630 ~ThreadInterruptTest() {}
21631
21632 void RunTest() {
21633 InterruptThread i_thread(this);
21634 i_thread.Start();
21635
21636 sem_.Wait();
21637 CHECK_EQ(kExpectedValue, sem_value_);
21638 }
21639
21640 private:
21641 static const int kExpectedValue = 1;
21642
21643 class InterruptThread : public v8::base::Thread {
21644 public:
21645 explicit InterruptThread(ThreadInterruptTest* test)
21646 : Thread(Options("InterruptThread")), test_(test) {}
21647
21648 virtual void Run() {
21649 struct sigaction action;
21650
21651 // Ensure that we'll enter waiting condition
21652 v8::base::OS::Sleep(100);
21653
21654 // Setup signal handler
21655 memset(&action, 0, sizeof(action));
21656 action.sa_handler = SignalHandler;
21657 sigaction(SIGCHLD, &action, NULL);
21658
21659 // Send signal
21660 kill(getpid(), SIGCHLD);
21661
21662 // Ensure that if wait has returned because of error
21663 v8::base::OS::Sleep(100);
21664
21665 // Set value and signal semaphore
21666 test_->sem_value_ = 1;
21667 test_->sem_.Signal();
21668 }
21669
21670 static void SignalHandler(int signal) {
21671 }
21672
21673 private:
21674 ThreadInterruptTest* test_;
21675 };
21676
21677 v8::base::Semaphore sem_;
21678 volatile int sem_value_;
21679};
21680
21681
21682THREADED_TEST(SemaphoreInterruption) {
21683 ThreadInterruptTest().RunTest();
21684}
21685
21686
21687#endif // V8_OS_POSIX
21688
21689
21690static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21691 Local<Value> name,
21692 v8::AccessType type,
21693 Local<Value> data) {
21694 i::PrintF("Named access blocked.\n");
21695 return false;
21696}
21697
21698
21699static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21700 uint32_t key,
21701 v8::AccessType type,
21702 Local<Value> data) {
21703 i::PrintF("Indexed access blocked.\n");
21704 return false;
21705}
21706
21707
21708void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21709 CHECK(false);
21710}
21711
21712
21713TEST(JSONStringifyAccessCheck) {
21714 v8::V8::Initialize();
21715 v8::Isolate* isolate = CcTest::isolate();
21716 v8::HandleScope scope(isolate);
21717
21718 // Create an ObjectTemplate for global objects and install access
21719 // check callbacks that will block access.
21720 v8::Handle<v8::ObjectTemplate> global_template =
21721 v8::ObjectTemplate::New(isolate);
21722 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21723 IndexAccessAlwaysBlocked);
21724
21725 // Create a context and set an x property on it's global object.
21726 LocalContext context0(NULL, global_template);
21727 v8::Handle<v8::Object> global0 = context0->Global();
21728 global0->Set(v8_str("x"), v8_num(42));
21729 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21730
21731 for (int i = 0; i < 2; i++) {
21732 if (i == 1) {
21733 // Install a toJSON function on the second run.
21734 v8::Handle<v8::FunctionTemplate> toJSON =
21735 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21736
21737 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21738 }
21739 // Create a context with a different security token so that the
21740 // failed access check callback will be called on each access.
21741 LocalContext context1(NULL, global_template);
21742 context1->Global()->Set(v8_str("other"), global0);
21743
21744 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21745 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21746 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21747
21748 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21749 array->Set(0, v8_str("a"));
21750 array->Set(1, v8_str("b"));
21751 context1->Global()->Set(v8_str("array"), array);
21752 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21753 array->TurnOnAccessCheck();
21754 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21755 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21756 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21757 }
21758}
21759
21760
21761bool access_check_fail_thrown = false;
21762bool catch_callback_called = false;
21763
21764
21765// Failed access check callback that performs a GC on each invocation.
21766void FailedAccessCheckThrows(Local<v8::Object> target,
21767 v8::AccessType type,
21768 Local<v8::Value> data) {
21769 access_check_fail_thrown = true;
21770 i::PrintF("Access check failed. Error thrown.\n");
21771 CcTest::isolate()->ThrowException(
21772 v8::Exception::Error(v8_str("cross context")));
21773}
21774
21775
21776void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21777 for (int i = 0; i < args.Length(); i++) {
21778 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21779 }
21780 catch_callback_called = true;
21781}
21782
21783
21784void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21785 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21786}
21787
21788
21789void CheckCorrectThrow(const char* script) {
21790 // Test that the script, when wrapped into a try-catch, triggers the catch
21791 // clause due to failed access check throwing an exception.
21792 // The subsequent try-catch should run without any exception.
21793 access_check_fail_thrown = false;
21794 catch_callback_called = false;
21795 i::ScopedVector<char> source(1024);
21796 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21797 CompileRun(source.start());
21798 CHECK(access_check_fail_thrown);
21799 CHECK(catch_callback_called);
21800
21801 access_check_fail_thrown = false;
21802 catch_callback_called = false;
21803 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21804 CHECK(!access_check_fail_thrown);
21805 CHECK(!catch_callback_called);
21806}
21807
21808
21809TEST(AccessCheckThrows) {
21810 i::FLAG_allow_natives_syntax = true;
21811 v8::V8::Initialize();
21812 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21813 v8::Isolate* isolate = CcTest::isolate();
21814 v8::HandleScope scope(isolate);
21815
21816 // Create an ObjectTemplate for global objects and install access
21817 // check callbacks that will block access.
21818 v8::Handle<v8::ObjectTemplate> global_template =
21819 v8::ObjectTemplate::New(isolate);
21820 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21821 IndexAccessAlwaysBlocked);
21822
21823 // Create a context and set an x property on it's global object.
21824 LocalContext context0(NULL, global_template);
21825 v8::Handle<v8::Object> global0 = context0->Global();
21826
21827 // Create a context with a different security token so that the
21828 // failed access check callback will be called on each access.
21829 LocalContext context1(NULL, global_template);
21830 context1->Global()->Set(v8_str("other"), global0);
21831
21832 v8::Handle<v8::FunctionTemplate> catcher_fun =
21833 v8::FunctionTemplate::New(isolate, CatcherCallback);
21834 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21835
21836 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21837 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21838 context1->Global()->Set(v8_str("has_own_property"),
21839 has_own_property_fun->GetFunction());
21840
21841 { v8::TryCatch try_catch;
21842 access_check_fail_thrown = false;
21843 CompileRun("other.x;");
21844 CHECK(access_check_fail_thrown);
21845 CHECK(try_catch.HasCaught());
21846 }
21847
21848 CheckCorrectThrow("other.x");
21849 CheckCorrectThrow("other[1]");
21850 CheckCorrectThrow("JSON.stringify(other)");
21851 CheckCorrectThrow("has_own_property(other, 'x')");
21852 CheckCorrectThrow("%GetProperty(other, 'x')");
21853 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21854 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21855 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21856 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21857 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21858 CheckCorrectThrow("%HasProperty(other, 'x')");
21859 CheckCorrectThrow("%HasElement(other, 1)");
21860 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21861 CheckCorrectThrow("%GetPropertyNames(other)");
21862 // PROPERTY_ATTRIBUTES_NONE = 0
21863 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21864 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21865 "other, 'x', null, null, 1)");
21866
21867 // Reset the failed access check callback so it does not influence
21868 // the other tests.
21869 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21870}
21871
21872
21873THREADED_TEST(Regress256330) {
21874 i::FLAG_allow_natives_syntax = true;
21875 LocalContext context;
21876 v8::HandleScope scope(context->GetIsolate());
21877 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21878 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21879 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21880 CompileRun("\"use strict\"; var o = new Bug;"
21881 "function f(o) { o.x = 10; };"
21882 "f(o); f(o); f(o);"
21883 "%OptimizeFunctionOnNextCall(f);"
21884 "f(o);");
21885 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21886}
21887
21888
21889THREADED_TEST(CrankshaftInterceptorSetter) {
21890 i::FLAG_allow_natives_syntax = true;
21891 v8::HandleScope scope(CcTest::isolate());
21892 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21893 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21894 LocalContext env;
21895 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21896 CompileRun("var obj = new Obj;"
21897 // Initialize fields to avoid transitions later.
21898 "obj.age = 0;"
21899 "obj.accessor_age = 42;"
21900 "function setter(i) { this.accessor_age = i; };"
21901 "function getter() { return this.accessor_age; };"
21902 "function setAge(i) { obj.age = i; };"
21903 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21904 "setAge(1);"
21905 "setAge(2);"
21906 "setAge(3);"
21907 "%OptimizeFunctionOnNextCall(setAge);"
21908 "setAge(4);");
21909 // All stores went through the interceptor.
21910 ExpectInt32("obj.interceptor_age", 4);
21911 ExpectInt32("obj.accessor_age", 42);
21912}
21913
21914
21915THREADED_TEST(CrankshaftInterceptorGetter) {
21916 i::FLAG_allow_natives_syntax = true;
21917 v8::HandleScope scope(CcTest::isolate());
21918 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21919 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21920 LocalContext env;
21921 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21922 CompileRun("var obj = new Obj;"
21923 // Initialize fields to avoid transitions later.
21924 "obj.age = 1;"
21925 "obj.accessor_age = 42;"
21926 "function getter() { return this.accessor_age; };"
21927 "function getAge() { return obj.interceptor_age; };"
21928 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21929 "getAge();"
21930 "getAge();"
21931 "getAge();"
21932 "%OptimizeFunctionOnNextCall(getAge);");
21933 // Access through interceptor.
21934 ExpectInt32("getAge()", 1);
21935}
21936
21937
21938THREADED_TEST(CrankshaftInterceptorFieldRead) {
21939 i::FLAG_allow_natives_syntax = true;
21940 v8::HandleScope scope(CcTest::isolate());
21941 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21942 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21943 LocalContext env;
21944 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21945 CompileRun("var obj = new Obj;"
21946 "obj.__proto__.interceptor_age = 42;"
21947 "obj.age = 100;"
21948 "function getAge() { return obj.interceptor_age; };");
21949 ExpectInt32("getAge();", 100);
21950 ExpectInt32("getAge();", 100);
21951 ExpectInt32("getAge();", 100);
21952 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21953 // Access through interceptor.
21954 ExpectInt32("getAge();", 100);
21955}
21956
21957
21958THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21959 i::FLAG_allow_natives_syntax = true;
21960 v8::HandleScope scope(CcTest::isolate());
21961 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21962 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21963 LocalContext env;
21964 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21965 CompileRun("var obj = new Obj;"
21966 "obj.age = 100000;"
21967 "function setAge(i) { obj.age = i };"
21968 "setAge(100);"
21969 "setAge(101);"
21970 "setAge(102);"
21971 "%OptimizeFunctionOnNextCall(setAge);"
21972 "setAge(103);");
21973 ExpectInt32("obj.age", 100000);
21974 ExpectInt32("obj.interceptor_age", 103);
21975}
21976
21977
21978class RequestInterruptTestBase {
21979 public:
21980 RequestInterruptTestBase()
21981 : env_(),
21982 isolate_(env_->GetIsolate()),
21983 sem_(0),
21984 warmup_(20000),
21985 should_continue_(true) {
21986 }
21987
21988 virtual ~RequestInterruptTestBase() { }
21989
21990 virtual void StartInterruptThread() = 0;
21991
21992 virtual void TestBody() = 0;
21993
21994 void RunTest() {
21995 StartInterruptThread();
21996
21997 v8::HandleScope handle_scope(isolate_);
21998
21999 TestBody();
22000
22001 isolate_->ClearInterrupt();
22002
22003 // Verify we arrived here because interruptor was called
22004 // not due to a bug causing us to exit the loop too early.
22005 CHECK(!should_continue());
22006 }
22007
22008 void WakeUpInterruptor() {
22009 sem_.Signal();
22010 }
22011
22012 bool should_continue() const { return should_continue_; }
22013
22014 bool ShouldContinue() {
22015 if (warmup_ > 0) {
22016 if (--warmup_ == 0) {
22017 WakeUpInterruptor();
22018 }
22019 }
22020
22021 return should_continue_;
22022 }
22023
22024 static void ShouldContinueCallback(
22025 const v8::FunctionCallbackInfo<Value>& info) {
22026 RequestInterruptTestBase* test =
22027 reinterpret_cast<RequestInterruptTestBase*>(
22028 info.Data().As<v8::External>()->Value());
22029 info.GetReturnValue().Set(test->ShouldContinue());
22030 }
22031
22032 LocalContext env_;
22033 v8::Isolate* isolate_;
22034 v8::base::Semaphore sem_;
22035 int warmup_;
22036 bool should_continue_;
22037};
22038
22039
22040class RequestInterruptTestBaseWithSimpleInterrupt
22041 : public RequestInterruptTestBase {
22042 public:
22043 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22044
22045 virtual void StartInterruptThread() {
22046 i_thread.Start();
22047 }
22048
22049 private:
22050 class InterruptThread : public v8::base::Thread {
22051 public:
22052 explicit InterruptThread(RequestInterruptTestBase* test)
22053 : Thread(Options("RequestInterruptTest")), test_(test) {}
22054
22055 virtual void Run() {
22056 test_->sem_.Wait();
22057 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22058 }
22059
22060 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22061 reinterpret_cast<RequestInterruptTestBase*>(data)->
22062 should_continue_ = false;
22063 }
22064
22065 private:
22066 RequestInterruptTestBase* test_;
22067 };
22068
22069 InterruptThread i_thread;
22070};
22071
22072
22073class RequestInterruptTestWithFunctionCall
22074 : public RequestInterruptTestBaseWithSimpleInterrupt {
22075 public:
22076 virtual void TestBody() {
22077 Local<Function> func = Function::New(
22078 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22079 env_->Global()->Set(v8_str("ShouldContinue"), func);
22080
22081 CompileRun("while (ShouldContinue()) { }");
22082 }
22083};
22084
22085
22086class RequestInterruptTestWithMethodCall
22087 : public RequestInterruptTestBaseWithSimpleInterrupt {
22088 public:
22089 virtual void TestBody() {
22090 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22091 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22092 proto->Set(v8_str("shouldContinue"), Function::New(
22093 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22094 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22095
22096 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22097 }
22098};
22099
22100
22101class RequestInterruptTestWithAccessor
22102 : public RequestInterruptTestBaseWithSimpleInterrupt {
22103 public:
22104 virtual void TestBody() {
22105 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22106 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22107 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22108 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22109 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22110
22111 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22112 }
22113};
22114
22115
22116class RequestInterruptTestWithNativeAccessor
22117 : public RequestInterruptTestBaseWithSimpleInterrupt {
22118 public:
22119 virtual void TestBody() {
22120 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22121 t->InstanceTemplate()->SetNativeDataProperty(
22122 v8_str("shouldContinue"),
22123 &ShouldContinueNativeGetter,
22124 NULL,
22125 v8::External::New(isolate_, this));
22126 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22127
22128 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22129 }
22130
22131 private:
22132 static void ShouldContinueNativeGetter(
22133 Local<String> property,
22134 const v8::PropertyCallbackInfo<v8::Value>& info) {
22135 RequestInterruptTestBase* test =
22136 reinterpret_cast<RequestInterruptTestBase*>(
22137 info.Data().As<v8::External>()->Value());
22138 info.GetReturnValue().Set(test->ShouldContinue());
22139 }
22140};
22141
22142
22143class RequestInterruptTestWithMethodCallAndInterceptor
22144 : public RequestInterruptTestBaseWithSimpleInterrupt {
22145 public:
22146 virtual void TestBody() {
22147 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22148 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22149 proto->Set(v8_str("shouldContinue"), Function::New(
22150 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22151 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22152 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22153
22154 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22155
22156 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22157 }
22158
22159 private:
22160 static void EmptyInterceptor(
22161 Local<String> property,
22162 const v8::PropertyCallbackInfo<v8::Value>& info) {
22163 }
22164};
22165
22166
22167class RequestInterruptTestWithMathAbs
22168 : public RequestInterruptTestBaseWithSimpleInterrupt {
22169 public:
22170 virtual void TestBody() {
22171 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22172 isolate_,
22173 WakeUpInterruptorCallback,
22174 v8::External::New(isolate_, this)));
22175
22176 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22177 isolate_,
22178 ShouldContinueCallback,
22179 v8::External::New(isolate_, this)));
22180
22181 i::FLAG_allow_natives_syntax = true;
22182 CompileRun("function loopish(o) {"
22183 " var pre = 10;"
22184 " while (o.abs(1) > 0) {"
22185 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22186 " if (pre > 0) {"
22187 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22188 " }"
22189 " }"
22190 "}"
22191 "var i = 50;"
22192 "var obj = {abs: function () { return i-- }, x: null};"
22193 "delete obj.x;"
22194 "loopish(obj);"
22195 "%OptimizeFunctionOnNextCall(loopish);"
22196 "loopish(Math);");
22197
22198 i::FLAG_allow_natives_syntax = false;
22199 }
22200
22201 private:
22202 static void WakeUpInterruptorCallback(
22203 const v8::FunctionCallbackInfo<Value>& info) {
22204 if (!info[0]->BooleanValue()) return;
22205
22206 RequestInterruptTestBase* test =
22207 reinterpret_cast<RequestInterruptTestBase*>(
22208 info.Data().As<v8::External>()->Value());
22209 test->WakeUpInterruptor();
22210 }
22211
22212 static void ShouldContinueCallback(
22213 const v8::FunctionCallbackInfo<Value>& info) {
22214 RequestInterruptTestBase* test =
22215 reinterpret_cast<RequestInterruptTestBase*>(
22216 info.Data().As<v8::External>()->Value());
22217 info.GetReturnValue().Set(test->should_continue());
22218 }
22219};
22220
22221
22222TEST(RequestInterruptTestWithFunctionCall) {
22223 RequestInterruptTestWithFunctionCall().RunTest();
22224}
22225
22226
22227TEST(RequestInterruptTestWithMethodCall) {
22228 RequestInterruptTestWithMethodCall().RunTest();
22229}
22230
22231
22232TEST(RequestInterruptTestWithAccessor) {
22233 RequestInterruptTestWithAccessor().RunTest();
22234}
22235
22236
22237TEST(RequestInterruptTestWithNativeAccessor) {
22238 RequestInterruptTestWithNativeAccessor().RunTest();
22239}
22240
22241
22242TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22243 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22244}
22245
22246
22247TEST(RequestInterruptTestWithMathAbs) {
22248 RequestInterruptTestWithMathAbs().RunTest();
22249}
22250
22251
22252class ClearInterruptFromAnotherThread
22253 : public RequestInterruptTestBase {
22254 public:
22255 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22256
22257 virtual void StartInterruptThread() {
22258 i_thread.Start();
22259 }
22260
22261 virtual void TestBody() {
22262 Local<Function> func = Function::New(
22263 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22264 env_->Global()->Set(v8_str("ShouldContinue"), func);
22265
22266 CompileRun("while (ShouldContinue()) { }");
22267 }
22268
22269 private:
22270 class InterruptThread : public v8::base::Thread {
22271 public:
22272 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22273 : Thread(Options("RequestInterruptTest")), test_(test) {}
22274
22275 virtual void Run() {
22276 test_->sem_.Wait();
22277 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22278 test_->sem_.Wait();
22279 test_->isolate_->ClearInterrupt();
22280 test_->sem2_.Signal();
22281 }
22282
22283 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22284 ClearInterruptFromAnotherThread* test =
22285 reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22286 test->sem_.Signal();
22287 bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22288 // Crash instead of timeout to make this failure more prominent.
22289 CHECK(success);
22290 test->should_continue_ = false;
22291 }
22292
22293 private:
22294 ClearInterruptFromAnotherThread* test_;
22295 };
22296
22297 InterruptThread i_thread;
22298 v8::base::Semaphore sem2_;
22299};
22300
22301
22302TEST(ClearInterruptFromAnotherThread) {
22303 ClearInterruptFromAnotherThread().RunTest();
22304}
22305
22306
22307static Local<Value> function_new_expected_env;
22308static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22309 CHECK_EQ(function_new_expected_env, info.Data());
22310 info.GetReturnValue().Set(17);
22311}
22312
22313
22314THREADED_TEST(FunctionNew) {
22315 LocalContext env;
22316 v8::Isolate* isolate = env->GetIsolate();
22317 v8::HandleScope scope(isolate);
22318 Local<Object> data = v8::Object::New(isolate);
22319 function_new_expected_env = data;
22320 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22321 env->Global()->Set(v8_str("func"), func);
22322 Local<Value> result = CompileRun("func();");
22323 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22324 // Verify function not cached
22325 int serial_number =
22326 i::Smi::cast(v8::Utils::OpenHandle(*func)
22327 ->shared()->get_api_func_data()->serial_number())->value();
22328 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22329 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22330 i::Handle<i::Object> elm =
22331 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22332 CHECK(elm->IsUndefined());
22333 // Verify that each Function::New creates a new function instance
22334 Local<Object> data2 = v8::Object::New(isolate);
22335 function_new_expected_env = data2;
22336 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22337 CHECK(!func2->IsNull());
22338 CHECK_NE(func, func2);
22339 env->Global()->Set(v8_str("func2"), func2);
22340 Local<Value> result2 = CompileRun("func2();");
22341 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22342}
22343
22344
22345TEST(EscapeableHandleScope) {
22346 HandleScope outer_scope(CcTest::isolate());
22347 LocalContext context;
22348 const int runs = 10;
22349 Local<String> values[runs];
22350 for (int i = 0; i < runs; i++) {
22351 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22352 Local<String> value;
22353 if (i != 0) value = v8_str("escape value");
22354 values[i] = inner_scope.Escape(value);
22355 }
22356 for (int i = 0; i < runs; i++) {
22357 Local<String> expected;
22358 if (i != 0) {
22359 CHECK_EQ(v8_str("escape value"), values[i]);
22360 } else {
22361 CHECK(values[i].IsEmpty());
22362 }
22363 }
22364}
22365
22366
22367static void SetterWhichExpectsThisAndHolderToDiffer(
22368 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22369 CHECK(info.Holder() != info.This());
22370}
22371
22372
22373TEST(Regress239669) {
22374 LocalContext context;
22375 v8::Isolate* isolate = context->GetIsolate();
22376 v8::HandleScope scope(isolate);
22377 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22378 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22379 context->Global()->Set(v8_str("P"), templ->NewInstance());
22380 CompileRun(
22381 "function C1() {"
22382 " this.x = 23;"
22383 "};"
22384 "C1.prototype = P;"
22385 "for (var i = 0; i < 4; i++ ) {"
22386 " new C1();"
22387 "}");
22388}
22389
22390
22391class ApiCallOptimizationChecker {
22392 private:
22393 static Local<Object> data;
22394 static Local<Object> receiver;
22395 static Local<Object> holder;
22396 static Local<Object> callee;
22397 static int count;
22398
22399 static void OptimizationCallback(
22400 const v8::FunctionCallbackInfo<v8::Value>& info) {
22401 CHECK(callee == info.Callee());
22402 CHECK(data == info.Data());
22403 CHECK(receiver == info.This());
22404 if (info.Length() == 1) {
22405 CHECK_EQ(v8_num(1), info[0]);
22406 }
22407 CHECK(holder == info.Holder());
22408 count++;
22409 info.GetReturnValue().Set(v8_str("returned"));
22410 }
22411
22412 public:
22413 enum SignatureType {
22414 kNoSignature,
22415 kSignatureOnReceiver,
22416 kSignatureOnPrototype
22417 };
22418
22419 void RunAll() {
22420 SignatureType signature_types[] =
22421 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22422 for (unsigned i = 0; i < arraysize(signature_types); i++) {
22423 SignatureType signature_type = signature_types[i];
22424 for (int j = 0; j < 2; j++) {
22425 bool global = j == 0;
22426 int key = signature_type +
22427 arraysize(signature_types) * (global ? 1 : 0);
22428 Run(signature_type, global, key);
22429 }
22430 }
22431 }
22432
22433 void Run(SignatureType signature_type, bool global, int key) {
22434 v8::Isolate* isolate = CcTest::isolate();
22435 v8::HandleScope scope(isolate);
22436 // Build a template for signature checks.
22437 Local<v8::ObjectTemplate> signature_template;
22438 Local<v8::Signature> signature;
22439 {
22440 Local<v8::FunctionTemplate> parent_template =
22441 FunctionTemplate::New(isolate);
22442 parent_template->SetHiddenPrototype(true);
22443 Local<v8::FunctionTemplate> function_template
22444 = FunctionTemplate::New(isolate);
22445 function_template->Inherit(parent_template);
22446 switch (signature_type) {
22447 case kNoSignature:
22448 break;
22449 case kSignatureOnReceiver:
22450 signature = v8::Signature::New(isolate, function_template);
22451 break;
22452 case kSignatureOnPrototype:
22453 signature = v8::Signature::New(isolate, parent_template);
22454 break;
22455 }
22456 signature_template = function_template->InstanceTemplate();
22457 }
22458 // Global object must pass checks.
22459 Local<v8::Context> context =
22460 v8::Context::New(isolate, NULL, signature_template);
22461 v8::Context::Scope context_scope(context);
22462 // Install regular object that can pass signature checks.
22463 Local<Object> function_receiver = signature_template->NewInstance();
22464 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22465 // Get the holder objects.
22466 Local<Object> inner_global =
22467 Local<Object>::Cast(context->Global()->GetPrototype());
22468 // Install functions on hidden prototype object if there is one.
22469 data = Object::New(isolate);
22470 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22471 isolate, OptimizationCallback, data, signature);
22472 Local<Function> function = function_template->GetFunction();
22473 Local<Object> global_holder = inner_global;
22474 Local<Object> function_holder = function_receiver;
22475 if (signature_type == kSignatureOnPrototype) {
22476 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22477 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22478 }
22479 global_holder->Set(v8_str("g_f"), function);
22480 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22481 function_holder->Set(v8_str("f"), function);
22482 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22483 // Initialize expected values.
22484 callee = function;
22485 count = 0;
22486 if (global) {
22487 receiver = context->Global();
22488 holder = inner_global;
22489 } else {
22490 holder = function_receiver;
22491 // If not using a signature, add something else to the prototype chain
22492 // to test the case that holder != receiver
22493 if (signature_type == kNoSignature) {
22494 receiver = Local<Object>::Cast(CompileRun(
22495 "var receiver_subclass = {};\n"
22496 "receiver_subclass.__proto__ = function_receiver;\n"
22497 "receiver_subclass"));
22498 } else {
22499 receiver = Local<Object>::Cast(CompileRun(
22500 "var receiver_subclass = function_receiver;\n"
22501 "receiver_subclass"));
22502 }
22503 }
22504 // With no signature, the holder is not set.
22505 if (signature_type == kNoSignature) holder = receiver;
22506 // build wrap_function
22507 i::ScopedVector<char> wrap_function(200);
22508 if (global) {
22509 i::SNPrintF(
22510 wrap_function,
22511 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22512 "function wrap_get_%d() { return this.g_acc; }\n"
22513 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22514 key, key, key);
22515 } else {
22516 i::SNPrintF(
22517 wrap_function,
22518 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22519 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22520 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22521 key, key, key);
22522 }
22523 // build source string
22524 i::ScopedVector<char> source(1000);
22525 i::SNPrintF(
22526 source,
22527 "%s\n" // wrap functions
22528 "function wrap_f() { return wrap_f_%d(); }\n"
22529 "function wrap_get() { return wrap_get_%d(); }\n"
22530 "function wrap_set() { return wrap_set_%d(); }\n"
22531 "check = function(returned) {\n"
22532 " if (returned !== 'returned') { throw returned; }\n"
22533 "}\n"
22534 "\n"
22535 "check(wrap_f());\n"
22536 "check(wrap_f());\n"
22537 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22538 "check(wrap_f());\n"
22539 "\n"
22540 "check(wrap_get());\n"
22541 "check(wrap_get());\n"
22542 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22543 "check(wrap_get());\n"
22544 "\n"
22545 "check = function(returned) {\n"
22546 " if (returned !== 1) { throw returned; }\n"
22547 "}\n"
22548 "check(wrap_set());\n"
22549 "check(wrap_set());\n"
22550 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22551 "check(wrap_set());\n",
22552 wrap_function.start(), key, key, key, key, key, key);
22553 v8::TryCatch try_catch;
22554 CompileRun(source.start());
22555 DCHECK(!try_catch.HasCaught());
22556 CHECK_EQ(9, count);
22557 }
22558};
22559
22560
22561Local<Object> ApiCallOptimizationChecker::data;
22562Local<Object> ApiCallOptimizationChecker::receiver;
22563Local<Object> ApiCallOptimizationChecker::holder;
22564Local<Object> ApiCallOptimizationChecker::callee;
22565int ApiCallOptimizationChecker::count = 0;
22566
22567
22568TEST(TestFunctionCallOptimization) {
22569 i::FLAG_allow_natives_syntax = true;
22570 ApiCallOptimizationChecker checker;
22571 checker.RunAll();
22572}
22573
22574
22575static const char* last_event_message;
22576static int last_event_status;
22577void StoringEventLoggerCallback(const char* message, int status) {
22578 last_event_message = message;
22579 last_event_status = status;
22580}
22581
22582
22583TEST(EventLogging) {
22584 v8::Isolate* isolate = CcTest::isolate();
22585 isolate->SetEventLogger(StoringEventLoggerCallback);
22586 v8::internal::HistogramTimer histogramTimer(
22587 "V8.Test", 0, 10000, 50,
22588 reinterpret_cast<v8::internal::Isolate*>(isolate));
22589 histogramTimer.Start();
22590 CHECK_EQ("V8.Test", last_event_message);
22591 CHECK_EQ(0, last_event_status);
22592 histogramTimer.Stop();
22593 CHECK_EQ("V8.Test", last_event_message);
22594 CHECK_EQ(1, last_event_status);
22595}
22596
22597
22598TEST(Promises) {
22599 LocalContext context;
22600 v8::Isolate* isolate = context->GetIsolate();
22601 v8::HandleScope scope(isolate);
22602 Handle<Object> global = context->Global();
22603
22604 // Creation.
22605 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22606 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22607 Handle<v8::Promise> p = pr->GetPromise();
22608 Handle<v8::Promise> r = rr->GetPromise();
22609
22610 // IsPromise predicate.
22611 CHECK(p->IsPromise());
22612 CHECK(r->IsPromise());
22613 Handle<Value> o = v8::Object::New(isolate);
22614 CHECK(!o->IsPromise());
22615
22616 // Resolution and rejection.
22617 pr->Resolve(v8::Integer::New(isolate, 1));
22618 CHECK(p->IsPromise());
22619 rr->Reject(v8::Integer::New(isolate, 2));
22620 CHECK(r->IsPromise());
22621
22622 // Chaining non-pending promises.
22623 CompileRun(
22624 "var x1 = 0;\n"
22625 "var x2 = 0;\n"
22626 "function f1(x) { x1 = x; return x+1 };\n"
22627 "function f2(x) { x2 = x; return x+1 };\n");
22628 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22629 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22630
22631 p->Chain(f1);
22632 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22633 isolate->RunMicrotasks();
22634 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22635
22636 p->Catch(f2);
22637 isolate->RunMicrotasks();
22638 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22639
22640 r->Catch(f2);
22641 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22642 isolate->RunMicrotasks();
22643 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22644
22645 r->Chain(f1);
22646 isolate->RunMicrotasks();
22647 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22648
22649 // Chaining pending promises.
22650 CompileRun("x1 = x2 = 0;");
22651 pr = v8::Promise::Resolver::New(isolate);
22652 rr = v8::Promise::Resolver::New(isolate);
22653
22654 pr->GetPromise()->Chain(f1);
22655 rr->GetPromise()->Catch(f2);
22656 isolate->RunMicrotasks();
22657 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22658 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22659
22660 pr->Resolve(v8::Integer::New(isolate, 1));
22661 rr->Reject(v8::Integer::New(isolate, 2));
22662 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22663 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22664
22665 isolate->RunMicrotasks();
22666 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22667 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22668
22669 // Multi-chaining.
22670 CompileRun("x1 = x2 = 0;");
22671 pr = v8::Promise::Resolver::New(isolate);
22672 pr->GetPromise()->Chain(f1)->Chain(f2);
22673 pr->Resolve(v8::Integer::New(isolate, 3));
22674 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22675 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22676 isolate->RunMicrotasks();
22677 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22678 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22679
22680 CompileRun("x1 = x2 = 0;");
22681 rr = v8::Promise::Resolver::New(isolate);
22682 rr->GetPromise()->Catch(f1)->Chain(f2);
22683 rr->Reject(v8::Integer::New(isolate, 3));
22684 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22685 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22686 isolate->RunMicrotasks();
22687 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22688 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22689}
22690
22691
22692TEST(PromiseThen) {
22693 LocalContext context;
22694 v8::Isolate* isolate = context->GetIsolate();
22695 v8::HandleScope scope(isolate);
22696 Handle<Object> global = context->Global();
22697
22698 // Creation.
22699 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22700 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22701 Handle<v8::Promise> p = pr->GetPromise();
22702 Handle<v8::Promise> q = qr->GetPromise();
22703
22704 CHECK(p->IsPromise());
22705 CHECK(q->IsPromise());
22706
22707 pr->Resolve(v8::Integer::New(isolate, 1));
22708 qr->Resolve(p);
22709
22710 // Chaining non-pending promises.
22711 CompileRun(
22712 "var x1 = 0;\n"
22713 "var x2 = 0;\n"
22714 "function f1(x) { x1 = x; return x+1 };\n"
22715 "function f2(x) { x2 = x; return x+1 };\n");
22716 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22717 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22718
22719 // Chain
22720 q->Chain(f1);
22721 CHECK(global->Get(v8_str("x1"))->IsNumber());
22722 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22723 isolate->RunMicrotasks();
22724 CHECK(!global->Get(v8_str("x1"))->IsNumber());
22725 CHECK_EQ(p, global->Get(v8_str("x1")));
22726
22727 // Then
22728 CompileRun("x1 = x2 = 0;");
22729 q->Then(f1);
22730 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22731 isolate->RunMicrotasks();
22732 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22733
22734 // Then
22735 CompileRun("x1 = x2 = 0;");
22736 pr = v8::Promise::Resolver::New(isolate);
22737 qr = v8::Promise::Resolver::New(isolate);
22738
22739 qr->Resolve(pr);
22740 qr->GetPromise()->Then(f1)->Then(f2);
22741
22742 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22743 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22744 isolate->RunMicrotasks();
22745 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22746 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22747
22748 pr->Resolve(v8::Integer::New(isolate, 3));
22749
22750 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22751 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22752 isolate->RunMicrotasks();
22753 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22754 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22755}
22756
22757
22758TEST(DisallowJavascriptExecutionScope) {
22759 LocalContext context;
22760 v8::Isolate* isolate = context->GetIsolate();
22761 v8::HandleScope scope(isolate);
22762 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22763 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22764 CompileRun("2+2");
22765}
22766
22767
22768TEST(AllowJavascriptExecutionScope) {
22769 LocalContext context;
22770 v8::Isolate* isolate = context->GetIsolate();
22771 v8::HandleScope scope(isolate);
22772 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22773 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22774 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22775 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22776 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22777 CompileRun("1+1");
22778 }
22779}
22780
22781
22782TEST(ThrowOnJavascriptExecution) {
22783 LocalContext context;
22784 v8::Isolate* isolate = context->GetIsolate();
22785 v8::HandleScope scope(isolate);
22786 v8::TryCatch try_catch;
22787 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22788 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22789 CompileRun("1+1");
22790 CHECK(try_catch.HasCaught());
22791}
22792
22793
22794TEST(Regress354123) {
22795 LocalContext current;
22796 v8::Isolate* isolate = current->GetIsolate();
22797 v8::HandleScope scope(isolate);
22798
22799 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22800 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22801 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22802
22803 // Test access using __proto__ from the prototype chain.
22804 named_access_count = 0;
22805 CompileRun("friend.__proto__ = {};");
22806 CHECK_EQ(2, named_access_count);
22807 CompileRun("friend.__proto__;");
22808 CHECK_EQ(4, named_access_count);
22809
22810 // Test access using __proto__ as a hijacked function (A).
22811 named_access_count = 0;
22812 CompileRun("var p = Object.prototype;"
22813 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22814 "f.call(friend, {});");
22815 CHECK_EQ(1, named_access_count);
22816 CompileRun("var p = Object.prototype;"
22817 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22818 "f.call(friend);");
22819 CHECK_EQ(2, named_access_count);
22820
22821 // Test access using __proto__ as a hijacked function (B).
22822 named_access_count = 0;
22823 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22824 "f.call(friend, {});");
22825 CHECK_EQ(1, named_access_count);
22826 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22827 "f.call(friend);");
22828 CHECK_EQ(2, named_access_count);
22829
22830 // Test access using Object.setPrototypeOf reflective method.
22831 named_access_count = 0;
22832 CompileRun("Object.setPrototypeOf(friend, {});");
22833 CHECK_EQ(1, named_access_count);
22834 CompileRun("Object.getPrototypeOf(friend);");
22835 CHECK_EQ(2, named_access_count);
22836}
22837
22838
22839TEST(CaptureStackTraceForStackOverflow) {
22840 v8::internal::FLAG_stack_size = 150;
22841 LocalContext current;
22842 v8::Isolate* isolate = current->GetIsolate();
22843 v8::HandleScope scope(isolate);
22844 V8::SetCaptureStackTraceForUncaughtExceptions(
22845 true, 10, v8::StackTrace::kDetailed);
22846 v8::TryCatch try_catch;
22847 CompileRun("(function f(x) { f(x+1); })(0)");
22848 CHECK(try_catch.HasCaught());
22849}
22850
22851
22852TEST(ScriptNameAndLineNumber) {
22853 LocalContext env;
22854 v8::Isolate* isolate = env->GetIsolate();
22855 v8::HandleScope scope(isolate);
22856 const char* url = "http://www.foo.com/foo.js";
22857 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22858 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22859 Local<Script> script = v8::ScriptCompiler::Compile(
22860 isolate, &script_source);
22861 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22862 CHECK(!script_name.IsEmpty());
22863 CHECK(script_name->IsString());
22864 String::Utf8Value utf8_name(script_name);
22865 CHECK_EQ(url, *utf8_name);
22866 int line_number = script->GetUnboundScript()->GetLineNumber(0);
22867 CHECK_EQ(13, line_number);
22868}
22869
22870
22871void SourceURLHelper(const char* source, const char* expected_source_url,
22872 const char* expected_source_mapping_url) {
22873 Local<Script> script = v8_compile(source);
22874 if (expected_source_url != NULL) {
22875 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22876 CHECK_EQ(expected_source_url, *url);
22877 } else {
22878 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22879 }
22880 if (expected_source_mapping_url != NULL) {
22881 v8::String::Utf8Value url(
22882 script->GetUnboundScript()->GetSourceMappingURL());
22883 CHECK_EQ(expected_source_mapping_url, *url);
22884 } else {
22885 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22886 }
22887}
22888
22889
22890TEST(ScriptSourceURLAndSourceMappingURL) {
22891 LocalContext env;
22892 v8::Isolate* isolate = env->GetIsolate();
22893 v8::HandleScope scope(isolate);
22894 SourceURLHelper("function foo() {}\n"
22895 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22896 SourceURLHelper("function foo() {}\n"
22897 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22898
22899 // Both sourceURL and sourceMappingURL.
22900 SourceURLHelper("function foo() {}\n"
22901 "//# sourceURL=bar3.js\n"
22902 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
22903
22904 // Two source URLs; the first one is ignored.
22905 SourceURLHelper("function foo() {}\n"
22906 "//# sourceURL=ignoreme.js\n"
22907 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
22908 SourceURLHelper("function foo() {}\n"
22909 "//# sourceMappingURL=ignoreme.js\n"
22910 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
22911
22912 // SourceURL or sourceMappingURL in the middle of the script.
22913 SourceURLHelper("function foo() {}\n"
22914 "//# sourceURL=bar7.js\n"
22915 "function baz() {}\n", "bar7.js", NULL);
22916 SourceURLHelper("function foo() {}\n"
22917 "//# sourceMappingURL=bar8.js\n"
22918 "function baz() {}\n", NULL, "bar8.js");
22919
22920 // Too much whitespace.
22921 SourceURLHelper("function foo() {}\n"
22922 "//# sourceURL=bar9.js\n"
22923 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
22924 SourceURLHelper("function foo() {}\n"
22925 "//# sourceURL =bar11.js\n"
22926 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
22927
22928 // Disallowed characters in value.
22929 SourceURLHelper("function foo() {}\n"
22930 "//# sourceURL=bar13 .js \n"
22931 "//# sourceMappingURL=bar14 .js \n",
22932 NULL, NULL);
22933 SourceURLHelper("function foo() {}\n"
22934 "//# sourceURL=bar15\t.js \n"
22935 "//# sourceMappingURL=bar16\t.js \n",
22936 NULL, NULL);
22937 SourceURLHelper("function foo() {}\n"
22938 "//# sourceURL=bar17'.js \n"
22939 "//# sourceMappingURL=bar18'.js \n",
22940 NULL, NULL);
22941 SourceURLHelper("function foo() {}\n"
22942 "//# sourceURL=bar19\".js \n"
22943 "//# sourceMappingURL=bar20\".js \n",
22944 NULL, NULL);
22945
22946 // Not too much whitespace.
22947 SourceURLHelper("function foo() {}\n"
22948 "//# sourceURL= bar21.js \n"
22949 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
22950}
22951
22952
22953TEST(GetOwnPropertyDescriptor) {
22954 LocalContext env;
22955 v8::Isolate* isolate = env->GetIsolate();
22956 v8::HandleScope scope(isolate);
22957 CompileRun(
22958 "var x = { value : 13};"
22959 "Object.defineProperty(x, 'p0', {value : 12});"
22960 "Object.defineProperty(x, 'p1', {"
22961 " set : function(value) { this.value = value; },"
22962 " get : function() { return this.value; },"
22963 "});");
22964 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
22965 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
22966 CHECK(desc->IsUndefined());
22967 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
22968 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
22969 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
22970 Local<Function> set =
22971 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
22972 Local<Function> get =
22973 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
22974 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
22975 Handle<Value> args[] = { v8_num(14) };
22976 set->Call(x, 1, args);
22977 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
22978}
22979
22980
22981TEST(Regress411877) {
22982 v8::Isolate* isolate = CcTest::isolate();
22983 v8::HandleScope handle_scope(isolate);
22984 v8::Handle<v8::ObjectTemplate> object_template =
22985 v8::ObjectTemplate::New(isolate);
22986 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
22987 IndexedAccessCounter);
22988
22989 v8::Handle<Context> context = Context::New(isolate);
22990 v8::Context::Scope context_scope(context);
22991
22992 context->Global()->Set(v8_str("o"), object_template->NewInstance());
22993 CompileRun("Object.getOwnPropertyNames(o)");
22994}
22995
22996
22997TEST(GetHiddenPropertyTableAfterAccessCheck) {
22998 v8::Isolate* isolate = CcTest::isolate();
22999 v8::HandleScope handle_scope(isolate);
23000 v8::Handle<v8::ObjectTemplate> object_template =
23001 v8::ObjectTemplate::New(isolate);
23002 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23003 IndexedAccessCounter);
23004
23005 v8::Handle<Context> context = Context::New(isolate);
23006 v8::Context::Scope context_scope(context);
23007
23008 v8::Handle<v8::Object> obj = object_template->NewInstance();
23009 obj->Set(v8_str("key"), v8_str("value"));
23010 obj->Delete(v8_str("key"));
23011
23012 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23013}
23014
23015
23016TEST(Regress411793) {
23017 v8::Isolate* isolate = CcTest::isolate();
23018 v8::HandleScope handle_scope(isolate);
23019 v8::Handle<v8::ObjectTemplate> object_template =
23020 v8::ObjectTemplate::New(isolate);
23021 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23022 IndexedAccessCounter);
23023
23024 v8::Handle<Context> context = Context::New(isolate);
23025 v8::Context::Scope context_scope(context);
23026
23027 context->Global()->Set(v8_str("o"), object_template->NewInstance());
23028 CompileRun(
23029 "Object.defineProperty(o, 'key', "
23030 " { get: function() {}, set: function() {} });");
23031}
23032
23033class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23034 public:
23035 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23036
23037 virtual size_t GetMoreData(const uint8_t** src) {
23038 // Unlike in real use cases, this function will never block.
23039 if (chunks_[index_] == NULL) {
23040 return 0;
23041 }
23042 // Copy the data, since the caller takes ownership of it.
23043 size_t len = strlen(chunks_[index_]);
23044 // We don't need to zero-terminate since we return the length.
23045 uint8_t* copy = new uint8_t[len];
23046 memcpy(copy, chunks_[index_], len);
23047 *src = copy;
23048 ++index_;
23049 return len;
23050 }
23051
23052 // Helper for constructing a string from chunks (the compilation needs it
23053 // too).
23054 static char* FullSourceString(const char** chunks) {
23055 size_t total_len = 0;
23056 for (size_t i = 0; chunks[i] != NULL; ++i) {
23057 total_len += strlen(chunks[i]);
23058 }
23059 char* full_string = new char[total_len + 1];
23060 size_t offset = 0;
23061 for (size_t i = 0; chunks[i] != NULL; ++i) {
23062 size_t len = strlen(chunks[i]);
23063 memcpy(full_string + offset, chunks[i], len);
23064 offset += len;
23065 }
23066 full_string[total_len] = 0;
23067 return full_string;
23068 }
23069
23070 private:
23071 const char** chunks_;
23072 unsigned index_;
23073};
23074
23075
23076// Helper function for running streaming tests.
23077void RunStreamingTest(const char** chunks,
23078 v8::ScriptCompiler::StreamedSource::Encoding encoding =
23079 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23080 bool expected_success = true) {
23081 LocalContext env;
23082 v8::Isolate* isolate = env->GetIsolate();
23083 v8::HandleScope scope(isolate);
23084 v8::TryCatch try_catch;
23085
23086 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23087 encoding);
23088 v8::ScriptCompiler::ScriptStreamingTask* task =
23089 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23090
23091 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23092 // task here in the main thread.
23093 task->Run();
23094 delete task;
23095
23096 v8::ScriptOrigin origin(v8_str("http://foo.com"));
23097 char* full_source = TestSourceStream::FullSourceString(chunks);
23098
23099 // The possible errors are only produced while compiling.
23100 CHECK_EQ(false, try_catch.HasCaught());
23101
23102 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23103 isolate, &source, v8_str(full_source), origin);
23104 if (expected_success) {
23105 CHECK(!script.IsEmpty());
23106 v8::Handle<Value> result(script->Run());
23107 // All scripts are supposed to return the fixed value 13 when ran.
23108 CHECK_EQ(13, result->Int32Value());
23109 } else {
23110 CHECK(script.IsEmpty());
23111 CHECK(try_catch.HasCaught());
23112 }
23113 delete[] full_source;
23114}
23115
23116
23117TEST(StreamingSimpleScript) {
23118 // This script is unrealistically small, since no one chunk is enough to fill
23119 // the backing buffer of Scanner, let alone overflow it.
23120 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23121 NULL};
23122 RunStreamingTest(chunks);
23123}
23124
23125
23126TEST(StreamingBiggerScript) {
23127 const char* chunk1 =
23128 "function foo() {\n"
23129 " // Make this chunk sufficiently long so that it will overflow the\n"
23130 " // backing buffer of the Scanner.\n"
23131 " var i = 0;\n"
23132 " var result = 0;\n"
23133 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23134 " result = 0;\n"
23135 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23136 " result = 0;\n"
23137 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23138 " result = 0;\n"
23139 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23140 " return result;\n"
23141 "}\n";
23142 const char* chunks[] = {chunk1, "foo(); ", NULL};
23143 RunStreamingTest(chunks);
23144}
23145
23146
23147TEST(StreamingScriptWithParseError) {
23148 // Test that parse errors from streamed scripts are propagated correctly.
23149 {
23150 char chunk1[] =
23151 " // This will result in a parse error.\n"
23152 " var if else then foo";
23153 char chunk2[] = " 13\n";
23154 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23155
23156 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23157 false);
23158 }
23159 // Test that the next script succeeds normally.
23160 {
23161 char chunk1[] =
23162 " // This will be parsed successfully.\n"
23163 " function foo() { return ";
23164 char chunk2[] = " 13; }\n";
23165 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23166
23167 RunStreamingTest(chunks);
23168 }
23169}
23170
23171
23172TEST(StreamingUtf8Script) {
23173 // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
23174 // don't like it.
23175 const char* chunk1 =
23176 "function foo() {\n"
23177 " // This function will contain an UTF-8 character which is not in\n"
23178 " // ASCII.\n"
23179 " var foob\xeb\x91\x80r = 13;\n"
23180 " return foob\xeb\x91\x80r;\n"
23181 "}\n";
23182 const char* chunks[] = {chunk1, "foo(); ", NULL};
23183 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23184}
23185
23186
23187TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23188 // A sanity check to prove that the approach of splitting UTF-8
23189 // characters is correct. Here is an UTF-8 character which will take three
23190 // bytes.
23191 const char* reference = "\xeb\x91\x80";
23192 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
23193
23194 char chunk1[] =
23195 "function foo() {\n"
23196 " // This function will contain an UTF-8 character which is not in\n"
23197 " // ASCII.\n"
23198 " var foob";
23199 char chunk2[] =
23200 "XXXr = 13;\n"
23201 " return foob\xeb\x91\x80r;\n"
23202 "}\n";
23203 for (int i = 0; i < 3; ++i) {
23204 chunk2[i] = reference[i];
23205 }
23206 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23207 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23208}
23209
23210
23211TEST(StreamingUtf8ScriptWithSplitCharacters) {
23212 // Stream data where a multi-byte UTF-8 character is split between two data
23213 // chunks.
23214 const char* reference = "\xeb\x91\x80";
23215 char chunk1[] =
23216 "function foo() {\n"
23217 " // This function will contain an UTF-8 character which is not in\n"
23218 " // ASCII.\n"
23219 " var foobX";
23220 char chunk2[] =
23221 "XXr = 13;\n"
23222 " return foob\xeb\x91\x80r;\n"
23223 "}\n";
23224 chunk1[strlen(chunk1) - 1] = reference[0];
23225 chunk2[0] = reference[1];
23226 chunk2[1] = reference[2];
23227 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23228 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23229}
23230
23231
23232TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
23233 // Tests edge cases which should still be decoded correctly.
23234
23235 // Case 1: a chunk contains only bytes for a split character (and no other
23236 // data). This kind of a chunk would be exceptionally small, but we should
23237 // still decode it correctly.
23238 const char* reference = "\xeb\x91\x80";
23239 // The small chunk is at the beginning of the split character
23240 {
23241 char chunk1[] =
23242 "function foo() {\n"
23243 " // This function will contain an UTF-8 character which is not in\n"
23244 " // ASCII.\n"
23245 " var foob";
23246 char chunk2[] = "XX";
23247 char chunk3[] =
23248 "Xr = 13;\n"
23249 " return foob\xeb\x91\x80r;\n"
23250 "}\n";
23251 chunk2[0] = reference[0];
23252 chunk2[1] = reference[1];
23253 chunk3[0] = reference[2];
23254 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23255 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23256 }
23257 // The small chunk is at the end of a character
23258 {
23259 char chunk1[] =
23260 "function foo() {\n"
23261 " // This function will contain an UTF-8 character which is not in\n"
23262 " // ASCII.\n"
23263 " var foobX";
23264 char chunk2[] = "XX";
23265 char chunk3[] =
23266 "r = 13;\n"
23267 " return foob\xeb\x91\x80r;\n"
23268 "}\n";
23269 chunk1[strlen(chunk1) - 1] = reference[0];
23270 chunk2[0] = reference[1];
23271 chunk2[1] = reference[2];
23272 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23273 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23274 }
23275 // Case 2: the script ends with a multi-byte character. Make sure that it's
23276 // decoded correctly and not just ignored.
23277 {
23278 char chunk1[] =
23279 "var foob\xeb\x91\x80 = 13;\n"
23280 "foob\xeb\x91\x80";
23281 const char* chunks[] = {chunk1, NULL};
23282 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23283 }
23284}
23285
23286
23287TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
23288 // Test cases where a UTF-8 character is split over several chunks. Those
23289 // cases are not supported (the embedder should give the data in big enough
23290 // chunks), but we shouldn't crash, just produce a parse error.
23291 const char* reference = "\xeb\x91\x80";
23292 char chunk1[] =
23293 "function foo() {\n"
23294 " // This function will contain an UTF-8 character which is not in\n"
23295 " // ASCII.\n"
23296 " var foobX";
23297 char chunk2[] = "X";
23298 char chunk3[] =
23299 "Xr = 13;\n"
23300 " return foob\xeb\x91\x80r;\n"
23301 "}\n";
23302 chunk1[strlen(chunk1) - 1] = reference[0];
23303 chunk2[0] = reference[1];
23304 chunk3[0] = reference[2];
23305 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23306
23307 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23308}
23309
23310
23311TEST(StreamingProducesParserCache) {
23312 i::FLAG_min_preparse_length = 0;
23313 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23314 NULL};
23315
23316 LocalContext env;
23317 v8::Isolate* isolate = env->GetIsolate();
23318 v8::HandleScope scope(isolate);
23319
23320 v8::ScriptCompiler::StreamedSource source(
23321 new TestSourceStream(chunks),
23322 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
23323 v8::ScriptCompiler::ScriptStreamingTask* task =
23324 v8::ScriptCompiler::StartStreamingScript(
23325 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
23326
23327 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23328 // task here in the main thread.
23329 task->Run();
23330 delete task;
23331
23332 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
23333 CHECK(cached_data != NULL);
23334 CHECK(cached_data->data != NULL);
23335 CHECK_GT(cached_data->length, 0);
23336}
23337
23338
23339TEST(StreamingScriptWithInvalidUtf8) {
23340 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
23341 // chunk don't produce a crash.
23342 const char* reference = "\xeb\x91\x80\x80\x80";
23343 char chunk1[] =
23344 "function foo() {\n"
23345 " // This function will contain an UTF-8 character which is not in\n"
23346 " // ASCII.\n"
23347 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
23348 char chunk2[] =
23349 "r = 13;\n"
23350 " return foob\xeb\x91\x80\x80\x80r;\n"
23351 "}\n";
23352 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
23353
23354 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23355 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23356}