1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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
28 #include <climits>
29 #include <csignal>
30 #include <map>
31 #include <string>
32
33 #include "src/v8.h"
34
35 #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"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Name;
67 using ::v8::Message;
68 using ::v8::MessageCallback;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::Script;
73 using ::v8::StackTrace;
74 using ::v8::String;
75 using ::v8::Symbol;
76 using ::v8::TryCatch;
77 using ::v8::Undefined;
78 using ::v8::UniqueId;
79 using ::v8::V8;
80 using ::v8::Value;
81
82
83 #define THREADED_PROFILED_TEST(Name) \
84 static void Test##Name(); \
85 TEST(Name##WithProfiler) { \
86 RunWithProfiler(&Test##Name); \
87 } \
88 THREADED_TEST(Name)
89
90
RunWithProfiler(void (* test)())91 void 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();
97
98 cpu_profiler->StartProfiling(profile_name);
99 (*test)();
100 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101 }
102
103
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
IncrementingSignatureCallback(const v8::FunctionCallbackInfo<v8::Value> & args)106 static void IncrementingSignatureCallback(
107 const v8::FunctionCallbackInfo<v8::Value>& args) {
108 ApiTestFuzzer::Fuzz();
109 signature_callback_count++;
110 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());
114 for (int i = 0; i < args.Length(); i++)
115 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116 args.GetReturnValue().Set(result);
117 }
118
119
SignatureCallback(const v8::FunctionCallbackInfo<v8::Value> & args)120 static void SignatureCallback(
121 const v8::FunctionCallbackInfo<v8::Value>& args) {
122 ApiTestFuzzer::Fuzz();
123 v8::Handle<v8::Array> result =
124 v8::Array::New(args.GetIsolate(), args.Length());
125 for (int i = 0; i < args.Length(); i++) {
126 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
127 }
128 args.GetReturnValue().Set(result);
129 }
130
131
132 // Tests that call v8::V8::Dispose() cannot be threaded.
UNINITIALIZED_TEST(InitializeAndDisposeOnce)133 UNINITIALIZED_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.
UNINITIALIZED_TEST(InitializeAndDisposeMultiple)140 UNINITIALIZED_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());
146 }
147
148
THREADED_TEST(Handles)149 THREADED_TEST(Handles) {
150 v8::HandleScope scope(CcTest::isolate());
151 Local<Context> local_env;
152 {
153 LocalContext env;
154 local_env = env.local();
155 }
156
157 // Local context should still be live.
158 CHECK(!local_env.IsEmpty());
159 local_env->Enter();
160
161 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162 CHECK(!undef.IsEmpty());
163 CHECK(undef->IsUndefined());
164
165 const char* source = "1 + 2 + 3";
166 Local<Script> script = v8_compile(source);
167 CHECK_EQ(6, script->Run()->Int32Value());
168
169 local_env->Exit();
170 }
171
172
THREADED_TEST(IsolateOfContext)173 THREADED_TEST(IsolateOfContext) {
174 v8::HandleScope scope(CcTest::isolate());
175 v8::Handle<Context> env = Context::New(CcTest::isolate());
176
177 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
TestSignature(const char * loop_js,Local<Value> receiver)188 static 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();
198 v8::TryCatch try_catch;
199 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
THREADED_TEST(ReceiverSignature)210 THREADED_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);
223 sub_fun->Inherit(fun);
224 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());
238 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
239 env->Global()->Set(v8_str("fun_instance"), fun_instance);
240 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241 CompileRun(
242 "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 }
282 }
283
284
THREADED_TEST(ArgumentSignature)285 THREADED_TEST(ArgumentSignature) {
286 LocalContext env;
287 v8::Isolate* isolate = env->GetIsolate();
288 v8::HandleScope scope(isolate);
289 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
290 cons->SetClassName(v8_str("Cons"));
291 v8::Handle<v8::Signature> sig = v8::Signature::New(
292 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
293 v8::Handle<v8::FunctionTemplate> fun =
294 v8::FunctionTemplate::New(isolate,
295 SignatureCallback,
296 v8::Handle<Value>(),
297 sig);
298 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
310 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
311 cons1->SetClassName(v8_str("Cons1"));
312 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
313 cons2->SetClassName(v8_str("Cons2"));
314 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
315 cons3->SetClassName(v8_str("Cons3"));
316
317 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
318 v8::Handle<v8::Signature> wsig = v8::Signature::New(
319 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
320 v8::Handle<v8::FunctionTemplate> fun2 =
321 v8::FunctionTemplate::New(isolate,
322 SignatureCallback,
323 v8::Handle<Value>(),
324 wsig);
325
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
THREADED_TEST(HulIgennem)354 THREADED_TEST(HulIgennem) {
355 LocalContext env;
356 v8::Isolate* isolate = env->GetIsolate();
357 v8::HandleScope scope(isolate);
358 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
359 Local<String> undef_str = undef->ToString();
360 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361 undef_str->WriteUtf8(value);
362 CHECK_EQ(0, strcmp(value, "undefined"));
363 i::DeleteArray(value);
364 }
365
366
THREADED_TEST(Access)367 THREADED_TEST(Access) {
368 LocalContext env;
369 v8::Isolate* isolate = env->GetIsolate();
370 v8::HandleScope scope(isolate);
371 Local<v8::Object> obj = v8::Object::New(isolate);
372 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
THREADED_TEST(AccessElement)383 THREADED_TEST(AccessElement) {
384 LocalContext env;
385 v8::HandleScope scope(env->GetIsolate());
386 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
387 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
THREADED_TEST(Script)402 THREADED_TEST(Script) {
403 LocalContext env;
404 v8::HandleScope scope(env->GetIsolate());
405 const char* source = "1 + 2 + 3";
406 Local<Script> script = v8_compile(source);
407 CHECK_EQ(6, script->Run()->Int32Value());
408 }
409
410
411 class TestResource: public String::ExternalStringResource {
412 public:
TestResource(uint16_t * data,int * counter=NULL,bool owning_data=true)413 explicit TestResource(uint16_t* data, int* counter = NULL,
414 bool owning_data = true)
415 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
416 while (data[length_]) ++length_;
417 }
418
~TestResource()419 ~TestResource() {
420 if (owning_data_) i::DeleteArray(data_);
421 if (counter_ != NULL) ++*counter_;
422 }
423
data() const424 const uint16_t* data() const {
425 return data_;
426 }
427
length() const428 size_t length() const {
429 return length_;
430 }
431
432 private:
433 uint16_t* data_;
434 size_t length_;
435 int* counter_;
436 bool owning_data_;
437 };
438
439
440 class TestOneByteResource : public String::ExternalOneByteStringResource {
441 public:
TestOneByteResource(const char * data,int * counter=NULL,size_t offset=0)442 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) {}
448
~TestOneByteResource()449 ~TestOneByteResource() {
450 i::DeleteArray(orig_data_);
451 if (counter_ != NULL) ++*counter_;
452 }
453
data() const454 const char* data() const {
455 return data_;
456 }
457
length() const458 size_t length() const {
459 return length_;
460 }
461
462 private:
463 const char* orig_data_;
464 const char* data_;
465 size_t length_;
466 int* counter_;
467 };
468
469
THREADED_TEST(ScriptUsingStringResource)470 THREADED_TEST(ScriptUsingStringResource) {
471 int dispose_count = 0;
472 const char* c_source = "1 + 2 * 3";
473 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
474 {
475 LocalContext env;
476 v8::HandleScope scope(env->GetIsolate());
477 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
478 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479 Local<Script> script = v8_compile(source);
480 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()));
486 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);
491 CHECK_EQ(0, dispose_count);
492 }
493 CcTest::i_isolate()->compilation_cache()->Clear();
494 CcTest::heap()->CollectAllAvailableGarbage();
495 CHECK_EQ(1, dispose_count);
496 }
497
498
THREADED_TEST(ScriptUsingOneByteStringResource)499 THREADED_TEST(ScriptUsingOneByteStringResource) {
500 int dispose_count = 0;
501 const char* c_source = "1 + 2 * 3";
502 {
503 LocalContext env;
504 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);
516 Local<Value> value = script->Run();
517 CHECK(value->IsNumber());
518 CHECK_EQ(7, value->Int32Value());
519 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
520 CHECK_EQ(0, dispose_count);
521 }
522 CcTest::i_isolate()->compilation_cache()->Clear();
523 CcTest::heap()->CollectAllAvailableGarbage();
524 CHECK_EQ(1, dispose_count);
525 }
526
527
THREADED_TEST(ScriptMakingExternalString)528 THREADED_TEST(ScriptMakingExternalString) {
529 int dispose_count = 0;
530 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
531 {
532 LocalContext env;
533 v8::HandleScope scope(env->GetIsolate());
534 Local<String> source =
535 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
536 // Trigger GCs so that the newly allocated string moves to old gen.
537 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);
544 bool success = source->MakeExternal(new TestResource(two_byte_source,
545 &dispose_count));
546 CHECK(success);
547 Local<Script> script = v8_compile(source);
548 Local<Value> value = script->Run();
549 CHECK(value->IsNumber());
550 CHECK_EQ(7, value->Int32Value());
551 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
552 CHECK_EQ(0, dispose_count);
553 }
554 CcTest::i_isolate()->compilation_cache()->Clear();
555 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
556 CHECK_EQ(1, dispose_count);
557 }
558
559
THREADED_TEST(ScriptMakingExternalOneByteString)560 THREADED_TEST(ScriptMakingExternalOneByteString) {
561 int dispose_count = 0;
562 const char* c_source = "1 + 2 * 3";
563 {
564 LocalContext env;
565 v8::HandleScope scope(env->GetIsolate());
566 Local<String> source = v8_str(c_source);
567 // Trigger GCs so that the newly allocated string moves to old gen.
568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
570 bool success = source->MakeExternal(
571 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
572 CHECK(success);
573 Local<Script> script = v8_compile(source);
574 Local<Value> value = script->Run();
575 CHECK(value->IsNumber());
576 CHECK_EQ(7, value->Int32Value());
577 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
578 CHECK_EQ(0, dispose_count);
579 }
580 CcTest::i_isolate()->compilation_cache()->Clear();
581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
582 CHECK_EQ(1, dispose_count);
583 }
584
585
TEST(MakingExternalStringConditions)586 TEST(MakingExternalStringConditions) {
587 LocalContext env;
588 v8::HandleScope scope(env->GetIsolate());
589
590 // Free some space in the new space so that we can check freshness.
591 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593
594 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
595 Local<String> small_string =
596 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
597 i::DeleteArray(two_byte_string);
598
599 // 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.
602 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
604 // Old space strings should be accepted.
605 CHECK(small_string->CanMakeExternal());
606
607 two_byte_string = AsciiToTwoByteString("small string 2");
608 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
609 i::DeleteArray(two_byte_string);
610
611 // 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';
623
624 two_byte_string = AsciiToTwoByteString(buf);
625 Local<String> large_string =
626 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
627 i::DeleteArray(buf);
628 i::DeleteArray(two_byte_string);
629 // Large strings should be immediately accepted.
630 CHECK(large_string->CanMakeExternal());
631 }
632
633
TEST(MakingExternalOneByteStringConditions)634 TEST(MakingExternalOneByteStringConditions) {
635 LocalContext env;
636 v8::HandleScope scope(env->GetIsolate());
637
638 // Free some space in the new space so that we can check freshness.
639 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641
642 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
643 // 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.
646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
648 // Old space strings should be accepted.
649 CHECK(small_string->CanMakeExternal());
650
651 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
652 // 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';
664 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
665 i::DeleteArray(buf);
666 // Large strings should be immediately accepted.
667 CHECK(large_string->CanMakeExternal());
668 }
669
670
TEST(MakingExternalUnalignedOneByteString)671 TEST(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);
702 }
703
704
THREADED_TEST(UsingExternalString)705 THREADED_TEST(UsingExternalString) {
706 i::Factory* factory = CcTest::i_isolate()->factory();
707 {
708 v8::HandleScope scope(CcTest::isolate());
709 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
710 Local<String> string = String::NewExternal(
711 CcTest::isolate(), new TestResource(two_byte_string));
712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713 // Trigger GCs so that the newly allocated string moves to old gen.
714 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());
719 }
720 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 }
723
724
THREADED_TEST(UsingExternalOneByteString)725 THREADED_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);
742 }
743
744
THREADED_TEST(ScavengeExternalString)745 THREADED_TEST(ScavengeExternalString) {
746 i::FLAG_stress_compaction = false;
747 i::FLAG_gc_global = false;
748 int dispose_count = 0;
749 bool in_new_space = false;
750 {
751 v8::HandleScope scope(CcTest::isolate());
752 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
753 Local<String> string = String::NewExternal(
754 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
755 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
756 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));
759 CHECK_EQ(0, dispose_count);
760 }
761 CcTest::heap()->CollectGarbage(
762 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
763 CHECK_EQ(1, dispose_count);
764 }
765
766
THREADED_TEST(ScavengeExternalOneByteString)767 THREADED_TEST(ScavengeExternalOneByteString) {
768 i::FLAG_stress_compaction = false;
769 i::FLAG_gc_global = false;
770 int dispose_count = 0;
771 bool in_new_space = false;
772 {
773 v8::HandleScope scope(CcTest::isolate());
774 const char* one_byte_string = "test string";
775 Local<String> string = String::NewExternal(
776 CcTest::isolate(),
777 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
778 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
779 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));
782 CHECK_EQ(0, dispose_count);
783 }
784 CcTest::heap()->CollectGarbage(
785 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
786 CHECK_EQ(1, dispose_count);
787 }
788
789
790 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
791 public:
792 // Only used by non-threaded tests, so it can use static fields.
793 static int dispose_calls;
794 static int dispose_count;
795
TestOneByteResourceWithDisposeControl(const char * data,bool dispose)796 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
797 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
798
Dispose()799 void Dispose() {
800 ++dispose_calls;
801 if (dispose_) delete this;
802 }
803 private:
804 bool dispose_;
805 };
806
807
808 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
809 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
810
811
TEST(ExternalStringWithDisposeHandling)812 TEST(ExternalStringWithDisposeHandling) {
813 const char* c_source = "1 + 2 * 3";
814
815 // Use a stack allocated external string resource allocated object.
816 TestOneByteResourceWithDisposeControl::dispose_count = 0;
817 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
818 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
819 {
820 LocalContext env;
821 v8::HandleScope scope(env->GetIsolate());
822 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
823 Local<Script> script = v8_compile(source);
824 Local<Value> value = script->Run();
825 CHECK(value->IsNumber());
826 CHECK_EQ(7, value->Int32Value());
827 CcTest::heap()->CollectAllAvailableGarbage();
828 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
829 }
830 CcTest::i_isolate()->compilation_cache()->Clear();
831 CcTest::heap()->CollectAllAvailableGarbage();
832 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
833 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
834
835 // Use a heap allocated external string resource allocated object.
836 TestOneByteResourceWithDisposeControl::dispose_count = 0;
837 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
838 TestOneByteResource* res_heap =
839 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
840 {
841 LocalContext env;
842 v8::HandleScope scope(env->GetIsolate());
843 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
844 Local<Script> script = v8_compile(source);
845 Local<Value> value = script->Run();
846 CHECK(value->IsNumber());
847 CHECK_EQ(7, value->Int32Value());
848 CcTest::heap()->CollectAllAvailableGarbage();
849 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
850 }
851 CcTest::i_isolate()->compilation_cache()->Clear();
852 CcTest::heap()->CollectAllAvailableGarbage();
853 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
854 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
855 }
856
857
THREADED_TEST(StringConcat)858 THREADED_TEST(StringConcat) {
859 {
860 LocalContext env;
861 v8::HandleScope scope(env->GetIsolate());
862 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);
870
871 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
872 Local<String> right =
873 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
874 i::DeleteArray(two_byte_source);
875
876 Local<String> source = String::Concat(left, right);
877 right = String::NewExternal(
878 env->GetIsolate(),
879 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
880 source = String::Concat(source, right);
881 right = String::NewExternal(
882 env->GetIsolate(),
883 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);
887
888 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
889 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
890 i::DeleteArray(two_byte_source);
891
892 source = String::Concat(source, right);
893 right = String::NewExternal(
894 env->GetIsolate(),
895 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
896 source = String::Concat(source, right);
897 Local<Script> script = v8_compile(source);
898 Local<Value> value = script->Run();
899 CHECK(value->IsNumber());
900 CHECK_EQ(68, value->Int32Value());
901 }
902 CcTest::i_isolate()->compilation_cache()->Clear();
903 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
904 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
905 }
906
907
THREADED_TEST(GlobalProperties)908 THREADED_TEST(GlobalProperties) {
909 LocalContext env;
910 v8::HandleScope scope(env->GetIsolate());
911 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
918 template<typename T>
CheckReturnValue(const T & t,i::Address callback)919 static 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());
932
933 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());
940 }
941 }
942
943
handle_callback_impl(const v8::FunctionCallbackInfo<Value> & info,i::Address callback)944 static 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
handle_callback(const v8::FunctionCallbackInfo<Value> & info)953 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
954 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
955 }
956
957
handle_callback_2(const v8::FunctionCallbackInfo<Value> & info)958 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
959 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
960 }
961
construct_callback(const v8::FunctionCallbackInfo<Value> & info)962 static 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
Return239Callback(Local<String> name,const v8::PropertyCallbackInfo<Value> & info)973 static 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
982 template<typename Handler>
TestFunctionTemplateInitializer(Handler handler,Handler handler_2)983 static void TestFunctionTemplateInitializer(Handler handler,
984 Handler handler_2) {
985 // Test constructor calls.
986 {
987 LocalContext env;
988 v8::Isolate* isolate = env->GetIsolate();
989 v8::HandleScope scope(isolate);
990
991 Local<v8::FunctionTemplate> fun_templ =
992 v8::FunctionTemplate::New(isolate, handler);
993 Local<Function> fun = fun_templ->GetFunction();
994 env->Global()->Set(v8_str("obj"), fun);
995 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
1019 template<typename Constructor, typename Accessor>
TestFunctionTemplateAccessor(Constructor constructor,Accessor accessor)1020 static 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++) {
1037 CHECK_EQ(1, script->Run()->Int32Value());
1038 }
1039 script = v8_compile("obj_instance.m");
1040 for (int i = 0; i < 30; i++) {
1041 CHECK_EQ(239, script->Run()->Int32Value());
1042 }
1043 }
1044
1045
THREADED_PROFILED_TEST(FunctionTemplate)1046 THREADED_PROFILED_TEST(FunctionTemplate) {
1047 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1048 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1049 }
1050
1051
SimpleCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1052 static 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
1059 template<typename Callback>
TestSimpleCallback(Callback callback)1060 static 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
THREADED_PROFILED_TEST(SimpleCallback)1083 THREADED_PROFILED_TEST(SimpleCallback) {
1084 TestSimpleCallback(SimpleCallback);
1085 }
1086
1087
1088 template<typename T>
1089 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1090
1091 // constant return values
1092 static int32_t fast_return_value_int32 = 471;
1093 static uint32_t fast_return_value_uint32 = 571;
1094 static const double kFastReturnValueDouble = 2.7;
1095 // variable return values
1096 static bool fast_return_value_bool = false;
1097 enum ReturnValueOddball {
1098 kNullReturnValue,
1099 kUndefinedReturnValue,
1100 kEmptyStringReturnValue
1101 };
1102 static ReturnValueOddball fast_return_value_void;
1103 static 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.
address_of(v8::FunctionCallback callback)1107 static i::Address address_of(v8::FunctionCallback callback) {
1108 return FUNCTION_ADDR(callback);
1109 }
1110
1111 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1112 void 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
1118 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1119 void 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
1125 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1126 void FastReturnValueCallback<double>(
1127 const v8::FunctionCallbackInfo<v8::Value>& info) {
1128 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1129 info.GetReturnValue().Set(kFastReturnValueDouble);
1130 }
1131
1132 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1133 void 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
1139 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1140 void 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
1156 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1157 void 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
1166 template<typename T>
TestFastReturnValues()1167 Handle<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
THREADED_PROFILED_TEST(FastReturnValues)1182 THREADED_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
THREADED_TEST(FunctionTemplateSetLength)1249 THREADED_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());
1282 }
1283 }
1284
1285
1286 static void* expected_ptr;
callback(const v8::FunctionCallbackInfo<v8::Value> & args)1287 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1288 void* ptr = v8::External::Cast(*args.Data())->Value();
1289 CHECK_EQ(expected_ptr, ptr);
1290 args.GetReturnValue().Set(true);
1291 }
1292
1293
TestExternalPointerWrapping()1294 static void TestExternalPointerWrapping() {
1295 LocalContext env;
1296 v8::Isolate* isolate = env->GetIsolate();
1297 v8::HandleScope scope(isolate);
1298
1299 v8::Handle<v8::Value> data =
1300 v8::External::New(isolate, expected_ptr);
1301
1302 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1303 obj->Set(v8_str("func"),
1304 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1305 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
THREADED_TEST(ExternalWrap)1315 THREADED_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)
1348 // Check a value with a leading 1 bit in x64 Smi encoding.
1349 expected_ptr = reinterpret_cast<void*>(0x400000000);
1350 TestExternalPointerWrapping();
1351
1352 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1353 TestExternalPointerWrapping();
1354
1355 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1356 TestExternalPointerWrapping();
1357 #endif
1358 }
1359
1360
THREADED_TEST(FindInstanceInPrototypeChain)1361 THREADED_TEST(FindInstanceInPrototypeChain) {
1362 LocalContext env;
1363 v8::Isolate* isolate = env->GetIsolate();
1364 v8::HandleScope scope(isolate);
1365
1366 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);
1369 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
THREADED_TEST(TinyInteger)1409 THREADED_TEST(TinyInteger) {
1410 LocalContext env;
1411 v8::Isolate* isolate = env->GetIsolate();
1412 v8::HandleScope scope(isolate);
1413
1414 int32_t value = 239;
1415 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);
1419 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1420 }
1421
1422
THREADED_TEST(BigSmiInteger)1423 THREADED_TEST(BigSmiInteger) {
1424 LocalContext env;
1425 v8::HandleScope scope(env->GetIsolate());
1426 v8::Isolate* isolate = CcTest::isolate();
1427
1428 int32_t value = i::Smi::kMaxValue;
1429 // We cannot add one to a Smi::kMaxValue without wrapping.
1430 if (i::SmiValuesAre31Bits()) {
1431 CHECK(i::Smi::IsValid(value));
1432 CHECK(!i::Smi::IsValid(value + 1));
1433
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);
1438 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1439 }
1440 }
1441
1442
THREADED_TEST(BigInteger)1443 THREADED_TEST(BigInteger) {
1444 LocalContext env;
1445 v8::HandleScope scope(env->GetIsolate());
1446 v8::Isolate* isolate = CcTest::isolate();
1447
1448 // We cannot add one to a Smi::kMaxValue without wrapping.
1449 if (i::SmiValuesAre31Bits()) {
1450 // 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));
1456
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);
1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462 }
1463 }
1464
1465
THREADED_TEST(TinyUnsignedInteger)1466 THREADED_TEST(TinyUnsignedInteger) {
1467 LocalContext env;
1468 v8::HandleScope scope(env->GetIsolate());
1469 v8::Isolate* isolate = CcTest::isolate();
1470
1471 uint32_t value = 239;
1472
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);
1477 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1478 }
1479
1480
THREADED_TEST(BigUnsignedSmiInteger)1481 THREADED_TEST(BigUnsignedSmiInteger) {
1482 LocalContext env;
1483 v8::HandleScope scope(env->GetIsolate());
1484 v8::Isolate* isolate = CcTest::isolate();
1485
1486 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1487 CHECK(i::Smi::IsValid(value));
1488 CHECK(!i::Smi::IsValid(value + 1));
1489
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);
1494 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1495 }
1496
1497
THREADED_TEST(BigUnsignedInteger)1498 THREADED_TEST(BigUnsignedInteger) {
1499 LocalContext env;
1500 v8::HandleScope scope(env->GetIsolate());
1501 v8::Isolate* isolate = CcTest::isolate();
1502
1503 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));
1506
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);
1511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512 }
1513
1514
THREADED_TEST(OutOfSignedRangeUnsignedInteger)1515 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1516 LocalContext env;
1517 v8::HandleScope scope(env->GetIsolate());
1518 v8::Isolate* isolate = CcTest::isolate();
1519
1520 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.
1523
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);
1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529 }
1530
1531
THREADED_TEST(IsNativeError)1532 THREADED_TEST(IsNativeError) {
1533 LocalContext env;
1534 v8::HandleScope scope(env->GetIsolate());
1535 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
THREADED_TEST(ArgumentsObject)1545 THREADED_TEST(ArgumentsObject) {
1546 LocalContext env;
1547 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
THREADED_TEST(IsMapOrSet)1558 THREADED_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
THREADED_TEST(StringObject)1594 THREADED_TEST(StringObject) {
1595 LocalContext env;
1596 v8::HandleScope scope(env->GetIsolate());
1597 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());
1607 Local<v8::String> the_string = as_boxed->ValueOf();
1608 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>();
1613 the_string = as_boxed->ValueOf();
1614 CHECK(!the_string.IsEmpty());
1615 ExpectObject("\"test\"", the_string);
1616 }
1617
1618
THREADED_TEST(NumberObject)1619 THREADED_TEST(NumberObject) {
1620 LocalContext env;
1621 v8::HandleScope scope(env->GetIsolate());
1622 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());
1630 double the_number = as_boxed->ValueOf();
1631 CHECK_EQ(42.0, the_number);
1632 v8::Handle<v8::Value> new_boxed_number =
1633 v8::NumberObject::New(env->GetIsolate(), 43);
1634 CHECK(new_boxed_number->IsNumberObject());
1635 as_boxed = new_boxed_number.As<v8::NumberObject>();
1636 the_number = as_boxed->ValueOf();
1637 CHECK_EQ(43.0, the_number);
1638 }
1639
1640
THREADED_TEST(BooleanObject)1641 THREADED_TEST(BooleanObject) {
1642 LocalContext env;
1643 v8::HandleScope scope(env->GetIsolate());
1644 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());
1653 bool the_boolean = as_boxed->ValueOf();
1654 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>();
1660 CHECK_EQ(true, as_boxed->ValueOf());
1661 as_boxed = boxed_false.As<v8::BooleanObject>();
1662 CHECK_EQ(false, as_boxed->ValueOf());
1663 }
1664
1665
THREADED_TEST(PrimitiveAndWrappedBooleans)1666 THREADED_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());
1715 }
1716
1717
THREADED_TEST(Number)1718 THREADED_TEST(Number) {
1719 LocalContext env;
1720 v8::HandleScope scope(env->GetIsolate());
1721 double PI = 3.1415926;
1722 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723 CHECK_EQ(PI, pi_obj->NumberValue());
1724 }
1725
1726
THREADED_TEST(ToNumber)1727 THREADED_TEST(ToNumber) {
1728 LocalContext env;
1729 v8::Isolate* isolate = CcTest::isolate();
1730 v8::HandleScope scope(isolate);
1731 Local<String> str = v8_str("3.1415926");
1732 CHECK_EQ(3.1415926, str->NumberValue());
1733 v8::Handle<v8::Boolean> t = v8::True(isolate);
1734 CHECK_EQ(1.0, t->NumberValue());
1735 v8::Handle<v8::Boolean> f = v8::False(isolate);
1736 CHECK_EQ(0.0, f->NumberValue());
1737 }
1738
1739
THREADED_TEST(Date)1740 THREADED_TEST(Date) {
1741 LocalContext env;
1742 v8::HandleScope scope(env->GetIsolate());
1743 double PI = 3.1415926;
1744 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745 CHECK_EQ(3.0, date->NumberValue());
1746 date.As<v8::Date>()->Set(v8_str("property"),
1747 v8::Integer::New(env->GetIsolate(), 42));
1748 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1749 }
1750
1751
THREADED_TEST(Boolean)1752 THREADED_TEST(Boolean) {
1753 LocalContext env;
1754 v8::Isolate* isolate = env->GetIsolate();
1755 v8::HandleScope scope(isolate);
1756 v8::Handle<v8::Boolean> t = v8::True(isolate);
1757 CHECK(t->Value());
1758 v8::Handle<v8::Boolean> f = v8::False(isolate);
1759 CHECK(!f->Value());
1760 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761 CHECK(!u->BooleanValue());
1762 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763 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());
1768 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());
1772 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773 }
1774
1775
DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value> & args)1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777 ApiTestFuzzer::Fuzz();
1778 args.GetReturnValue().Set(v8_num(13.4));
1779 }
1780
1781
GetM(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1782 static void GetM(Local<String> name,
1783 const v8::PropertyCallbackInfo<v8::Value>& info) {
1784 ApiTestFuzzer::Fuzz();
1785 info.GetReturnValue().Set(v8_num(876));
1786 }
1787
1788
THREADED_TEST(GlobalPrototype)1789 THREADED_TEST(GlobalPrototype) {
1790 v8::Isolate* isolate = CcTest::isolate();
1791 v8::HandleScope scope(isolate);
1792 v8::Handle<v8::FunctionTemplate> func_templ =
1793 v8::FunctionTemplate::New(isolate);
1794 func_templ->PrototypeTemplate()->Set(
1795 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797 templ->Set(isolate, "x", v8_num(200));
1798 templ->SetAccessor(v8_str("m"), GetM);
1799 LocalContext env(0, templ);
1800 v8::Handle<Script> script(v8_compile("dummy()"));
1801 v8::Handle<Value> result(script->Run());
1802 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
THREADED_TEST(ObjectTemplate)1808 THREADED_TEST(ObjectTemplate) {
1809 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));
1814 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());
1819 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822 templ2->Set(isolate, "a", v8_num(12));
1823 templ2->Set(isolate, "b", templ1);
1824 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
GetFlabby(const v8::FunctionCallbackInfo<v8::Value> & args)1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834 ApiTestFuzzer::Fuzz();
1835 args.GetReturnValue().Set(v8_num(17.2));
1836 }
1837
1838
GetKnurd(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)1839 static void GetKnurd(Local<String> property,
1840 const v8::PropertyCallbackInfo<v8::Value>& info) {
1841 ApiTestFuzzer::Fuzz();
1842 info.GetReturnValue().Set(v8_num(15.2));
1843 }
1844
1845
THREADED_TEST(DescriptorInheritance)1846 THREADED_TEST(DescriptorInheritance) {
1847 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));
1854
1855 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
1857 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858 base1->Inherit(super);
1859 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1860
1861 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862 base2->Inherit(super);
1863 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1864
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
1904 int echo_named_call_count;
1905
1906
EchoNamedProperty(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1907 static void EchoNamedProperty(Local<String> name,
1908 const v8::PropertyCallbackInfo<v8::Value>& info) {
1909 ApiTestFuzzer::Fuzz();
1910 CHECK_EQ(v8_str("data"), info.Data());
1911 echo_named_call_count++;
1912 info.GetReturnValue().Set(name);
1913 }
1914
1915
1916 // Helper functions for Interceptor/Accessor interaction tests
1917
SimpleAccessorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1918 void 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)));
1923 }
1924
SimpleAccessorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926 const v8::PropertyCallbackInfo<void>& info) {
1927 Handle<Object> self = Handle<Object>::Cast(info.This());
1928 self->Set(String::Concat(v8_str("accessor_"), name), value);
1929 }
1930
SymbolAccessorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1931 void 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);
1938 }
1939
SymbolAccessorSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)1940 void 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);
1947 }
1948
EmptyInterceptorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1949 void EmptyInterceptorGetter(Local<String> name,
1950 const v8::PropertyCallbackInfo<v8::Value>& info) {
1951 }
1952
EmptyInterceptorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1953 void EmptyInterceptorSetter(Local<String> name,
1954 Local<Value> value,
1955 const v8::PropertyCallbackInfo<v8::Value>& info) {
1956 }
1957
InterceptorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1958 void InterceptorGetter(Local<String> name,
1959 const v8::PropertyCallbackInfo<v8::Value>& info) {
1960 // Intercept names that start with 'interceptor_'.
1961 String::Utf8Value utf8(name);
1962 char* name_str = *utf8;
1963 char prefix[] = "interceptor_";
1964 int i;
1965 for (i = 0; name_str[i] && prefix[i]; ++i) {
1966 if (name_str[i] != prefix[i]) return;
1967 }
1968 Handle<Object> self = Handle<Object>::Cast(info.This());
1969 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1970 }
1971
InterceptorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)1972 void 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;
1983 }
1984 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 }
1991 }
1992
AddAccessor(Handle<FunctionTemplate> templ,Handle<String> name,v8::AccessorGetterCallback getter,v8::AccessorSetterCallback setter)1993 void AddAccessor(Handle<FunctionTemplate> templ,
1994 Handle<String> name,
1995 v8::AccessorGetterCallback getter,
1996 v8::AccessorSetterCallback setter) {
1997 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1998 }
1999
AddInterceptor(Handle<FunctionTemplate> templ,v8::NamedPropertyGetterCallback getter,v8::NamedPropertySetterCallback setter)2000 void AddInterceptor(Handle<FunctionTemplate> templ,
2001 v8::NamedPropertyGetterCallback getter,
2002 v8::NamedPropertySetterCallback setter) {
2003 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2004 }
2005
2006
AddAccessor(Handle<FunctionTemplate> templ,Handle<Name> name,v8::AccessorNameGetterCallback getter,v8::AccessorNameSetterCallback setter)2007 void 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
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors)2015 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2016 v8::HandleScope scope(CcTest::isolate());
2017 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2018 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2019 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
2032
THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange)2033 THREADED_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
THREADED_TEST(EmptyInterceptorBreakTransitions)2053 THREADED_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
THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors)2068 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2069 v8::Isolate* isolate = CcTest::isolate();
2070 v8::HandleScope scope(isolate);
2071 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2072 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2073 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
2089
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties)2090 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2091 v8::Isolate* isolate = CcTest::isolate();
2092 v8::HandleScope scope(isolate);
2093 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2094 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2095 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
2110
THREADED_TEST(SwitchFromInterceptorToAccessor)2111 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2112 v8::HandleScope scope(CcTest::isolate());
2113 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2114 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
2128
THREADED_TEST(SwitchFromAccessorToInterceptor)2129 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2130 v8::HandleScope scope(CcTest::isolate());
2131 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2132 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
2146
THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance)2147 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2148 v8::HandleScope scope(CcTest::isolate());
2149 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2150 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2151 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
2166
THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance)2167 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2168 v8::HandleScope scope(CcTest::isolate());
2169 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2170 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2171 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
2186
THREADED_TEST(SwitchFromInterceptorToJSAccessor)2187 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2188 v8::HandleScope scope(CcTest::isolate());
2189 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2190 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
2211
THREADED_TEST(SwitchFromJSAccessorToInterceptor)2212 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2213 v8::HandleScope scope(CcTest::isolate());
2214 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2215 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
2236
THREADED_TEST(SwitchFromInterceptorToProperty)2237 THREADED_TEST(SwitchFromInterceptorToProperty) {
2238 v8::HandleScope scope(CcTest::isolate());
2239 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2240 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2241 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
2254
THREADED_TEST(SwitchFromPropertyToInterceptor)2255 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2256 v8::HandleScope scope(CcTest::isolate());
2257 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2258 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2259 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 }
2271
2272
THREADED_TEST(NamedPropertyHandlerGetter)2273 THREADED_TEST(NamedPropertyHandlerGetter) {
2274 echo_named_call_count = 0;
2275 v8::HandleScope scope(CcTest::isolate());
2276 v8::Handle<v8::FunctionTemplate> templ =
2277 v8::FunctionTemplate::New(CcTest::isolate());
2278 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);
2289 String::Utf8Value value(str);
2290 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
2298 int echo_indexed_call_count = 0;
2299
2300
EchoIndexedProperty(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)2301 static void EchoIndexedProperty(
2302 uint32_t index,
2303 const v8::PropertyCallbackInfo<v8::Value>& info) {
2304 ApiTestFuzzer::Fuzz();
2305 CHECK_EQ(v8_num(637), info.Data());
2306 echo_indexed_call_count++;
2307 info.GetReturnValue().Set(v8_num(index));
2308 }
2309
2310
THREADED_TEST(IndexedPropertyHandlerGetter)2311 THREADED_TEST(IndexedPropertyHandlerGetter) {
2312 v8::Isolate* isolate = CcTest::isolate();
2313 v8::HandleScope scope(isolate);
2314 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2315 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
2326 v8::Handle<v8::Object> bottom;
2327
CheckThisIndexedPropertyHandler(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)2328 static void CheckThisIndexedPropertyHandler(
2329 uint32_t index,
2330 const v8::PropertyCallbackInfo<v8::Value>& info) {
2331 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2332 ApiTestFuzzer::Fuzz();
2333 CHECK(info.This()->Equals(bottom));
2334 }
2335
CheckThisNamedPropertyHandler(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)2336 static void CheckThisNamedPropertyHandler(
2337 Local<String> name,
2338 const v8::PropertyCallbackInfo<v8::Value>& info) {
2339 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2340 ApiTestFuzzer::Fuzz();
2341 CHECK(info.This()->Equals(bottom));
2342 }
2343
CheckThisIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)2344 void CheckThisIndexedPropertySetter(
2345 uint32_t index,
2346 Local<Value> value,
2347 const v8::PropertyCallbackInfo<v8::Value>& info) {
2348 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2349 ApiTestFuzzer::Fuzz();
2350 CHECK(info.This()->Equals(bottom));
2351 }
2352
2353
CheckThisNamedPropertySetter(Local<String> property,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)2354 void CheckThisNamedPropertySetter(
2355 Local<String> property,
2356 Local<Value> value,
2357 const v8::PropertyCallbackInfo<v8::Value>& info) {
2358 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2359 ApiTestFuzzer::Fuzz();
2360 CHECK(info.This()->Equals(bottom));
2361 }
2362
CheckThisIndexedPropertyQuery(uint32_t index,const v8::PropertyCallbackInfo<v8::Integer> & info)2363 void 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));
2369 }
2370
2371
CheckThisNamedPropertyQuery(Local<String> property,const v8::PropertyCallbackInfo<v8::Integer> & info)2372 void CheckThisNamedPropertyQuery(
2373 Local<String> property,
2374 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2375 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2376 ApiTestFuzzer::Fuzz();
2377 CHECK(info.This()->Equals(bottom));
2378 }
2379
2380
CheckThisIndexedPropertyDeleter(uint32_t index,const v8::PropertyCallbackInfo<v8::Boolean> & info)2381 void CheckThisIndexedPropertyDeleter(
2382 uint32_t index,
2383 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2384 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2385 ApiTestFuzzer::Fuzz();
2386 CHECK(info.This()->Equals(bottom));
2387 }
2388
2389
CheckThisNamedPropertyDeleter(Local<String> property,const v8::PropertyCallbackInfo<v8::Boolean> & info)2390 void 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
CheckThisIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)2399 void 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
CheckThisNamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)2407 void 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
THREADED_PROFILED_TEST(PropertyHandlerInPrototype)2415 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2416 LocalContext env;
2417 v8::Isolate* isolate = env->GetIsolate();
2418 v8::HandleScope scope(isolate);
2419
2420 // Set up a prototype chain with three interceptors.
2421 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2422 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
2440 bottom->SetPrototype(middle);
2441 middle->SetPrototype(top);
2442 env->Global()->Set(v8_str("obj"), bottom);
2443
2444 // Indexed and named get.
2445 CompileRun("obj[0]");
2446 CompileRun("obj.x");
2447
2448 // Indexed and named set.
2449 CompileRun("obj[1] = 42");
2450 CompileRun("obj.y = 42");
2451
2452 // Indexed and named query.
2453 CompileRun("0 in obj");
2454 CompileRun("'x' in obj");
2455
2456 // Indexed and named deleter.
2457 CompileRun("delete obj[0]");
2458 CompileRun("delete obj.x");
2459
2460 // Enumerators.
2461 CompileRun("for (var p in obj) ;");
2462 }
2463
2464
PrePropertyHandlerGet(Local<String> key,const v8::PropertyCallbackInfo<v8::Value> & info)2465 static void PrePropertyHandlerGet(
2466 Local<String> key,
2467 const v8::PropertyCallbackInfo<v8::Value>& info) {
2468 ApiTestFuzzer::Fuzz();
2469 if (v8_str("pre")->Equals(key)) {
2470 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2471 }
2472 }
2473
2474
PrePropertyHandlerQuery(Local<String> key,const v8::PropertyCallbackInfo<v8::Integer> & info)2475 static void PrePropertyHandlerQuery(
2476 Local<String> key,
2477 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2478 if (v8_str("pre")->Equals(key)) {
2479 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2480 }
2481 }
2482
2483
THREADED_TEST(PrePropertyHandler)2484 THREADED_TEST(PrePropertyHandler) {
2485 v8::Isolate* isolate = CcTest::isolate();
2486 v8::HandleScope scope(isolate);
2487 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2488 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2489 0,
2490 PrePropertyHandlerQuery);
2491 LocalContext env(NULL, desc->InstanceTemplate());
2492 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2493 v8::Handle<Value> result_pre = CompileRun("pre");
2494 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2495 v8::Handle<Value> result_on = CompileRun("on");
2496 CHECK_EQ(v8_str("Object: on"), result_on);
2497 v8::Handle<Value> result_post = CompileRun("post");
2498 CHECK(result_post.IsEmpty());
2499 }
2500
2501
THREADED_TEST(UndefinedIsNotEnumerable)2502 THREADED_TEST(UndefinedIsNotEnumerable) {
2503 LocalContext env;
2504 v8::HandleScope scope(env->GetIsolate());
2505 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2506 CHECK(result->IsFalse());
2507 }
2508
2509
2510 v8::Handle<Script> call_recursively_script;
2511 static const int kTargetRecursionDepth = 200; // near maximum
2512
2513
CallScriptRecursivelyCall(const v8::FunctionCallbackInfo<v8::Value> & args)2514 static void CallScriptRecursivelyCall(
2515 const v8::FunctionCallbackInfo<v8::Value>& args) {
2516 ApiTestFuzzer::Fuzz();
2517 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2518 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());
2522 }
2523
2524
CallFunctionRecursivelyCall(const v8::FunctionCallbackInfo<v8::Value> & args)2525 static void CallFunctionRecursivelyCall(
2526 const v8::FunctionCallbackInfo<v8::Value>& args) {
2527 ApiTestFuzzer::Fuzz();
2528 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2529 if (depth == kTargetRecursionDepth) {
2530 printf("[depth = %d]\n", depth);
2531 return;
2532 }
2533 args.This()->Set(v8_str("depth"),
2534 v8::Integer::New(args.GetIsolate(), depth + 1));
2535 v8::Handle<Value> function =
2536 args.This()->Get(v8_str("callFunctionRecursively"));
2537 args.GetReturnValue().Set(
2538 function.As<Function>()->Call(args.This(), 0, NULL));
2539 }
2540
2541
THREADED_TEST(DeepCrossLanguageRecursion)2542 THREADED_TEST(DeepCrossLanguageRecursion) {
2543 v8::Isolate* isolate = CcTest::isolate();
2544 v8::HandleScope scope(isolate);
2545 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2546 global->Set(v8_str("callScriptRecursively"),
2547 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2548 global->Set(v8_str("callFunctionRecursively"),
2549 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2550 LocalContext env(NULL, global);
2551
2552 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2553 call_recursively_script = v8_compile("callScriptRecursively()");
2554 call_recursively_script->Run();
2555 call_recursively_script = v8::Handle<Script>();
2556
2557 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2558 CompileRun("callFunctionRecursively()");
2559 }
2560
2561
ThrowingPropertyHandlerGet(Local<String> key,const v8::PropertyCallbackInfo<v8::Value> & info)2562 static void ThrowingPropertyHandlerGet(
2563 Local<String> key,
2564 const v8::PropertyCallbackInfo<v8::Value>& info) {
2565 ApiTestFuzzer::Fuzz();
2566 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2567 }
2568
2569
ThrowingPropertyHandlerSet(Local<String> key,Local<Value>,const v8::PropertyCallbackInfo<v8::Value> & info)2570 static 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
2576 }
2577
2578
THREADED_TEST(CallbackExceptionRegression)2579 THREADED_TEST(CallbackExceptionRegression) {
2580 v8::Isolate* isolate = CcTest::isolate();
2581 v8::HandleScope scope(isolate);
2582 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2583 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2584 ThrowingPropertyHandlerSet);
2585 LocalContext env;
2586 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2587 v8::Handle<Value> otto = CompileRun(
2588 "try { with (obj) { otto; } } catch (e) { e; }");
2589 CHECK_EQ(v8_str("otto"), otto);
2590 v8::Handle<Value> netto = CompileRun(
2591 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2592 CHECK_EQ(v8_str("netto"), netto);
2593 }
2594
2595
THREADED_TEST(FunctionPrototype)2596 THREADED_TEST(FunctionPrototype) {
2597 v8::Isolate* isolate = CcTest::isolate();
2598 v8::HandleScope scope(isolate);
2599 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2600 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2601 LocalContext env;
2602 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2603 Local<Script> script = v8_compile("Foo.prototype.plak");
2604 CHECK_EQ(script->Run()->Int32Value(), 321);
2605 }
2606
2607
THREADED_TEST(InternalFields)2608 THREADED_TEST(InternalFields) {
2609 LocalContext env;
2610 v8::Isolate* isolate = env->GetIsolate();
2611 v8::HandleScope scope(isolate);
2612
2613 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2614 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
THREADED_TEST(GlobalObjectInternalFields)2624 THREADED_TEST(GlobalObjectInternalFields) {
2625 v8::Isolate* isolate = CcTest::isolate();
2626 v8::HandleScope scope(isolate);
2627 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2628 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
THREADED_TEST(GlobalObjectHasRealIndexedProperty)2639 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2640 LocalContext env;
2641 v8::HandleScope scope(CcTest::isolate());
2642
2643 v8::Local<v8::Object> global = env->Global();
2644 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2645 CHECK(global->HasRealIndexedProperty(0));
2646 }
2647
2648
CheckAlignedPointerInInternalField(Handle<v8::Object> obj,void * value)2649 static 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 }
2656
2657
THREADED_TEST(InternalFieldsAlignedPointers)2658 THREADED_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);
2664 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());
2668
2669 CheckAlignedPointerInInternalField(obj, NULL);
2670
2671 int* heap_allocated = new int[100];
2672 CheckAlignedPointerInInternalField(obj, heap_allocated);
2673 delete[] heap_allocated;
2674
2675 int stack_allocated[100];
2676 CheckAlignedPointerInInternalField(obj, stack_allocated);
2677
2678 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2679 CheckAlignedPointerInInternalField(obj, huge);
2680
2681 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2682 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2683 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2684 }
2685
2686
CheckAlignedPointerInEmbedderData(LocalContext * env,int index,void * value)2687 static 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
AlignedTestPointer(int i)2697 static void* AlignedTestPointer(int i) {
2698 return reinterpret_cast<void*>(i * 1234);
2699 }
2700
2701
THREADED_TEST(EmbedderDataAlignedPointers)2702 THREADED_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
CheckEmbedderData(LocalContext * env,int index,v8::Handle<Value> data)2729 static 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
THREADED_TEST(EmbedderData)2737 THREADED_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));
2749 }
2750
2751
THREADED_TEST(IdentityHash)2752 THREADED_TEST(IdentityHash) {
2753 LocalContext env;
2754 v8::Isolate* isolate = env->GetIsolate();
2755 v8::HandleScope scope(isolate);
2756
2757 // Ensure that the test starts with an fresh heap to test whether the hash
2758 // code is based on the address.
2759 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2760 Local<v8::Object> obj = v8::Object::New(isolate);
2761 int hash = obj->GetIdentityHash();
2762 int hash1 = obj->GetIdentityHash();
2763 CHECK_EQ(hash, hash1);
2764 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2765 // 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);
2769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2770 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2771 // 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);
2777
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");
2782 Local<v8::Object> o1 = v8::Object::New(isolate);
2783 Local<v8::Object> o2 = v8::Object::New(isolate);
2784 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2785 }
2786 {
2787 CompileRun(
2788 "function cnst() { return 42; };\n"
2789 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2790 Local<v8::Object> o1 = v8::Object::New(isolate);
2791 Local<v8::Object> o2 = v8::Object::New(isolate);
2792 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2793 }
2794 }
2795
2796
THREADED_TEST(GlobalProxyIdentityHash)2797 THREADED_TEST(GlobalProxyIdentityHash) {
2798 LocalContext env;
2799 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 }
2814
2815
THREADED_TEST(SymbolProperties)2816 THREADED_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
THREADED_TEST(SymbolTemplateProperties)2924 THREADED_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
THREADED_TEST(PrivateProperties)2938 THREADED_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
THREADED_TEST(GlobalSymbols)2997 THREADED_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
CheckWellKnownSymbol(v8::Local<v8::Symbol> (* getter)(v8::Isolate *),const char * name)3022 static 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
THREADED_TEST(WellKnownSymbols)3039 THREADED_TEST(WellKnownSymbols) {
3040 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3041 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3042 }
3043
3044
THREADED_TEST(GlobalPrivates)3045 THREADED_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
3067 class ScopedArrayBufferContents {
3068 public:
ScopedArrayBufferContents(const v8::ArrayBuffer::Contents & contents)3069 explicit ScopedArrayBufferContents(
3070 const v8::ArrayBuffer::Contents& contents)
3071 : contents_(contents) {}
~ScopedArrayBufferContents()3072 ~ScopedArrayBufferContents() { free(contents_.Data()); }
Data() const3073 void* Data() const { return contents_.Data(); }
ByteLength() const3074 size_t ByteLength() const { return contents_.ByteLength(); }
3075 private:
3076 const v8::ArrayBuffer::Contents contents_;
3077 };
3078
3079 template <typename T>
CheckInternalFieldsAreZero(v8::Handle<T> value)3080 static 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
THREADED_TEST(ArrayBuffer_ApiInternalToExternal)3088 THREADED_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
THREADED_TEST(ArrayBuffer_JSInternalToExternal)3124 THREADED_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
THREADED_TEST(ArrayBuffer_External)3166 THREADED_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
CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv)3198 static 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
CheckIsNeutered(v8::Handle<v8::TypedArray> ta)3204 static 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
CheckIsTypedArrayVarNeutered(const char * name)3211 static 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
3223 template <typename TypedArray, int kElementSize>
CreateAndCheck(Handle<v8::ArrayBuffer> ab,int byteOffset,int length)3224 static 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
THREADED_TEST(ArrayBuffer_NeuteringApi)3236 THREADED_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
THREADED_TEST(ArrayBuffer_NeuteringScript)3286 THREADED_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
THREADED_TEST(HiddenProperties)3331 THREADED_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());
3337 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
3341 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3342
3343 // Make sure delete of a non-existent hidden value works
3344 CHECK(obj->DeleteHiddenValue(key));
3345
3346 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3347 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3348 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3349 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3350
3351 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3352
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());
3358 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3359 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3360 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3361
3362 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3363
3364 // Add another property and delete it afterwards to force the object in
3365 // slow case.
3366 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3367 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
3373 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3374
3375 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3376 CHECK(obj->GetHiddenValue(key).IsEmpty());
3377
3378 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3379 CHECK(obj->DeleteHiddenValue(key));
3380 CHECK(obj->GetHiddenValue(key).IsEmpty());
3381 }
3382
3383
THREADED_TEST(Regress97784)3384 THREADED_TEST(Regress97784) {
3385 // Regression test for crbug.com/97784
3386 // Messing with the Object.prototype should not have effect on
3387 // hidden properties.
3388 LocalContext env;
3389 v8::HandleScope scope(env->GetIsolate());
3390
3391 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3392 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.
3406 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3407 ExpectFalse("set_called");
3408 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3409 }
3410
3411
3412 static bool interceptor_for_hidden_properties_called;
InterceptorForHiddenProperties(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)3413 static void InterceptorForHiddenProperties(
3414 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3415 interceptor_for_hidden_properties_called = true;
3416 }
3417
3418
THREADED_TEST(HiddenPropertiesWithInterceptors)3419 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3420 LocalContext context;
3421 v8::Isolate* isolate = context->GetIsolate();
3422 v8::HandleScope scope(isolate);
3423
3424 interceptor_for_hidden_properties_called = false;
3425
3426 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3427
3428 // Associate an interceptor with an object and start setting hidden values.
3429 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3430 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();
3434 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3435 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3436 CHECK(!interceptor_for_hidden_properties_called);
3437 }
3438
3439
THREADED_TEST(External)3440 THREADED_TEST(External) {
3441 v8::HandleScope scope(CcTest::isolate());
3442 int x = 3;
3443 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3444 LocalContext env;
3445 env->Global()->Set(v8_str("ext"), ext);
3446 Local<Value> reext_obj = CompileRun("this.ext");
3447 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3448 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");
3455 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]);
3459
3460 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3461 CHECK_EQ('0', *char_ptr);
3462 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3463 CHECK_EQ('1', *char_ptr);
3464 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3465 CHECK_EQ('2', *char_ptr);
3466 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3467 CHECK_EQ('3', *char_ptr);
3468 i::DeleteArray(data);
3469 }
3470
3471
THREADED_TEST(GlobalHandle)3472 THREADED_TEST(GlobalHandle) {
3473 v8::Isolate* isolate = CcTest::isolate();
3474 v8::Persistent<String> global;
3475 {
3476 v8::HandleScope scope(isolate);
3477 global.Reset(isolate, v8_str("str"));
3478 }
3479 {
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
THREADED_TEST(ResettingGlobalHandle)3496 THREADED_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
THREADED_TEST(ResettingGlobalHandleToEmpty)3524 THREADED_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
3548 template<class T>
PassUnique(v8::UniquePersistent<T> unique)3549 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3550 return unique.Pass();
3551 }
3552
3553
3554 template<class T>
ReturnUnique(v8::Isolate * isolate,const v8::Persistent<T> & global)3555 static 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
THREADED_TEST(UniquePersistent)3562 THREADED_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
3615 template<typename K, typename V>
3616 class 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 };
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)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 }
MapFromWeakCallbackData(const v8::WeakCallbackData<V,WeakCallbackDataType> & data)3632 static MapType* MapFromWeakCallbackData(
3633 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3634 return data.GetParameter()->map;
3635 }
KeyFromWeakCallbackData(const v8::WeakCallbackData<V,WeakCallbackDataType> & data)3636 static K KeyFromWeakCallbackData(
3637 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3638 return data.GetParameter()->key;
3639 }
DisposeCallbackData(WeakCallbackDataType * data)3640 static void DisposeCallbackData(WeakCallbackDataType* data) {
3641 delete data;
3642 }
Dispose(v8::Isolate * isolate,v8::UniquePersistent<V> value,K key)3643 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3644 K key) { }
3645 };
3646
3647
3648 template<typename Map>
TestPersistentValueMap()3649 static 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
TEST(PersistentValueMap)3701 TEST(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
TEST(PersistentValueVector)3712 TEST(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
THREADED_TEST(GlobalHandleUpcast)3755 THREADED_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
THREADED_TEST(HandleEquality)3768 THREADED_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
THREADED_TEST(LocalHandle)3806 THREADED_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);
3811 }
3812
3813
3814 class WeakCallCounter {
3815 public:
WeakCallCounter(int id)3816 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
id()3817 int id() { return id_; }
increment()3818 void increment() { number_of_weak_calls_++; }
NumberOfWeakCalls()3819 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3820 private:
3821 int id_;
3822 int number_of_weak_calls_;
3823 };
3824
3825
3826 template<typename T>
3827 struct WeakCallCounterAndPersistent {
WeakCallCounterAndPersistentWeakCallCounterAndPersistent3828 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3829 : counter(counter) {}
3830 WeakCallCounter* counter;
3831 v8::Persistent<T> handle;
3832 };
3833
3834
3835 template <typename T>
WeakPointerCallback(const v8::WeakCallbackData<T,WeakCallCounterAndPersistent<T>> & data)3836 static 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
3844 template<typename T>
MakeUniqueId(const Persistent<T> & p)3845 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3846 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3847 }
3848
3849
THREADED_TEST(ApiObjectGroups)3850 THREADED_TEST(ApiObjectGroups) {
3851 LocalContext env;
3852 v8::Isolate* iso = env->GetIsolate();
3853 HandleScope scope(iso);
3854
3855 WeakCallCounter counter(1234);
3856
3857 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);
3863
3864 {
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);
3879 }
3880
3881 WeakCallCounterAndPersistent<Value> root(&counter);
3882 root.handle.Reset(iso, g1s1.handle); // make a root.
3883
3884 // Connect group 1 and 2, make a cycle.
3885 {
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 }
3892
3893 {
3894 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);
3902 }
3903 // Do a single full GC, ensure incremental marking is stopped.
3904 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3905 iso)->heap();
3906 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3907
3908 // All object should be alive.
3909 CHECK_EQ(0, counter.NumberOfWeakCalls());
3910
3911 // Weaken the root.
3912 root.handle.SetWeak(&root, &WeakPointerCallback);
3913 // But make children strong roots---all the objects (except for children)
3914 // should be collectable now.
3915 g1c1.handle.ClearWeak();
3916 g2c1.handle.ClearWeak();
3917
3918 // Groups are deleted, rebuild groups.
3919 {
3920 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);
3928 }
3929
3930 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3931
3932 // All objects should be gone. 5 global handles in total.
3933 CHECK_EQ(5, counter.NumberOfWeakCalls());
3934
3935 // And now make children weak again and collect them.
3936 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3937 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3938
3939 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3940 CHECK_EQ(7, counter.NumberOfWeakCalls());
3941 }
3942
3943
THREADED_TEST(ApiObjectGroupsForSubtypes)3944 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3945 LocalContext env;
3946 v8::Isolate* iso = env->GetIsolate();
3947 HandleScope scope(iso);
3948
3949 WeakCallCounter counter(1234);
3950
3951 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);
3957
3958 {
3959 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);
3966
3967 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);
3973 }
3974
3975 WeakCallCounterAndPersistent<Value> root(&counter);
3976 root.handle.Reset(iso, g1s1.handle); // make a root.
3977
3978 // Connect group 1 and 2, make a cycle.
3979 {
3980 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)));
3985 }
3986
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);
4001
4002 // All object should be alive.
4003 CHECK_EQ(0, counter.NumberOfWeakCalls());
4004
4005 // Weaken the root.
4006 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();
4011
4012 // Groups are deleted, rebuild groups.
4013 {
4014 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);
4022 }
4023
4024 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
THREADED_TEST(ApiObjectGroupsCycle)4038 THREADED_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.
TEST(ApiObjectGroupsCycleForScavenger)4149 TEST(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);
4248
4249 // All objects should be gone. 7 global handles in total.
4250 CHECK_EQ(7, counter.NumberOfWeakCalls());
4251 }
4252
4253
THREADED_TEST(ScriptException)4254 THREADED_TEST(ScriptException) {
4255 LocalContext env;
4256 v8::HandleScope scope(env->GetIsolate());
4257 Local<Script> script = v8_compile("throw 'panama!';");
4258 v8::TryCatch try_catch;
4259 Local<Value> result = script->Run();
4260 CHECK(result.IsEmpty());
4261 CHECK(try_catch.HasCaught());
4262 String::Utf8Value exception_value(try_catch.Exception());
4263 CHECK_EQ(*exception_value, "panama!");
4264 }
4265
4266
TEST(TryCatchCustomException)4267 TEST(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
4279 bool message_received;
4280
4281
check_message_0(v8::Handle<v8::Message> message,v8::Handle<Value> data)4282 static void check_message_0(v8::Handle<v8::Message> message,
4283 v8::Handle<Value> data) {
4284 CHECK_EQ(5.76, data->NumberValue());
4285 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4286 CHECK(!message->IsSharedCrossOrigin());
4287 message_received = true;
4288 }
4289
4290
THREADED_TEST(MessageHandler0)4291 THREADED_TEST(MessageHandler0) {
4292 message_received = false;
4293 v8::HandleScope scope(CcTest::isolate());
4294 CHECK(!message_received);
4295 LocalContext context;
4296 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4297 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4298 script->Run();
4299 CHECK(message_received);
4300 // clear out the message listener
4301 v8::V8::RemoveMessageListeners(check_message_0);
4302 }
4303
4304
check_message_1(v8::Handle<v8::Message> message,v8::Handle<Value> data)4305 static 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
TEST(MessageHandler1)4314 TEST(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
check_message_2(v8::Handle<v8::Message> message,v8::Handle<Value> data)4327 static 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
TEST(MessageHandler2)4339 TEST(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
check_message_3(v8::Handle<v8::Message> message,v8::Handle<Value> data)4356 static 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
TEST(MessageHandler3)4364 TEST(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
check_message_4(v8::Handle<v8::Message> message,v8::Handle<Value> data)4385 static 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
TEST(MessageHandler4)4393 TEST(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
check_message_5a(v8::Handle<v8::Message> message,v8::Handle<Value> data)4414 static 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
check_message_5b(v8::Handle<v8::Message> message,v8::Handle<Value> data)4422 static 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
TEST(MessageHandler5)4430 TEST(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);
4462 }
4463
4464
THREADED_TEST(GetSetProperty)4465 THREADED_TEST(GetSetProperty) {
4466 LocalContext context;
4467 v8::Isolate* isolate = context->GetIsolate();
4468 v8::HandleScope scope(isolate);
4469 context->Global()->Set(v8_str("foo"), v8_num(14));
4470 context->Global()->Set(v8_str("12"), v8_num(92));
4471 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4472 context->Global()->Set(v8_num(13), v8_num(56));
4473 Local<Value> foo = CompileRun("this.foo");
4474 CHECK_EQ(14, foo->Int32Value());
4475 Local<Value> twelve = CompileRun("this[12]");
4476 CHECK_EQ(92, twelve->Int32Value());
4477 Local<Value> sixteen = CompileRun("this[16]");
4478 CHECK_EQ(32, sixteen->Int32Value());
4479 Local<Value> thirteen = CompileRun("this[13]");
4480 CHECK_EQ(56, thirteen->Int32Value());
4481 CHECK_EQ(92,
4482 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4483 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4484 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4485 CHECK_EQ(32,
4486 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4487 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4488 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4489 CHECK_EQ(56,
4490 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4491 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4492 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4493 }
4494
4495
THREADED_TEST(PropertyAttributes)4496 THREADED_TEST(PropertyAttributes) {
4497 LocalContext context;
4498 v8::HandleScope scope(context->GetIsolate());
4499 // 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));
4503 // read-only
4504 prop = v8_str("read_only");
4505 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4506 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4507 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4508 CompileRun("read_only = 9");
4509 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");
4514 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4515 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4516 CompileRun("delete dont_delete");
4517 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4518 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4519 // dont-enum
4520 prop = v8_str("dont_enum");
4521 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4522 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());
4534 String::Utf8Value exception_value(try_catch.Exception());
4535 CHECK_EQ("exception", *exception_value);
4536 try_catch.Reset();
4537 }
4538
4539
THREADED_TEST(Array)4540 THREADED_TEST(Array) {
4541 LocalContext context;
4542 v8::HandleScope scope(context->GetIsolate());
4543 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4544 CHECK_EQ(0, array->Length());
4545 CHECK(array->Get(0)->IsUndefined());
4546 CHECK(!array->Has(0));
4547 CHECK(array->Get(100)->IsUndefined());
4548 CHECK(!array->Has(100));
4549 array->Set(2, v8_num(7));
4550 CHECK_EQ(3, array->Length());
4551 CHECK(!array->Has(0));
4552 CHECK(!array->Has(1));
4553 CHECK(array->Has(2));
4554 CHECK_EQ(7, array->Get(2)->Int32Value());
4555 Local<Value> obj = CompileRun("[1, 2, 3]");
4556 Local<v8::Array> arr = obj.As<v8::Array>();
4557 CHECK_EQ(3, arr->Length());
4558 CHECK_EQ(1, arr->Get(0)->Int32Value());
4559 CHECK_EQ(2, arr->Get(1)->Int32Value());
4560 CHECK_EQ(3, arr->Get(2)->Int32Value());
4561 array = v8::Array::New(context->GetIsolate(), 27);
4562 CHECK_EQ(27, array->Length());
4563 array = v8::Array::New(context->GetIsolate(), -27);
4564 CHECK_EQ(0, array->Length());
4565 }
4566
4567
HandleF(const v8::FunctionCallbackInfo<v8::Value> & args)4568 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4569 v8::EscapableHandleScope scope(args.GetIsolate());
4570 ApiTestFuzzer::Fuzz();
4571 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4572 for (int i = 0; i < args.Length(); i++)
4573 result->Set(i, args[i]);
4574 args.GetReturnValue().Set(scope.Escape(result));
4575 }
4576
4577
THREADED_TEST(Vector)4578 THREADED_TEST(Vector) {
4579 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));
4583 LocalContext context(0, global);
4584
4585 const char* fun = "f()";
4586 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4587 CHECK_EQ(0, a0->Length());
4588
4589 const char* fun2 = "f(11)";
4590 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4591 CHECK_EQ(1, a1->Length());
4592 CHECK_EQ(11, a1->Get(0)->Int32Value());
4593
4594 const char* fun3 = "f(12, 13)";
4595 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4596 CHECK_EQ(2, a2->Length());
4597 CHECK_EQ(12, a2->Get(0)->Int32Value());
4598 CHECK_EQ(13, a2->Get(1)->Int32Value());
4599
4600 const char* fun4 = "f(14, 15, 16)";
4601 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4602 CHECK_EQ(3, a3->Length());
4603 CHECK_EQ(14, a3->Get(0)->Int32Value());
4604 CHECK_EQ(15, a3->Get(1)->Int32Value());
4605 CHECK_EQ(16, a3->Get(2)->Int32Value());
4606
4607 const char* fun5 = "f(17, 18, 19, 20)";
4608 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4609 CHECK_EQ(4, a4->Length());
4610 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());
4614 }
4615
4616
THREADED_TEST(FunctionCall)4617 THREADED_TEST(FunctionCall) {
4618 LocalContext context;
4619 v8::Isolate* isolate = context->GetIsolate();
4620 v8::HandleScope scope(isolate);
4621 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;"
4628 "}"
4629 "function ReturnThisSloppy() {"
4630 " return this;"
4631 "}"
4632 "function ReturnThisStrict() {"
4633 " 'use strict';"
4634 " return this;"
4635 "}");
4636 Local<Function> Foo =
4637 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4638 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")));
4642
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());
4650 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4651
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());
4656 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());
4658
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());
4664 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());
4667
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());
4674 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());
4678
4679 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());
4692
4693 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)));
4703 }
4704
4705
THREADED_TEST(ConstructCall)4706 THREADED_TEST(ConstructCall) {
4707 LocalContext context;
4708 v8::Isolate* isolate = context->GetIsolate();
4709 v8::HandleScope scope(isolate);
4710 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());
4728 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4729
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());
4734 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());
4736
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());
4742 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());
4745
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());
4752 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());
4756 }
4757
4758
CheckUncle(v8::TryCatch * try_catch)4759 static void CheckUncle(v8::TryCatch* try_catch) {
4760 CHECK(try_catch->HasCaught());
4761 String::Utf8Value str_value(try_catch->Exception());
4762 CHECK_EQ(*str_value, "uncle?");
4763 try_catch->Reset();
4764 }
4765
4766
THREADED_TEST(ConversionNumber)4767 THREADED_TEST(ConversionNumber) {
4768 LocalContext env;
4769 v8::HandleScope scope(env->GetIsolate());
4770 // 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
THREADED_TEST(isNumberType)4815 THREADED_TEST(isNumberType) {
4816 LocalContext env;
4817 v8::HandleScope scope(env->GetIsolate());
4818 // 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());
4853 // 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());
4863 }
4864
4865
THREADED_TEST(ConversionException)4866 THREADED_TEST(ConversionException) {
4867 LocalContext env;
4868 v8::Isolate* isolate = env->GetIsolate();
4869 v8::HandleScope scope(isolate);
4870 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
4898 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4899 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();
4912 CHECK_NE(0, std::isnan(number_value));
4913 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
ThrowFromC(const v8::FunctionCallbackInfo<v8::Value> & args)4921 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4922 ApiTestFuzzer::Fuzz();
4923 args.GetIsolate()->ThrowException(v8_str("konto"));
4924 }
4925
4926
CCatcher(const v8::FunctionCallbackInfo<v8::Value> & args)4927 void 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());
4933 v8::TryCatch try_catch;
4934 Local<Value> result = CompileRun(args[0]->ToString());
4935 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4936 args.GetReturnValue().Set(try_catch.HasCaught());
4937 }
4938
4939
THREADED_TEST(APICatch)4940 THREADED_TEST(APICatch) {
4941 v8::Isolate* isolate = CcTest::isolate();
4942 v8::HandleScope scope(isolate);
4943 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4944 templ->Set(v8_str("ThrowFromC"),
4945 v8::FunctionTemplate::New(isolate, ThrowFromC));
4946 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
THREADED_TEST(APIThrowTryCatch)4959 THREADED_TEST(APIThrowTryCatch) {
4960 v8::Isolate* isolate = CcTest::isolate();
4961 v8::HandleScope scope(isolate);
4962 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4963 templ->Set(v8_str("ThrowFromC"),
4964 v8::FunctionTemplate::New(isolate, ThrowFromC));
4965 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.
TEST(TryCatchInTryFinally)4979 TEST(TryCatchInTryFinally) {
4980 v8::Isolate* isolate = CcTest::isolate();
4981 v8::HandleScope scope(isolate);
4982 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4983 templ->Set(v8_str("CCatcher"),
4984 v8::FunctionTemplate::New(isolate, CCatcher));
4985 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
check_reference_error_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)4997 static 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
Fail(const v8::FunctionCallbackInfo<v8::Value> & args)5005 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5006 ApiTestFuzzer::Fuzz();
5007 CHECK(false);
5008 }
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.
TEST(APIThrowMessageOverwrittenToString)5014 TEST(APIThrowMessageOverwrittenToString) {
5015 v8::Isolate* isolate = CcTest::isolate();
5016 v8::HandleScope scope(isolate);
5017 v8::V8::AddMessageListener(check_reference_error_message);
5018 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5019 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5020 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'; }");
5031 CompileRun("ReferenceError.prototype.toString ="
5032 " function() { return 'Whoops' }");
5033 CompileRun("asdf;");
5034 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;");
5042 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5043 CHECK(string->Equals(v8_str("Whoops")));
5044 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;");
5049 v8::V8::RemoveMessageListeners(check_reference_error_message);
5050 }
5051
5052
check_custom_error_tostring(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)5053 static 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
TEST(CustomErrorToString)5061 TEST(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
check_custom_error_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)5079 static 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
TEST(CustomErrorMessage)5088 TEST(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);
5128 }
5129
5130
receive_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)5131 static void receive_message(v8::Handle<v8::Message> message,
5132 v8::Handle<v8::Value> data) {
5133 message->Get();
5134 message_received = true;
5135 }
5136
5137
TEST(APIThrowMessage)5138 TEST(APIThrowMessage) {
5139 message_received = false;
5140 v8::Isolate* isolate = CcTest::isolate();
5141 v8::HandleScope scope(isolate);
5142 v8::V8::AddMessageListener(receive_message);
5143 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5144 templ->Set(v8_str("ThrowFromC"),
5145 v8::FunctionTemplate::New(isolate, ThrowFromC));
5146 LocalContext context(0, templ);
5147 CompileRun("ThrowFromC();");
5148 CHECK(message_received);
5149 v8::V8::RemoveMessageListeners(receive_message);
5150 }
5151
5152
TEST(APIThrowMessageAndVerboseTryCatch)5153 TEST(APIThrowMessageAndVerboseTryCatch) {
5154 message_received = false;
5155 v8::Isolate* isolate = CcTest::isolate();
5156 v8::HandleScope scope(isolate);
5157 v8::V8::AddMessageListener(receive_message);
5158 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5159 templ->Set(v8_str("ThrowFromC"),
5160 v8::FunctionTemplate::New(isolate, ThrowFromC));
5161 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);
5168 v8::V8::RemoveMessageListeners(receive_message);
5169 }
5170
5171
TEST(APIStackOverflowAndVerboseTryCatch)5172 TEST(APIStackOverflowAndVerboseTryCatch) {
5173 message_received = false;
5174 LocalContext context;
5175 v8::HandleScope scope(context->GetIsolate());
5176 v8::V8::AddMessageListener(receive_message);
5177 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
THREADED_TEST(ExternalScriptException)5187 THREADED_TEST(ExternalScriptException) {
5188 v8::Isolate* isolate = CcTest::isolate();
5189 v8::HandleScope scope(isolate);
5190 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5191 templ->Set(v8_str("ThrowFromC"),
5192 v8::FunctionTemplate::New(isolate, ThrowFromC));
5193 LocalContext context(0, templ);
5194
5195 v8::TryCatch try_catch;
5196 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5197 CHECK(result.IsEmpty());
5198 CHECK(try_catch.HasCaught());
5199 String::Utf8Value exception_value(try_catch.Exception());
5200 CHECK_EQ("konto", *exception_value);
5201 }
5202
5203
5204
CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value> & args)5205 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5206 ApiTestFuzzer::Fuzz();
5207 CHECK_EQ(4, args.Length());
5208 int count = args[0]->Int32Value();
5209 int cInterval = args[2]->Int32Value();
5210 if (count == 0) {
5211 args.GetIsolate()->ThrowException(v8_str("FromC"));
5212 return;
5213 } else {
5214 Local<v8::Object> global =
5215 args.GetIsolate()->GetCurrentContext()->Global();
5216 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;
5223 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5224 int expected = args[3]->Int32Value();
5225 if (try_catch.HasCaught()) {
5226 CHECK_EQ(expected, count);
5227 CHECK(result.IsEmpty());
5228 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5229 } else {
5230 CHECK_NE(expected, count);
5231 }
5232 args.GetReturnValue().Set(result);
5233 return;
5234 } else {
5235 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5236 return;
5237 }
5238 }
5239 }
5240
5241
JSCheck(const v8::FunctionCallbackInfo<v8::Value> & args)5242 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5243 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 }
5253 }
5254
5255
THREADED_TEST(EvalInTryFinally)5256 THREADED_TEST(EvalInTryFinally) {
5257 LocalContext context;
5258 v8::HandleScope scope(context->GetIsolate());
5259 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.
TEST(ExceptionOrder)5291 TEST(ExceptionOrder) {
5292 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));
5296 templ->Set(v8_str("CThrowCountDown"),
5297 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5298 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
ThrowValue(const v8::FunctionCallbackInfo<v8::Value> & args)5349 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5350 ApiTestFuzzer::Fuzz();
5351 CHECK_EQ(1, args.Length());
5352 args.GetIsolate()->ThrowException(args[0]);
5353 }
5354
5355
THREADED_TEST(ThrowValues)5356 THREADED_TEST(ThrowValues) {
5357 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));
5361 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());
5373 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());
5380 }
5381
5382
THREADED_TEST(CatchZero)5383 THREADED_TEST(CatchZero) {
5384 LocalContext context;
5385 v8::HandleScope scope(context->GetIsolate());
5386 v8::TryCatch try_catch;
5387 CHECK(!try_catch.HasCaught());
5388 CompileRun("throw 10");
5389 CHECK(try_catch.HasCaught());
5390 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5391 try_catch.Reset();
5392 CHECK(!try_catch.HasCaught());
5393 CompileRun("throw 0");
5394 CHECK(try_catch.HasCaught());
5395 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5396 }
5397
5398
THREADED_TEST(CatchExceptionFromWith)5399 THREADED_TEST(CatchExceptionFromWith) {
5400 LocalContext context;
5401 v8::HandleScope scope(context->GetIsolate());
5402 v8::TryCatch try_catch;
5403 CHECK(!try_catch.HasCaught());
5404 CompileRun("var o = {}; with (o) { throw 42; }");
5405 CHECK(try_catch.HasCaught());
5406 }
5407
5408
THREADED_TEST(TryCatchAndFinallyHidingException)5409 THREADED_TEST(TryCatchAndFinallyHidingException) {
5410 LocalContext context;
5411 v8::HandleScope scope(context->GetIsolate());
5412 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
WithTryCatch(const v8::FunctionCallbackInfo<v8::Value> & args)5420 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5421 v8::TryCatch try_catch;
5422 }
5423
5424
THREADED_TEST(TryCatchAndFinally)5425 THREADED_TEST(TryCatchAndFinally) {
5426 LocalContext context;
5427 v8::Isolate* isolate = context->GetIsolate();
5428 v8::HandleScope scope(isolate);
5429 context->Global()->Set(
5430 v8_str("native_with_try_catch"),
5431 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5432 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
TryCatchNested1Helper(int depth)5444 static 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
TryCatchNested2Helper(int depth)5457 static 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
TEST(TryCatchNested)5470 TEST(TryCatchNested) {
5471 v8::V8::Initialize();
5472 LocalContext context;
5473 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
TryCatchMixedNestingCheck(v8::TryCatch * try_catch)5493 void 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
TryCatchMixedNestingHelper(const v8::FunctionCallbackInfo<v8::Value> & args)5505 void 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.
TEST(TryCatchMixedNesting)5521 TEST(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
TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value> & args)5535 void 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
TEST(TryCatchNative)5543 TEST(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
TryCatchNativeResetHelper(const v8::FunctionCallbackInfo<v8::Value> & args)5557 void 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
TEST(TryCatchNativeReset)5568 TEST(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
THREADED_TEST(Equality)5582 THREADED_TEST(Equality) {
5583 LocalContext context;
5584 v8::Isolate* isolate = context->GetIsolate();
5585 v8::HandleScope scope(context->GetIsolate());
5586 // 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
5596 // Assume String is not internalized.
5597 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)));
5602 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5603 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5604 CHECK(!not_a_number->StrictEquals(not_a_number));
5605 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5606 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5607
5608 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)));
5622 }
5623
5624
THREADED_TEST(MultiRun)5625 THREADED_TEST(MultiRun) {
5626 LocalContext context;
5627 v8::HandleScope scope(context->GetIsolate());
5628 Local<Script> script = v8_compile("x");
5629 for (int i = 0; i < 10; i++)
5630 script->Run();
5631 }
5632
5633
GetXValue(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)5634 static void GetXValue(Local<String> name,
5635 const v8::PropertyCallbackInfo<v8::Value>& info) {
5636 ApiTestFuzzer::Fuzz();
5637 CHECK_EQ(info.Data(), v8_str("donut"));
5638 CHECK_EQ(name, v8_str("x"));
5639 info.GetReturnValue().Set(name);
5640 }
5641
5642
THREADED_TEST(SimplePropertyRead)5643 THREADED_TEST(SimplePropertyRead) {
5644 LocalContext context;
5645 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"));
5649 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5650 Local<Script> script = v8_compile("obj.x");
5651 for (int i = 0; i < 10; i++) {
5652 Local<Value> result = script->Run();
5653 CHECK_EQ(result, v8_str("x"));
5654 }
5655 }
5656
5657
THREADED_TEST(DefinePropertyOnAPIAccessor)5658 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5659 LocalContext context;
5660 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"));
5664 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5665
5666 // Uses getOwnPropertyDescriptor to check the configurable status
5667 Local<Script> script_desc = v8_compile(
5668 "var prop = Object.getOwnPropertyDescriptor( "
5669 "obj, 'x');"
5670 "prop.configurable;");
5671 Local<Value> result = script_desc->Run();
5672 CHECK_EQ(result->BooleanValue(), true);
5673
5674 // Redefine get - but still configurable
5675 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");
5680 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
5688 script_define = v8_compile(
5689 "var desc = { get: function(){return 43; },"
5690 " configurable: false };"
5691 "Object.defineProperty(obj, 'x', desc);"
5692 "obj.x");
5693 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());
5702 String::Utf8Value exception_value(try_catch.Exception());
5703 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5704 }
5705
5706
THREADED_TEST(DefinePropertyOnDefineGetterSetter)5707 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5708 v8::Isolate* isolate = CcTest::isolate();
5709 v8::HandleScope scope(isolate);
5710 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5711 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5712 LocalContext context;
5713 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5714
5715 Local<Script> script_desc = v8_compile(
5716 "var prop ="
5717 "Object.getOwnPropertyDescriptor( "
5718 "obj, 'x');"
5719 "prop.configurable;");
5720 Local<Value> result = script_desc->Run();
5721 CHECK_EQ(result->BooleanValue(), true);
5722
5723 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");
5728 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
5736 script_define = v8_compile(
5737 "var desc = {get: function(){return 43; },"
5738 " configurable: false };"
5739 "Object.defineProperty(obj, 'x', desc);"
5740 "obj.x");
5741 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());
5750 String::Utf8Value exception_value(try_catch.Exception());
5751 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5752 }
5753
5754
GetGlobalProperty(LocalContext * context,char const * name)5755 static 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 }
5759
5760
THREADED_TEST(DefineAPIAccessorOnObject)5761 THREADED_TEST(DefineAPIAccessorOnObject) {
5762 v8::Isolate* isolate = CcTest::isolate();
5763 v8::HandleScope scope(isolate);
5764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5765 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
THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden)5836 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5837 v8::Isolate* isolate = CcTest::isolate();
5838 v8::HandleScope scope(isolate);
5839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840 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());
5870 String::Utf8Value exception_value(try_catch.Exception());
5871 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5872 }
5873 {
5874 v8::TryCatch try_catch;
5875 CompileRun("Object.defineProperty(obj2, 'x',"
5876 "{get: function() { return 'func'; }})");
5877 CHECK(try_catch.HasCaught());
5878 String::Utf8Value exception_value(try_catch.Exception());
5879 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5880 }
5881 }
5882
5883
Get239Value(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)5884 static void Get239Value(Local<String> name,
5885 const v8::PropertyCallbackInfo<v8::Value>& info) {
5886 ApiTestFuzzer::Fuzz();
5887 CHECK_EQ(info.Data(), v8_str("donut"));
5888 CHECK_EQ(name, v8_str("239"));
5889 info.GetReturnValue().Set(name);
5890 }
5891
5892
THREADED_TEST(ElementAPIAccessor)5893 THREADED_TEST(ElementAPIAccessor) {
5894 v8::Isolate* isolate = CcTest::isolate();
5895 v8::HandleScope scope(isolate);
5896 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5897 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
5917
5918 v8::Persistent<Value> xValue;
5919
5920
SetXValue(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)5921 static void SetXValue(Local<String> name,
5922 Local<Value> value,
5923 const v8::PropertyCallbackInfo<void>& info) {
5924 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());
5928 xValue.Reset(info.GetIsolate(), value);
5929 }
5930
5931
THREADED_TEST(SimplePropertyWrite)5932 THREADED_TEST(SimplePropertyWrite) {
5933 v8::Isolate* isolate = CcTest::isolate();
5934 v8::HandleScope scope(isolate);
5935 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5936 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5937 LocalContext context;
5938 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5939 Local<Script> script = v8_compile("obj.x = 4");
5940 for (int i = 0; i < 10; i++) {
5941 CHECK(xValue.IsEmpty());
5942 script->Run();
5943 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5944 xValue.Reset();
5945 }
5946 }
5947
5948
THREADED_TEST(SetterOnly)5949 THREADED_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
THREADED_TEST(NoAccessors)5966 THREADED_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
XPropertyGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)5983 static void XPropertyGetter(Local<String> property,
5984 const v8::PropertyCallbackInfo<v8::Value>& info) {
5985 ApiTestFuzzer::Fuzz();
5986 CHECK(info.Data()->IsUndefined());
5987 info.GetReturnValue().Set(property);
5988 }
5989
5990
THREADED_TEST(NamedInterceptorPropertyRead)5991 THREADED_TEST(NamedInterceptorPropertyRead) {
5992 v8::Isolate* isolate = CcTest::isolate();
5993 v8::HandleScope scope(isolate);
5994 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5995 templ->SetNamedPropertyHandler(XPropertyGetter);
5996 LocalContext context;
5997 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5998 Local<Script> script = v8_compile("obj.x");
5999 for (int i = 0; i < 10; i++) {
6000 Local<Value> result = script->Run();
6001 CHECK_EQ(result, v8_str("x"));
6002 }
6003 }
6004
6005
THREADED_TEST(NamedInterceptorDictionaryIC)6006 THREADED_TEST(NamedInterceptorDictionaryIC) {
6007 v8::Isolate* isolate = CcTest::isolate();
6008 v8::HandleScope scope(isolate);
6009 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6010 templ->SetNamedPropertyHandler(XPropertyGetter);
6011 LocalContext context;
6012 // Create an object with a named interceptor.
6013 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6014 Local<Script> script = v8_compile("interceptor_obj.x");
6015 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
THREADED_TEST(NamedInterceptorDictionaryICMultipleContext)6037 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6038 v8::Isolate* isolate = CcTest::isolate();
6039 v8::HandleScope scope(isolate);
6040 v8::Local<Context> context1 = Context::New(isolate);
6041
6042 context1->Enter();
6043 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6044 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();
6075 }
6076
6077
SetXOnPrototypeGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)6078 static void SetXOnPrototypeGetter(
6079 Local<String> property,
6080 const v8::PropertyCallbackInfo<v8::Value>& info) {
6081 // Set x on the prototype object and do not handle the get request.
6082 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6083 proto.As<v8::Object>()->Set(v8_str("x"),
6084 v8::Integer::New(info.GetIsolate(), 23));
6085 }
6086
6087
6088 // This is a regression test for http://crbug.com/20104. Map
6089 // transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead)6090 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6091 v8::Isolate* isolate = CcTest::isolate();
6092 v8::HandleScope scope(isolate);
6093 Local<v8::FunctionTemplate> function_template =
6094 v8::FunctionTemplate::New(isolate);
6095 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
IndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)6108 static void IndexedPropertyGetter(
6109 uint32_t index,
6110 const v8::PropertyCallbackInfo<v8::Value>& info) {
6111 ApiTestFuzzer::Fuzz();
6112 if (index == 37) {
6113 info.GetReturnValue().Set(v8_num(625));
6114 }
6115 }
6116
6117
IndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)6118 static void IndexedPropertySetter(
6119 uint32_t index,
6120 Local<Value> value,
6121 const v8::PropertyCallbackInfo<v8::Value>& info) {
6122 ApiTestFuzzer::Fuzz();
6123 if (index == 39) {
6124 info.GetReturnValue().Set(value);
6125 }
6126 }
6127
6128
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)6129 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6130 v8::Isolate* isolate = CcTest::isolate();
6131 v8::HandleScope scope(isolate);
6132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6133 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6134 IndexedPropertySetter);
6135 LocalContext context;
6136 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6137 Local<Script> getter_script = v8_compile(
6138 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6139 Local<Script> setter_script = v8_compile(
6140 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6141 "obj[17] = 23;"
6142 "obj.foo;");
6143 Local<Script> interceptor_setter_script = v8_compile(
6144 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6145 "obj[39] = 47;"
6146 "obj.foo;"); // This setter should not run, due to the interceptor.
6147 Local<Script> interceptor_getter_script = v8_compile(
6148 "obj[37];");
6149 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
UnboxedDoubleIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)6160 static void UnboxedDoubleIndexedPropertyGetter(
6161 uint32_t index,
6162 const v8::PropertyCallbackInfo<v8::Value>& info) {
6163 ApiTestFuzzer::Fuzz();
6164 if (index < 25) {
6165 info.GetReturnValue().Set(v8_num(index));
6166 }
6167 }
6168
6169
UnboxedDoubleIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)6170 static void UnboxedDoubleIndexedPropertySetter(
6171 uint32_t index,
6172 Local<Value> value,
6173 const v8::PropertyCallbackInfo<v8::Value>& info) {
6174 ApiTestFuzzer::Fuzz();
6175 if (index < 25) {
6176 info.GetReturnValue().Set(v8_num(index));
6177 }
6178 }
6179
6180
UnboxedDoubleIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)6181 void UnboxedDoubleIndexedPropertyEnumerator(
6182 const v8::PropertyCallbackInfo<v8::Array>& info) {
6183 // Force the list of returned keys to be stored in a FastDoubleArray.
6184 Local<Script> indexed_property_names_script = v8_compile(
6185 "keys = new Array(); keys[125000] = 1;"
6186 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6187 "keys.length = 25; keys;");
6188 Local<Value> result = indexed_property_names_script->Run();
6189 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6190 }
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.
THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor)6195 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6196 v8::Isolate* isolate = CcTest::isolate();
6197 v8::HandleScope scope(isolate);
6198 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6199 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.
6207 Local<Script> create_unboxed_double_script = v8_compile(
6208 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6209 "key_count = 0; "
6210 "for (x in obj) {key_count++;};"
6211 "obj;");
6212 Local<Value> result = create_unboxed_double_script->Run();
6213 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6214 Local<Script> key_count_check = v8_compile("key_count;");
6215 result = key_count_check->Run();
6216 CHECK_EQ(v8_num(40013), result);
6217 }
6218
6219
SloppyArgsIndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)6220 void SloppyArgsIndexedPropertyEnumerator(
6221 const v8::PropertyCallbackInfo<v8::Array>& info) {
6222 // Force the list of returned keys to be stored in a Arguments object.
6223 Local<Script> indexed_property_names_script = v8_compile(
6224 "function f(w,x) {"
6225 " return arguments;"
6226 "}"
6227 "keys = f(0, 1, 2, 3);"
6228 "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));
6236 }
6237
6238
SloppyIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)6239 static void SloppyIndexedPropertyGetter(
6240 uint32_t index,
6241 const v8::PropertyCallbackInfo<v8::Value>& info) {
6242 ApiTestFuzzer::Fuzz();
6243 if (index < 4) {
6244 info.GetReturnValue().Set(v8_num(index));
6245 }
6246 }
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.
THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor)6251 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6252 v8::Isolate* isolate = CcTest::isolate();
6253 v8::HandleScope scope(isolate);
6254 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6255 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6256 0,
6257 0,
6258 0,
6259 SloppyArgsIndexedPropertyEnumerator);
6260 LocalContext context;
6261 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6262 Local<Script> create_args_script = v8_compile(
6263 "var key_count = 0;"
6264 "for (x in obj) {key_count++;} key_count;");
6265 Local<Value> result = create_args_script->Run();
6266 CHECK_EQ(v8_num(4), result);
6267 }
6268
6269
IdentityIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)6270 static void IdentityIndexedPropertyGetter(
6271 uint32_t index,
6272 const v8::PropertyCallbackInfo<v8::Value>& info) {
6273 info.GetReturnValue().Set(index);
6274 }
6275
6276
THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor)6277 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6278 v8::Isolate* isolate = CcTest::isolate();
6279 v8::HandleScope scope(isolate);
6280 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6281 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
THREADED_TEST(IndexedInterceptorWithNoSetter)6299 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6300 v8::Isolate* isolate = CcTest::isolate();
6301 v8::HandleScope scope(isolate);
6302 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6303 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
THREADED_TEST(IndexedInterceptorWithAccessorCheck)6323 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6324 v8::Isolate* isolate = CcTest::isolate();
6325 v8::HandleScope scope(isolate);
6326 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6327 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 =
6335 "var result = 'PASSED';"
6336 "for (var i = 0; i < 100; i++) {"
6337 " try {"
6338 " var v = obj[0];"
6339 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6340 " break;"
6341 " } catch (e) {"
6342 " /* pass */"
6343 " }"
6344 "}"
6345 "result";
6346 ExpectString(code, "PASSED");
6347 }
6348
6349
THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn)6350 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6351 i::FLAG_allow_natives_syntax = true;
6352 v8::Isolate* isolate = CcTest::isolate();
6353 v8::HandleScope scope(isolate);
6354 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6355 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 =
6362 "var result = 'PASSED';"
6363 "for (var i = 0; i < 100; i++) {"
6364 " var expected = i;"
6365 " if (i == 5) {"
6366 " %EnableAccessChecks(obj);"
6367 " }"
6368 " 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";
6385 ExpectString(code, "PASSED");
6386 }
6387
6388
THREADED_TEST(IndexedInterceptorWithDifferentIndices)6389 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6390 v8::Isolate* isolate = CcTest::isolate();
6391 v8::HandleScope scope(isolate);
6392 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6393 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
THREADED_TEST(IndexedInterceptorWithNegativeIndices)6413 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6414 v8::Isolate* isolate = CcTest::isolate();
6415 v8::HandleScope scope(isolate);
6416 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6417 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
THREADED_TEST(IndexedInterceptorWithNotSmiLookup)6453 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6454 v8::Isolate* isolate = CcTest::isolate();
6455 v8::HandleScope scope(isolate);
6456 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6457 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;"
6467 " var key = i;"
6468 " if (i == 50) {"
6469 " key = 'foobar';"
6470 " expected = undefined;"
6471 " }"
6472 " var v = obj[key];"
6473 " 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
THREADED_TEST(IndexedInterceptorGoingMegamorphic)6483 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6484 v8::Isolate* isolate = CcTest::isolate();
6485 v8::HandleScope scope(isolate);
6486 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6487 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
THREADED_TEST(IndexedInterceptorReceiverTurningSmi)6514 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6515 v8::Isolate* isolate = CcTest::isolate();
6516 v8::HandleScope scope(isolate);
6517 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6518 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
THREADED_TEST(IndexedInterceptorOnProto)6545 THREADED_TEST(IndexedInterceptorOnProto) {
6546 v8::Isolate* isolate = CcTest::isolate();
6547 v8::HandleScope scope(isolate);
6548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6549 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
THREADED_TEST(MultiContexts)6570 THREADED_TEST(MultiContexts) {
6571 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));
6576
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
THREADED_TEST(FunctionPrototypeAcrossContexts)6605 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6606 // Make sure that functions created by cloning boilerplates cannot
6607 // communicate through their __proto__ field.
6608
6609 v8::HandleScope scope(CcTest::isolate());
6610
6611 LocalContext env0;
6612 v8::Handle<v8::Object> global0 =
6613 env0->Global();
6614 v8::Handle<v8::Object> object0 =
6615 global0->Get(v8_str("Object")).As<v8::Object>();
6616 v8::Handle<v8::Object> tostring0 =
6617 object0->Get(v8_str("toString")).As<v8::Object>();
6618 v8::Handle<v8::Object> proto0 =
6619 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6620 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 =
6626 global1->Get(v8_str("Object")).As<v8::Object>();
6627 v8::Handle<v8::Object> tostring1 =
6628 object1->Get(v8_str("toString")).As<v8::Object>();
6629 v8::Handle<v8::Object> proto1 =
6630 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6631 CHECK(!proto1->Has(v8_str("custom")));
6632 }
6633
6634
THREADED_TEST(Regress892105)6635 THREADED_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
6642 v8::HandleScope scope(CcTest::isolate());
6643
6644 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6645 "Array.prototype.arr = 4567;"
6646 "8901");
6647
6648 LocalContext env0;
6649 Local<Script> script0 = v8_compile(source);
6650 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6651
6652 LocalContext env1;
6653 Local<Script> script1 = v8_compile(source);
6654 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6655 }
6656
6657
THREADED_TEST(UndetectableObject)6658 THREADED_TEST(UndetectableObject) {
6659 LocalContext env;
6660 v8::HandleScope scope(env->GetIsolate());
6661
6662 Local<v8::FunctionTemplate> desc =
6663 v8::FunctionTemplate::New(env->GetIsolate());
6664 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
THREADED_TEST(VoidLiteral)6702 THREADED_TEST(VoidLiteral) {
6703 LocalContext env;
6704 v8::Isolate* isolate = env->GetIsolate();
6705 v8::HandleScope scope(isolate);
6706
6707 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6708 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
6745
THREADED_TEST(ExtensibleOnUndetectable)6746 THREADED_TEST(ExtensibleOnUndetectable) {
6747 LocalContext env;
6748 v8::Isolate* isolate = env->GetIsolate();
6749 v8::HandleScope scope(isolate);
6750
6751 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6752 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
6760 Local<Script> script = v8_compile(source);
6761
6762 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6763
6764 ExpectBoolean("Object.isExtensible(undetectable)", true);
6765
6766 source = v8_str("Object.preventExtensions(undetectable);");
6767 script = v8_compile(source);
6768 script->Run();
6769 ExpectBoolean("Object.isExtensible(undetectable)", false);
6770
6771 source = v8_str("undetectable.y = 2000;");
6772 script = v8_compile(source);
6773 script->Run();
6774 ExpectBoolean("undetectable.y == undefined", true);
6775 }
6776
6777
6778
THREADED_TEST(UndetectableString)6779 THREADED_TEST(UndetectableString) {
6780 LocalContext env;
6781 v8::HandleScope scope(env->GetIsolate());
6782
6783 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6784 String::kUndetectableString);
6785 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
TEST(UndetectableOptimized)6820 TEST(UndetectableOptimized) {
6821 i::FLAG_allow_natives_syntax = true;
6822 LocalContext env;
6823 v8::HandleScope scope(env->GetIsolate());
6824
6825 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6826 String::kUndetectableString);
6827 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
6853 // The point of this test is type checking. We run it only so compilers
6854 // don't complain about an unused function.
TEST(PersistentHandles)6855 TEST(PersistentHandles) {
6856 LocalContext env;
6857 v8::Isolate* isolate = CcTest::isolate();
6858 v8::HandleScope scope(isolate);
6859 Local<String> str = v8_str("foo");
6860 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();
6868 }
6869
6870
HandleLogDelegator(const v8::FunctionCallbackInfo<v8::Value> & args)6871 static void HandleLogDelegator(
6872 const v8::FunctionCallbackInfo<v8::Value>& args) {
6873 ApiTestFuzzer::Fuzz();
6874 }
6875
6876
THREADED_TEST(GlobalObjectTemplate)6877 THREADED_TEST(GlobalObjectTemplate) {
6878 v8::Isolate* isolate = CcTest::isolate();
6879 v8::HandleScope handle_scope(isolate);
6880 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6881 global_template->Set(v8_str("JSNI_Log"),
6882 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6883 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6884 Context::Scope context_scope(context);
6885 CompileRun("JSNI_Log('LOG')");
6886 }
6887
6888
6889 static const char* kSimpleExtensionSource =
6890 "function Foo() {"
6891 " return 4;"
6892 "}";
6893
6894
TEST(SimpleExtensions)6895 TEST(SimpleExtensions) {
6896 v8::HandleScope handle_scope(CcTest::isolate());
6897 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6898 const char* extension_names[] = { "simpletest" };
6899 v8::ExtensionConfiguration extensions(1, extension_names);
6900 v8::Handle<Context> context =
6901 Context::New(CcTest::isolate(), &extensions);
6902 Context::Scope lock(context);
6903 v8::Handle<Value> result = CompileRun("Foo()");
6904 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6905 }
6906
6907
6908 static const char* kStackTraceFromExtensionSource =
6909 "function foo() {"
6910 " throw new Error();"
6911 "}"
6912 "function bar() {"
6913 " foo();"
6914 "}";
6915
6916
TEST(StackTraceInExtension)6917 TEST(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
TEST(NullExtensions)6935 TEST(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));
6945 }
6946
6947
6948 static const char* kEmbeddedExtensionSource =
6949 "function Ret54321(){return 54321;}~~@@$"
6950 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6951 static const int kEmbeddedExtensionSourceValidLen = 34;
6952
6953
TEST(ExtensionMissingSourceLength)6954 TEST(ExtensionMissingSourceLength) {
6955 v8::HandleScope handle_scope(CcTest::isolate());
6956 v8::RegisterExtension(new Extension("srclentest_fail",
6957 kEmbeddedExtensionSource));
6958 const char* extension_names[] = { "srclentest_fail" };
6959 v8::ExtensionConfiguration extensions(1, extension_names);
6960 v8::Handle<Context> context =
6961 Context::New(CcTest::isolate(), &extensions);
6962 CHECK_EQ(0, *context);
6963 }
6964
6965
TEST(ExtensionWithSourceLength)6966 TEST(ExtensionWithSourceLength) {
6967 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6968 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6969 v8::HandleScope handle_scope(CcTest::isolate());
6970 i::ScopedVector<char> extension_name(32);
6971 i::SNPrintF(extension_name, "ext #%d", source_len);
6972 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);
6977 v8::Handle<Context> context =
6978 Context::New(CcTest::isolate(), &extensions);
6979 if (source_len == kEmbeddedExtensionSourceValidLen) {
6980 Context::Scope lock(context);
6981 v8::Handle<Value> result = CompileRun("Ret54321()");
6982 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6983 } else {
6984 // Anything but exactly the right length should fail to compile.
6985 CHECK_EQ(0, *context);
6986 }
6987 }
6988 }
6989
6990
6991 static const char* kEvalExtensionSource1 =
6992 "function UseEval1() {"
6993 " var x = 42;"
6994 " return eval('x');"
6995 "}";
6996
6997
6998 static const char* kEvalExtensionSource2 =
6999 "(function() {"
7000 " var x = 42;"
7001 " function e() {"
7002 " return eval('x');"
7003 " }"
7004 " this.UseEval2 = e;"
7005 "})()";
7006
7007
TEST(UseEvalFromExtension)7008 TEST(UseEvalFromExtension) {
7009 v8::HandleScope handle_scope(CcTest::isolate());
7010 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);
7014 v8::Handle<Context> context =
7015 Context::New(CcTest::isolate(), &extensions);
7016 Context::Scope lock(context);
7017 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));
7021 }
7022
7023
7024 static const char* kWithExtensionSource1 =
7025 "function UseWith1() {"
7026 " var x = 42;"
7027 " with({x:87}) { return x; }"
7028 "}";
7029
7030
7031
7032 static 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
TEST(UseWithFromExtension)7042 TEST(UseWithFromExtension) {
7043 v8::HandleScope handle_scope(CcTest::isolate());
7044 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);
7048 v8::Handle<Context> context =
7049 Context::New(CcTest::isolate(), &extensions);
7050 Context::Scope lock(context);
7051 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));
7055 }
7056
7057
TEST(AutoExtensions)7058 TEST(AutoExtensions) {
7059 v8::HandleScope handle_scope(CcTest::isolate());
7060 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7061 extension->set_auto_enable(true);
7062 v8::RegisterExtension(extension);
7063 v8::Handle<Context> context =
7064 Context::New(CcTest::isolate());
7065 Context::Scope lock(context);
7066 v8::Handle<Value> result = CompileRun("Foo()");
7067 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7068 }
7069
7070
7071 static 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.
TEST(SyntaxErrorExtensions)7077 TEST(SyntaxErrorExtensions) {
7078 v8::HandleScope handle_scope(CcTest::isolate());
7079 v8::RegisterExtension(new Extension("syntaxerror",
7080 kSyntaxErrorInExtensionSource));
7081 const char* extension_names[] = { "syntaxerror" };
7082 v8::ExtensionConfiguration extensions(1, extension_names);
7083 v8::Handle<Context> context =
7084 Context::New(CcTest::isolate(), &extensions);
7085 CHECK(context.IsEmpty());
7086 }
7087
7088
7089 static 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.
TEST(ExceptionExtensions)7095 TEST(ExceptionExtensions) {
7096 v8::HandleScope handle_scope(CcTest::isolate());
7097 v8::RegisterExtension(new Extension("exception",
7098 kExceptionInExtensionSource));
7099 const char* extension_names[] = { "exception" };
7100 v8::ExtensionConfiguration extensions(1, extension_names);
7101 v8::Handle<Context> context =
7102 Context::New(CcTest::isolate(), &extensions);
7103 CHECK(context.IsEmpty());
7104 }
7105
7106
7107 static const char* kNativeCallInExtensionSource =
7108 "function call_runtime_last_index_of(x) {"
7109 " return %StringLastIndexOf(x, 'bob', 10);"
7110 "}";
7111
7112
7113 static const char* kNativeCallTest =
7114 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7115
7116 // Test that a native runtime calls are supported in extensions.
TEST(NativeCallInExtensions)7117 TEST(NativeCallInExtensions) {
7118 v8::HandleScope handle_scope(CcTest::isolate());
7119 v8::RegisterExtension(new Extension("nativecall",
7120 kNativeCallInExtensionSource));
7121 const char* extension_names[] = { "nativecall" };
7122 v8::ExtensionConfiguration extensions(1, extension_names);
7123 v8::Handle<Context> context =
7124 Context::New(CcTest::isolate(), &extensions);
7125 Context::Scope lock(context);
7126 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7127 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7128 }
7129
7130
7131 class NativeFunctionExtension : public Extension {
7132 public:
NativeFunctionExtension(const char * name,const char * source,v8::FunctionCallback fun=& Echo)7133 NativeFunctionExtension(const char* name,
7134 const char* source,
7135 v8::FunctionCallback fun = &Echo)
7136 : Extension(name, source),
7137 function_(fun) { }
7138
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Handle<v8::String> name)7139 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7140 v8::Isolate* isolate,
7141 v8::Handle<v8::String> name) {
7142 return v8::FunctionTemplate::New(isolate, function_);
7143 }
7144
Echo(const v8::FunctionCallbackInfo<v8::Value> & args)7145 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7146 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7147 }
7148 private:
7149 v8::FunctionCallback function_;
7150 };
7151
7152
TEST(NativeFunctionDeclaration)7153 TEST(NativeFunctionDeclaration) {
7154 v8::HandleScope handle_scope(CcTest::isolate());
7155 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);
7160 v8::Handle<Context> context =
7161 Context::New(CcTest::isolate(), &extensions);
7162 Context::Scope lock(context);
7163 v8::Handle<Value> result = CompileRun("foo(42);");
7164 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7165 }
7166
7167
TEST(NativeFunctionDeclarationError)7168 TEST(NativeFunctionDeclarationError) {
7169 v8::HandleScope handle_scope(CcTest::isolate());
7170 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);
7176 v8::Handle<Context> context =
7177 Context::New(CcTest::isolate(), &extensions);
7178 CHECK(context.IsEmpty());
7179 }
7180
7181
TEST(NativeFunctionDeclarationErrorEscape)7182 TEST(NativeFunctionDeclarationErrorEscape) {
7183 v8::HandleScope handle_scope(CcTest::isolate());
7184 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);
7192 v8::Handle<Context> context =
7193 Context::New(CcTest::isolate(), &extensions);
7194 CHECK(context.IsEmpty());
7195 }
7196
7197
CheckDependencies(const char * name,const char * expected)7198 static void CheckDependencies(const char* name, const char* expected) {
7199 v8::HandleScope handle_scope(CcTest::isolate());
7200 v8::ExtensionConfiguration config(1, &name);
7201 LocalContext context(&config);
7202 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7203 context->Global()->Get(v8_str("loaded")));
7204 }
7205
7206
7207 /*
7208 * Configuration:
7209 *
7210 * /-- B <--\
7211 * A <- -- D <-- E
7212 * \-- C <--/
7213 */
THREADED_TEST(ExtensionDependency)7214 THREADED_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");
7228 v8::HandleScope handle_scope(CcTest::isolate());
7229 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
7236 static 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
CallFun(const v8::FunctionCallbackInfo<v8::Value> & args)7247 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7248 ApiTestFuzzer::Fuzz();
7249 if (args.IsConstructCall()) {
7250 args.This()->Set(v8_str("data"), args.Data());
7251 args.GetReturnValue().SetNull();
7252 return;
7253 }
7254 args.GetReturnValue().Set(args.Data());
7255 }
7256
7257
7258 class FunctionExtension : public Extension {
7259 public:
FunctionExtension()7260 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7261 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7262 v8::Isolate* isolate,
7263 v8::Handle<String> name);
7264 };
7265
7266
7267 static int lookup_count = 0;
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Handle<String> name)7268 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7269 v8::Isolate* isolate, v8::Handle<String> name) {
7270 lookup_count++;
7271 if (name->Equals(v8_str("A"))) {
7272 return v8::FunctionTemplate::New(
7273 isolate, CallFun, v8::Integer::New(isolate, 8));
7274 } else if (name->Equals(v8_str("B"))) {
7275 return v8::FunctionTemplate::New(
7276 isolate, CallFun, v8::Integer::New(isolate, 7));
7277 } else if (name->Equals(v8_str("C"))) {
7278 return v8::FunctionTemplate::New(
7279 isolate, CallFun, v8::Integer::New(isolate, 6));
7280 } else {
7281 return v8::Handle<v8::FunctionTemplate>();
7282 }
7283 }
7284
7285
THREADED_TEST(FunctionLookup)7286 THREADED_TEST(FunctionLookup) {
7287 v8::RegisterExtension(new FunctionExtension());
7288 v8::HandleScope handle_scope(CcTest::isolate());
7289 static const char* exts[1] = { "functiontest" };
7290 v8::ExtensionConfiguration config(1, exts);
7291 LocalContext context(&config);
7292 CHECK_EQ(3, lookup_count);
7293 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)"));
7299 }
7300
7301
THREADED_TEST(NativeFunctionConstructCall)7302 THREADED_TEST(NativeFunctionConstructCall) {
7303 v8::RegisterExtension(new FunctionExtension());
7304 v8::HandleScope handle_scope(CcTest::isolate());
7305 static const char* exts[1] = { "functiontest" };
7306 v8::ExtensionConfiguration config(1, exts);
7307 LocalContext context(&config);
7308 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.
7311 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"));
7317 }
7318 }
7319
7320
7321 static const char* last_location;
7322 static const char* last_message;
StoringErrorCallback(const char * location,const char * message)7323 void 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.
TEST(ErrorReporting)7334 TEST(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);
7342 v8::Handle<Context> context =
7343 Context::New(CcTest::isolate(), &config);
7344 CHECK(context.IsEmpty());
7345 CHECK_NE(last_location, NULL);
7346 }
7347
7348
MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,v8::Handle<Value> data)7349 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7350 v8::Handle<Value> data) {
7351 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7352 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7353 message->GetScriptOrigin().ResourceName());
7354 message->GetLineNumber();
7355 message->GetSourceLine();
7356 }
7357
7358
THREADED_TEST(ErrorWithMissingScriptInfo)7359 THREADED_TEST(ErrorWithMissingScriptInfo) {
7360 LocalContext context;
7361 v8::HandleScope scope(context->GetIsolate());
7362 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7363 CompileRun("throw Error()");
7364 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7365 }
7366
7367
7368 struct FlagAndPersistent {
7369 bool flag;
7370 v8::Persistent<v8::Object> handle;
7371 };
7372
7373
DisposeAndSetFlag(const v8::WeakCallbackData<v8::Object,FlagAndPersistent> & data)7374 static void DisposeAndSetFlag(
7375 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7376 data.GetParameter()->handle.Reset();
7377 data.GetParameter()->flag = true;
7378 }
7379
7380
THREADED_TEST(IndependentWeakHandle)7381 THREADED_TEST(IndependentWeakHandle) {
7382 v8::Isolate* iso = CcTest::isolate();
7383 v8::HandleScope scope(iso);
7384 v8::Handle<Context> context = Context::New(iso);
7385 Context::Scope context_scope(context);
7386
7387 FlagAndPersistent object_a, object_b;
7388
7389 {
7390 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));
7393 }
7394
7395 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);
7406 }
7407
7408
InvokeScavenge()7409 static void InvokeScavenge() {
7410 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7411 }
7412
7413
InvokeMarkSweep()7414 static void InvokeMarkSweep() {
7415 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7416 }
7417
7418
ForceScavenge(const v8::WeakCallbackData<v8::Object,FlagAndPersistent> & data)7419 static void ForceScavenge(
7420 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7421 data.GetParameter()->handle.Reset();
7422 data.GetParameter()->flag = true;
7423 InvokeScavenge();
7424 }
7425
7426
ForceMarkSweep(const v8::WeakCallbackData<v8::Object,FlagAndPersistent> & data)7427 static void ForceMarkSweep(
7428 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7429 data.GetParameter()->handle.Reset();
7430 data.GetParameter()->flag = true;
7431 InvokeMarkSweep();
7432 }
7433
7434
THREADED_TEST(GCFromWeakCallbacks)7435 THREADED_TEST(GCFromWeakCallbacks) {
7436 v8::Isolate* isolate = CcTest::isolate();
7437 v8::HandleScope scope(isolate);
7438 v8::Handle<Context> context = Context::New(isolate);
7439 Context::Scope context_scope(context);
7440
7441 static const int kNumberOfGCTypes = 2;
7442 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7443 Callback;
7444 Callback gc_forcing_callback[kNumberOfGCTypes] =
7445 {&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++) {
7452 FlagAndPersistent object;
7453 {
7454 v8::HandleScope handle_scope(isolate);
7455 object.handle.Reset(isolate, v8::Object::New(isolate));
7456 }
7457 object.flag = false;
7458 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7459 object.handle.MarkIndependent();
7460 invoke_gc[outer_gc]();
7461 CHECK(object.flag);
7462 }
7463 }
7464 }
7465
7466
RevivingCallback(const v8::WeakCallbackData<v8::Object,FlagAndPersistent> & data)7467 static void RevivingCallback(
7468 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7469 data.GetParameter()->handle.ClearWeak();
7470 data.GetParameter()->flag = true;
7471 }
7472
7473
THREADED_TEST(IndependentHandleRevival)7474 THREADED_TEST(IndependentHandleRevival) {
7475 v8::Isolate* isolate = CcTest::isolate();
7476 v8::HandleScope scope(isolate);
7477 v8::Handle<Context> context = Context::New(isolate);
7478 Context::Scope context_scope(context);
7479
7480 FlagAndPersistent object;
7481 {
7482 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));
7486 v8::Local<String> y_str = v8_str("y");
7487 o->Set(y_str, y_str);
7488 }
7489 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);
7495 {
7496 v8::HandleScope handle_scope(isolate);
7497 v8::Local<v8::Object> o =
7498 v8::Local<v8::Object>::New(isolate, object.handle);
7499 v8::Local<String> y_str = v8_str("y");
7500 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7501 CHECK(o->Get(y_str)->Equals(y_str));
7502 }
7503 }
7504
7505
7506 v8::Handle<Function> args_fun;
7507
7508
ArgumentsTestCallback(const v8::FunctionCallbackInfo<v8::Value> & args)7509 static void ArgumentsTestCallback(
7510 const v8::FunctionCallbackInfo<v8::Value>& args) {
7511 ApiTestFuzzer::Fuzz();
7512 v8::Isolate* isolate = args.GetIsolate();
7513 CHECK_EQ(args_fun, args.Callee());
7514 CHECK_EQ(3, args.Length());
7515 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);
7521 }
7522
7523
THREADED_TEST(Arguments)7524 THREADED_TEST(Arguments) {
7525 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));
7530 LocalContext context(NULL, global);
7531 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7532 v8_compile("f(1, 2, 3)")->Run();
7533 }
7534
7535
NoBlockGetterX(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> &)7536 static void NoBlockGetterX(Local<String> name,
7537 const v8::PropertyCallbackInfo<v8::Value>&) {
7538 }
7539
7540
NoBlockGetterI(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> &)7541 static void NoBlockGetterI(uint32_t index,
7542 const v8::PropertyCallbackInfo<v8::Value>&) {
7543 }
7544
7545
PDeleter(Local<String> name,const v8::PropertyCallbackInfo<v8::Boolean> & info)7546 static void PDeleter(Local<String> name,
7547 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7548 if (!name->Equals(v8_str("foo"))) {
7549 return; // not intercepted
7550 }
7551
7552 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7553 }
7554
7555
IDeleter(uint32_t index,const v8::PropertyCallbackInfo<v8::Boolean> & info)7556 static void IDeleter(uint32_t index,
7557 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7558 if (index != 2) {
7559 return; // not intercepted
7560 }
7561
7562 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7563 }
7564
7565
THREADED_TEST(Deleter)7566 THREADED_TEST(Deleter) {
7567 v8::Isolate* isolate = CcTest::isolate();
7568 v8::HandleScope scope(isolate);
7569 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7570 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
GetK(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)7593 static void GetK(Local<String> name,
7594 const v8::PropertyCallbackInfo<v8::Value>& info) {
7595 ApiTestFuzzer::Fuzz();
7596 if (name->Equals(v8_str("foo")) ||
7597 name->Equals(v8_str("bar")) ||
7598 name->Equals(v8_str("baz"))) {
7599 info.GetReturnValue().SetUndefined();
7600 }
7601 }
7602
7603
IndexedGetK(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)7604 static void IndexedGetK(uint32_t index,
7605 const v8::PropertyCallbackInfo<v8::Value>& info) {
7606 ApiTestFuzzer::Fuzz();
7607 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7608 }
7609
7610
NamedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)7611 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7612 ApiTestFuzzer::Fuzz();
7613 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);
7618 }
7619
7620
IndexedEnum(const v8::PropertyCallbackInfo<v8::Array> & info)7621 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7622 ApiTestFuzzer::Fuzz();
7623 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);
7627 }
7628
7629
THREADED_TEST(Enumerators)7630 THREADED_TEST(Enumerators) {
7631 v8::Isolate* isolate = CcTest::isolate();
7632 v8::HandleScope scope(isolate);
7633 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7634 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.
7664 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)));
7668 // Indexed interceptor properties in the order they are returned
7669 // from the enumerator interceptor.
7670 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)));
7672 // Named properties in insertion order.
7673 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)));
7681 // Named interceptor properties.
7682 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)));
7685 }
7686
7687
7688 int p_getter_count;
7689 int p_getter_count2;
7690
7691
PGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)7692 static void PGetter(Local<String> name,
7693 const v8::PropertyCallbackInfo<v8::Value>& info) {
7694 ApiTestFuzzer::Fuzz();
7695 p_getter_count++;
7696 v8::Handle<v8::Object> global =
7697 info.GetIsolate()->GetCurrentContext()->Global();
7698 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 }
7708 }
7709
7710
RunHolderTest(v8::Handle<v8::ObjectTemplate> obj)7711 static 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
PGetter2(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)7727 static void PGetter2(Local<String> name,
7728 const v8::PropertyCallbackInfo<v8::Value>& info) {
7729 ApiTestFuzzer::Fuzz();
7730 p_getter_count2++;
7731 v8::Handle<v8::Object> global =
7732 info.GetIsolate()->GetCurrentContext()->Global();
7733 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 }
7743 }
7744
7745
THREADED_TEST(GetterHolders)7746 THREADED_TEST(GetterHolders) {
7747 v8::Isolate* isolate = CcTest::isolate();
7748 v8::HandleScope scope(isolate);
7749 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7750 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
THREADED_TEST(PreInterceptorHolders)7760 THREADED_TEST(PreInterceptorHolders) {
7761 v8::Isolate* isolate = CcTest::isolate();
7762 v8::HandleScope scope(isolate);
7763 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7764 obj->SetNamedPropertyHandler(PGetter2);
7765 p_getter_count2 = 0;
7766 RunHolderTest(obj);
7767 CHECK_EQ(40, p_getter_count2);
7768 }
7769
7770
THREADED_TEST(ObjectInstantiation)7771 THREADED_TEST(ObjectInstantiation) {
7772 v8::Isolate* isolate = CcTest::isolate();
7773 v8::HandleScope scope(isolate);
7774 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7775 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++) {
7779 v8::HandleScope inner_scope(CcTest::isolate());
7780 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 =
7784 CompileRun("o.__proto__ === o2.__proto__");
7785 CHECK_EQ(v8::True(isolate), value);
7786 context->Global()->Set(v8_str("o"), obj);
7787 }
7788 }
7789
7790
StrCmp16(uint16_t * a,uint16_t * b)7791 static 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
StrNCmp16(uint16_t * a,uint16_t * b,int n)7801 static 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
GetUtf8Length(Handle<String> str)7812 int GetUtf8Length(Handle<String> str) {
7813 int len = str->Utf8Length();
7814 if (len < 0) {
7815 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7816 i::String::Flatten(istr);
7817 len = str->Utf8Length();
7818 }
7819 return len;
7820 }
7821
7822
THREADED_TEST(StringWrite)7823 THREADED_TEST(StringWrite) {
7824 LocalContext context;
7825 v8::HandleScope scope(context->GetIsolate());
7826 v8::Handle<String> str = v8_str("abcde");
7827 // abc<Icelandic eth><Unicode snowman>.
7828 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7829 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);
7847 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 "}");
7858 v8::Handle<v8::Object> global = context->Global();
7859 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7860 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7861
7862 CHECK_EQ(5, str2->Length());
7863 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7864 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7865
7866 char buf[100];
7867 char utf8buf[0xd800 * 3];
7868 uint16_t wbuf[100];
7869 int len;
7870 int charlen;
7871
7872 memset(utf8buf, 0x1, 1000);
7873 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7874 CHECK_EQ(9, len);
7875 CHECK_EQ(5, charlen);
7876 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7877
7878 memset(utf8buf, 0x1, 1000);
7879 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7880 CHECK_EQ(8, len);
7881 CHECK_EQ(5, charlen);
7882 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7883
7884 memset(utf8buf, 0x1, 1000);
7885 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7886 CHECK_EQ(5, len);
7887 CHECK_EQ(4, charlen);
7888 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7889
7890 memset(utf8buf, 0x1, 1000);
7891 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7892 CHECK_EQ(5, len);
7893 CHECK_EQ(4, charlen);
7894 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7895
7896 memset(utf8buf, 0x1, 1000);
7897 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7898 CHECK_EQ(5, len);
7899 CHECK_EQ(4, charlen);
7900 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7901
7902 memset(utf8buf, 0x1, 1000);
7903 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7904 CHECK_EQ(3, len);
7905 CHECK_EQ(3, charlen);
7906 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7907
7908 memset(utf8buf, 0x1, 1000);
7909 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7910 CHECK_EQ(3, len);
7911 CHECK_EQ(3, charlen);
7912 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7913
7914 memset(utf8buf, 0x1, 1000);
7915 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7916 CHECK_EQ(2, len);
7917 CHECK_EQ(2, charlen);
7918 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7919
7920 // 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
7967 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
7992 memset(buf, 0x1, sizeof(buf));
7993 memset(wbuf, 0x1, sizeof(wbuf));
7994 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7995 CHECK_EQ(5, len);
7996 len = str->Write(wbuf);
7997 CHECK_EQ(5, len);
7998 CHECK_EQ(0, strcmp("abcde", buf));
7999 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8000 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8001
8002 memset(buf, 0x1, sizeof(buf));
8003 memset(wbuf, 0x1, sizeof(wbuf));
8004 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8005 CHECK_EQ(4, len);
8006 len = str->Write(wbuf, 0, 4);
8007 CHECK_EQ(4, len);
8008 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8009 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8010 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8011
8012 memset(buf, 0x1, sizeof(buf));
8013 memset(wbuf, 0x1, sizeof(wbuf));
8014 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8015 CHECK_EQ(5, len);
8016 len = str->Write(wbuf, 0, 5);
8017 CHECK_EQ(5, len);
8018 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8019 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8020 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8021
8022 memset(buf, 0x1, sizeof(buf));
8023 memset(wbuf, 0x1, sizeof(wbuf));
8024 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8025 CHECK_EQ(5, len);
8026 len = str->Write(wbuf, 0, 6);
8027 CHECK_EQ(5, len);
8028 CHECK_EQ(0, strcmp("abcde", buf));
8029 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8030 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8031
8032 memset(buf, 0x1, sizeof(buf));
8033 memset(wbuf, 0x1, sizeof(wbuf));
8034 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8035 CHECK_EQ(1, len);
8036 len = str->Write(wbuf, 4, -1);
8037 CHECK_EQ(1, len);
8038 CHECK_EQ(0, strcmp("e", buf));
8039 uint16_t answer5[] = {'e', '\0'};
8040 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8041
8042 memset(buf, 0x1, sizeof(buf));
8043 memset(wbuf, 0x1, sizeof(wbuf));
8044 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8045 CHECK_EQ(1, len);
8046 len = str->Write(wbuf, 4, 6);
8047 CHECK_EQ(1, len);
8048 CHECK_EQ(0, strcmp("e", buf));
8049 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8050
8051 memset(buf, 0x1, sizeof(buf));
8052 memset(wbuf, 0x1, sizeof(wbuf));
8053 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8054 CHECK_EQ(1, len);
8055 len = str->Write(wbuf, 4, 1);
8056 CHECK_EQ(1, len);
8057 CHECK_EQ(0, strncmp("e\1", buf, 2));
8058 uint16_t answer6[] = {'e', 0x101};
8059 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8060
8061 memset(buf, 0x1, sizeof(buf));
8062 memset(wbuf, 0x1, sizeof(wbuf));
8063 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8064 CHECK_EQ(1, len);
8065 len = str->Write(wbuf, 3, 1);
8066 CHECK_EQ(1, len);
8067 CHECK_EQ(0, strncmp("d\1", buf, 2));
8068 uint16_t answer7[] = {'d', 0x101};
8069 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8070
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';
8085 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8086 0,
8087 6,
8088 String::NO_NULL_TERMINATION);
8089 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"));
8107
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));
8128 }
8129
8130
Utf16Helper(LocalContext & context,const char * name,const char * lengths_name,int len)8131 static void Utf16Helper(
8132 LocalContext& context, // NOLINT
8133 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));
8145 int length = GetUtf8Length(string);
8146 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8147 }
8148 }
8149
8150
StringGet(Handle<String> str,int index)8151 static 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
WriteUtf8Helper(LocalContext & context,const char * name,const char * lengths_name,int len)8158 static void WriteUtf8Helper(
8159 LocalContext& context, // NOLINT
8160 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
THREADED_TEST(Utf16)8229 THREADED_TEST(Utf16) {
8230 LocalContext context;
8231 v8::HandleScope scope(context->GetIsolate());
8232 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
SameSymbol(Handle<String> s1,Handle<String> s2)8281 static 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
SameSymbolHelper(v8::Isolate * isolate,const char * a,const char * b)8287 static 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);
8293 CHECK(SameSymbol(symbol1, symbol2));
8294 }
8295
8296
THREADED_TEST(Utf16Symbol)8297 THREADED_TEST(Utf16Symbol) {
8298 LocalContext context;
8299 v8::HandleScope scope(context->GetIsolate());
8300
8301 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);
8305 CHECK(SameSymbol(symbol1, symbol2));
8306
8307 SameSymbolHelper(context->GetIsolate(),
8308 "\360\220\220\205", // 4 byte encoding.
8309 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8310 SameSymbolHelper(context->GetIsolate(),
8311 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8312 "\360\220\220\206"); // 4 byte encoding.
8313 SameSymbolHelper(context->GetIsolate(),
8314 "x\360\220\220\205", // 4 byte encoding.
8315 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8316 SameSymbolHelper(context->GetIsolate(),
8317 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8318 "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);");
8334 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);
8350 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"));
8357 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)));
8363 }
8364
8365
THREADED_TEST(ToArrayIndex)8366 THREADED_TEST(ToArrayIndex) {
8367 LocalContext context;
8368 v8::Isolate* isolate = context->GetIsolate();
8369 v8::HandleScope scope(isolate);
8370
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());
8385 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8386 index = num->ToArrayIndex();
8387 CHECK(!index.IsEmpty());
8388 CHECK_EQ(1.0, index->Uint32Value());
8389 num = v8::Number::New(isolate, -1);
8390 index = num->ToArrayIndex();
8391 CHECK(index.IsEmpty());
8392 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8393 index = obj->ToArrayIndex();
8394 CHECK(index.IsEmpty());
8395 }
8396
8397
THREADED_TEST(ErrorConstruction)8398 THREADED_TEST(ErrorConstruction) {
8399 LocalContext context;
8400 v8::HandleScope scope(context->GetIsolate());
8401
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());
8406 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8407 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8408 CHECK(reference_error->IsObject());
8409 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8410 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8411 CHECK(syntax_error->IsObject());
8412 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8413 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8414 CHECK(type_error->IsObject());
8415 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8416 v8::Handle<Value> error = v8::Exception::Error(foo);
8417 CHECK(error->IsObject());
8418 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8419 }
8420
8421
YGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)8422 static void YGetter(Local<String> name,
8423 const v8::PropertyCallbackInfo<v8::Value>& info) {
8424 ApiTestFuzzer::Fuzz();
8425 info.GetReturnValue().Set(v8_num(10));
8426 }
8427
8428
YSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)8429 static void YSetter(Local<String> name,
8430 Local<Value> value,
8431 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);
8435 }
8436
8437
THREADED_TEST(DeleteAccessor)8438 THREADED_TEST(DeleteAccessor) {
8439 v8::Isolate* isolate = CcTest::isolate();
8440 v8::HandleScope scope(isolate);
8441 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8442 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
THREADED_TEST(TypeSwitch)8452 THREADED_TEST(TypeSwitch) {
8453 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);
8458 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8459 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8460 LocalContext context;
8461 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8462 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
8478 static int trouble_nesting = 0;
TroubleCallback(const v8::FunctionCallbackInfo<v8::Value> & args)8479 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8480 ApiTestFuzzer::Fuzz();
8481 trouble_nesting++;
8482
8483 // Call a JS function that throws an uncaught exception.
8484 Local<v8::Object> arg_this =
8485 args.GetIsolate()->GetCurrentContext()->Global();
8486 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());
8490 args.GetReturnValue().Set(
8491 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8492 }
8493
8494
8495 static int report_count = 0;
ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,v8::Handle<Value>)8496 static 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.
TEST(ApiUncaughtException)8504 TEST(ApiUncaughtException) {
8505 report_count = 0;
8506 LocalContext env;
8507 v8::Isolate* isolate = env->GetIsolate();
8508 v8::HandleScope scope(isolate);
8509 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8510
8511 Local<v8::FunctionTemplate> fun =
8512 v8::FunctionTemplate::New(isolate, TroubleCallback);
8513 v8::Local<v8::Object> global = env->Global();
8514 global->Set(v8_str("trouble"), fun->GetFunction());
8515
8516 CompileRun(
8517 "function trouble_callee() {"
8518 " var x = null;"
8519 " return x.foo;"
8520 "};"
8521 "function trouble_caller() {"
8522 " trouble();"
8523 "};");
8524 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
8535 static const char* script_resource_name = "ExceptionInNativeScript.js";
ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,v8::Handle<Value>)8536 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8537 v8::Handle<Value>) {
8538 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8539 CHECK(!name_val.IsEmpty() && name_val->IsString());
8540 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8541 CHECK_EQ(script_resource_name, *name);
8542 CHECK_EQ(3, message->GetLineNumber());
8543 v8::String::Utf8Value source_line(message->GetSourceLine());
8544 CHECK_EQ(" new o.foo();", *source_line);
8545 }
8546
8547
TEST(ExceptionInNativeScript)8548 TEST(ExceptionInNativeScript) {
8549 LocalContext env;
8550 v8::Isolate* isolate = env->GetIsolate();
8551 v8::HandleScope scope(isolate);
8552 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8553
8554 Local<v8::FunctionTemplate> fun =
8555 v8::FunctionTemplate::New(isolate, TroubleCallback);
8556 v8::Local<v8::Object> global = env->Global();
8557 global->Set(v8_str("trouble"), fun->GetFunction());
8558
8559 CompileRunWithOrigin(
8560 "function trouble() {\n"
8561 " var o = {};\n"
8562 " new o.foo();\n"
8563 "};",
8564 script_resource_name);
8565 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
8571
TEST(CompilationErrorUsingTryCatchHandler)8572 TEST(CompilationErrorUsingTryCatchHandler) {
8573 LocalContext env;
8574 v8::HandleScope scope(env->GetIsolate());
8575 v8::TryCatch try_catch;
8576 v8_compile("This doesn't &*&@#$&*^ compile.");
8577 CHECK_NE(NULL, *try_catch.Exception());
8578 CHECK(try_catch.HasCaught());
8579 }
8580
8581
TEST(TryCatchFinallyUsingTryCatchHandler)8582 TEST(TryCatchFinallyUsingTryCatchHandler) {
8583 LocalContext env;
8584 v8::HandleScope scope(env->GetIsolate());
8585 v8::TryCatch try_catch;
8586 CompileRun("try { throw ''; } catch (e) {}");
8587 CHECK(!try_catch.HasCaught());
8588 CompileRun("try { throw ''; } finally {}");
8589 CHECK(try_catch.HasCaught());
8590 try_catch.Reset();
8591 CompileRun(
8592 "(function() {"
8593 "try { throw ''; } finally { return; }"
8594 "})()");
8595 CHECK(!try_catch.HasCaught());
8596 CompileRun(
8597 "(function()"
8598 " { try { throw ''; } finally { throw 0; }"
8599 "})()");
8600 CHECK(try_catch.HasCaught());
8601 }
8602
8603
CEvaluate(const v8::FunctionCallbackInfo<v8::Value> & args)8604 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8605 v8::HandleScope scope(args.GetIsolate());
8606 CompileRun(args[0]->ToString());
8607 }
8608
8609
TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler)8610 TEST(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.
8640 static bool g_security_callback_result = false;
NamedSecurityTestCallback(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)8641 static 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
IndexedSecurityTestCallback(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)8655 static 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
8669 // SecurityHandler can't be run twice
TEST(SecurityHandler)8670 TEST(SecurityHandler) {
8671 v8::Isolate* isolate = CcTest::isolate();
8672 v8::HandleScope scope0(isolate);
8673 v8::Handle<v8::ObjectTemplate> global_template =
8674 v8::ObjectTemplate::New(isolate);
8675 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8676 IndexedSecurityTestCallback);
8677 // Create an environment
8678 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8679 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.
8691 v8::HandleScope scope1(isolate);
8692
8693 v8::Handle<Context> context1 =
8694 Context::New(isolate, NULL, global_template);
8695 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.
8712 v8::HandleScope scope2(isolate);
8713 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();
8726 context0->Exit();
8727 }
8728
8729
THREADED_TEST(SecurityChecks)8730 THREADED_TEST(SecurityChecks) {
8731 LocalContext env1;
8732 v8::HandleScope handle_scope(env1->GetIsolate());
8733 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8734
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.
8742 CompileRun("spy=function(){return spy;}");
8743 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8744 CHECK(spy->IsFunction());
8745
8746 // Create another function accessing global objects.
8747 CompileRun("spy2=function(){return new this.Array();}");
8748 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 }
8769 }
8770
8771
8772 // Regression test case for issue 1183439.
THREADED_TEST(SecurityChecksForPrototypeChain)8773 THREADED_TEST(SecurityChecksForPrototypeChain) {
8774 LocalContext current;
8775 v8::HandleScope scope(current->GetIsolate());
8776 v8::Handle<Context> other = Context::New(current->GetIsolate());
8777
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++) {
8795 CHECK(access_other0->Run().IsEmpty());
8796 CHECK(access_other1->Run().IsEmpty());
8797 }
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++) {
8808 CHECK(access_f0->Run().IsEmpty());
8809 CHECK(access_f1->Run().IsEmpty());
8810 }
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++) {
8828 CHECK(access_f2->Run().IsEmpty());
8829 CHECK(access_f3->Run().IsEmpty());
8830 }
8831 }
8832
8833
8834 static bool named_security_check_with_gc_called;
8835
NamedSecurityCallbackWithGC(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)8836 static 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
8846 static bool indexed_security_check_with_gc_called;
8847
IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)8848 static 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
TEST(SecurityTestGCAllowed)8858 TEST(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);
8886 }
8887
8888
THREADED_TEST(CrossDomainDelete)8889 THREADED_TEST(CrossDomainDelete) {
8890 LocalContext env1;
8891 v8::HandleScope handle_scope(env1->GetIsolate());
8892 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8893
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 =
8909 CompileRun("delete env1.prop");
8910 CHECK(result.IsEmpty());
8911 }
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());
8917 }
8918
8919
THREADED_TEST(CrossDomainIsPropertyEnumerable)8920 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8921 LocalContext env1;
8922 v8::HandleScope handle_scope(env1->GetIsolate());
8923 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8924
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);
8939 Local<Value> result = CompileRun(test);
8940 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);
8947 Local<Value> result = CompileRun(test);
8948 CHECK(result.IsEmpty());
8949 }
8950 }
8951
8952
THREADED_TEST(CrossDomainForIn)8953 THREADED_TEST(CrossDomainForIn) {
8954 LocalContext env1;
8955 v8::HandleScope handle_scope(env1->GetIsolate());
8956 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8957
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);
8975 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 "})()");
8987 CHECK(result->IsTrue());
8988 }
8989 }
8990
8991
TEST(ContextDetachGlobal)8992 TEST(ContextDetachGlobal) {
8993 LocalContext env1;
8994 v8::HandleScope handle_scope(env1->GetIsolate());
8995 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8996
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
9008 // Create a function in env2 and add a reference to it in env1.
9009 Local<v8::Object> global2 = env2->Global();
9010 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9011 CompileRun("function getProp() {return prop;}");
9012
9013 env1->Global()->Set(v8_str("getProp"),
9014 global2->Get(v8_str("getProp")));
9015
9016 // Detach env2's global, and reuse the global object of env2
9017 env2->Exit();
9018 env2->DetachGlobal();
9019
9020 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9021 0,
9022 v8::Handle<v8::ObjectTemplate>(),
9023 global2);
9024 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());
9031 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9032 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9033 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"));
9048 CHECK(r.IsEmpty());
9049 }
9050 }
9051
9052
TEST(DetachGlobal)9053 TEST(DetachGlobal) {
9054 LocalContext env1;
9055 v8::HandleScope scope(env1->GetIsolate());
9056
9057 // Create second environment.
9058 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9059
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);
9069 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9070 }
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");
9087 CHECK(result.IsEmpty());
9088
9089 // Reuse global2 for env3.
9090 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9091 0,
9092 v8::Handle<v8::ObjectTemplate>(),
9093 global2);
9094 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);
9102 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9103 }
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");
9117 CHECK(result.IsEmpty());
9118 }
9119
9120
GetThisX(const v8::FunctionCallbackInfo<v8::Value> & info)9121 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9122 info.GetReturnValue().Set(
9123 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9124 }
9125
9126
TEST(DetachedAccesses)9127 TEST(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 }
9240 }
9241
9242
9243 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
NamedAccessBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)9244 static bool NamedAccessBlocker(Local<v8::Object> global,
9245 Local<Value> name,
9246 v8::AccessType type,
9247 Local<Value> data) {
9248 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9249 allowed_access_type[type];
9250 }
9251
9252
IndexedAccessBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)9253 static bool IndexedAccessBlocker(Local<v8::Object> global,
9254 uint32_t key,
9255 v8::AccessType type,
9256 Local<Value> data) {
9257 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9258 allowed_access_type[type];
9259 }
9260
9261
9262 static int g_echo_value = -1;
9263
9264
EchoGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)9265 static void EchoGetter(
9266 Local<String> name,
9267 const v8::PropertyCallbackInfo<v8::Value>& info) {
9268 info.GetReturnValue().Set(v8_num(g_echo_value));
9269 }
9270
9271
EchoSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> &)9272 static void EchoSetter(Local<String> name,
9273 Local<Value> value,
9274 const v8::PropertyCallbackInfo<void>&) {
9275 if (value->IsNumber())
9276 g_echo_value = value->Int32Value();
9277 }
9278
9279
UnreachableGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)9280 static void UnreachableGetter(
9281 Local<String> name,
9282 const v8::PropertyCallbackInfo<v8::Value>& info) {
9283 CHECK(false); // This function should not be called..
9284 }
9285
9286
UnreachableSetter(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> &)9287 static void UnreachableSetter(Local<String>,
9288 Local<Value>,
9289 const v8::PropertyCallbackInfo<void>&) {
9290 CHECK(false); // This function should nto be called.
9291 }
9292
9293
UnreachableFunction(const v8::FunctionCallbackInfo<v8::Value> & info)9294 static void UnreachableFunction(
9295 const v8::FunctionCallbackInfo<v8::Value>& info) {
9296 CHECK(false); // This function should not be called..
9297 }
9298
9299
TEST(AccessControl)9300 TEST(AccessControl) {
9301 v8::Isolate* isolate = CcTest::isolate();
9302 v8::HandleScope handle_scope(isolate);
9303 v8::Handle<v8::ObjectTemplate> global_template =
9304 v8::ObjectTemplate::New(isolate);
9305
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
9316
9317 // 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
9323 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
9330 // Create an environment
9331 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9332 context0->Enter();
9333
9334 v8::Handle<v8::Object> global0 = context0->Global();
9335
9336 // 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
9357 v8::HandleScope scope1(isolate);
9358
9359 v8::Local<Context> context1 = Context::New(isolate);
9360 context1->Enter();
9361
9362 v8::Handle<v8::Object> global1 = context1->Global();
9363 global1->Set(v8_str("other"), global0);
9364
9365 // Access blocked property.
9366 CompileRun("other.blocked_prop = 1");
9367
9368 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());
9373
9374 // Access blocked element.
9375 CHECK(CompileRun("other[239] = 1").IsEmpty());
9376
9377 CHECK(CompileRun("other[239]").IsEmpty());
9378 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9379 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9380
9381 // Enable ACCESS_HAS
9382 allowed_access_type[v8::ACCESS_HAS] = true;
9383 CHECK(CompileRun("other[239]").IsEmpty());
9384 // ... and now we can get the descriptor...
9385 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9386 .IsEmpty());
9387 // ... 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.
9392 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9393
9394 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9395 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9396 .IsEmpty());
9397
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);
9405 ExpectObject(
9406 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9407 ExpectUndefined(
9408 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9409
9410 allowed_access_type[v8::ACCESS_HAS] = false;
9411 allowed_access_type[v8::ACCESS_GET] = false;
9412
9413 // Access an element with JS accessor.
9414 CHECK(CompileRun("other[42] = 2").IsEmpty());
9415
9416 CHECK(CompileRun("other[42]").IsEmpty());
9417 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9418
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);
9425 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9426 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9427
9428 allowed_access_type[v8::ACCESS_HAS] = false;
9429 allowed_access_type[v8::ACCESS_GET] = false;
9430
9431 v8::Handle<Value> value;
9432
9433 // Access accessible property
9434 value = CompileRun("other.accessible_prop = 3");
9435 CHECK(value->IsNumber());
9436 CHECK_EQ(3, value->Int32Value());
9437 CHECK_EQ(3, g_echo_value);
9438
9439 value = CompileRun("other.accessible_prop");
9440 CHECK(value->IsNumber());
9441 CHECK_EQ(3, value->Int32Value());
9442
9443 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')");
9449 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.
9453 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 "})()");
9469 CHECK(value->IsTrue());
9470
9471 context1->Exit();
9472 context0->Exit();
9473 }
9474
9475
TEST(AccessControlES5)9476 TEST(AccessControlES5) {
9477 v8::Isolate* isolate = CcTest::isolate();
9478 v8::HandleScope handle_scope(isolate);
9479 v8::Handle<v8::ObjectTemplate> global_template =
9480 v8::ObjectTemplate::New(isolate);
9481
9482 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9483 IndexedAccessBlocker);
9484
9485 // 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
9493 // 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
9500 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9501 context0->Enter();
9502
9503 v8::Handle<v8::Object> global0 = context0->Global();
9504
9505 v8::Local<Context> context1 = Context::New(isolate);
9506 context1->Enter();
9507 v8::Handle<v8::Object> global1 = context1->Global();
9508 global1->Set(v8_str("other"), global0);
9509
9510 // Regression test for issue 1154.
9511 CHECK(CompileRun("Object.keys(other)").IsEmpty());
9512 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9513
9514 // Regression test for issue 1027.
9515 CompileRun("Object.defineProperty(\n"
9516 " other, 'blocked_prop', {configurable: false})");
9517 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9518 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9519 .IsEmpty());
9520
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)");
9532
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;
9540 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9541 value = CompileRun("other.accessible_prop == 42");
9542 CHECK(value->IsTrue());
9543 }
9544
9545
BlockEverythingNamed(Local<v8::Object> object,Local<Value> name,v8::AccessType type,Local<Value> data)9546 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9547 v8::AccessType type, Local<Value> data) {
9548 return false;
9549 }
9550
9551
BlockEverythingIndexed(Local<v8::Object> object,uint32_t key,v8::AccessType type,Local<Value> data)9552 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9553 v8::AccessType type, Local<Value> data) {
9554 return false;
9555 }
9556
9557
THREADED_TEST(AccessControlGetOwnPropertyNames)9558 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9559 v8::Isolate* isolate = CcTest::isolate();
9560 v8::HandleScope handle_scope(isolate);
9561 v8::Handle<v8::ObjectTemplate> obj_template =
9562 v8::ObjectTemplate::New(isolate);
9563
9564 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9565 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9566 BlockEverythingIndexed);
9567
9568 // Create an environment
9569 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9570 context0->Enter();
9571
9572 v8::Handle<v8::Object> global0 = context0->Global();
9573
9574 v8::HandleScope scope1(CcTest::isolate());
9575
9576 v8::Local<Context> context1 = Context::New(isolate);
9577 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");
9591 CHECK(value.IsEmpty());
9592
9593 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9594 CHECK(value.IsEmpty());
9595
9596 context1->Exit();
9597 context0->Exit();
9598 }
9599
9600
TEST(SuperAccessControl)9601 TEST(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
IndexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)9621 static 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
NamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)9630 static void NamedPropertyEnumerator(
9631 const v8::PropertyCallbackInfo<v8::Array>& info) {
9632 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9633 result->Set(0, v8_str("x"));
9634 result->Set(1, v8::Object::New(info.GetIsolate()));
9635 info.GetReturnValue().Set(result);
9636 }
9637
9638
THREADED_TEST(GetOwnPropertyNamesWithInterceptor)9639 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9640 v8::Isolate* isolate = CcTest::isolate();
9641 v8::HandleScope handle_scope(isolate);
9642 v8::Handle<v8::ObjectTemplate> obj_template =
9643 v8::ObjectTemplate::New(isolate);
9644
9645 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);
9649 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
9656 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));
9667 }
9668
9669
ConstTenGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)9670 static void ConstTenGetter(Local<String> name,
9671 const v8::PropertyCallbackInfo<v8::Value>& info) {
9672 info.GetReturnValue().Set(v8_num(10));
9673 }
9674
9675
THREADED_TEST(CrossDomainAccessors)9676 THREADED_TEST(CrossDomainAccessors) {
9677 v8::Isolate* isolate = CcTest::isolate();
9678 v8::HandleScope handle_scope(isolate);
9679
9680 v8::Handle<v8::FunctionTemplate> func_template =
9681 v8::FunctionTemplate::New(isolate);
9682
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
9701 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9702 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.
9709 v8::HandleScope scope1(CcTest::isolate());
9710 v8::Local<Context> context1 = Context::New(isolate);
9711 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();
9722 CHECK(value.IsEmpty());
9723
9724 context1->Exit();
9725 context0->Exit();
9726 }
9727
9728
9729 static int named_access_count = 0;
9730 static int indexed_access_count = 0;
9731
NamedAccessCounter(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)9732 static 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
IndexedAccessCounter(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)9741 static 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.
TEST(AccessControlIC)9751 TEST(AccessControlIC) {
9752 named_access_count = 0;
9753 indexed_access_count = 0;
9754
9755 v8::Isolate* isolate = CcTest::isolate();
9756 v8::HandleScope handle_scope(isolate);
9757
9758 // Create an environment.
9759 v8::Local<Context> context0 = Context::New(isolate);
9760 context0->Enter();
9761
9762 // Create an object that requires access-check functions to be
9763 // called for cross-domain access.
9764 v8::Handle<v8::ObjectTemplate> object_template =
9765 v8::ObjectTemplate::New(isolate);
9766 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9767 IndexedAccessCounter);
9768 Local<v8::Object> object = object_template->NewInstance();
9769
9770 v8::HandleScope scope1(isolate);
9771
9772 // Create another environment.
9773 v8::Local<Context> context1 = Context::New(isolate);
9774 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();
9861 }
9862
9863
NamedAccessFlatten(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)9864 static 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));
9874 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9875 CHECK_EQ(4, len);
9876
9877 uint16_t buf2[100];
9878
9879 memset(buf, 0x1, sizeof(buf));
9880 len = name.As<String>()->Write(buf2);
9881 CHECK_EQ(4, len);
9882
9883 return true;
9884 }
9885
9886
IndexedAccessFlatten(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)9887 static 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.
THREADED_TEST(AccessControlFlatten)9900 THREADED_TEST(AccessControlFlatten) {
9901 named_access_count = 0;
9902 indexed_access_count = 0;
9903
9904 v8::Isolate* isolate = CcTest::isolate();
9905 v8::HandleScope handle_scope(isolate);
9906
9907 // Create an environment.
9908 v8::Local<Context> context0 = Context::New(isolate);
9909 context0->Enter();
9910
9911 // Create an object that requires access-check functions to be
9912 // called for cross-domain access.
9913 v8::Handle<v8::ObjectTemplate> object_template =
9914 v8::ObjectTemplate::New(isolate);
9915 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9916 IndexedAccessFlatten);
9917 Local<v8::Object> object = object_template->NewInstance();
9918
9919 v8::HandleScope scope1(isolate);
9920
9921 // Create another environment.
9922 v8::Local<Context> context1 = Context::New(isolate);
9923 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();
9936 }
9937
9938
AccessControlNamedGetter(Local<String>,const v8::PropertyCallbackInfo<v8::Value> & info)9939 static void AccessControlNamedGetter(
9940 Local<String>,
9941 const v8::PropertyCallbackInfo<v8::Value>& info) {
9942 info.GetReturnValue().Set(42);
9943 }
9944
9945
AccessControlNamedSetter(Local<String>,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)9946 static void AccessControlNamedSetter(
9947 Local<String>,
9948 Local<Value> value,
9949 const v8::PropertyCallbackInfo<v8::Value>& info) {
9950 info.GetReturnValue().Set(value);
9951 }
9952
9953
AccessControlIndexedGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)9954 static void AccessControlIndexedGetter(
9955 uint32_t index,
9956 const v8::PropertyCallbackInfo<v8::Value>& info) {
9957 info.GetReturnValue().Set(v8_num(42));
9958 }
9959
9960
AccessControlIndexedSetter(uint32_t,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)9961 static void AccessControlIndexedSetter(
9962 uint32_t,
9963 Local<Value> value,
9964 const v8::PropertyCallbackInfo<v8::Value>& info) {
9965 info.GetReturnValue().Set(value);
9966 }
9967
9968
THREADED_TEST(AccessControlInterceptorIC)9969 THREADED_TEST(AccessControlInterceptorIC) {
9970 named_access_count = 0;
9971 indexed_access_count = 0;
9972
9973 v8::Isolate* isolate = CcTest::isolate();
9974 v8::HandleScope handle_scope(isolate);
9975
9976 // Create an environment.
9977 v8::Local<Context> context0 = Context::New(isolate);
9978 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.
9983 v8::Handle<v8::ObjectTemplate> object_template =
9984 v8::ObjectTemplate::New(isolate);
9985 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
9993 v8::HandleScope scope1(isolate);
9994
9995 // Create another environment.
9996 v8::Local<Context> context1 = Context::New(isolate);
9997 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();
10033 }
10034
10035
THREADED_TEST(Version)10036 THREADED_TEST(Version) {
10037 v8::V8::GetVersion();
10038 }
10039
10040
InstanceFunctionCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10041 static void InstanceFunctionCallback(
10042 const v8::FunctionCallbackInfo<v8::Value>& args) {
10043 ApiTestFuzzer::Fuzz();
10044 args.GetReturnValue().Set(v8_num(12));
10045 }
10046
10047
THREADED_TEST(InstanceProperties)10048 THREADED_TEST(InstanceProperties) {
10049 LocalContext context;
10050 v8::Isolate* isolate = context->GetIsolate();
10051 v8::HandleScope handle_scope(isolate);
10052
10053 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10054 Local<ObjectTemplate> instance = t->InstanceTemplate();
10055
10056 instance->Set(v8_str("x"), v8_num(42));
10057 instance->Set(v8_str("f"),
10058 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10059
10060 Local<Value> o = t->GetFunction()->NewInstance();
10061
10062 context->Global()->Set(v8_str("i"), o);
10063 Local<Value> value = CompileRun("i.x");
10064 CHECK_EQ(42, value->Int32Value());
10065
10066 value = CompileRun("i.f()");
10067 CHECK_EQ(12, value->Int32Value());
10068 }
10069
10070
GlobalObjectInstancePropertiesGet(Local<String> key,const v8::PropertyCallbackInfo<v8::Value> &)10071 static void GlobalObjectInstancePropertiesGet(
10072 Local<String> key,
10073 const v8::PropertyCallbackInfo<v8::Value>&) {
10074 ApiTestFuzzer::Fuzz();
10075 }
10076
10077
THREADED_TEST(GlobalObjectInstanceProperties)10078 THREADED_TEST(GlobalObjectInstanceProperties) {
10079 v8::Isolate* isolate = CcTest::isolate();
10080 v8::HandleScope handle_scope(isolate);
10081
10082 Local<Value> global_object;
10083
10084 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10085 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"),
10090 v8::FunctionTemplate::New(isolate,
10091 InstanceFunctionCallback));
10092
10093 // 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
10109 {
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
10115 Local<Value> value = CompileRun("x");
10116 CHECK_EQ(42, value->Int32Value());
10117 value = CompileRun("f()");
10118 CHECK_EQ(12, value->Int32Value());
10119 value = CompileRun(script);
10120 CHECK_EQ(1, value->Int32Value());
10121 }
10122
10123 {
10124 // Create new environment reusing the global object.
10125 LocalContext env(NULL, instance_template, global_object);
10126 Local<Value> value = CompileRun("x");
10127 CHECK_EQ(42, value->Int32Value());
10128 value = CompileRun("f()");
10129 CHECK_EQ(12, value->Int32Value());
10130 value = CompileRun(script);
10131 CHECK_EQ(1, value->Int32Value());
10132 }
10133 }
10134
10135
THREADED_TEST(CallKnownGlobalReceiver)10136 THREADED_TEST(CallKnownGlobalReceiver) {
10137 v8::Isolate* isolate = CcTest::isolate();
10138 v8::HandleScope handle_scope(isolate);
10139
10140 Local<Value> global_object;
10141
10142 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10143 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();
10165 foo = CompileRun(script);
10166 }
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);
10172 CompileRun("foo()");
10173 }
10174 }
10175
10176
ShadowFunctionCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10177 static void ShadowFunctionCallback(
10178 const v8::FunctionCallbackInfo<v8::Value>& args) {
10179 ApiTestFuzzer::Fuzz();
10180 args.GetReturnValue().Set(v8_num(42));
10181 }
10182
10183
10184 static int shadow_y;
10185 static int shadow_y_setter_call_count;
10186 static int shadow_y_getter_call_count;
10187
10188
ShadowYSetter(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> &)10189 static void ShadowYSetter(Local<String>,
10190 Local<Value>,
10191 const v8::PropertyCallbackInfo<void>&) {
10192 shadow_y_setter_call_count++;
10193 shadow_y = 42;
10194 }
10195
10196
ShadowYGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)10197 static void ShadowYGetter(Local<String> name,
10198 const v8::PropertyCallbackInfo<v8::Value>& info) {
10199 ApiTestFuzzer::Fuzz();
10200 shadow_y_getter_call_count++;
10201 info.GetReturnValue().Set(v8_num(shadow_y));
10202 }
10203
10204
ShadowIndexedGet(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> &)10205 static void ShadowIndexedGet(uint32_t index,
10206 const v8::PropertyCallbackInfo<v8::Value>&) {
10207 }
10208
10209
ShadowNamedGet(Local<String> key,const v8::PropertyCallbackInfo<v8::Value> &)10210 static void ShadowNamedGet(Local<String> key,
10211 const v8::PropertyCallbackInfo<v8::Value>&) {
10212 }
10213
10214
THREADED_TEST(ShadowObject)10215 THREADED_TEST(ShadowObject) {
10216 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10217 v8::Isolate* isolate = CcTest::isolate();
10218 v8::HandleScope handle_scope(isolate);
10219
10220 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10221 LocalContext context(NULL, global_template);
10222
10223 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10224 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10225 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10226 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10227 Local<ObjectTemplate> instance = t->InstanceTemplate();
10228
10229 proto->Set(v8_str("f"),
10230 v8::FunctionTemplate::New(isolate,
10231 ShadowFunctionCallback,
10232 Local<Value>()));
10233 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 =
10241 CompileRun("this.propertyIsEnumerable(0)");
10242 CHECK(value->IsBoolean());
10243 CHECK(!value->BooleanValue());
10244
10245 value = CompileRun("x");
10246 CHECK_EQ(12, value->Int32Value());
10247
10248 value = CompileRun("f()");
10249 CHECK_EQ(42, value->Int32Value());
10250
10251 CompileRun("y = 43");
10252 CHECK_EQ(1, shadow_y_setter_call_count);
10253 value = CompileRun("y");
10254 CHECK_EQ(1, shadow_y_getter_call_count);
10255 CHECK_EQ(42, value->Int32Value());
10256 }
10257
10258
THREADED_TEST(HiddenPrototype)10259 THREADED_TEST(HiddenPrototype) {
10260 LocalContext context;
10261 v8::Isolate* isolate = context->GetIsolate();
10262 v8::HandleScope handle_scope(isolate);
10263
10264 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10265 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10266 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10267 t1->SetHiddenPrototype(true);
10268 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10269 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10270 t2->SetHiddenPrototype(true);
10271 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10272 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10273 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());
10300 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10301 }
10302
10303
THREADED_TEST(HiddenPrototypeSet)10304 THREADED_TEST(HiddenPrototypeSet) {
10305 LocalContext context;
10306 v8::Isolate* isolate = context->GetIsolate();
10307 v8::HandleScope handle_scope(isolate);
10308
10309 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.
THREADED_TEST(HiddenPrototypeIdentityHash)10347 THREADED_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
THREADED_TEST(SetPrototype)10365 THREADED_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);
10371 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10372 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10373 t1->SetHiddenPrototype(true);
10374 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10375 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10376 t2->SetHiddenPrototype(true);
10377 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10378 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10379 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());
10406 CHECK_EQ(proto.As<v8::Object>(), o3);
10407
10408 // However, Object::GetPrototype ignores hidden prototype.
10409 Local<Value> proto0 = o0->GetPrototype();
10410 CHECK(proto0->IsObject());
10411 CHECK_EQ(proto0.As<v8::Object>(), o1);
10412
10413 Local<Value> proto1 = o1->GetPrototype();
10414 CHECK(proto1->IsObject());
10415 CHECK_EQ(proto1.As<v8::Object>(), o2);
10416
10417 Local<Value> proto2 = o2->GetPrototype();
10418 CHECK(proto2->IsObject());
10419 CHECK_EQ(proto2.As<v8::Object>(), o3);
10420 }
10421
10422
10423 // Getting property names of an object with a prototype chain that
10424 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10425 // crash the runtime.
THREADED_TEST(Regress91517)10426 THREADED_TEST(Regress91517) {
10427 i::FLAG_allow_natives_syntax = true;
10428 LocalContext context;
10429 v8::Isolate* isolate = context->GetIsolate();
10430 v8::HandleScope handle_scope(isolate);
10431
10432 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10433 t1->SetHiddenPrototype(true);
10434 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10435 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10436 t2->SetHiddenPrototype(true);
10437 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10438 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10439 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10440 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10441 t3->SetHiddenPrototype(true);
10442 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10443 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10444 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++) {
10449 i::SNPrintF(name_buf, "sdf%d", i);
10450 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
10463 // Call the runtime version of GetOwnPropertyNames() on the natively
10464 // created object through JavaScript.
10465 context->Global()->Set(v8_str("obj"), o4);
10466 // PROPERTY_ATTRIBUTES_NONE = 0
10467 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10468
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
10479 // Getting property names of an object with a hidden and inherited
10480 // prototype should not duplicate the accessor properties inherited.
THREADED_TEST(Regress269562)10481 THREADED_TEST(Regress269562) {
10482 i::FLAG_allow_natives_syntax = true;
10483 LocalContext context;
10484 v8::HandleScope handle_scope(context->GetIsolate());
10485
10486 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
THREADED_TEST(FunctionReadOnlyPrototype)10536 THREADED_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));
10543 t1->ReadOnlyPrototype();
10544 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10545 // Configured value of ReadOnly flag.
10546 CHECK(CompileRun(
10547 "(function() {"
10548 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10549 " return (descriptor['writable'] == false);"
10550 "})()")->BooleanValue());
10551 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10552 CHECK_EQ(42,
10553 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10554
10555 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10556 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10557 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10558 // Default value of ReadOnly flag.
10559 CHECK(CompileRun(
10560 "(function() {"
10561 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10562 " return (descriptor['writable'] == true);"
10563 "})()")->BooleanValue());
10564 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10565 }
10566
10567
THREADED_TEST(SetPrototypeThrows)10568 THREADED_TEST(SetPrototypeThrows) {
10569 LocalContext context;
10570 v8::Isolate* isolate = context->GetIsolate();
10571 v8::HandleScope handle_scope(isolate);
10572
10573 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10574
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());
10584 DCHECK(!CcTest::i_isolate()->has_pending_exception());
10585
10586 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10587 }
10588
10589
THREADED_TEST(FunctionRemovePrototype)10590 THREADED_TEST(FunctionRemovePrototype) {
10591 LocalContext context;
10592 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
THREADED_TEST(GetterSetterExceptions)10611 THREADED_TEST(GetterSetterExceptions) {
10612 LocalContext context;
10613 v8::Isolate* isolate = context->GetIsolate();
10614 v8::HandleScope handle_scope(isolate);
10615 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;
10624 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10625 x->Get(v8_str("get"));
10626 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10627 x->Get(v8_str("get"));
10628 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10629 x->Get(v8_str("get"));
10630 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10631 x->Get(v8_str("get"));
10632 }
10633
10634
THREADED_TEST(Constructor)10635 THREADED_TEST(Constructor) {
10636 LocalContext context;
10637 v8::Isolate* isolate = context->GetIsolate();
10638 v8::HandleScope handle_scope(isolate);
10639 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10640 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();
10644 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10645 CHECK(obj->IsJSObject());
10646 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10647 CHECK(value->BooleanValue());
10648 }
10649
10650
ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10651 static void ConstructorCallback(
10652 const v8::FunctionCallbackInfo<v8::Value>& args) {
10653 ApiTestFuzzer::Fuzz();
10654 Local<Object> This;
10655
10656 if (args.IsConstructCall()) {
10657 Local<Object> Holder = args.Holder();
10658 This = Object::New(args.GetIsolate());
10659 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]);
10668 args.GetReturnValue().Set(This);
10669 }
10670
10671
FakeConstructorCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10672 static void FakeConstructorCallback(
10673 const v8::FunctionCallbackInfo<v8::Value>& args) {
10674 ApiTestFuzzer::Fuzz();
10675 args.GetReturnValue().Set(args[0]);
10676 }
10677
10678
THREADED_TEST(ConstructorForObject)10679 THREADED_TEST(ConstructorForObject) {
10680 LocalContext context;
10681 v8::Isolate* isolate = context->GetIsolate();
10682 v8::HandleScope handle_scope(isolate);
10683
10684 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10685 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());
10712 String::Utf8Value string_value1(value->ToString());
10713 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());
10722 String::Utf8Value string_value2(value->ToString());
10723 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
10731 Handle<Value> args3[] = { v8::True(isolate) };
10732 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.
10741 Handle<Value> args4[] = { v8::Undefined(isolate) };
10742 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.
10750 Handle<Value> args5[] = { v8::Null(isolate) };
10751 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.
10760 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10761 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());
10769 String::Utf8Value exception_value1(try_catch.Exception());
10770 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());
10776 String::Utf8Value exception_value2(try_catch.Exception());
10777 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10778 try_catch.Reset();
10779 }
10780
10781 // Check the case when constructor throws exception.
10782 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10783 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());
10792 String::Utf8Value exception_value1(try_catch.Exception());
10793 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());
10799 String::Utf8Value exception_value2(try_catch.Exception());
10800 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 =
10806 FunctionTemplate::New(isolate, FakeConstructorCallback);
10807 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
10826 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10827 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
THREADED_TEST(FunctionDescriptorException)10847 THREADED_TEST(FunctionDescriptorException) {
10848 LocalContext context;
10849 v8::Isolate* isolate = context->GetIsolate();
10850 v8::HandleScope handle_scope(isolate);
10851 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10852 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);"
10861 // " if (str.indexOf('TypeError') == -1) return 1;"
10862 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10863 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10864 " return 0;"
10865 " }"
10866 " return 4;"
10867 "}"
10868 "test();");
10869 CHECK_EQ(0, value->Int32Value());
10870 }
10871
10872
THREADED_TEST(EvalAliasedDynamic)10873 THREADED_TEST(EvalAliasedDynamic) {
10874 LocalContext current;
10875 v8::HandleScope scope(current->GetIsolate());
10876
10877 // Tests where aliased eval can only be resolved dynamically.
10878 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);");
10889 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;
10895 script = v8_compile(
10896 "function f(x) { "
10897 " var bar = 2;"
10898 " with (x) { return eval('bar'); }"
10899 "}"
10900 "result4 = f(this)");
10901 script->Run();
10902 CHECK(!try_catch.HasCaught());
10903 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10904
10905 try_catch.Reset();
10906 }
10907
10908
THREADED_TEST(CrossEval)10909 THREADED_TEST(CrossEval) {
10910 v8::HandleScope scope(CcTest::isolate());
10911 LocalContext other;
10912 LocalContext current;
10913
10914 Local<String> token = v8_str("<security token>");
10915 other->SetSecurityToken(token);
10916 current->SetSecurityToken(token);
10917
10918 // Set up reference from current to other.
10919 current->Global()->Set(v8_str("other"), other->Global());
10920
10921 // Check that new variables are introduced in other context.
10922 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10923 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.
10930 script = v8_compile("other.eval('na = 1234')");
10931 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;
10938 script = v8_compile("var bar = 42; other.eval('bar');");
10939 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.
10945 script = v8_compile(
10946 "(function() { "
10947 " var baz = 87;"
10948 " return other.eval('baz');"
10949 "})();");
10950 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));
10957 script = v8_compile("other.eval('bis')");
10958 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());
10964 script = v8_compile("other.eval('this == t')");
10965 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.
10971 script = v8_compile("with({x:2}){other.eval('x')}");
10972 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.
10978 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10979 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.
THREADED_TEST(EvalInDetachedGlobal)10987 THREADED_TEST(EvalInDetachedGlobal) {
10988 v8::Isolate* isolate = CcTest::isolate();
10989 v8::HandleScope scope(isolate);
10990
10991 v8::Local<Context> context0 = Context::New(isolate);
10992 v8::Local<Context> context1 = Context::New(isolate);
10993
10994 // Set up function in context0 that uses eval from context0.
10995 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();
11017 }
11018
11019
THREADED_TEST(CrossLazyLoad)11020 THREADED_TEST(CrossLazyLoad) {
11021 v8::HandleScope scope(CcTest::isolate());
11022 LocalContext other;
11023 LocalContext current;
11024
11025 Local<String> token = v8_str("<security token>");
11026 other->SetSecurityToken(token);
11027 current->SetSecurityToken(token);
11028
11029 // Set up reference from current to other.
11030 current->Global()->Set(v8_str("other"), other->Global());
11031
11032 // Trigger lazy loading in other context.
11033 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11034 Local<Value> value = script->Run();
11035 CHECK_EQ(42.0, value->NumberValue());
11036 }
11037
11038
call_as_function(const v8::FunctionCallbackInfo<v8::Value> & args)11039 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11040 ApiTestFuzzer::Fuzz();
11041 if (args.IsConstructCall()) {
11042 if (args[0]->IsInt32()) {
11043 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11044 return;
11045 }
11046 }
11047
11048 args.GetReturnValue().Set(args[0]);
11049 }
11050
11051
ReturnThis(const v8::FunctionCallbackInfo<v8::Value> & args)11052 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11053 args.GetReturnValue().Set(args.This());
11054 }
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.
THREADED_TEST(CallAsFunction)11060 THREADED_TEST(CallAsFunction) {
11061 LocalContext context;
11062 v8::Isolate* isolate = context->GetIsolate();
11063 v8::HandleScope scope(isolate);
11064
11065 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11066 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());
11073
11074 value = CompileRun("obj(42)");
11075 CHECK(!try_catch.HasCaught());
11076 CHECK_EQ(42, value->Int32Value());
11077
11078 value = CompileRun("(function(o){return o(49)})(obj)");
11079 CHECK(!try_catch.HasCaught());
11080 CHECK_EQ(49, value->Int32Value());
11081
11082 // test special case of call as function
11083 value = CompileRun("[obj]['0'](45)");
11084 CHECK(!try_catch.HasCaught());
11085 CHECK_EQ(45, value->Int32Value());
11086
11087 value = CompileRun("obj.call = Function.prototype.call;"
11088 "obj.call(null, 87)");
11089 CHECK(!try_catch.HasCaught());
11090 CHECK_EQ(87, value->Int32Value());
11091
11092 // 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());
11098
11099 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());
11103
11104 // 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
11118 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11119 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11120 USE(instance_template);
11121 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());
11131 String::Utf8Value exception_value1(try_catch.Exception());
11132 // TODO(verwaest): Better message
11133 CHECK_EQ("TypeError: object is not a function",
11134 *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());
11143 String::Utf8Value exception_value2(try_catch.Exception());
11144 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11145 try_catch.Reset();
11146 }
11147
11148 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11149 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());
11160 String::Utf8Value exception_value1(try_catch.Exception());
11161 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());
11167 String::Utf8Value exception_value2(try_catch.Exception());
11168 CHECK_EQ("23", *exception_value2);
11169 try_catch.Reset();
11170 }
11171
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 }
11244 }
11245
11246
11247 // Check whether a non-function object is callable.
THREADED_TEST(CallableObject)11248 THREADED_TEST(CallableObject) {
11249 LocalContext context;
11250 v8::Isolate* isolate = context->GetIsolate();
11251 v8::HandleScope scope(isolate);
11252
11253 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11254 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
11262 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11263 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 =
11271 FunctionTemplate::New(isolate, call_as_function);
11272 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
11280 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11281 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 }
11288 }
11289
11290
Recurse(v8::Isolate * isolate,int depth,int iterations)11291 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11292 v8::HandleScope scope(isolate);
11293 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11294 for (int i = 0; i < iterations; i++) {
11295 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11296 }
11297 return Recurse(isolate, depth - 1, iterations);
11298 }
11299
11300
THREADED_TEST(HandleIteration)11301 THREADED_TEST(HandleIteration) {
11302 static const int kIterations = 500;
11303 static const int kNesting = 200;
11304 LocalContext context;
11305 v8::Isolate* isolate = context->GetIsolate();
11306 v8::HandleScope scope0(isolate);
11307 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11308 {
11309 v8::HandleScope scope1(isolate);
11310 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11311 for (int i = 0; i < kIterations; i++) {
11312 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11313 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11314 }
11315
11316 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11317 {
11318 v8::HandleScope scope2(CcTest::isolate());
11319 for (int j = 0; j < kIterations; j++) {
11320 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11321 CHECK_EQ(j + 1 + kIterations,
11322 v8::HandleScope::NumberOfHandles(isolate));
11323 }
11324 }
11325 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11326 }
11327 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11328 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11329 }
11330
11331
InterceptorHasOwnPropertyGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11332 static void InterceptorHasOwnPropertyGetter(
11333 Local<String> name,
11334 const v8::PropertyCallbackInfo<v8::Value>& info) {
11335 ApiTestFuzzer::Fuzz();
11336 }
11337
11338
THREADED_TEST(InterceptorHasOwnProperty)11339 THREADED_TEST(InterceptorHasOwnProperty) {
11340 LocalContext context;
11341 v8::Isolate* isolate = context->GetIsolate();
11342 v8::HandleScope scope(isolate);
11343 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11344 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
InterceptorHasOwnPropertyGetterGC(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11363 static void InterceptorHasOwnPropertyGetterGC(
11364 Local<String> name,
11365 const v8::PropertyCallbackInfo<v8::Value>& info) {
11366 ApiTestFuzzer::Fuzz();
11367 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11368 }
11369
11370
THREADED_TEST(InterceptorHasOwnPropertyCausingGC)11371 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11372 LocalContext context;
11373 v8::Isolate* isolate = context->GetIsolate();
11374 v8::HandleScope scope(isolate);
11375 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11376 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
11401 typedef void (*NamedPropertyGetter)(
11402 Local<String> property,
11403 const v8::PropertyCallbackInfo<v8::Value>& info);
11404
11405
CheckInterceptorLoadIC(NamedPropertyGetter getter,const char * source,int expected)11406 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11407 const char* source,
11408 int expected) {
11409 v8::Isolate* isolate = CcTest::isolate();
11410 v8::HandleScope scope(isolate);
11411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11412 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11413 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
InterceptorLoadICGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11420 static void InterceptorLoadICGetter(
11421 Local<String> name,
11422 const v8::PropertyCallbackInfo<v8::Value>& info) {
11423 ApiTestFuzzer::Fuzz();
11424 v8::Isolate* isolate = CcTest::isolate();
11425 CHECK_EQ(isolate, info.GetIsolate());
11426 CHECK_EQ(v8_str("data"), info.Data());
11427 CHECK_EQ(v8_str("x"), name);
11428 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11429 }
11430
11431
11432 // This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC)11433 THREADED_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
InterceptorLoadXICGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11447 static void InterceptorLoadXICGetter(
11448 Local<String> name,
11449 const v8::PropertyCallbackInfo<v8::Value>& info) {
11450 ApiTestFuzzer::Fuzz();
11451 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>());
11455 }
11456
11457
THREADED_TEST(InterceptorLoadICWithFieldOnHolder)11458 THREADED_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
THREADED_TEST(InterceptorLoadICWithSubstitutedProto)11469 THREADED_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
THREADED_TEST(InterceptorLoadICWithPropertyOnProto)11480 THREADED_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
THREADED_TEST(InterceptorLoadICUndefined)11491 THREADED_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
THREADED_TEST(InterceptorLoadICWithOverride)11501 THREADED_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.
THREADED_TEST(InterceptorLoadICFieldNotNeeded)11521 THREADED_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.
THREADED_TEST(InterceptorLoadICInvalidatedField)11541 THREADED_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
11562 static int interceptor_load_not_handled_calls = 0;
InterceptorLoadNotHandled(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11563 static void InterceptorLoadNotHandled(
11564 Local<String> name,
11565 const v8::PropertyCallbackInfo<v8::Value>& info) {
11566 ++interceptor_load_not_handled_calls;
11567 }
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.
THREADED_TEST(InterceptorLoadICPostInterceptor)11572 THREADED_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
11594 // 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.
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal)11597 THREADED_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
SetOnThis(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)11615 static void SetOnThis(Local<String> name,
11616 Local<Value> value,
11617 const v8::PropertyCallbackInfo<void>& info) {
11618 Local<Object>::Cast(info.This())->ForceSet(name, value);
11619 }
11620
11621
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder)11622 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11623 v8::Isolate* isolate = CcTest::isolate();
11624 v8::HandleScope scope(isolate);
11625 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11626 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11627 templ->SetAccessor(v8_str("y"), Return239Callback);
11628 LocalContext context;
11629 context->Global()->Set(v8_str("o"), templ->NewInstance());
11630
11631 // Check the case when receiver and interceptor's holder
11632 // are the same objects.
11633 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());
11639
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());
11649 }
11650
11651
THREADED_TEST(InterceptorLoadICWithCallbackOnProto)11652 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11653 v8::Isolate* isolate = CcTest::isolate();
11654 v8::HandleScope scope(isolate);
11655 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11656 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11657 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11658 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11659
11660 LocalContext context;
11661 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11662 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11663
11664 // Check the case when receiver and interceptor's holder
11665 // are the same objects.
11666 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());
11673
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());
11683 }
11684
11685
THREADED_TEST(InterceptorLoadICForCallbackWithOverride)11686 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11687 v8::Isolate* isolate = CcTest::isolate();
11688 v8::HandleScope scope(isolate);
11689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11690 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11691 templ->SetAccessor(v8_str("y"), Return239Callback);
11692
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.
THREADED_TEST(InterceptorLoadICCallbackNotNeeded)11715 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11716 v8::Isolate* isolate = CcTest::isolate();
11717 v8::HandleScope scope(isolate);
11718 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11719 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11720 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11721 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11722
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.
THREADED_TEST(InterceptorLoadICInvalidatedCallback)11744 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11745 v8::Isolate* isolate = CcTest::isolate();
11746 v8::HandleScope scope(isolate);
11747 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11748 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11749 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11750 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11751
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.
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal)11777 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11778 v8::Isolate* isolate = CcTest::isolate();
11779 v8::HandleScope scope(isolate);
11780 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11781 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11782 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11783 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11784
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
InterceptorLoadICGetter0(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11806 static void InterceptorLoadICGetter0(
11807 Local<String> name,
11808 const v8::PropertyCallbackInfo<v8::Value>& info) {
11809 ApiTestFuzzer::Fuzz();
11810 CHECK(v8_str("x")->Equals(name));
11811 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11812 }
11813
11814
THREADED_TEST(InterceptorReturningZero)11815 THREADED_TEST(InterceptorReturningZero) {
11816 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11817 "o.x == undefined ? 1 : 0",
11818 0);
11819 }
11820
11821
InterceptorStoreICSetter(Local<String> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)11822 static void InterceptorStoreICSetter(
11823 Local<String> key,
11824 Local<Value> value,
11825 const v8::PropertyCallbackInfo<v8::Value>& info) {
11826 CHECK(v8_str("x")->Equals(key));
11827 CHECK_EQ(42, value->Int32Value());
11828 info.GetReturnValue().Set(value);
11829 }
11830
11831
11832 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)11833 THREADED_TEST(InterceptorStoreIC) {
11834 v8::Isolate* isolate = CcTest::isolate();
11835 v8::HandleScope scope(isolate);
11836 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11837 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11838 InterceptorStoreICSetter,
11839 0, 0, 0, v8_str("data"));
11840 LocalContext context;
11841 context->Global()->Set(v8_str("o"), templ->NewInstance());
11842 CompileRun(
11843 "for (var i = 0; i < 1000; i++) {"
11844 " o.x = 42;"
11845 "}");
11846 }
11847
11848
THREADED_TEST(InterceptorStoreICWithNoSetter)11849 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11850 v8::Isolate* isolate = CcTest::isolate();
11851 v8::HandleScope scope(isolate);
11852 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11853 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
11867 v8::Handle<Value> call_ic_function;
11868 v8::Handle<Value> call_ic_function2;
11869 v8::Handle<Value> call_ic_function3;
11870
InterceptorCallICGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11871 static void InterceptorCallICGetter(
11872 Local<String> name,
11873 const v8::PropertyCallbackInfo<v8::Value>& info) {
11874 ApiTestFuzzer::Fuzz();
11875 CHECK(v8_str("x")->Equals(name));
11876 info.GetReturnValue().Set(call_ic_function);
11877 }
11878
11879
11880 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)11881 THREADED_TEST(InterceptorCallIC) {
11882 v8::Isolate* isolate = CcTest::isolate();
11883 v8::HandleScope scope(isolate);
11884 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11885 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.
THREADED_TEST(InterceptorCallICSeesOthers)11901 THREADED_TEST(InterceptorCallICSeesOthers) {
11902 v8::Isolate* isolate = CcTest::isolate();
11903 v8::HandleScope scope(isolate);
11904 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11905 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
11918 static v8::Handle<Value> call_ic_function4;
InterceptorCallICGetter4(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)11919 static void InterceptorCallICGetter4(
11920 Local<String> name,
11921 const v8::PropertyCallbackInfo<v8::Value>& info) {
11922 ApiTestFuzzer::Fuzz();
11923 CHECK(v8_str("x")->Equals(name));
11924 info.GetReturnValue().Set(call_ic_function4);
11925 }
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
THREADED_TEST(InterceptorCallICCacheableNotNeeded)11931 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11932 v8::Isolate* isolate = CcTest::isolate();
11933 v8::HandleScope scope(isolate);
11934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11935 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(
11941 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11942 "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
THREADED_TEST(InterceptorCallICInvalidatedCacheable)11952 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11953 v8::Isolate* isolate = CcTest::isolate();
11954 v8::HandleScope scope(isolate);
11955 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11956 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
11978 // This test checks that if interceptor doesn't provide a function,
11979 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)11980 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11981 v8::Isolate* isolate = CcTest::isolate();
11982 v8::HandleScope scope(isolate);
11983 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11984 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
11999 static v8::Handle<Value> call_ic_function5;
InterceptorCallICGetter5(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12000 static void InterceptorCallICGetter5(
12001 Local<String> name,
12002 const v8::PropertyCallbackInfo<v8::Value>& info) {
12003 ApiTestFuzzer::Fuzz();
12004 if (v8_str("x")->Equals(name))
12005 info.GetReturnValue().Set(call_ic_function5);
12006 }
12007
12008
12009 // This test checks that if interceptor provides a function,
12010 // even if we cached constant function, interceptor's function
12011 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)12012 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12013 v8::Isolate* isolate = CcTest::isolate();
12014 v8::HandleScope scope(isolate);
12015 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12016 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
12033 static v8::Handle<Value> call_ic_function6;
InterceptorCallICGetter6(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12034 static void InterceptorCallICGetter6(
12035 Local<String> name,
12036 const v8::PropertyCallbackInfo<v8::Value>& info) {
12037 ApiTestFuzzer::Fuzz();
12038 if (v8_str("x")->Equals(name))
12039 info.GetReturnValue().Set(call_ic_function6);
12040 }
12041
12042
12043 // Same test as above, except the code is wrapped in a function
12044 // to test the optimized compiler.
THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped)12045 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12046 i::FLAG_allow_natives_syntax = true;
12047 v8::Isolate* isolate = CcTest::isolate();
12048 v8::HandleScope scope(isolate);
12049 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12050 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
12075 // Test the case when we stored constant function into
12076 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)12077 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12078 v8::Isolate* isolate = CcTest::isolate();
12079 v8::HandleScope scope(isolate);
12080 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12081 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.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)12108 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12109 v8::Isolate* isolate = CcTest::isolate();
12110 v8::HandleScope scope(isolate);
12111 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12112 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
12133 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorCallICCachedFromGlobal)12134 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12135 v8::Isolate* isolate = CcTest::isolate();
12136 v8::HandleScope scope(isolate);
12137 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12138 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
InterceptorCallICFastApi(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12162 static void InterceptorCallICFastApi(
12163 Local<String> name,
12164 const v8::PropertyCallbackInfo<v8::Value>& info) {
12165 ApiTestFuzzer::Fuzz();
12166 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12167 int* call_count =
12168 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12169 ++(*call_count);
12170 if ((*call_count) % 20 == 0) {
12171 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12172 }
12173 }
12174
FastApiCallback_TrivialSignature(const v8::FunctionCallbackInfo<v8::Value> & args)12175 static void FastApiCallback_TrivialSignature(
12176 const v8::FunctionCallbackInfo<v8::Value>& args) {
12177 ApiTestFuzzer::Fuzz();
12178 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12179 v8::Isolate* isolate = CcTest::isolate();
12180 CHECK_EQ(isolate, args.GetIsolate());
12181 CHECK_EQ(args.This(), args.Holder());
12182 CHECK(args.Data()->Equals(v8_str("method_data")));
12183 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12184 }
12185
FastApiCallback_SimpleSignature(const v8::FunctionCallbackInfo<v8::Value> & args)12186 static void FastApiCallback_SimpleSignature(
12187 const v8::FunctionCallbackInfo<v8::Value>& args) {
12188 ApiTestFuzzer::Fuzz();
12189 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12190 v8::Isolate* isolate = CcTest::isolate();
12191 CHECK_EQ(isolate, args.GetIsolate());
12192 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")));
12197 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12198 }
12199
12200
12201 // Helper to maximize the odds of object moving.
GenerateSomeGarbage()12202 static 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
12211
DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value> & args)12212 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12213 static int count = 0;
12214 if (count++ % 3 == 0) {
12215 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12216 // This should move the stub
12217 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12218 }
12219 }
12220
12221
THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub)12222 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12223 LocalContext context;
12224 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));
12231 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
ThrowingDirectApiCallback(const v8::FunctionCallbackInfo<v8::Value> & args)12244 void ThrowingDirectApiCallback(
12245 const v8::FunctionCallbackInfo<v8::Value>& args) {
12246 args.GetIsolate()->ThrowException(v8_str("g"));
12247 }
12248
12249
THREADED_TEST(CallICFastApi_DirectCall_Throw)12250 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12251 LocalContext context;
12252 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));
12259 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
DoDirectGetter()12274 static Handle<Value> DoDirectGetter() {
12275 if (++p_getter_count % 3 == 0) {
12276 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12277 GenerateSomeGarbage();
12278 }
12279 return v8_str("Direct Getter Result");
12280 }
12281
DirectGetterCallback(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12282 static void DirectGetterCallback(
12283 Local<String> name,
12284 const v8::PropertyCallbackInfo<v8::Value>& info) {
12285 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12286 info.GetReturnValue().Set(DoDirectGetter());
12287 }
12288
12289
12290 template<typename Accessor>
LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor)12291 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12292 LocalContext context;
12293 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);
12297 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12298 p_getter_count = 0;
12299 v8::Handle<v8::Value> result = CompileRun(
12300 "function f() {"
12301 " for (var i = 0; i < 30; i++) o1.p1;"
12302 " return o1.p1"
12303 "}"
12304 "f();");
12305 CHECK_EQ(v8_str("Direct Getter Result"), result);
12306 CHECK_EQ(31, p_getter_count);
12307 }
12308
12309
THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub)12310 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12311 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12312 }
12313
12314
ThrowingDirectGetterCallback(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12315 void ThrowingDirectGetterCallback(
12316 Local<String> name,
12317 const v8::PropertyCallbackInfo<v8::Value>& info) {
12318 info.GetIsolate()->ThrowException(v8_str("g"));
12319 }
12320
12321
THREADED_TEST(LoadICFastApi_DirectCall_Throw)12322 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12323 LocalContext context;
12324 v8::Isolate* isolate = context->GetIsolate();
12325 v8::HandleScope scope(isolate);
12326 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12327 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
THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature)12339 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12340 int interceptor_call_count = 0;
12341 v8::Isolate* isolate = CcTest::isolate();
12342 v8::HandleScope scope(isolate);
12343 v8::Handle<v8::FunctionTemplate> fun_templ =
12344 v8::FunctionTemplate::New(isolate);
12345 v8::Handle<v8::FunctionTemplate> method_templ =
12346 v8::FunctionTemplate::New(isolate,
12347 FastApiCallback_TrivialSignature,
12348 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();
12353 templ->SetNamedPropertyHandler(
12354 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12355 v8::External::New(isolate, &interceptor_call_count));
12356 LocalContext context;
12357 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12358 GenerateSomeGarbage();
12359 context->Global()->Set(v8_str("o"), fun->NewInstance());
12360 CompileRun(
12361 "var result = 0;"
12362 "for (var i = 0; i < 100; i++) {"
12363 " result = o.method(41);"
12364 "}");
12365 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12366 CHECK_EQ(100, interceptor_call_count);
12367 }
12368
12369
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature)12370 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12371 int interceptor_call_count = 0;
12372 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));
12379 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12380 proto_templ->Set(v8_str("method"), method_templ);
12381 fun_templ->SetHiddenPrototype(true);
12382 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12383 templ->SetNamedPropertyHandler(
12384 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12385 v8::External::New(isolate, &interceptor_call_count));
12386 LocalContext context;
12387 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12388 GenerateSomeGarbage();
12389 context->Global()->Set(v8_str("o"), fun->NewInstance());
12390 CompileRun(
12391 "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);"
12397 "}");
12398 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12399 CHECK_EQ(100, interceptor_call_count);
12400 }
12401
12402
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1)12403 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12404 int interceptor_call_count = 0;
12405 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));
12412 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12413 proto_templ->Set(v8_str("method"), method_templ);
12414 fun_templ->SetHiddenPrototype(true);
12415 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12416 templ->SetNamedPropertyHandler(
12417 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12418 v8::External::New(isolate, &interceptor_call_count));
12419 LocalContext context;
12420 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12421 GenerateSomeGarbage();
12422 context->Global()->Set(v8_str("o"), fun->NewInstance());
12423 CompileRun(
12424 "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 " }"
12435 "}");
12436 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
12441
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2)12442 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12443 int interceptor_call_count = 0;
12444 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));
12451 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12452 proto_templ->Set(v8_str("method"), method_templ);
12453 fun_templ->SetHiddenPrototype(true);
12454 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12455 templ->SetNamedPropertyHandler(
12456 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12457 v8::External::New(isolate, &interceptor_call_count));
12458 LocalContext context;
12459 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12460 GenerateSomeGarbage();
12461 context->Global()->Set(v8_str("o"), fun->NewInstance());
12462 CompileRun(
12463 "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 " }"
12474 "}");
12475 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
12480
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3)12481 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12482 int interceptor_call_count = 0;
12483 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));
12490 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12491 proto_templ->Set(v8_str("method"), method_templ);
12492 fun_templ->SetHiddenPrototype(true);
12493 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12494 templ->SetNamedPropertyHandler(
12495 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12496 v8::External::New(isolate, &interceptor_call_count));
12497 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;
12502 CompileRun(
12503 "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 " }"
12514 "}");
12515 CHECK(try_catch.HasCaught());
12516 // TODO(verwaest): Adjust message.
12517 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12518 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
12523
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError)12524 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12525 int interceptor_call_count = 0;
12526 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));
12533 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12534 proto_templ->Set(v8_str("method"), method_templ);
12535 fun_templ->SetHiddenPrototype(true);
12536 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12537 templ->SetNamedPropertyHandler(
12538 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12539 v8::External::New(isolate, &interceptor_call_count));
12540 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;
12545 CompileRun(
12546 "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 " }"
12557 "}");
12558 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
12565
THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature)12566 THREADED_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);
12571 v8::Handle<v8::FunctionTemplate> method_templ =
12572 v8::FunctionTemplate::New(isolate,
12573 FastApiCallback_TrivialSignature,
12574 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);
12578 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12579 USE(templ);
12580 LocalContext context;
12581 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12582 GenerateSomeGarbage();
12583 context->Global()->Set(v8_str("o"), fun->NewInstance());
12584 CompileRun(
12585 "var result = 0;"
12586 "for (var i = 0; i < 100; i++) {"
12587 " result = o.method(41);"
12588 "}");
12589
12590 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12591 }
12592
12593
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature)12594 THREADED_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));
12602 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12603 proto_templ->Set(v8_str("method"), method_templ);
12604 fun_templ->SetHiddenPrototype(true);
12605 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12606 CHECK(!templ.IsEmpty());
12607 LocalContext context;
12608 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12609 GenerateSomeGarbage();
12610 context->Global()->Set(v8_str("o"), fun->NewInstance());
12611 CompileRun(
12612 "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);"
12618 "}");
12619
12620 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12621 }
12622
12623
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1)12624 THREADED_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));
12632 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12633 proto_templ->Set(v8_str("method"), method_templ);
12634 fun_templ->SetHiddenPrototype(true);
12635 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12636 CHECK(!templ.IsEmpty());
12637 LocalContext context;
12638 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12639 GenerateSomeGarbage();
12640 context->Global()->Set(v8_str("o"), fun->NewInstance());
12641 CompileRun(
12642 "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 " }"
12653 "}");
12654 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12655 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12656 }
12657
12658
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2)12659 THREADED_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));
12667 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12668 proto_templ->Set(v8_str("method"), method_templ);
12669 fun_templ->SetHiddenPrototype(true);
12670 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12671 CHECK(!templ.IsEmpty());
12672 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;
12677 CompileRun(
12678 "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 " }"
12689 "}");
12690 CHECK(try_catch.HasCaught());
12691 // 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
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError)12698 THREADED_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"),
12731 try_catch.Exception()->ToString());
12732 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12733 }
12734
12735
12736 v8::Handle<Value> keyed_call_ic_function;
12737
InterceptorKeyedCallICGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12738 static void InterceptorKeyedCallICGetter(
12739 Local<String> name,
12740 const v8::PropertyCallbackInfo<v8::Value>& info) {
12741 ApiTestFuzzer::Fuzz();
12742 if (v8_str("x")->Equals(name)) {
12743 info.GetReturnValue().Set(keyed_call_ic_function);
12744 }
12745 }
12746
12747
12748 // Test the case when we stored cacheable lookup into
12749 // a stub, but the function name changed (to another cacheable function).
THREADED_TEST(InterceptorKeyedCallICKeyChange1)12750 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12751 v8::Isolate* isolate = CcTest::isolate();
12752 v8::HandleScope scope(isolate);
12753 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12754 templ->SetNamedPropertyHandler(NoBlockGetterX);
12755 LocalContext context;
12756 context->Global()->Set(v8_str("o"), templ->NewInstance());
12757 CompileRun(
12758 "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);"
12767 "}");
12768 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).
THREADED_TEST(InterceptorKeyedCallICKeyChange2)12775 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12776 v8::Isolate* isolate = CcTest::isolate();
12777 v8::HandleScope scope(isolate);
12778 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12779 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();
12784 CompileRun(
12785 "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);"
12796 "}");
12797 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.
THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal)12803 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12804 v8::Isolate* isolate = CcTest::isolate();
12805 v8::HandleScope scope(isolate);
12806 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12807 templ->SetNamedPropertyHandler(NoBlockGetterX);
12808 LocalContext context;
12809 context->Global()->Set(v8_str("o"), templ->NewInstance());
12810 CompileRun(
12811 "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);"
12823 "}");
12824 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.
THREADED_TEST(InterceptorKeyedCallICFromGlobal)12829 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12830 v8::Isolate* isolate = CcTest::isolate();
12831 v8::HandleScope scope(isolate);
12832 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12833 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12834 LocalContext context;
12835 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12836
12837 CompileRun(
12838 "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');"
12848 "}");
12849 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12850 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12851 }
12852
12853
12854 // Test the map transition before the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore)12855 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12856 v8::Isolate* isolate = CcTest::isolate();
12857 v8::HandleScope scope(isolate);
12858 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12859 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12860 LocalContext context;
12861 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12862
12863 CompileRun(
12864 "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);"
12872 "}");
12873 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12874 }
12875
12876
12877 // Test the map transition after the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeAfter)12878 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12879 v8::Isolate* isolate = CcTest::isolate();
12880 v8::HandleScope scope(isolate);
12881 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12882 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12883 LocalContext context;
12884 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12885
12886 CompileRun(
12887 "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);"
12895 "}");
12896 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12897 }
12898
12899
12900 static int interceptor_call_count = 0;
12901
InterceptorICRefErrorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12902 static void InterceptorICRefErrorGetter(
12903 Local<String> name,
12904 const v8::PropertyCallbackInfo<v8::Value>& info) {
12905 ApiTestFuzzer::Fuzz();
12906 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12907 info.GetReturnValue().Set(call_ic_function2);
12908 }
12909 }
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.
THREADED_TEST(InterceptorICReferenceErrors)12915 THREADED_TEST(InterceptorICReferenceErrors) {
12916 v8::Isolate* isolate = CcTest::isolate();
12917 v8::HandleScope scope(isolate);
12918 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12919 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
12944 static int interceptor_ic_exception_get_count = 0;
12945
InterceptorICExceptionGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12946 static void InterceptorICExceptionGetter(
12947 Local<String> name,
12948 const v8::PropertyCallbackInfo<v8::Value>& info) {
12949 ApiTestFuzzer::Fuzz();
12950 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12951 info.GetReturnValue().Set(call_ic_function3);
12952 }
12953 if (interceptor_ic_exception_get_count == 20) {
12954 info.GetIsolate()->ThrowException(v8_num(42));
12955 return;
12956 }
12957 }
12958
12959
12960 // Test interceptor load/call IC where the interceptor throws an
12961 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)12962 THREADED_TEST(InterceptorICGetterExceptions) {
12963 interceptor_ic_exception_get_count = 0;
12964 v8::Isolate* isolate = CcTest::isolate();
12965 v8::HandleScope scope(isolate);
12966 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12967 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
12992 static int interceptor_ic_exception_set_count = 0;
12993
InterceptorICExceptionSetter(Local<String> key,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)12994 static void InterceptorICExceptionSetter(
12995 Local<String> key,
12996 Local<Value> value,
12997 const v8::PropertyCallbackInfo<v8::Value>& info) {
12998 ApiTestFuzzer::Fuzz();
12999 if (++interceptor_ic_exception_set_count > 20) {
13000 info.GetIsolate()->ThrowException(v8_num(42));
13001 }
13002 }
13003
13004
13005 // Test interceptor store IC where the interceptor throws an exception
13006 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)13007 THREADED_TEST(InterceptorICSetterExceptions) {
13008 interceptor_ic_exception_set_count = 0;
13009 v8::Isolate* isolate = CcTest::isolate();
13010 v8::HandleScope scope(isolate);
13011 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13012 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.
THREADED_TEST(NullNamedInterceptor)13027 THREADED_TEST(NullNamedInterceptor) {
13028 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));
13033 LocalContext context;
13034 templ->Set(CcTest::isolate(), "x", v8_num(42));
13035 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.
THREADED_TEST(NullIndexedInterceptor)13044 THREADED_TEST(NullIndexedInterceptor) {
13045 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));
13050 LocalContext context;
13051 templ->Set(CcTest::isolate(), "42", v8_num(42));
13052 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
THREADED_TEST(NamedPropertyHandlerGetterAttributes)13060 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13061 v8::Isolate* isolate = CcTest::isolate();
13062 v8::HandleScope scope(isolate);
13063 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13064 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
ThrowingGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)13073 static void ThrowingGetter(Local<String> name,
13074 const v8::PropertyCallbackInfo<v8::Value>& info) {
13075 ApiTestFuzzer::Fuzz();
13076 info.GetIsolate()->ThrowException(Handle<Value>());
13077 info.GetReturnValue().SetUndefined();
13078 }
13079
13080
THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks)13081 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13082 LocalContext context;
13083 HandleScope scope(context->GetIsolate());
13084
13085 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13086 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13087 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13088
13089 Local<Object> instance = templ->GetFunction()->NewInstance();
13090
13091 Local<Object> another = Object::New(context->GetIsolate());
13092 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
ThrowingCallbackWithTryCatch(const v8::FunctionCallbackInfo<v8::Value> & args)13134 static void ThrowingCallbackWithTryCatch(
13135 const v8::FunctionCallbackInfo<v8::Value>& args) {
13136 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());
13142 CHECK(!CcTest::i_isolate()->has_pending_exception());
13143 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13144 }
13145
13146
13147 static int call_depth;
13148
13149
WithTryCatch(Handle<Message> message,Handle<Value> data)13150 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13151 TryCatch try_catch;
13152 }
13153
13154
ThrowFromJS(Handle<Message> message,Handle<Value> data)13155 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13156 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13157 }
13158
13159
ThrowViaApi(Handle<Message> message,Handle<Value> data)13160 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13161 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13162 }
13163
13164
WebKitLike(Handle<Message> message,Handle<Value> data)13165 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13166 Handle<String> errorMessageString = message->Get();
13167 CHECK(!errorMessageString.IsEmpty());
13168 message->GetStackTrace();
13169 message->GetScriptOrigin().ResourceName();
13170 }
13171
13172
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch)13173 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13174 LocalContext context;
13175 v8::Isolate* isolate = context->GetIsolate();
13176 HandleScope scope(isolate);
13177
13178 Local<Function> func =
13179 FunctionTemplate::New(isolate,
13180 ThrowingCallbackWithTryCatch)->GetFunction();
13181 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 }
13190 // Some small number to control number of times message handler should
13191 // throw an exception.
13192 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
ParentGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)13204 static void ParentGetter(Local<String> name,
13205 const v8::PropertyCallbackInfo<v8::Value>& info) {
13206 ApiTestFuzzer::Fuzz();
13207 info.GetReturnValue().Set(v8_num(1));
13208 }
13209
13210
ChildGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)13211 static void ChildGetter(Local<String> name,
13212 const v8::PropertyCallbackInfo<v8::Value>& info) {
13213 ApiTestFuzzer::Fuzz();
13214 info.GetReturnValue().Set(v8_num(42));
13215 }
13216
13217
THREADED_TEST(Overriding)13218 THREADED_TEST(Overriding) {
13219 LocalContext context;
13220 v8::Isolate* isolate = context->GetIsolate();
13221 v8::HandleScope scope(isolate);
13222
13223 // Parent template.
13224 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13225 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.
13230 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13231 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
13266 // Check that 'h' cannot be shadowed.
13267 value = v8_compile("o.h = 3; o.h")->Run();
13268 CHECK_EQ(1, value->Int32Value());
13269
13270 // Check that 'i' cannot be shadowed or changed.
13271 value = v8_compile("o.i = 3; o.i")->Run();
13272 CHECK_EQ(42, value->Int32Value());
13273 }
13274
13275
IsConstructHandler(const v8::FunctionCallbackInfo<v8::Value> & args)13276 static void IsConstructHandler(
13277 const v8::FunctionCallbackInfo<v8::Value>& args) {
13278 ApiTestFuzzer::Fuzz();
13279 args.GetReturnValue().Set(args.IsConstructCall());
13280 }
13281
13282
THREADED_TEST(IsConstructCall)13283 THREADED_TEST(IsConstructCall) {
13284 v8::Isolate* isolate = CcTest::isolate();
13285 v8::HandleScope scope(isolate);
13286
13287 // Function template with call handler.
13288 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13289 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
THREADED_TEST(ObjectProtoToString)13301 THREADED_TEST(ObjectProtoToString) {
13302 v8::Isolate* isolate = CcTest::isolate();
13303 v8::HandleScope scope(isolate);
13304 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13305 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();
13331 value = object.As<v8::Object>()->ObjectProtoToString();
13332 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13333 }
13334
13335
THREADED_TEST(ObjectGetConstructorName)13336 THREADED_TEST(ObjectGetConstructorName) {
13337 LocalContext context;
13338 v8::HandleScope scope(context->GetIsolate());
13339 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
13361 bool ApiTestFuzzer::fuzzing_ = false;
13362 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13363 int ApiTestFuzzer::active_tests_;
13364 int ApiTestFuzzer::tests_being_run_;
13365 int 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).
Fuzz()13370 void 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.
NextThread()13379 bool ApiTestFuzzer::NextThread() {
13380 int test_position = GetNextTestNumber();
13381 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13382 if (test_position == current_) {
13383 if (kLogThreading)
13384 printf("Stay with %s\n", test_name);
13385 return false;
13386 }
13387 if (kLogThreading) {
13388 printf("Switch from %s to %s\n",
13389 test_name,
13390 RegisterThreadedTest::nth(test_position)->name());
13391 }
13392 current_ = test_position;
13393 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13394 return true;
13395 }
13396
13397
Run()13398 void ApiTestFuzzer::Run() {
13399 // When it is our turn...
13400 gate_.Wait();
13401 {
13402 // ... get the V8 lock and start running the test.
13403 v8::Locker locker(CcTest::isolate());
13404 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) {
13411 all_tests_done_.Signal();
13412 } else {
13413 // Otherwise select a new test and start that.
13414 NextThread();
13415 }
13416 }
13417
13418
13419 static unsigned linear_congruential_generator;
13420
13421
SetUp(PartOfTest part)13422 void ApiTestFuzzer::SetUp(PartOfTest part) {
13423 linear_congruential_generator = i::FLAG_testing_prng_seed;
13424 fuzzing_ = true;
13425 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;
13429 for (int i = 0; i < tests_being_run_; i++) {
13430 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13431 }
13432 for (int i = 0; i < active_tests_; i++) {
13433 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13434 }
13435 }
13436
13437
CallTestNumber(int test_number)13438 static void CallTestNumber(int test_number) {
13439 (RegisterThreadedTest::nth(test_number)->callback())();
13440 }
13441
13442
RunAllTests()13443 void ApiTestFuzzer::RunAllTests() {
13444 // Set off the first test.
13445 current_ = -1;
13446 NextThread();
13447 // Wait till they are all done.
13448 all_tests_done_.Wait();
13449 }
13450
13451
GetNextTestNumber()13452 int 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
ContextSwitch()13463 void 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.
13467 v8::Unlocker unlocker(CcTest::isolate());
13468 // Wait till someone starts us again.
13469 gate_.Wait();
13470 // And we're off.
13471 }
13472 }
13473
13474
TearDown()13475 void 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.
TEST(Threading1)13485 TEST(Threading1) {
13486 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13487 ApiTestFuzzer::RunAllTests();
13488 ApiTestFuzzer::TearDown();
13489 }
13490
13491
TEST(Threading2)13492 TEST(Threading2) {
13493 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13494 ApiTestFuzzer::RunAllTests();
13495 ApiTestFuzzer::TearDown();
13496 }
13497
13498
TEST(Threading3)13499 TEST(Threading3) {
13500 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13501 ApiTestFuzzer::RunAllTests();
13502 ApiTestFuzzer::TearDown();
13503 }
13504
13505
TEST(Threading4)13506 TEST(Threading4) {
13507 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13508 ApiTestFuzzer::RunAllTests();
13509 ApiTestFuzzer::TearDown();
13510 }
13511
13512
CallTest()13513 void ApiTestFuzzer::CallTest() {
13514 v8::Isolate::Scope scope(CcTest::isolate());
13515 if (kLogThreading)
13516 printf("Start test %d\n", test_number_);
13517 CallTestNumber(test_number_);
13518 if (kLogThreading)
13519 printf("End test %d\n", test_number_);
13520 }
13521
13522
ThrowInJS(const v8::FunctionCallbackInfo<v8::Value> & args)13523 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13524 v8::Isolate* isolate = args.GetIsolate();
13525 CHECK(v8::Locker::IsLocked(isolate));
13526 ApiTestFuzzer::Fuzz();
13527 v8::Unlocker unlocker(isolate);
13528 const char* code = "throw 7;";
13529 {
13530 v8::Locker nested_locker(isolate);
13531 v8::HandleScope scope(isolate);
13532 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.
13540 exception = Local<Value>::New(isolate, try_catch.Exception());
13541 }
13542 args.GetIsolate()->ThrowException(exception);
13543 }
13544 }
13545
13546
ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value> & args)13547 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13548 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13549 ApiTestFuzzer::Fuzz();
13550 v8::Unlocker unlocker(CcTest::isolate());
13551 const char* code = "throw 7;";
13552 {
13553 v8::Locker nested_locker(CcTest::isolate());
13554 v8::HandleScope scope(args.GetIsolate());
13555 v8::Handle<Value> value = CompileRun(code);
13556 CHECK(value.IsEmpty());
13557 args.GetReturnValue().Set(v8_str("foo"));
13558 }
13559 }
13560
13561
13562 // These are locking tests that don't need to be run again
13563 // as part of the locking aggregation tests.
TEST(NestedLockers)13564 TEST(NestedLockers) {
13565 v8::Isolate* isolate = CcTest::isolate();
13566 v8::Locker locker(isolate);
13567 CHECK(v8::Locker::IsLocked(isolate));
13568 LocalContext env;
13569 v8::HandleScope scope(env->GetIsolate());
13570 Local<v8::FunctionTemplate> fun_templ =
13571 v8::FunctionTemplate::New(isolate, ThrowInJS);
13572 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.
TEST(NestedLockersNoTryCatch)13588 TEST(NestedLockersNoTryCatch) {
13589 v8::Locker locker(CcTest::isolate());
13590 LocalContext env;
13591 v8::HandleScope scope(env->GetIsolate());
13592 Local<v8::FunctionTemplate> fun_templ =
13593 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13594 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
THREADED_TEST(RecursiveLocking)13608 THREADED_TEST(RecursiveLocking) {
13609 v8::Locker locker(CcTest::isolate());
13610 {
13611 v8::Locker locker2(CcTest::isolate());
13612 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13613 }
13614 }
13615
13616
UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value> & args)13617 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13618 ApiTestFuzzer::Fuzz();
13619 v8::Unlocker unlocker(CcTest::isolate());
13620 }
13621
13622
THREADED_TEST(LockUnlockLock)13623 THREADED_TEST(LockUnlockLock) {
13624 {
13625 v8::Locker locker(CcTest::isolate());
13626 v8::HandleScope scope(CcTest::isolate());
13627 LocalContext env;
13628 Local<v8::FunctionTemplate> fun_templ =
13629 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13630 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 {
13639 v8::Locker locker(CcTest::isolate());
13640 v8::HandleScope scope(CcTest::isolate());
13641 LocalContext env;
13642 Local<v8::FunctionTemplate> fun_templ =
13643 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13644 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
GetGlobalObjectsCount()13655 static int GetGlobalObjectsCount() {
13656 int count = 0;
13657 i::HeapIterator it(CcTest::heap());
13658 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13659 if (object->IsJSGlobalObject()) count++;
13660 return count;
13661 }
13662
13663
CheckSurvivingGlobalObjectsCount(int expected)13664 static void CheckSurvivingGlobalObjectsCount(int expected) {
13665 // 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.
13670 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13671 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13672 int count = GetGlobalObjectsCount();
13673 #ifdef DEBUG
13674 if (count != expected) CcTest::heap()->TracePathToGlobal();
13675 #endif
13676 CHECK_EQ(expected, count);
13677 }
13678
13679
TEST(DontLeakGlobalObjects)13680 TEST(DontLeakGlobalObjects) {
13681 // Regression test for issues 1139850 and 1174891.
13682
13683 i::FLAG_expose_gc = true;
13684 v8::V8::Initialize();
13685
13686 for (int i = 0; i < 5; i++) {
13687 { v8::HandleScope scope(CcTest::isolate());
13688 LocalContext context;
13689 }
13690 CcTest::isolate()->ContextDisposedNotification();
13691 CheckSurvivingGlobalObjectsCount(0);
13692
13693 { v8::HandleScope scope(CcTest::isolate());
13694 LocalContext context;
13695 v8_compile("Date")->Run();
13696 }
13697 CcTest::isolate()->ContextDisposedNotification();
13698 CheckSurvivingGlobalObjectsCount(0);
13699
13700 { v8::HandleScope scope(CcTest::isolate());
13701 LocalContext context;
13702 v8_compile("/aaa/")->Run();
13703 }
13704 CcTest::isolate()->ContextDisposedNotification();
13705 CheckSurvivingGlobalObjectsCount(0);
13706
13707 { v8::HandleScope scope(CcTest::isolate());
13708 const char* extension_list[] = { "v8/gc" };
13709 v8::ExtensionConfiguration extensions(1, extension_list);
13710 LocalContext context(&extensions);
13711 v8_compile("gc();")->Run();
13712 }
13713 CcTest::isolate()->ContextDisposedNotification();
13714 CheckSurvivingGlobalObjectsCount(0);
13715 }
13716 }
13717
13718
TEST(CopyablePersistent)13719 TEST(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
WeakApiCallback(const v8::WeakCallbackData<v8::Object,Persistent<v8::Object>> & data)13747 static 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
TEST(WeakCallbackApi)13756 TEST(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
13778 v8::Persistent<v8::Object> some_object;
13779 v8::Persistent<v8::Object> bad_handle;
13780
NewPersistentHandleCallback(const v8::WeakCallbackData<v8::Object,v8::Persistent<v8::Object>> & data)13781 void 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();
13786 }
13787
13788
THREADED_TEST(NewPersistentHandleFromWeakCallback)13789 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13790 LocalContext context;
13791 v8::Isolate* isolate = context->GetIsolate();
13792
13793 v8::Persistent<v8::Object> handle1, handle2;
13794 {
13795 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));
13799 }
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.
13804 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13805 handle2.Reset();
13806 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13807 }
13808
13809
13810 v8::Persistent<v8::Object> to_be_disposed;
13811
DisposeAndForceGcCallback(const v8::WeakCallbackData<v8::Object,v8::Persistent<v8::Object>> & data)13812 void 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();
13817 }
13818
13819
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc)13820 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13821 LocalContext context;
13822 v8::Isolate* isolate = context->GetIsolate();
13823
13824 v8::Persistent<v8::Object> handle1, handle2;
13825 {
13826 v8::HandleScope scope(isolate);
13827 handle1.Reset(isolate, v8::Object::New(isolate));
13828 handle2.Reset(isolate, v8::Object::New(isolate));
13829 }
13830 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13831 to_be_disposed.Reset(isolate, handle2);
13832 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13833 }
13834
DisposingCallback(const v8::WeakCallbackData<v8::Object,v8::Persistent<v8::Object>> & data)13835 void DisposingCallback(
13836 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13837 data.GetParameter()->Reset();
13838 }
13839
HandleCreatingCallback(const v8::WeakCallbackData<v8::Object,v8::Persistent<v8::Object>> & data)13840 void 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();
13846 }
13847
13848
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback)13849 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13850 LocalContext context;
13851 v8::Isolate* isolate = context->GetIsolate();
13852
13853 v8::Persistent<v8::Object> handle1, handle2, handle3;
13854 {
13855 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));
13859 }
13860 handle2.SetWeak(&handle2, DisposingCallback);
13861 handle3.SetWeak(&handle3, HandleCreatingCallback);
13862 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13863 }
13864
13865
THREADED_TEST(CheckForCrossContextObjectLiterals)13866 THREADED_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];
13877 { v8::HandleScope scope(CcTest::isolate());
13878 LocalContext context;
13879 CompileRun(source);
13880 }
13881 { v8::HandleScope scope(CcTest::isolate());
13882 LocalContext context;
13883 CompileRun(source);
13884 }
13885 }
13886 }
13887
13888
NestedScope(v8::Local<Context> env)13889 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13890 v8::EscapableHandleScope inner(env->GetIsolate());
13891 env->Enter();
13892 v8::Local<Value> three = v8_num(3);
13893 v8::Local<Value> value = inner.Escape(three);
13894 env->Exit();
13895 return value;
13896 }
13897
13898
THREADED_TEST(NestedHandleScopeAndContexts)13899 THREADED_TEST(NestedHandleScopeAndContexts) {
13900 v8::Isolate* isolate = CcTest::isolate();
13901 v8::HandleScope outer(isolate);
13902 v8::Local<Context> env = Context::New(isolate);
13903 env->Enter();
13904 v8::Handle<Value> value = NestedScope(env);
13905 v8::Handle<String> str(value->ToString());
13906 CHECK(!str.IsEmpty());
13907 env->Exit();
13908 }
13909
13910
MatchPointers(void * key1,void * key2)13911 static bool MatchPointers(void* key1, void* key2) {
13912 return key1 == key2;
13913 }
13914
13915
13916 struct SymbolInfo {
13917 size_t id;
13918 size_t size;
13919 std::string name;
13920 };
13921
13922
13923 class SetFunctionEntryHookTest {
13924 public:
SetFunctionEntryHookTest()13925 SetFunctionEntryHookTest() {
13926 CHECK(instance_ == NULL);
13927 instance_ = this;
13928 }
~SetFunctionEntryHookTest()13929 ~SetFunctionEntryHookTest() {
13930 CHECK(instance_ == this);
13931 instance_ = NULL;
13932 }
Reset()13933 void Reset() {
13934 symbols_.clear();
13935 symbol_locations_.clear();
13936 invocations_.clear();
13937 }
13938 void RunTest();
13939 void OnJitEvent(const v8::JitCodeEvent* event);
JitEvent(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);
EntryHook(uintptr_t function,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
RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value> & args)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 };
13981 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13982
13983
13984 // Returns true if addr is in the range [start, start+len).
Overlaps(i::Address start,size_t len,i::Address addr)13985 static 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
InsertSymbolAt(i::Address addr,SymbolInfo * symbol)13992 void 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
OnJitEvent(const v8::JitCodeEvent * event)14019 void 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
OnEntryHook(uintptr_t function,uintptr_t return_addr_location)14062 void 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
FindSymbolForAddr(i::Address addr)14094 SymbolInfo* 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
CountInvocations(const char * caller_name,const char * function_name)14115 int 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
RunLoopInNewEnv(v8::Isolate * isolate)14145 void 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
RunTest()14188 void 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
TEST(SetFunctionEntryHook)14230 TEST(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
14243 static i::HashMap* code_map = NULL;
14244 static i::HashMap* jitcode_line_info = NULL;
14245 static int saw_bar = 0;
14246 static int move_events = 0;
14247
14248
FunctionNameIs(const char * expected,const v8::JitCodeEvent * event)14249 static 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
event_handler(const v8::JitCodeEvent * event)14286 static 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
UNINITIALIZED_TEST(SetJitCodeEventHandler)14386 UNINITIALIZED_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();
14488 }
14489
14490
THREADED_TEST(ExternalAllocatedMemory)14491 THREADED_TEST(ExternalAllocatedMemory) {
14492 v8::Isolate* isolate = CcTest::isolate();
14493 v8::HandleScope outer(isolate);
14494 v8::Local<Context> env(Context::New(isolate));
14495 CHECK(!env.IsEmpty());
14496 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));
14502 }
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.
THREADED_TEST(Regress54)14508 THREADED_TEST(Regress54) {
14509 LocalContext context;
14510 v8::Isolate* isolate = context->GetIsolate();
14511 v8::HandleScope outer(isolate);
14512 static v8::Persistent<v8::ObjectTemplate> templ;
14513 if (templ.IsEmpty()) {
14514 v8::EscapableHandleScope inner(isolate);
14515 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14516 local->SetInternalFieldCount(1);
14517 templ.Reset(isolate, inner.Escape(local));
14518 }
14519 v8::Handle<v8::Object> result =
14520 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14521 CHECK_EQ(1, result->InternalFieldCount());
14522 }
14523
14524
14525 // If part of the threaded tests, this test makes ThreadingTest fail
14526 // on mac.
TEST(CatchStackOverflow)14527 TEST(CatchStackOverflow) {
14528 LocalContext context;
14529 v8::HandleScope scope(context->GetIsolate());
14530 v8::TryCatch try_catch;
14531 v8::Handle<v8::Value> result = CompileRun(
14532 "function f() {"
14533 " return f();"
14534 "}"
14535 ""
14536 "f();");
14537 CHECK(result.IsEmpty());
14538 }
14539
14540
CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,const char * resource_name,int line_offset)14541 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14542 const char* resource_name,
14543 int line_offset) {
14544 v8::HandleScope scope(CcTest::isolate());
14545 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());
14556 v8::String::Utf8Value line(message->GetSourceLine());
14557 CHECK_EQ(" throw 'nirk';", *line);
14558 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14559 CHECK_EQ(resource_name, *name);
14560 }
14561
14562
THREADED_TEST(TryCatchSourceInfo)14563 THREADED_TEST(TryCatchSourceInfo) {
14564 LocalContext context;
14565 v8::HandleScope scope(context->GetIsolate());
14566 v8::Local<v8::String> source = v8_str(
14567 "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";
14584 script = CompileWithOrigin(source, resource_name);
14585 CheckTryCatchSourceInfo(script, resource_name, 0);
14586
14587 resource_name = "test1.js";
14588 v8::ScriptOrigin origin1(
14589 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14590 script = v8::Script::Compile(source, &origin1);
14591 CheckTryCatchSourceInfo(script, resource_name, 0);
14592
14593 resource_name = "test2.js";
14594 v8::ScriptOrigin origin2(
14595 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14596 v8::Integer::New(context->GetIsolate(), 7));
14597 script = v8::Script::Compile(source, &origin2);
14598 CheckTryCatchSourceInfo(script, resource_name, 7);
14599 }
14600
14601
THREADED_TEST(CompilationCache)14602 THREADED_TEST(CompilationCache) {
14603 LocalContext context;
14604 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");
14611 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
FunctionNameCallback(const v8::FunctionCallbackInfo<v8::Value> & args)14619 static void FunctionNameCallback(
14620 const v8::FunctionCallbackInfo<v8::Value>& args) {
14621 ApiTestFuzzer::Fuzz();
14622 args.GetReturnValue().Set(v8_num(42));
14623 }
14624
14625
THREADED_TEST(CallbackFunctionName)14626 THREADED_TEST(CallbackFunctionName) {
14627 LocalContext context;
14628 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));
14633 context->Global()->Set(v8_str("obj"), t->NewInstance());
14634 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14635 CHECK(value->IsString());
14636 v8::String::Utf8Value name(value);
14637 CHECK_EQ("asdf", *name);
14638 }
14639
14640
THREADED_TEST(DateAccess)14641 THREADED_TEST(DateAccess) {
14642 LocalContext context;
14643 v8::HandleScope scope(context->GetIsolate());
14644 v8::Handle<v8::Value> date =
14645 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14646 CHECK(date->IsDate());
14647 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14648 }
14649
14650
CheckProperties(v8::Isolate * isolate,v8::Handle<v8::Value> val,int elmc,const char * elmv[])14651 void CheckProperties(v8::Isolate* isolate,
14652 v8::Handle<v8::Value> val,
14653 int elmc,
14654 const char* elmv[]) {
14655 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14656 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14657 CHECK_EQ(elmc, props->Length());
14658 for (int i = 0; i < elmc; i++) {
14659 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14660 CHECK_EQ(elmv[i], *elm);
14661 }
14662 }
14663
14664
CheckOwnProperties(v8::Isolate * isolate,v8::Handle<v8::Value> val,int elmc,const char * elmv[])14665 void CheckOwnProperties(v8::Isolate* isolate,
14666 v8::Handle<v8::Value> val,
14667 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++) {
14673 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14674 CHECK_EQ(elmv[i], *elm);
14675 }
14676 }
14677
14678
THREADED_TEST(PropertyEnumeration)14679 THREADED_TEST(PropertyEnumeration) {
14680 LocalContext context;
14681 v8::Isolate* isolate = context->GetIsolate();
14682 v8::HandleScope scope(isolate);
14683 v8::Handle<v8::Value> obj = CompileRun(
14684 "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;"
14691 "result;");
14692 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14693 CHECK_EQ(4, elms->Length());
14694 int elmc0 = 0;
14695 const char** elmv0 = NULL;
14696 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);
14700 int elmc1 = 2;
14701 const char* elmv1[] = {"a", "b"};
14702 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);
14706 int elmc2 = 3;
14707 const char* elmv2[] = {"0", "1", "2"};
14708 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);
14712 int elmc3 = 4;
14713 const char* elmv3[] = {"w", "z", "x", "y"};
14714 CheckProperties(
14715 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14716 int elmc4 = 2;
14717 const char* elmv4[] = {"w", "z"};
14718 CheckOwnProperties(
14719 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14720 }
14721
14722
THREADED_TEST(PropertyEnumeration2)14723 THREADED_TEST(PropertyEnumeration2) {
14724 LocalContext context;
14725 v8::Isolate* isolate = context->GetIsolate();
14726 v8::HandleScope scope(isolate);
14727 v8::Handle<v8::Value> obj = CompileRun(
14728 "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;"
14735 "result;");
14736 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14737 CHECK_EQ(4, elms->Length());
14738 int elmc0 = 0;
14739 const char** elmv0 = NULL;
14740 CheckProperties(isolate,
14741 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14742
14743 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14744 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 }
14750
NamedSetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)14751 static 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
IndexedSetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)14759 static 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
THREADED_TEST(DisableAccessChecksWhileConfiguring)14767 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14768 LocalContext context;
14769 v8::Isolate* isolate = context->GetIsolate();
14770 v8::HandleScope scope(isolate);
14771 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14772 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14773 IndexedSetAccessBlocker);
14774 templ->Set(v8_str("x"), v8::True(isolate));
14775 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
NamedGetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)14782 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14783 Local<Value> name,
14784 v8::AccessType type,
14785 Local<Value> data) {
14786 return false;
14787 }
14788
14789
IndexedGetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)14790 static 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
THREADED_TEST(AccessChecksReenabledCorrectly)14799 THREADED_TEST(AccessChecksReenabledCorrectly) {
14800 LocalContext context;
14801 v8::Isolate* isolate = context->GetIsolate();
14802 v8::HandleScope scope(isolate);
14803 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14804 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;
14818 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14819 }
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");
14827 CHECK(value_1.IsEmpty());
14828
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");
14833 CHECK(value_2.IsEmpty());
14834 }
14835
14836
14837 // This tests that access check information remains on the global
14838 // object template when creating contexts.
THREADED_TEST(AccessControlRepeatedContextCreation)14839 THREADED_TEST(AccessControlRepeatedContextCreation) {
14840 v8::Isolate* isolate = CcTest::isolate();
14841 v8::HandleScope handle_scope(isolate);
14842 v8::Handle<v8::ObjectTemplate> global_template =
14843 v8::ObjectTemplate::New(isolate);
14844 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());
14852 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14853 CHECK(!context0.IsEmpty());
14854 CHECK(!constructor->access_check_info()->IsUndefined());
14855 }
14856
14857
THREADED_TEST(TurnOnAccessCheck)14858 THREADED_TEST(TurnOnAccessCheck) {
14859 v8::Isolate* isolate = CcTest::isolate();
14860 v8::HandleScope handle_scope(isolate);
14861
14862 // Create an environment with access check to the global object disabled by
14863 // default.
14864 v8::Handle<v8::ObjectTemplate> global_template =
14865 v8::ObjectTemplate::New(isolate);
14866 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14867 IndexedGetAccessBlocker,
14868 v8::Handle<v8::Value>(),
14869 false);
14870 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14871 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.
14909 Local<Object> hidden_global = Local<Object>::Cast(
14910 context->Global()->GetPrototype());
14911 context->DetachGlobal();
14912 hidden_global->TurnOnAccessCheck();
14913
14914 // Failing access check results in exception.
14915 CHECK(f1->Call(global, 0, NULL).IsEmpty());
14916 CHECK(f2->Call(global, 0, NULL).IsEmpty());
14917 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
14925 static const char* kPropertyA = "a";
14926 static const char* kPropertyH = "h";
14927
NamedGetAccessBlockAandH(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)14928 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14929 Local<Value> name,
14930 v8::AccessType type,
14931 Local<Value> data) {
14932 if (!name->IsString()) return false;
14933 i::Handle<i::String> name_handle =
14934 v8::Utils::OpenHandle(String::Cast(*name));
14935 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14936 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14937 }
14938
14939
THREADED_TEST(TurnOnAccessCheckAndRecompile)14940 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14941 v8::Isolate* isolate = CcTest::isolate();
14942 v8::HandleScope handle_scope(isolate);
14943
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
14946 // a and h.
14947 v8::Handle<v8::ObjectTemplate> global_template =
14948 v8::ObjectTemplate::New(isolate);
14949 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14950 IndexedGetAccessBlocker,
14951 v8::Handle<v8::Value>(),
14952 false);
14953 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14954 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.
14995 Local<Object> hidden_global = Local<Object>::Cast(
14996 context->Global()->GetPrototype());
14997 context->DetachGlobal();
14998 hidden_global->TurnOnAccessCheck();
14999
15000 // Failing access check results in exception.
15001 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15002 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15003 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);
15012 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());
15017
15018 // 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());
15023 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15024 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15025 }
15026
15027
15028 // Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization)15029 TEST(PreCompileSerialization) {
15030 v8::V8::Initialize();
15031 LocalContext env;
15032 v8::Isolate* isolate = env->GetIsolate();
15033 HandleScope handle_scope(isolate);
15034
15035 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);
15040 // Serialize.
15041 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);
15044
15045 // Deserialize.
15046 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15047
15048 // Verify that the original is the same as the deserialized.
15049 CHECK_EQ(cd->length, deserialized->length());
15050 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15051
15052 delete deserialized;
15053 i::DeleteArray(serialized_data);
15054 }
15055
15056
15057 // 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.
THREADED_TEST(DictionaryICLoadedFunction)15062 THREADED_TEST(DictionaryICLoadedFunction) {
15063 v8::HandleScope scope(CcTest::isolate());
15064 // Test LoadIC.
15065 for (int i = 0; i < 2; i++) {
15066 LocalContext context;
15067 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15068 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;
15074 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15075 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.
THREADED_TEST(CrossContextNew)15083 THREADED_TEST(CrossContextNew) {
15084 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);
15088
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();
15108 }
15109
15110
15111 // Verify that we can clone an object
TEST(ObjectClone)15112 TEST(ObjectClone) {
15113 LocalContext env;
15114 v8::Isolate* isolate = env->GetIsolate();
15115 v8::HandleScope scope(isolate);
15116
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());
15126 Local<v8::Object> obj = val.As<v8::Object>();
15127 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15128
15129 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15130 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15131 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")));
15136 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15137 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15138
15139 // Set a property on the clone, verify each object.
15140 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")));
15143 }
15144
15145
15146 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15147 public:
OneByteVectorResource(i::Vector<const char> vector)15148 explicit OneByteVectorResource(i::Vector<const char> vector)
15149 : data_(vector) {}
~OneByteVectorResource()15150 virtual ~OneByteVectorResource() {}
length() const15151 virtual size_t length() const { return data_.length(); }
data() const15152 virtual const char* data() const { return data_.start(); }
15153 private:
15154 i::Vector<const char> data_;
15155 };
15156
15157
15158 class UC16VectorResource : public v8::String::ExternalStringResource {
15159 public:
UC16VectorResource(i::Vector<const i::uc16> vector)15160 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15161 : data_(vector) {}
~UC16VectorResource()15162 virtual ~UC16VectorResource() {}
length() const15163 virtual size_t length() const { return data_.length(); }
data() const15164 virtual const i::uc16* data() const { return data_.start(); }
15165 private:
15166 i::Vector<const i::uc16> data_;
15167 };
15168
15169
MorphAString(i::String * string,OneByteVectorResource * one_byte_resource,UC16VectorResource * uc16_resource)15170 static void MorphAString(i::String* string,
15171 OneByteVectorResource* one_byte_resource,
15172 UC16VectorResource* uc16_resource) {
15173 CHECK(i::StringShape(string).IsExternal());
15174 if (string->IsOneByteRepresentation()) {
15175 // Check old map is not internalized or long.
15176 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15177 // Morph external string to be TwoByte string.
15178 string->set_map(CcTest::heap()->external_string_map());
15179 i::ExternalTwoByteString* morphed =
15180 i::ExternalTwoByteString::cast(string);
15181 morphed->set_resource(uc16_resource);
15182 } else {
15183 // 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);
15189 }
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.
THREADED_TEST(MorphCompositeStringTest)15195 THREADED_TEST(MorphCompositeStringTest) {
15196 char utf_buffer[129];
15197 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 {
15201 LocalContext env;
15202 i::Factory* factory = CcTest::i_isolate()->factory();
15203 v8::HandleScope scope(env->GetIsolate());
15204 OneByteVectorResource one_byte_resource(
15205 i::Vector<const char>(c_string, i::StrLength(c_string)));
15206 UC16VectorResource uc16_resource(
15207 i::Vector<const uint16_t>(two_byte_string,
15208 i::StrLength(c_string)));
15209
15210 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()));
15216
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
15225 CHECK(lhs->IsOneByte());
15226 CHECK(rhs->IsOneByte());
15227
15228 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15229 &uc16_resource);
15230 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15231 &uc16_resource);
15232
15233 // 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
15244 // 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";
15257 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15258 env->Global()->Get(v8_str("cons")));
15259 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15260 env->Global()->Get(v8_str("slice")));
15261 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15262 env->Global()->Get(v8_str("slice_on_cons")));
15263 }
15264 i::DeleteArray(two_byte_string);
15265 }
15266
15267
TEST(CompileExternalTwoByteSource)15268 TEST(CompileExternalTwoByteSource) {
15269 LocalContext context;
15270 v8::HandleScope scope(context->GetIsolate());
15271
15272 // This is a very short list of sources, which currently is to check for a
15273 // regression caused by r2703.
15274 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};
15279
15280 // Compile the sources as external two byte strings.
15281 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);
15286 v8::Script::Compile(source);
15287 }
15288 }
15289
15290
15291 #ifndef V8_INTERPRETED_REGEXP
15292
15293 struct RegExpInterruptionData {
15294 int loop_count;
15295 UC16VectorResource* string_resource;
15296 v8::Persistent<v8::String> string;
15297 } regexp_interruption_data;
15298
15299
15300 class RegExpInterruptionThread : public v8::base::Thread {
15301 public:
RegExpInterruptionThread(v8::Isolate * isolate)15302 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15303 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15304
Run()15305 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();
15311 }
15312 v8::base::OS::Sleep(50); // Wait a bit before terminating.
15313 v8::V8::TerminateExecution(isolate_);
15314 }
15315
15316 private:
15317 v8::Isolate* isolate_;
15318 };
15319
15320
RunBeforeGC(v8::GCType type,v8::GCCallbackFlags flags)15321 void 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);
15327 }
15328
15329
15330 // 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
TEST(RegExpInterruption)15334 TEST(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
15366 // is a read-only property in the prototype chain.
TEST(ReadOnlyPropertyInGlobalProto)15367 TEST(ReadOnlyPropertyInGlobalProto) {
15368 v8::Isolate* isolate = CcTest::isolate();
15369 v8::HandleScope scope(isolate);
15370 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15371 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__")));
15375 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);
15379 // Check without 'eval' or 'with'.
15380 v8::Handle<v8::Value> res =
15381 CompileRun("function f() { x = 42; return x; }; f()");
15382 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15383 // Check with 'eval'.
15384 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15385 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15386 // Check with 'with'.
15387 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15388 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15389 }
15390
15391 static int force_set_set_count = 0;
15392 static int force_set_get_count = 0;
15393 bool pass_on_get = false;
15394
ForceSetGetter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Value> & info)15395 static void ForceSetGetter(v8::Local<v8::String> name,
15396 const v8::PropertyCallbackInfo<v8::Value>& info) {
15397 force_set_get_count++;
15398 if (pass_on_get) {
15399 return;
15400 }
15401 info.GetReturnValue().Set(3);
15402 }
15403
ForceSetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)15404 static void ForceSetSetter(v8::Local<v8::String> name,
15405 v8::Local<v8::Value> value,
15406 const v8::PropertyCallbackInfo<void>& info) {
15407 force_set_set_count++;
15408 }
15409
ForceSetInterceptSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)15410 static void ForceSetInterceptSetter(
15411 v8::Local<v8::String> name,
15412 v8::Local<v8::Value> value,
15413 const v8::PropertyCallbackInfo<v8::Value>& info) {
15414 force_set_set_count++;
15415 info.GetReturnValue().SetUndefined();
15416 }
15417
15418
TEST(ForceSet)15419 TEST(ForceSet) {
15420 force_set_get_count = 0;
15421 force_set_set_count = 0;
15422 pass_on_get = false;
15423
15424 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");
15429 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15430 LocalContext context(NULL, templ);
15431 v8::Handle<v8::Object> global = context->Global();
15432
15433 // Ordinary properties
15434 v8::Handle<v8::String> simple_property =
15435 v8::String::NewFromUtf8(isolate, "p");
15436 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15437 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15438 // This should fail because the property is read-only
15439 global->Set(simple_property, v8::Int32::New(isolate, 5));
15440 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15441 // This should succeed even though the property is read-only
15442 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15443 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.
15451 global->Set(access_property, v8::Int32::New(isolate, 7));
15452 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
15457 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15458 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
15463
TEST(ForceSetWithInterceptor)15464 TEST(ForceSetWithInterceptor) {
15465 force_set_get_count = 0;
15466 force_set_set_count = 0;
15467 pass_on_get = false;
15468
15469 v8::Isolate* isolate = CcTest::isolate();
15470 v8::HandleScope scope(isolate);
15471 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15472 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15473 LocalContext context(NULL, templ);
15474 v8::Handle<v8::Object> global = context->Global();
15475
15476 v8::Handle<v8::String> some_property =
15477 v8::String::NewFromUtf8(isolate, "a");
15478 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.
15483 global->Set(some_property, v8::Int32::New(isolate, 7));
15484 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.
15496 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15497 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
15507 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15508 ->Int32Value());
15509 CHECK_EQ(1, force_set_set_count);
15510 CHECK_EQ(6, force_set_get_count);
15511 }
15512
15513
THREADED_TEST(ForceDelete)15514 THREADED_TEST(ForceDelete) {
15515 v8::Isolate* isolate = CcTest::isolate();
15516 v8::HandleScope scope(isolate);
15517 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15518 LocalContext context(NULL, templ);
15519 v8::Handle<v8::Object> global = context->Global();
15520
15521 // Ordinary properties
15522 v8::Handle<v8::String> simple_property =
15523 v8::String::NewFromUtf8(isolate, "p");
15524 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15525 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
15535 static int force_delete_interceptor_count = 0;
15536 static bool pass_on_delete = false;
15537
15538
ForceDeleteDeleter(v8::Local<v8::String> name,const v8::PropertyCallbackInfo<v8::Boolean> & info)15539 static void ForceDeleteDeleter(
15540 v8::Local<v8::String> name,
15541 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15542 force_delete_interceptor_count++;
15543 if (pass_on_delete) return;
15544 info.GetReturnValue().Set(true);
15545 }
15546
15547
THREADED_TEST(ForceDeleteWithInterceptor)15548 THREADED_TEST(ForceDeleteWithInterceptor) {
15549 force_delete_interceptor_count = 0;
15550 pass_on_delete = false;
15551
15552 v8::Isolate* isolate = CcTest::isolate();
15553 v8::HandleScope scope(isolate);
15554 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15555 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15556 LocalContext context(NULL, templ);
15557 v8::Handle<v8::Object> global = context->Global();
15558
15559 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);
15563
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.
THREADED_TEST(ForceDeleteIC)15586 THREADED_TEST(ForceDeleteIC) {
15587 LocalContext context;
15588 v8::HandleScope scope(context->GetIsolate());
15589 // 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
TEST(InlinedFunctionAcrossContexts)15606 TEST(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
15646 static v8::Local<Context> calling_context0;
15647 static v8::Local<Context> calling_context1;
15648 static v8::Local<Context> calling_context2;
15649
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.
GetCallingContextCallback(const v8::FunctionCallbackInfo<v8::Value> & args)15654 static void GetCallingContextCallback(
15655 const v8::FunctionCallbackInfo<v8::Value>& args) {
15656 ApiTestFuzzer::Fuzz();
15657 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
THREADED_TEST(GetCurrentContextWhenNotInContext)15664 THREADED_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());
15673 }
15674
15675
THREADED_TEST(GetCallingContext)15676 THREADED_TEST(GetCallingContext) {
15677 v8::Isolate* isolate = CcTest::isolate();
15678 v8::HandleScope scope(isolate);
15679
15680 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;
15686
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 =
15696 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15697 calling_context0->Global()->Set(v8_str("callback"),
15698 callback_templ->GetFunction());
15699 calling_context0->Exit();
15700
15701 // Expose context0 in context1 and set up a function that calls the
15702 // 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();
15716 ::calling_context0.Clear();
15717 ::calling_context1.Clear();
15718 ::calling_context2.Clear();
15719 }
15720
15721
15722 // Check that a variable declaration with no explicit initialization
15723 // value does shadow an existing property in the prototype chain.
THREADED_TEST(InitGlobalVarInProtoChain)15724 THREADED_TEST(InitGlobalVarInProtoChain) {
15725 LocalContext context;
15726 v8::HandleScope scope(context->GetIsolate());
15727 // Introduce a variable in the prototype chain.
15728 CompileRun("__proto__.x = 42");
15729 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15730 CHECK(!result->IsUndefined());
15731 CHECK_EQ(43, result->Int32Value());
15732 }
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
THREADED_TEST(ReplaceConstantFunction)15740 THREADED_TEST(ReplaceConstantFunction) {
15741 LocalContext context;
15742 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");
15749 obj->Set(foo_string, func_templ->GetFunction());
15750 v8::Handle<v8::Object> obj_clone = obj->Clone();
15751 obj_clone->Set(foo_string,
15752 v8::String::NewFromUtf8(isolate, "Hello"));
15753 CHECK(!obj->Get(foo_string)->IsUndefined());
15754 }
15755
15756
CheckElementValue(i::Isolate * isolate,int expected,i::Handle<i::Object> obj,int offset)15757 static 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());
15764 }
15765
15766
THREADED_TEST(PixelArray)15767 THREADED_TEST(PixelArray) {
15768 LocalContext context;
15769 i::Isolate* isolate = CcTest::i_isolate();
15770 i::Factory* factory = isolate->factory();
15771 v8::HandleScope scope(context->GetIsolate());
15772 const int kElementCount = 260;
15773 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15774 i::Handle<i::ExternalUint8ClampedArray> pixels =
15775 i::Handle<i::ExternalUint8ClampedArray>::cast(
15776 factory->NewExternalArray(kElementCount,
15777 v8::kExternalUint8ClampedArray,
15778 pixel_data));
15779 // Force GC to trigger verification.
15780 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15781 for (int i = 0; i < kElementCount; i++) {
15782 pixels->set(i, i % 256);
15783 }
15784 // Force GC to trigger verification.
15785 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15786 for (int i = 0; i < kElementCount; i++) {
15787 CHECK_EQ(i % 256, pixels->get_scalar(i));
15788 CHECK_EQ(i % 256, pixel_data[i]);
15789 }
15790
15791 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15792 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);
15796 CheckElementValue(isolate, 1, jsobj, 1);
15797 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15798 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
15846 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15847 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15848 i::Handle<i::Object> no_failure;
15849 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);
15854 *value.location() = i::Smi::FromInt(256);
15855 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);
15860 *value.location() = i::Smi::FromInt(-1);
15861 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);
15866
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());
15872 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);
15880 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());
15892 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);
15900
15901 result = CompileRun("for (var i = 0; i < 8; i++) {"
15902 " pixels[7] = undefined;"
15903 "}"
15904 "pixels[7];");
15905 CHECK_EQ(0, result->Int32Value());
15906 CheckElementValue(isolate, 0, jsobj, 7);
15907
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());
15913 CheckElementValue(isolate, 2, jsobj, 6);
15914
15915 result = CompileRun("for (var i = 0; i < 8; i++) {"
15916 " pixels[5] = NaN;"
15917 "}"
15918 "pixels[5];");
15919 CHECK_EQ(0, result->Int32Value());
15920 CheckElementValue(isolate, 0, jsobj, 5);
15921
15922 result = CompileRun("for (var i = 0; i < 8; i++) {"
15923 " pixels[8] = Infinity;"
15924 "}"
15925 "pixels[8];");
15926 CHECK_EQ(255, result->Int32Value());
15927 CheckElementValue(isolate, 255, jsobj, 8);
15928
15929 result = CompileRun("for (var i = 0; i < 8; i++) {"
15930 " pixels[9] = -Infinity;"
15931 "}"
15932 "pixels[9];");
15933 CHECK_EQ(0, result->Int32Value());
15934 CheckElementValue(isolate, 0, jsobj, 9);
15935
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
15963 // 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
15972 // 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
16059 // 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.
16115 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; }"
16123 "for (var i = 0; i < 5000; ++i) {"
16124 " result = pa_load(pixels);"
16125 "}"
16126 "result");
16127 CHECK_EQ(32640, result->Int32Value());
16128
16129 // 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 "}"
16140 "for (var i = 0; i < 5000; ++i) {"
16141 " pa_init(pixels);"
16142 "}"
16143 "result = pa_load(pixels);"
16144 "result");
16145 CHECK_EQ(32640, result->Int32Value());
16146
16147 free(pixel_data);
16148 }
16149
16150
THREADED_TEST(PixelArrayInfo)16151 THREADED_TEST(PixelArrayInfo) {
16152 LocalContext context;
16153 v8::HandleScope scope(context->GetIsolate());
16154 for (int size = 0; size < 100; size += 10) {
16155 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16156 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16157 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
NotHandledIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)16166 static void NotHandledIndexedPropertyGetter(
16167 uint32_t index,
16168 const v8::PropertyCallbackInfo<v8::Value>& info) {
16169 ApiTestFuzzer::Fuzz();
16170 }
16171
16172
NotHandledIndexedPropertySetter(uint32_t index,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)16173 static void NotHandledIndexedPropertySetter(
16174 uint32_t index,
16175 Local<Value> value,
16176 const v8::PropertyCallbackInfo<v8::Value>& info) {
16177 ApiTestFuzzer::Fuzz();
16178 }
16179
16180
THREADED_TEST(PixelArrayWithInterceptor)16181 THREADED_TEST(PixelArrayWithInterceptor) {
16182 LocalContext context;
16183 i::Factory* factory = CcTest::i_isolate()->factory();
16184 v8::Isolate* isolate = context->GetIsolate();
16185 v8::HandleScope scope(isolate);
16186 const int kElementCount = 260;
16187 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16188 i::Handle<i::ExternalUint8ClampedArray> pixels =
16189 i::Handle<i::ExternalUint8ClampedArray>::cast(
16190 factory->NewExternalArray(kElementCount,
16191 v8::kExternalUint8ClampedArray,
16192 pixel_data));
16193 for (int i = 0; i < kElementCount; i++) {
16194 pixels->set(i, i % 256);
16195 }
16196 v8::Handle<v8::ObjectTemplate> templ =
16197 v8::ObjectTemplate::New(context->GetIsolate());
16198 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
ExternalArrayElementSize(v8::ExternalArrayType array_type)16217 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16218 switch (array_type) {
16219 case v8::kExternalInt8Array:
16220 case v8::kExternalUint8Array:
16221 case v8::kExternalUint8ClampedArray:
16222 return 1;
16223 break;
16224 case v8::kExternalInt16Array:
16225 case v8::kExternalUint16Array:
16226 return 2;
16227 break;
16228 case v8::kExternalInt32Array:
16229 case v8::kExternalUint32Array:
16230 case v8::kExternalFloat32Array:
16231 return 4;
16232 break;
16233 case v8::kExternalFloat64Array:
16234 return 8;
16235 break;
16236 default:
16237 UNREACHABLE();
16238 return -1;
16239 }
16240 UNREACHABLE();
16241 return -1;
16242 }
16243
16244
16245 template <class ExternalArrayClass, class ElementType>
ObjectWithExternalArrayTestHelper(Handle<Context> context,v8::Handle<Object> obj,int element_count,v8::ExternalArrayType array_type,int64_t low,int64_t high)16246 static 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) {
16252 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16253 i::Isolate* isolate = jsobj->GetIsolate();
16254 obj->Set(v8_str("field"),
16255 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16256 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
16262 // 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;");
16271
16272 CHECK_EQ(28, result->Int32Value());
16273 // 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
16281
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;";
16336 i::SNPrintF(test_buf,
16337 boundary_program,
16338 low);
16339 result = CompileRun(test_buf.start());
16340 CHECK_EQ(low, result->IntegerValue());
16341
16342 i::SNPrintF(test_buf,
16343 boundary_program,
16344 high);
16345 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;");
16359 // Force GC to trigger verification.
16360 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16361 CHECK_EQ(28, result->Int32Value());
16362
16363 // Make sure out-of-range loads do not throw.
16364 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);
16373 result = CompileRun(test_buf.start());
16374 CHECK_EQ(false, result->BooleanValue());
16375
16376 // Make sure out-of-range stores do not throw.
16377 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);
16386 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());
16395 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()));
16401 } else {
16402 CheckElementValue(isolate, 0, jsobj, 7);
16403 }
16404
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());
16410 CHECK_EQ(2,
16411 static_cast<int>(
16412 i::Object::GetElement(
16413 isolate, jsobj, 6).ToHandleChecked()->Number()));
16414
16415 if (array_type != v8::kExternalFloat32Array &&
16416 array_type != v8::kExternalFloat64Array) {
16417 // 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());
16427 CheckElementValue(isolate, 0, jsobj, 5);
16428
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];");
16436 int expected_value =
16437 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16438 CHECK_EQ(expected_value, result->Int32Value());
16439 CheckElementValue(isolate, expected_value, jsobj, 5);
16440
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());
16449 CheckElementValue(isolate, 0, jsobj, 5);
16450
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];";
16458 const char* pixel_data =
16459 "var source_data = [0.6, 10.6];"
16460 "var expected_results = [1, 11];";
16461 bool is_unsigned =
16462 (array_type == v8::kExternalUint8Array ||
16463 array_type == v8::kExternalUint16Array ||
16464 array_type == v8::kExternalUint32Array);
16465 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16466
16467 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)));
16481 result = CompileRun(test_buf.start());
16482 CHECK_EQ(true, result->BooleanValue());
16483 }
16484
16485 i::Handle<ExternalArrayClass> array(
16486 ExternalArrayClass::cast(jsobj->elements()));
16487 for (int i = 0; i < element_count; i++) {
16488 array->set(i, static_cast<ElementType>(i));
16489 }
16490
16491 // 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
16521 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());
16547 }
16548
16549
16550 template <class FixedTypedArrayClass,
16551 i::ElementsKind elements_kind,
16552 class ElementType>
FixedTypedArrayTestHelper(v8::ExternalArrayType array_type,ElementType low,ElementType high)16553 static 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
THREADED_TEST(FixedUint8Array)16593 THREADED_TEST(FixedUint8Array) {
16594 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16595 v8::kExternalUint8Array,
16596 0x0, 0xFF);
16597 }
16598
16599
THREADED_TEST(FixedUint8ClampedArray)16600 THREADED_TEST(FixedUint8ClampedArray) {
16601 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16602 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16603 v8::kExternalUint8ClampedArray,
16604 0x0, 0xFF);
16605 }
16606
16607
THREADED_TEST(FixedInt8Array)16608 THREADED_TEST(FixedInt8Array) {
16609 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16610 v8::kExternalInt8Array,
16611 -0x80, 0x7F);
16612 }
16613
16614
THREADED_TEST(FixedUint16Array)16615 THREADED_TEST(FixedUint16Array) {
16616 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16617 v8::kExternalUint16Array,
16618 0x0, 0xFFFF);
16619 }
16620
16621
THREADED_TEST(FixedInt16Array)16622 THREADED_TEST(FixedInt16Array) {
16623 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16624 v8::kExternalInt16Array,
16625 -0x8000, 0x7FFF);
16626 }
16627
16628
THREADED_TEST(FixedUint32Array)16629 THREADED_TEST(FixedUint32Array) {
16630 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16631 v8::kExternalUint32Array,
16632 0x0, UINT_MAX);
16633 }
16634
16635
THREADED_TEST(FixedInt32Array)16636 THREADED_TEST(FixedInt32Array) {
16637 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16638 v8::kExternalInt32Array,
16639 INT_MIN, INT_MAX);
16640 }
16641
16642
THREADED_TEST(FixedFloat32Array)16643 THREADED_TEST(FixedFloat32Array) {
16644 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16645 v8::kExternalFloat32Array,
16646 -500, 500);
16647 }
16648
16649
THREADED_TEST(FixedFloat64Array)16650 THREADED_TEST(FixedFloat64Array) {
16651 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16652 v8::kExternalFloat64Array,
16653 -500, 500);
16654 }
16655
16656
16657 template <class ExternalArrayClass, class ElementType>
ExternalArrayTestHelper(v8::ExternalArrayType array_type,int64_t low,int64_t high)16658 static 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;
16700
16701 // 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));
16711 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16712 // 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
16775 // 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 {
16784 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));
16788 // 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 {
16799 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));
16802 // Set the elements to be the external array.
16803 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16804 array_type,
16805 kElementCount);
16806 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16807 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 {
16814 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));
16817 // 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 {
16829 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16830 // Start
16831 obj2->Set(v8_str("ee_test_field3"),
16832 v8::Int32::New(context->GetIsolate(), 256));
16833
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.
16841 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));
16844 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.
16854 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));
16857 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.
16863 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));
16866 context->Global()->Set(v8_str("ext_array"), obj2);
16867 result = CompileRun("ext_array[''] = function() {return 1503;};"
16868 "ext_array['']();");
16869 }
16870
16871 free(array_data);
16872 }
16873
16874
THREADED_TEST(ExternalInt8Array)16875 THREADED_TEST(ExternalInt8Array) {
16876 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16877 v8::kExternalInt8Array,
16878 -128,
16879 127);
16880 }
16881
16882
THREADED_TEST(ExternalUint8Array)16883 THREADED_TEST(ExternalUint8Array) {
16884 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16885 v8::kExternalUint8Array,
16886 0,
16887 255);
16888 }
16889
16890
THREADED_TEST(ExternalUint8ClampedArray)16891 THREADED_TEST(ExternalUint8ClampedArray) {
16892 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16893 v8::kExternalUint8ClampedArray,
16894 0,
16895 255);
16896 }
16897
16898
THREADED_TEST(ExternalInt16Array)16899 THREADED_TEST(ExternalInt16Array) {
16900 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16901 v8::kExternalInt16Array,
16902 -32768,
16903 32767);
16904 }
16905
16906
THREADED_TEST(ExternalUint16Array)16907 THREADED_TEST(ExternalUint16Array) {
16908 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16909 v8::kExternalUint16Array,
16910 0,
16911 65535);
16912 }
16913
16914
THREADED_TEST(ExternalInt32Array)16915 THREADED_TEST(ExternalInt32Array) {
16916 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16917 v8::kExternalInt32Array,
16918 INT_MIN, // -2147483648
16919 INT_MAX); // 2147483647
16920 }
16921
16922
THREADED_TEST(ExternalUint32Array)16923 THREADED_TEST(ExternalUint32Array) {
16924 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16925 v8::kExternalUint32Array,
16926 0,
16927 UINT_MAX); // 4294967295
16928 }
16929
16930
THREADED_TEST(ExternalFloat32Array)16931 THREADED_TEST(ExternalFloat32Array) {
16932 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16933 v8::kExternalFloat32Array,
16934 -500,
16935 500);
16936 }
16937
16938
THREADED_TEST(ExternalFloat64Array)16939 THREADED_TEST(ExternalFloat64Array) {
16940 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16941 v8::kExternalFloat64Array,
16942 -500,
16943 500);
16944 }
16945
16946
THREADED_TEST(ExternalArrays)16947 THREADED_TEST(ExternalArrays) {
16948 TestExternalInt8Array();
16949 TestExternalUint8Array();
16950 TestExternalInt16Array();
16951 TestExternalUint16Array();
16952 TestExternalInt32Array();
16953 TestExternalUint32Array();
16954 TestExternalFloat32Array();
16955 }
16956
16957
ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type)16958 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16959 LocalContext context;
16960 v8::HandleScope scope(context->GetIsolate());
16961 for (int size = 0; size < 100; size += 10) {
16962 int element_size = ExternalArrayElementSize(array_type);
16963 void* external_data = malloc(size * element_size);
16964 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16965 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
THREADED_TEST(ExternalArrayInfo)16976 THREADED_TEST(ExternalArrayInfo) {
16977 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);
16986 }
16987
16988
ExtArrayLimitsHelper(v8::Isolate * isolate,v8::ExternalArrayType array_type,int size)16989 void 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
TEST(ExternalArrayLimits)17002 TEST(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
17027 template <typename ElementType, typename TypedArray,
17028 class ExternalArrayClass>
TypedArrayTestHelper(v8::ExternalArrayType array_type,int64_t low,int64_t high)17029 void 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
THREADED_TEST(Uint8Array)17061 THREADED_TEST(Uint8Array) {
17062 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17063 v8::kExternalUint8Array, 0, 0xFF);
17064 }
17065
17066
THREADED_TEST(Int8Array)17067 THREADED_TEST(Int8Array) {
17068 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17069 v8::kExternalInt8Array, -0x80, 0x7F);
17070 }
17071
17072
THREADED_TEST(Uint16Array)17073 THREADED_TEST(Uint16Array) {
17074 TypedArrayTestHelper<uint16_t,
17075 v8::Uint16Array,
17076 i::ExternalUint16Array>(
17077 v8::kExternalUint16Array, 0, 0xFFFF);
17078 }
17079
17080
THREADED_TEST(Int16Array)17081 THREADED_TEST(Int16Array) {
17082 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17083 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17084 }
17085
17086
THREADED_TEST(Uint32Array)17087 THREADED_TEST(Uint32Array) {
17088 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17089 v8::kExternalUint32Array, 0, UINT_MAX);
17090 }
17091
17092
THREADED_TEST(Int32Array)17093 THREADED_TEST(Int32Array) {
17094 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17095 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17096 }
17097
17098
THREADED_TEST(Float32Array)17099 THREADED_TEST(Float32Array) {
17100 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17101 v8::kExternalFloat32Array, -500, 500);
17102 }
17103
17104
THREADED_TEST(Float64Array)17105 THREADED_TEST(Float64Array) {
17106 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17107 v8::kExternalFloat64Array, -500, 500);
17108 }
17109
17110
THREADED_TEST(Uint8ClampedArray)17111 THREADED_TEST(Uint8ClampedArray) {
17112 TypedArrayTestHelper<uint8_t,
17113 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17114 v8::kExternalUint8ClampedArray, 0, 0xFF);
17115 }
17116
17117
THREADED_TEST(DataView)17118 THREADED_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
17152 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)17153 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17154 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17155 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17156 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17157 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17158 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17159 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17160 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17161 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17162
17163 #undef IS_ARRAY_BUFFER_VIEW_TEST
17164
17165
17166
17167 THREADED_TEST(ScriptContextDependence) {
17168 LocalContext c1;
17169 v8::HandleScope scope(c1->GetIsolate());
17170 const char *source = "foo";
17171 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));
17178 CHECK_EQ(dep->Run()->Int32Value(), 100);
17179 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17180 LocalContext c2;
17181 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17182 v8::Integer::New(c2->GetIsolate(), 101));
17183 CHECK_EQ(dep->Run()->Int32Value(), 100);
17184 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17185 }
17186
17187
THREADED_TEST(StackTrace)17188 THREADED_TEST(StackTrace) {
17189 LocalContext context;
17190 v8::HandleScope scope(context->GetIsolate());
17191 v8::TryCatch try_catch;
17192 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17193 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();
17201 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
17207 // Checks that a StackFrame has certain expected values.
checkStackFrame(const char * expected_script_name,const char * expected_func_name,int expected_line_number,int expected_column,bool is_eval,bool is_constructor,v8::Handle<v8::StackFrame> frame)17208 void 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) {
17212 v8::HandleScope scope(CcTest::isolate());
17213 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
AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value> & args)17229 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17230 v8::HandleScope scope(args.GetIsolate());
17231 const char* origin = "capture-stack-trace-test";
17232 const int kOverviewTest = 1;
17233 const int kDetailedTest = 2;
17234
17235 DCHECK(args.Length() == 1);
17236
17237 int testGroup = args[0]->Int32Value();
17238 if (testGroup == kOverviewTest) {
17239 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17240 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17241 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));
17246 // This is the source string inside the eval which has the call to foo.
17247 checkStackFrame(NULL, "", 1, 5, false, false,
17248 stackTrace->GetFrame(2));
17249 // The last frame is an anonymous function which has the initial eval call.
17250 checkStackFrame(origin, "", 8, 7, false, false,
17251 stackTrace->GetFrame(3));
17252
17253 CHECK(stackTrace->AsArray()->IsArray());
17254 } else if (testGroup == kDetailedTest) {
17255 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17256 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17257 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));
17262 bool is_eval = true;
17263 // This is the source string inside the eval which has the call to baz.
17264 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17265 stackTrace->GetFrame(2));
17266 // The last frame is an anonymous function which has the initial eval call.
17267 checkStackFrame(origin, "", 10, 1, false, false,
17268 stackTrace->GetFrame(3));
17269
17270 CHECK(stackTrace->AsArray()->IsArray());
17271 }
17272 }
17273
17274
17275 // Tests the C++ StackTrace API.
17276 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17277 // THREADED_TEST(CaptureStackTrace) {
TEST(CaptureStackTrace)17278 TEST(CaptureStackTrace) {
17279 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);
17284 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17285 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17286 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();');";
17299 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));
17303 v8::Handle<Value> overview_result(
17304 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17305 ->BindToCurrentContext()
17306 ->Run());
17307 CHECK(!overview_result.IsEmpty());
17308 CHECK(overview_result->IsObject());
17309
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();');";
17319 v8::Handle<v8::String> detailed_src =
17320 v8::String::NewFromUtf8(isolate, detailed_source);
17321 // Make the script using a non-zero line and column offset.
17322 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17323 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17324 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17325 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());
17330 CHECK(!detailed_result.IsEmpty());
17331 CHECK(detailed_result->IsObject());
17332 }
17333
17334
StackTraceForUncaughtExceptionListener(v8::Handle<v8::Message> message,v8::Handle<Value>)17335 static 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
17346
TEST(CaptureStackTraceForUncaughtException)17347 TEST(CaptureStackTraceForUncaughtException) {
17348 report_count = 0;
17349 LocalContext env;
17350 v8::HandleScope scope(env->GetIsolate());
17351 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17352 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17353
17354 CompileRunWithOrigin(
17355 "function foo() {\n"
17356 " throw 1;\n"
17357 "};\n"
17358 "function bar() {\n"
17359 " foo();\n"
17360 "};",
17361 "origin");
17362 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
TEST(CaptureStackTraceForUncaughtExceptionAndSetters)17371 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17372 LocalContext env;
17373 v8::HandleScope scope(env->GetIsolate());
17374 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
RethrowStackTraceHandler(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)17391 static 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).
TEST(RethrowStackTrace)17407 TEST(RethrowStackTrace) {
17408 LocalContext env;
17409 v8::HandleScope scope(env->GetIsolate());
17410 // 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
RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)17435 static 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.
TEST(RethrowPrimitiveStackTrace)17449 TEST(RethrowPrimitiveStackTrace) {
17450 LocalContext env;
17451 v8::HandleScope scope(env->GetIsolate());
17452 // 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
RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)17471 static 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.
TEST(RethrowExistingStackTrace)17483 TEST(RethrowExistingStackTrace) {
17484 LocalContext env;
17485 v8::HandleScope scope(env->GetIsolate());
17486 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
RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)17497 static 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.
TEST(RethrowBogusErrorStackTrace)17508 TEST(RethrowBogusErrorStackTrace) {
17509 LocalContext env;
17510 v8::HandleScope scope(env->GetIsolate());
17511 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
AnalyzeStackOfEvalWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17522 void 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);
17527 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 }
17535 }
17536
17537
TEST(SourceURLInStackTrace)17538 TEST(SourceURLInStackTrace) {
17539 v8::Isolate* isolate = CcTest::isolate();
17540 v8::HandleScope scope(isolate);
17541 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17542 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17543 v8::FunctionTemplate::New(isolate,
17544 AnalyzeStackOfEvalWithSourceURL));
17545 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"
17558 "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
17568 static int scriptIdInStack[2];
17569
AnalyzeScriptIdInStack(const v8::FunctionCallbackInfo<v8::Value> & args)17570 void 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
TEST(ScriptIdInStackTrace)17582 TEST(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
AnalyzeStackOfInlineScriptWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17605 void 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
TEST(InlineScriptWithSourceURLInStackTrace)17621 TEST(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
AnalyzeStackOfDynamicScriptWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17651 void 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
TEST(DynamicWithSourceURLInStackTrace)17667 TEST(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
TEST(DynamicWithSourceURLInStackTraceString)17697 TEST(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
TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL)17720 TEST(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
TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL)17744 TEST(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
CreateGarbageInOldSpace()17768 static 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 }
17775 }
17776
17777
17778 // Test that idle notification can be handled and eventually returns true.
TEST(IdleNotification)17779 TEST(IdleNotification) {
17780 const intptr_t MB = 1024 * 1024;
17781 const int IdlePauseInMs = 1000;
17782 LocalContext env;
17783 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);
17791 }
17792 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17793 CHECK(finished);
17794 CHECK_LT(final_size, initial_size + 1);
17795 }
17796
17797
17798 // Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithSmallHint)17799 TEST(IdleNotificationWithSmallHint) {
17800 const intptr_t MB = 1024 * 1024;
17801 const int IdlePauseInMs = 900;
17802 LocalContext env;
17803 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);
17811 }
17812 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17813 CHECK(finished);
17814 CHECK_LT(final_size, initial_size + 1);
17815 }
17816
17817
17818 // Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithLargeHint)17819 TEST(IdleNotificationWithLargeHint) {
17820 const intptr_t MB = 1024 * 1024;
17821 const int IdlePauseInMs = 900;
17822 LocalContext env;
17823 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);
17831 }
17832 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17833 CHECK(finished);
17834 CHECK_LT(final_size, initial_size + 1);
17835 }
17836
17837
TEST(Regress2107)17838 TEST(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
TEST(Regress2333)17872 TEST(Regress2333) {
17873 LocalContext env;
17874 for (int i = 0; i < 3; i++) {
17875 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17876 }
17877 }
17878
17879 static uint32_t* stack_limit;
17880
GetStackLimitCallback(const v8::FunctionCallbackInfo<v8::Value> & args)17881 static void GetStackLimitCallback(
17882 const v8::FunctionCallbackInfo<v8::Value>& args) {
17883 stack_limit = reinterpret_cast<uint32_t*>(
17884 CcTest::i_isolate()->stack_guard()->real_climit());
17885 }
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.
ComputeStackLimit(uint32_t size)17891 static 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
17902 // We need at least 165kB for an x64 debug build with clang and ASAN.
17903 static const int stack_breathing_room = 256 * i::KB;
17904
17905
TEST(SetStackLimit)17906 TEST(SetStackLimit) {
17907 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17908
17909 // Set stack limit.
17910 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17911
17912 // Execute a script.
17913 LocalContext env;
17914 v8::HandleScope scope(env->GetIsolate());
17915 Local<v8::FunctionTemplate> fun_templ =
17916 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17917 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
TEST(SetStackLimitInThread)17925 TEST(SetStackLimitInThread) {
17926 uint32_t* set_limit;
17927 {
17928 v8::Locker locker(CcTest::isolate());
17929 set_limit = ComputeStackLimit(stack_breathing_room);
17930
17931 // Set stack limit.
17932 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17933
17934 // Execute a script.
17935 v8::HandleScope scope(CcTest::isolate());
17936 LocalContext env;
17937 Local<v8::FunctionTemplate> fun_templ =
17938 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17939 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 {
17946 v8::Locker locker(CcTest::isolate());
17947 CHECK(stack_limit == set_limit);
17948 }
17949 }
17950
17951
THREADED_TEST(GetHeapStatistics)17952 THREADED_TEST(GetHeapStatistics) {
17953 LocalContext c1;
17954 v8::HandleScope scope(c1->GetIsolate());
17955 v8::HeapStatistics heap_statistics;
17956 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17957 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17958 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17959 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
17964 class VisitorImpl : public v8::ExternalResourceVisitor {
17965 public:
VisitorImpl(TestResource ** resource)17966 explicit VisitorImpl(TestResource** resource) {
17967 for (int i = 0; i < 4; i++) {
17968 resource_[i] = resource[i];
17969 found_resource_[i] = false;
17970 }
17971 }
~VisitorImpl()17972 virtual ~VisitorImpl() {}
VisitExternalString(v8::Handle<v8::String> string)17973 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17974 if (!string->IsExternal()) {
17975 CHECK(string->IsExternalOneByte());
17976 return;
17977 }
17978 v8::String::ExternalStringResource* resource =
17979 string->GetExternalStringResource();
17980 CHECK(resource);
17981 for (int i = 0; i < 4; i++) {
17982 if (resource_[i] == resource) {
17983 CHECK(!found_resource_[i]);
17984 found_resource_[i] = true;
17985 }
17986 }
17987 }
CheckVisitedResources()17988 void CheckVisitedResources() {
17989 for (int i = 0; i < 4; i++) {
17990 CHECK(found_resource_[i]);
17991 }
17992 }
17993
17994 private:
17995 v8::String::ExternalStringResource* resource_[4];
17996 bool found_resource_[4];
17997 };
17998
17999
TEST(ExternalizeOldSpaceTwoByteCons)18000 TEST(ExternalizeOldSpaceTwoByteCons) {
18001 LocalContext env;
18002 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
TEST(ExternalizeOldSpaceOneByteCons)18022 TEST(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
TEST(VisitExternalStrings)18044 TEST(VisitExternalStrings) {
18045 LocalContext env;
18046 v8::HandleScope scope(env->GetIsolate());
18047 const char* string = "Some string";
18048 uint16_t* two_byte_string = AsciiToTwoByteString(string);
18049 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]);
18056
18057 // 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());
18076 CHECK(string1->IsExternal());
18077 CHECK(string2->IsExternal());
18078 CHECK(string3->IsExternal());
18079
18080 VisitorImpl visitor(resource);
18081 v8::V8::VisitExternalResources(&visitor);
18082 visitor.CheckVisitedResources();
18083 }
18084
18085
TEST(ExternalStringCollectedAtTearDown)18086 TEST(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
TEST(ExternalInternalizedStringCollectedAtTearDown)18106 TEST(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
TEST(ExternalInternalizedStringCollectedAtGC)18130 TEST(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
DoubleFromBits(uint64_t value)18155 static double DoubleFromBits(uint64_t value) {
18156 double target;
18157 i::MemCopy(&target, &value, sizeof(target));
18158 return target;
18159 }
18160
18161
DoubleToBits(double value)18162 static uint64_t DoubleToBits(double value) {
18163 uint64_t target;
18164 i::MemCopy(&target, &value, sizeof(target));
18165 return target;
18166 }
18167
18168
DoubleToDateTime(double input)18169 static double DoubleToDateTime(double input) {
18170 double date_limit = 864e13;
18171 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18172 return v8::base::OS::nan_value();
18173 }
18174 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18175 }
18176
18177
18178 // 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.
DoubleFromBits(uint32_t high_bits,uint32_t low_bits)18180 static 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
THREADED_TEST(QuietSignalingNaNs)18185 THREADED_TEST(QuietSignalingNaNs) {
18186 LocalContext context;
18187 v8::Isolate* isolate = context->GetIsolate();
18188 v8::HandleScope scope(isolate);
18189 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.
18232 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18233 double stored_number = number->NumberValue();
18234 if (!std::isnan(test_value)) {
18235 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).
18239 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18240 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18241 // 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
18245 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18246 #endif
18247 }
18248
18249 // Check that Date::New preserves non-NaNs in the date range and
18250 // quiets SNaNs.
18251 v8::Handle<v8::Value> date =
18252 v8::Date::New(isolate, test_value);
18253 double expected_stored_date = DoubleToDateTime(test_value);
18254 double stored_date = date->NumberValue();
18255 if (!std::isnan(expected_stored_date)) {
18256 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).
18260 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18261 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18262 // 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
18266 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18267 #endif
18268 }
18269 }
18270 }
18271
18272
SpaghettiIncident(const v8::FunctionCallbackInfo<v8::Value> & args)18273 static void SpaghettiIncident(
18274 const v8::FunctionCallbackInfo<v8::Value>& args) {
18275 v8::HandleScope scope(args.GetIsolate());
18276 v8::TryCatch tc;
18277 v8::Handle<v8::String> str(args[0]->ToString());
18278 USE(str);
18279 if (tc.HasCaught())
18280 tc.ReThrow();
18281 }
18282
18283
18284 // Test that an exception can be propagated down through a spaghetti
18285 // stack using ReThrow.
THREADED_TEST(SpaghettiStackReThrow)18286 THREADED_TEST(SpaghettiStackReThrow) {
18287 v8::Isolate* isolate = CcTest::isolate();
18288 v8::HandleScope scope(isolate);
18289 LocalContext context;
18290 context->Global()->Set(
18291 v8::String::NewFromUtf8(isolate, "s"),
18292 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18293 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
TEST(Regress528)18313 TEST(Regress528) {
18314 v8::V8::Initialize();
18315 v8::Isolate* isolate = CcTest::isolate();
18316 v8::HandleScope scope(isolate);
18317 v8::Local<Context> other_context;
18318 int gc_count;
18319
18320 // Create a context used to keep the code from aging in the compilation
18321 // cache.
18322 other_context = Context::New(isolate);
18323
18324 // Context-dependent context data creates reference from the compilation
18325 // cache to the global object.
18326 const char* source_simple = "1";
18327 {
18328 v8::HandleScope scope(isolate);
18329 v8::Local<Context> context = Context::New(isolate);
18330
18331 context->Enter();
18332 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18333 context->SetEmbedderData(0, obj);
18334 CompileRun(source_simple);
18335 context->Exit();
18336 }
18337 isolate->ContextDisposedNotification();
18338 for (gc_count = 1; gc_count < 10; gc_count++) {
18339 other_context->Enter();
18340 CompileRun(source_simple);
18341 other_context->Exit();
18342 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18343 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()";
18351 {
18352 v8::HandleScope scope(isolate);
18353 v8::Local<Context> context = Context::New(isolate);
18354
18355 context->Enter();
18356 CompileRun(source_eval);
18357 context->Exit();
18358 }
18359 isolate->ContextDisposedNotification();
18360 for (gc_count = 1; gc_count < 10; gc_count++) {
18361 other_context->Enter();
18362 CompileRun(source_eval);
18363 other_context->Exit();
18364 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18365 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()";
18373 {
18374 v8::HandleScope scope(isolate);
18375 v8::Local<Context> context = Context::New(isolate);
18376
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 }
18386 isolate->ContextDisposedNotification();
18387 for (gc_count = 1; gc_count < 10; gc_count++) {
18388 other_context->Enter();
18389 CompileRun(source_exception);
18390 other_context->Exit();
18391 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18392 if (GetGlobalObjectsCount() == 1) break;
18393 }
18394 CHECK_GE(2, gc_count);
18395 CHECK_EQ(1, GetGlobalObjectsCount());
18396
18397 isolate->ContextDisposedNotification();
18398 }
18399
18400
THREADED_TEST(ScriptOrigin)18401 THREADED_TEST(ScriptOrigin) {
18402 LocalContext env;
18403 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() {}");
18408 v8::Script::Compile(script, &origin)->Run();
18409 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18410 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18411 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18412 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18413
18414 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18415 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18416 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18417
18418 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18419 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18420 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18421 }
18422
18423
THREADED_TEST(FunctionGetInferredName)18424 THREADED_TEST(FunctionGetInferredName) {
18425 LocalContext env;
18426 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(),
18431 "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(
18434 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18435 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18436 }
18437
18438
THREADED_TEST(FunctionGetDisplayName)18439 THREADED_TEST(FunctionGetDisplayName) {
18440 LocalContext env;
18441 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
THREADED_TEST(ScriptLineNumber)18506 THREADED_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() {}");
18513 v8::Script::Compile(script, &origin)->Run();
18514 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18515 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18516 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18517 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18518 CHECK_EQ(0, f->GetScriptLineNumber());
18519 CHECK_EQ(2, g->GetScriptLineNumber());
18520 }
18521
18522
THREADED_TEST(ScriptColumnNumber)18523 THREADED_TEST(ScriptColumnNumber) {
18524 LocalContext env;
18525 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() {}");
18533 v8::Script::Compile(script, &origin)->Run();
18534 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18535 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18536 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18537 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18538 CHECK_EQ(14, foo->GetScriptColumnNumber());
18539 CHECK_EQ(17, bar->GetScriptColumnNumber());
18540 }
18541
18542
THREADED_TEST(FunctionIsBuiltin)18543 THREADED_TEST(FunctionIsBuiltin) {
18544 LocalContext env;
18545 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
THREADED_TEST(FunctionGetScriptId)18561 THREADED_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() {}");
18571 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18572 script->Run();
18573 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18574 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18575 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18576 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18577 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18578 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18579 }
18580
18581
THREADED_TEST(FunctionGetBoundFunction)18582 THREADED_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());
18606 }
18607
18608
GetterWhichReturns42(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)18609 static 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
SetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)18618 static 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
FooGetInterceptor(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)18628 void 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
FooSetInterceptor(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)18637 void 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));
18645 }
18646
18647
TEST(SetterOnConstructorPrototype)18648 TEST(SetterOnConstructorPrototype) {
18649 v8::Isolate* isolate = CcTest::isolate();
18650 v8::HandleScope scope(isolate);
18651 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18652 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18653 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;
18667 script = v8_compile("new C1();");
18668 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
18674 script = v8_compile("new C2();");
18675 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
NamedPropertyGetterWhichReturns42(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)18683 static void NamedPropertyGetterWhichReturns42(
18684 Local<String> name,
18685 const v8::PropertyCallbackInfo<v8::Value>& info) {
18686 info.GetReturnValue().Set(v8_num(42));
18687 }
18688
18689
NamedPropertySetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)18690 static void NamedPropertySetterWhichSetsYOnThisTo23(
18691 Local<String> name,
18692 Local<Value> value,
18693 const v8::PropertyCallbackInfo<v8::Value>& info) {
18694 if (name->Equals(v8_str("x"))) {
18695 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18696 }
18697 }
18698
18699
THREADED_TEST(InterceptorOnConstructorPrototype)18700 THREADED_TEST(InterceptorOnConstructorPrototype) {
18701 v8::Isolate* isolate = CcTest::isolate();
18702 v8::HandleScope scope(isolate);
18703 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18704 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;
18719 script = v8_compile("new C1();");
18720 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
18726 script = v8_compile("new C2();");
18727 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 }
18733
18734
TEST(Regress618)18735 TEST(Regress618) {
18736 const char* source = "function C1() {"
18737 " this.x = 23;"
18738 "};"
18739 "C1.prototype = P;";
18740
18741 LocalContext context;
18742 v8::Isolate* isolate = context->GetIsolate();
18743 v8::HandleScope scope(isolate);
18744 v8::Local<v8::Script> script;
18745
18746 // Use a simple object as prototype.
18747 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18748 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
18754 script = v8_compile("new C1();");
18755 // 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++) {
18758 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.
18764 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18765 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18766 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
18772 script = v8_compile("new C1();");
18773 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
18780 v8::Isolate* gc_callbacks_isolate = NULL;
18781 int prologue_call_count = 0;
18782 int epilogue_call_count = 0;
18783 int prologue_call_count_second = 0;
18784 int epilogue_call_count_second = 0;
18785 int prologue_call_count_alloc = 0;
18786 int epilogue_call_count_alloc = 0;
18787
PrologueCallback(v8::GCType,v8::GCCallbackFlags flags)18788 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18789 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18790 ++prologue_call_count;
18791 }
18792
18793
PrologueCallback(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18794 void 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
EpilogueCallback(v8::GCType,v8::GCCallbackFlags flags)18803 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18804 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18805 ++epilogue_call_count;
18806 }
18807
18808
EpilogueCallback(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18809 void 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
PrologueCallbackSecond(v8::GCType,v8::GCCallbackFlags flags)18818 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18819 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18820 ++prologue_call_count_second;
18821 }
18822
18823
PrologueCallbackSecond(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18824 void 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
EpilogueCallbackSecond(v8::GCType,v8::GCCallbackFlags flags)18833 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18834 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18835 ++epilogue_call_count_second;
18836 }
18837
18838
EpilogueCallbackSecond(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18839 void 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
PrologueCallbackAlloc(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18848 void 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
EpilogueCallbackAlloc(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)18868 void 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
TEST(GCCallbacksOld)18888 TEST(GCCallbacksOld) {
18889 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);
18895 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18896 CHECK_EQ(1, prologue_call_count);
18897 CHECK_EQ(1, epilogue_call_count);
18898 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18899 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18900 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18901 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);
18907 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18908 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);
18914 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18915 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 }
18920
18921
TEST(GCCallbacks)18922 TEST(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
THREADED_TEST(AddToJSFunctionResultCache)18968 THREADED_TEST(AddToJSFunctionResultCache) {
18969 i::FLAG_stress_compaction = false;
18970 i::FLAG_allow_natives_syntax = true;
18971 v8::HandleScope scope(CcTest::isolate());
18972
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 "})()";
18989 CcTest::heap()->ClearJSFunctionResultCaches();
18990 ExpectString(code, "PASSED");
18991 }
18992
18993
THREADED_TEST(FillJSFunctionResultCache)18994 THREADED_TEST(FillJSFunctionResultCache) {
18995 i::FLAG_allow_natives_syntax = true;
18996 LocalContext context;
18997 v8::HandleScope scope(context->GetIsolate());
18998
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 "})()";
19010 CcTest::heap()->ClearJSFunctionResultCaches();
19011 ExpectString(code, "PASSED");
19012 }
19013
19014
THREADED_TEST(RoundRobinGetFromCache)19015 THREADED_TEST(RoundRobinGetFromCache) {
19016 i::FLAG_allow_natives_syntax = true;
19017 LocalContext context;
19018 v8::HandleScope scope(context->GetIsolate());
19019
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]);"
19028 " if (v.toString() !== values[i].toString())"
19029 " return 'Wrong value for ' + "
19030 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19031 " };"
19032 " return 'PASSED';"
19033 "})()";
19034 CcTest::heap()->ClearJSFunctionResultCaches();
19035 ExpectString(code, "PASSED");
19036 }
19037
19038
THREADED_TEST(ReverseGetFromCache)19039 THREADED_TEST(ReverseGetFromCache) {
19040 i::FLAG_allow_natives_syntax = true;
19041 LocalContext context;
19042 v8::HandleScope scope(context->GetIsolate());
19043
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 "})()";
19058 CcTest::heap()->ClearJSFunctionResultCaches();
19059 ExpectString(code, "PASSED");
19060 }
19061
19062
THREADED_TEST(TestEviction)19063 THREADED_TEST(TestEviction) {
19064 i::FLAG_allow_natives_syntax = true;
19065 LocalContext context;
19066 v8::HandleScope scope(context->GetIsolate());
19067
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 "})()";
19075 CcTest::heap()->ClearJSFunctionResultCaches();
19076 ExpectString(code, "PASSED");
19077 }
19078
19079
THREADED_TEST(TwoByteStringInOneByteCons)19080 THREADED_TEST(TwoByteStringInOneByteCons) {
19081 // See Chromium issue 47824.
19082 LocalContext context;
19083 v8::HandleScope scope(context->GetIsolate());
19084
19085 const char* init_code =
19086 "var str1 = 'abelspendabel';"
19087 "var str2 = str1 + str1 + str1;"
19088 "str2;";
19089 Local<Value> result = CompileRun(init_code);
19090
19091 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19092 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19093
19094 CHECK(result->IsString());
19095 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19096 int length = string->length();
19097 CHECK(string->IsOneByteRepresentation());
19098
19099 i::Handle<i::String> flat_string = i::String::Flatten(string);
19100
19101 CHECK(string->IsOneByteRepresentation());
19102 CHECK(flat_string->IsOneByteRepresentation());
19103
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
19116 // 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 }
19127
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
19160 ExpectObject("str2.indexOf('els');", indexof);
19161
19162 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19163
19164 reresult = CompileRun("str2.charCodeAt(2);");
19165 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19166 }
19167
19168
TEST(ContainsOnlyOneByte)19169 TEST(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
19241 // Failed access check callback that performs a GC on each invocation.
FailedAccessCheckCallbackGC(Local<v8::Object> target,v8::AccessType type,Local<v8::Value> data)19242 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19243 v8::AccessType type,
19244 Local<v8::Value> data) {
19245 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19246 }
19247
19248
TEST(GCInFailedAccessCheckCallback)19249 TEST(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
19256 v8::Isolate* isolate = CcTest::isolate();
19257 v8::HandleScope scope(isolate);
19258
19259 // Create an ObjectTemplate for global objects and install access
19260 // check callbacks that will block access.
19261 v8::Handle<v8::ObjectTemplate> global_template =
19262 v8::ObjectTemplate::New(isolate);
19263 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
19316 // HasOwnElement.
19317 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 }
19327
19328
TEST(IsolateNewDispose)19329 TEST(IsolateNewDispose) {
19330 v8::Isolate* current_isolate = CcTest::isolate();
19331 v8::Isolate* isolate = v8::Isolate::New();
19332 CHECK(isolate != NULL);
19333 CHECK(current_isolate != isolate);
19334 CHECK(current_isolate == CcTest::isolate());
19335
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
19343
UNINITIALIZED_TEST(DisposeIsolateWhenInUse)19344 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19345 v8::Isolate* isolate = v8::Isolate::New();
19346 {
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);
19358 }
19359 isolate->Dispose();
19360 }
19361
19362
TEST(RunTwoIsolatesOnSingleThread)19363 TEST(RunTwoIsolatesOnSingleThread) {
19364 // Run isolate 1.
19365 v8::Isolate* isolate1 = v8::Isolate::New();
19366 isolate1->Enter();
19367 v8::Persistent<v8::Context> context1;
19368 {
19369 v8::HandleScope scope(isolate1);
19370 context1.Reset(isolate1, Context::New(isolate1));
19371 }
19372
19373 {
19374 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);
19378 // 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);
19389 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);
19394
19395 // Run something in new isolate.
19396 CompileRun("var foo = 'isolate 2';");
19397 ExpectString("function f() { return foo; }; f()", "isolate 2");
19398 }
19399
19400 {
19401 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);
19405 // 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.
19412 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 }
19419
19420 {
19421 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);
19425 // 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);
19443 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);
19447 ExpectString("function f() { return foo; }; f()", "isolate 2");
19448 }
19449
19450 {
19451 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);
19455 ExpectString("function f() { return foo; }; f()", "isolate 1");
19456 }
19457
19458 {
19459 v8::Isolate::Scope iscope(isolate2);
19460 context2.Reset();
19461 }
19462
19463 context1.Reset();
19464 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 {
19479 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);
19483 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19484 }
19485 }
19486
19487
CalcFibonacci(v8::Isolate * isolate,int limit)19488 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19489 v8::Isolate::Scope isolate_scope(isolate);
19490 v8::HandleScope scope(isolate);
19491 LocalContext context(isolate);
19492 i::ScopedVector<char> code(1024);
19493 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);
19498 Local<Value> value = CompileRun(code.start());
19499 CHECK(value->IsNumber());
19500 return static_cast<int>(value->NumberValue());
19501 }
19502
19503 class IsolateThread : public v8::base::Thread {
19504 public:
IsolateThread(int fib_limit)19505 explicit IsolateThread(int fib_limit)
19506 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
19507
Run()19508 void Run() {
19509 v8::Isolate* isolate = v8::Isolate::New();
19510 result_ = CalcFibonacci(isolate, fib_limit_);
19511 isolate->Dispose();
19512 }
19513
result()19514 int result() { return result_; }
19515
19516 private:
19517 int fib_limit_;
19518 int result_;
19519 };
19520
19521
TEST(MultipleIsolatesOnIndividualThreads)19522 TEST(MultipleIsolatesOnIndividualThreads) {
19523 IsolateThread thread1(21);
19524 IsolateThread thread2(12);
19525
19526 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19527 thread1.Start();
19528 thread2.Start();
19529
19530 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19531 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19532
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());
19542 }
19543
19544
TEST(IsolateDifferentContexts)19545 TEST(IsolateDifferentContexts) {
19546 v8::Isolate* isolate = v8::Isolate::New();
19547 Local<v8::Context> context;
19548 {
19549 v8::Isolate::Scope isolate_scope(isolate);
19550 v8::HandleScope handle_scope(isolate);
19551 context = v8::Context::New(isolate);
19552 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);
19559 v8::HandleScope handle_scope(isolate);
19560 context = v8::Context::New(isolate);
19561 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 }
19566 isolate->Dispose();
19567 }
19568
19569 class InitDefaultIsolateThread : public v8::base::Thread {
19570 public:
19571 enum TestCase {
19572 SetResourceConstraints,
19573 SetFatalHandler,
19574 SetCounterFunction,
19575 SetCreateHistogramFunction,
19576 SetAddHistogramSampleFunction
19577 };
19578
InitDefaultIsolateThread(TestCase testCase)19579 explicit InitDefaultIsolateThread(TestCase testCase)
19580 : Thread(Options("InitDefaultIsolateThread")),
19581 testCase_(testCase),
19582 result_(false) {}
19583
Run()19584 void Run() {
19585 v8::Isolate::CreateParams create_params;
19586 switch (testCase_) {
19587 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;
19594 }
19595 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;
19601
19602 case SetFatalHandler:
19603 v8::V8::SetFatalErrorHandler(NULL);
19604 break;
19605
19606 case SetCounterFunction:
19607 CcTest::isolate()->SetCounterFunction(NULL);
19608 break;
19609
19610 case SetCreateHistogramFunction:
19611 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19612 break;
19613
19614 case SetAddHistogramSampleFunction:
19615 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19616 break;
19617 }
19618 isolate->Exit();
19619 isolate->Dispose();
19620 result_ = true;
19621 }
19622
result()19623 bool result() { return result_; }
19624
19625 private:
19626 TestCase testCase_;
19627 bool result_;
19628 };
19629
19630
InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase)19631 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19632 InitDefaultIsolateThread thread(testCase);
19633 thread.Start();
19634 thread.Join();
19635 CHECK_EQ(thread.result(), true);
19636 }
19637
19638
TEST(InitializeDefaultIsolateOnSecondaryThread1)19639 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19640 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19641 }
19642
19643
TEST(InitializeDefaultIsolateOnSecondaryThread2)19644 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19645 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19646 }
19647
19648
TEST(InitializeDefaultIsolateOnSecondaryThread3)19649 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19650 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19651 }
19652
19653
TEST(InitializeDefaultIsolateOnSecondaryThread4)19654 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19655 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19656 }
19657
19658
TEST(InitializeDefaultIsolateOnSecondaryThread5)19659 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19660 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19661 }
19662
19663
TEST(StringCheckMultipleContexts)19664 TEST(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.
19670 LocalContext context1;
19671 v8::HandleScope scope(context1->GetIsolate());
19672 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.
19679 LocalContext context2;
19680 v8::HandleScope scope(context2->GetIsolate());
19681 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19682 ExpectString(code, "not a");
19683 }
19684 }
19685
19686
TEST(NumberCheckMultipleContexts)19687 TEST(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.
19693 LocalContext context1;
19694 v8::HandleScope scope(context1->GetIsolate());
19695 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.
19702 LocalContext context2;
19703 v8::HandleScope scope(context2->GetIsolate());
19704 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19705 ExpectString(code, "not 42");
19706 }
19707 }
19708
19709
TEST(BooleanCheckMultipleContexts)19710 TEST(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.
19716 LocalContext context1;
19717 v8::HandleScope scope(context1->GetIsolate());
19718 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.
19725 LocalContext context2;
19726 v8::HandleScope scope(context2->GetIsolate());
19727 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19728 ExpectString(code, "");
19729 }
19730 }
19731
19732
TEST(DontDeleteCellLoadIC)19733 TEST(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.
19740 LocalContext context1;
19741 v8::HandleScope scope(context1->GetIsolate());
19742 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.
19751 LocalContext context2;
19752 v8::HandleScope scope(context2->GetIsolate());
19753 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\";");
19766 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19767 ExpectString("readCell()", "new_second");
19768 ExpectString("readCell()", "new_second");
19769 }
19770 }
19771
19772
TEST(DontDeleteCellLoadICForceDelete)19773 TEST(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.
19779 LocalContext context;
19780 v8::HandleScope scope(context->GetIsolate());
19781 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
TEST(DontDeleteCellLoadICAPI)19801 TEST(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.
19807 LocalContext context;
19808 v8::HandleScope scope(context->GetIsolate());
19809 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19810 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
19829 class Visitor42 : public v8::PersistentHandleVisitor {
19830 public:
Visitor42(v8::Persistent<v8::Object> * object)19831 explicit Visitor42(v8::Persistent<v8::Object>* object)
19832 : counter_(0), object_(object) { }
19833
VisitPersistentHandle(Persistent<Value> * value,uint16_t class_id)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
TEST(PersistentHandleVisitor)19853 TEST(PersistentHandleVisitor) {
19854 LocalContext context;
19855 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
TEST(WrapperClassId)19870 TEST(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
TEST(PersistentHandleInNewSpaceVisitor)19882 TEST(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
TEST(RegExp)19908 TEST(RegExp) {
19909 LocalContext context;
19910 v8::HandleScope scope(context->GetIsolate());
19911
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")));
19915 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19916
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")));
19922 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19923 static_cast<int>(re->GetFlags()));
19924
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")));
19930 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19931 static_cast<int>(re->GetFlags()));
19932
19933 re = CompileRun("/quux/").As<v8::RegExp>();
19934 CHECK(re->IsRegExp());
19935 CHECK(re->GetSource()->Equals(v8_str("quux")));
19936 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19937
19938 re = CompileRun("/quux/gm").As<v8::RegExp>();
19939 CHECK(re->IsRegExp());
19940 CHECK(re->GetSource()->Equals(v8_str("quux")));
19941 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19942 static_cast<int>(re->GetFlags()));
19943
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")));
19951 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19952
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")));
19958 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19959 static_cast<int>(re->GetFlags()));
19960
19961 context->Global()->Set(v8_str("re"), re);
19962 ExpectTrue("re.test('FoobarbaZ')");
19963
19964 // RegExps are objects on which you can set properties.
19965 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19966 v8::Handle<v8::Value> value(CompileRun("re.property"));
19967 CHECK_EQ(32, value->Int32Value());
19968
19969 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
THREADED_TEST(Equals)19978 THREADED_TEST(Equals) {
19979 LocalContext localContext;
19980 v8::HandleScope handleScope(localContext->GetIsolate());
19981
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
Getter(v8::Local<v8::String> property,const v8::PropertyCallbackInfo<v8::Value> & info)19997 static void Getter(v8::Local<v8::String> property,
19998 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19999 info.GetReturnValue().Set(v8_str("42!"));
20000 }
20001
20002
Enumerator(const v8::PropertyCallbackInfo<v8::Array> & info)20003 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20004 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20005 result->Set(0, v8_str("universalAnswer"));
20006 info.GetReturnValue().Set(result);
20007 }
20008
20009
TEST(NamedEnumeratorAndForIn)20010 TEST(NamedEnumeratorAndForIn) {
20011 LocalContext context;
20012 v8::Isolate* isolate = context->GetIsolate();
20013 v8::HandleScope handle_scope(isolate);
20014 v8::Context::Scope context_scope(context.local());
20015
20016 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20017 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 }
20024
20025
TEST(DefinePropertyPostDetach)20026 TEST(DefinePropertyPostDetach) {
20027 LocalContext context;
20028 v8::HandleScope scope(context->GetIsolate());
20029 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 }
20040
20041
InstallContextId(v8::Handle<Context> context,int id)20042 static void InstallContextId(v8::Handle<Context> context, int id) {
20043 Context::Scope scope(context);
20044 CompileRun("Object.prototype").As<Object>()->
20045 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20046 }
20047
20048
CheckContextId(v8::Handle<Object> object,int expected)20049 static void CheckContextId(v8::Handle<Object> object, int expected) {
20050 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20051 }
20052
20053
THREADED_TEST(CreationContext)20054 THREADED_TEST(CreationContext) {
20055 v8::Isolate* isolate = CcTest::isolate();
20056 HandleScope handle_scope(isolate);
20057 Handle<Context> context1 = Context::New(isolate);
20058 InstallContextId(context1, 1);
20059 Handle<Context> context2 = Context::New(isolate);
20060 InstallContextId(context2, 2);
20061 Handle<Context> context3 = Context::New(isolate);
20062 InstallContextId(context3, 3);
20063
20064 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20065
20066 Local<Object> object1;
20067 Local<Function> func1;
20068 {
20069 Context::Scope scope(context1);
20070 object1 = Object::New(isolate);
20071 func1 = tmpl->GetFunction();
20072 }
20073
20074 Local<Object> object2;
20075 Local<Function> func2;
20076 {
20077 Context::Scope scope(context2);
20078 object2 = Object::New(isolate);
20079 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 }
20135 }
20136
20137
THREADED_TEST(CreationContextOfJsFunction)20138 THREADED_TEST(CreationContextOfJsFunction) {
20139 HandleScope handle_scope(CcTest::isolate());
20140 Handle<Context> context = Context::New(CcTest::isolate());
20141 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);
20151 }
20152
20153
HasOwnPropertyIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)20154 void HasOwnPropertyIndexedPropertyGetter(
20155 uint32_t index,
20156 const v8::PropertyCallbackInfo<v8::Value>& info) {
20157 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20158 }
20159
20160
HasOwnPropertyNamedPropertyGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)20161 void 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"));
20165 }
20166
20167
HasOwnPropertyIndexedPropertyQuery(uint32_t index,const v8::PropertyCallbackInfo<v8::Integer> & info)20168 void HasOwnPropertyIndexedPropertyQuery(
20169 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20170 if (index == 42) info.GetReturnValue().Set(1);
20171 }
20172
20173
HasOwnPropertyNamedPropertyQuery(Local<String> property,const v8::PropertyCallbackInfo<v8::Integer> & info)20174 void HasOwnPropertyNamedPropertyQuery(
20175 Local<String> property,
20176 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20177 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20178 }
20179
20180
HasOwnPropertyNamedPropertyQuery2(Local<String> property,const v8::PropertyCallbackInfo<v8::Integer> & info)20181 void HasOwnPropertyNamedPropertyQuery2(
20182 Local<String> property,
20183 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20184 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20185 }
20186
20187
HasOwnPropertyAccessorGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)20188 void HasOwnPropertyAccessorGetter(
20189 Local<String> property,
20190 const v8::PropertyCallbackInfo<v8::Value>& info) {
20191 info.GetReturnValue().Set(v8_str("yes"));
20192 }
20193
20194
TEST(HasOwnProperty)20195 TEST(HasOwnProperty) {
20196 LocalContext env;
20197 v8::Isolate* isolate = env->GetIsolate();
20198 v8::HandleScope scope(isolate);
20199 { // 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.
20221 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20222 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.
20229 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20230 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.
20237 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20238 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.
20244 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20245 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.
20251 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20252 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.
20258 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20259 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
TEST(IndexedInterceptorWithStringProto)20269 TEST(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
CheckCodeGenerationAllowed()20291 void 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
CheckCodeGenerationDisallowed()20301 void 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
CodeGenerationAllowed(Local<Context> context)20320 bool CodeGenerationAllowed(Local<Context> context) {
20321 ApiTestFuzzer::Fuzz();
20322 return true;
20323 }
20324
20325
CodeGenerationDisallowed(Local<Context> context)20326 bool CodeGenerationDisallowed(Local<Context> context) {
20327 ApiTestFuzzer::Fuzz();
20328 return false;
20329 }
20330
20331
THREADED_TEST(AllowCodeGenFromStrings)20332 THREADED_TEST(AllowCodeGenFromStrings) {
20333 LocalContext context;
20334 v8::HandleScope scope(context->GetIsolate());
20335
20336 // eval and the Function constructor allowed by default.
20337 CHECK(context->IsCodeGenerationFromStringsAllowed());
20338 CheckCodeGenerationAllowed();
20339
20340 // Disallow eval and the Function constructor.
20341 context->AllowCodeGenerationFromStrings(false);
20342 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20343 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);
20352 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20353 CheckCodeGenerationAllowed();
20354
20355 // Set a callback that disallows the code generation.
20356 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20357 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20358 CheckCodeGenerationDisallowed();
20359 }
20360
20361
TEST(SetErrorMessageForCodeGenFromStrings)20362 TEST(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
NonObjectThis(const v8::FunctionCallbackInfo<v8::Value> & args)20380 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20381 }
20382
20383
THREADED_TEST(CallAPIFunctionOnNonObject)20384 THREADED_TEST(CallAPIFunctionOnNonObject) {
20385 LocalContext context;
20386 v8::Isolate* isolate = context->GetIsolate();
20387 v8::HandleScope scope(isolate);
20388 Handle<FunctionTemplate> templ =
20389 v8::FunctionTemplate::New(isolate, NonObjectThis);
20390 Handle<Function> function = templ->GetFunction();
20391 context->Global()->Set(v8_str("f"), function);
20392 TryCatch try_catch;
20393 CompileRun("f.call(2)");
20394 }
20395
20396
20397 // Regression test for issue 1470.
THREADED_TEST(ReadOnlyIndexedProperties)20398 THREADED_TEST(ReadOnlyIndexedProperties) {
20399 v8::Isolate* isolate = CcTest::isolate();
20400 v8::HandleScope scope(isolate);
20401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20402
20403 LocalContext context;
20404 Local<v8::Object> obj = templ->NewInstance();
20405 context->Global()->Set(v8_str("obj"), obj);
20406 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20407 obj->Set(v8_str("1"), v8_str("foobar"));
20408 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20409 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20410 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.
20414 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20415 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20416 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20417 }
20418
20419
THREADED_TEST(Regress1516)20420 THREADED_TEST(Regress1516) {
20421 LocalContext context;
20422 v8::HandleScope scope(context->GetIsolate());
20423
20424 { v8::HandleScope temp_scope(context->GetIsolate());
20425 CompileRun("({'a': 0})");
20426 }
20427
20428 int elements;
20429 { i::MapCache* map_cache =
20430 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20431 elements = map_cache->NumberOfElements();
20432 CHECK_LE(1, elements);
20433 }
20434
20435 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()) {
20439 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20440 CHECK_GT(elements, map_cache->NumberOfElements());
20441 }
20442 }
20443 }
20444
20445
BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)20446 static 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
THREADED_TEST(Regress93759)20464 THREADED_TEST(Regress93759) {
20465 v8::Isolate* isolate = CcTest::isolate();
20466 HandleScope scope(isolate);
20467
20468 // Template for object with security check.
20469 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20470 // 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.
20476 Local<FunctionTemplate> hidden_proto_template =
20477 v8::FunctionTemplate::New(isolate);
20478 hidden_proto_template->SetHiddenPrototype(true);
20479
20480 Local<FunctionTemplate> protected_hidden_proto_template =
20481 v8::FunctionTemplate::New(isolate);
20482 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.
20488 Local<Context> context = v8::Context::New(isolate);
20489 context->Enter();
20490
20491 // Plain object, no security check.
20492 Local<Object> simple_object = Object::New(isolate);
20493
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 =
20510 Object::New(isolate);
20511 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 =
20517 Object::New(isolate);
20518 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.
20524 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20525 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)");
20538 CHECK(result2.IsEmpty());
20539
20540 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20541 CHECK(result3->Equals(global_object->GetPrototype()));
20542
20543 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20544 CHECK(result4.IsEmpty());
20545
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)");
20551 CHECK(result6.IsEmpty());
20552 }
20553
20554
THREADED_TEST(Regress125988)20555 THREADED_TEST(Regress125988) {
20556 v8::HandleScope scope(CcTest::isolate());
20557 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20558 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
TestReceiver(Local<Value> expected_result,Local<Value> expected_receiver,const char * code)20579 static 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
THREADED_TEST(ForeignFunctionReceiver)20589 THREADED_TEST(ForeignFunctionReceiver) {
20590 v8::Isolate* isolate = CcTest::isolate();
20591 HandleScope scope(isolate);
20592
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
20598 Local<Context> foreign_context = v8::Context::New(isolate);
20599 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
20674 // Calling with environment record as base.
20675 TestReceiver(i, foreign_context->Global(), "func()");
20676 // Calling with no base.
20677 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20678 }
20679
20680
20681 uint8_t callback_fired = 0;
20682
20683
CallCompletedCallback1()20684 void CallCompletedCallback1() {
20685 v8::base::OS::Print("Firing callback 1.\n");
20686 callback_fired ^= 1; // Toggle first bit.
20687 }
20688
20689
CallCompletedCallback2()20690 void CallCompletedCallback2() {
20691 v8::base::OS::Print("Firing callback 2.\n");
20692 callback_fired ^= 2; // Toggle second bit.
20693 }
20694
20695
RecursiveCall(const v8::FunctionCallbackInfo<v8::Value> & args)20696 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20697 int32_t level = args[0]->Int32Value();
20698 if (level < 3) {
20699 level++;
20700 v8::base::OS::Print("Entering recursion level %d.\n", level);
20701 char script[64];
20702 i::Vector<char> script_vector(script, sizeof(script));
20703 i::SNPrintF(script_vector, "recursion(%d)", level);
20704 CompileRun(script_vector.start());
20705 v8::base::OS::Print("Leaving recursion level %d.\n", level);
20706 CHECK_EQ(0, callback_fired);
20707 } else {
20708 v8::base::OS::Print("Recursion ends.\n");
20709 CHECK_EQ(0, callback_fired);
20710 }
20711 }
20712
20713
TEST(CallCompletedCallback)20714 TEST(CallCompletedCallback) {
20715 LocalContext env;
20716 v8::HandleScope scope(env->GetIsolate());
20717 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20718 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20719 env->Global()->Set(v8_str("recursion"),
20720 recursive_runtime->GetFunction());
20721 // Adding the same callback a second time has no effect.
20722 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)"));
20728 script->Run();
20729 CHECK_EQ(3, callback_fired);
20730
20731 v8::base::OS::Print("\n--- Script (2) ---\n");
20732 callback_fired = 0;
20733 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20734 script->Run();
20735 CHECK_EQ(2, callback_fired);
20736
20737 v8::base::OS::Print("\n--- Function ---\n");
20738 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
CallCompletedCallbackNoException()20747 void CallCompletedCallbackNoException() {
20748 v8::HandleScope scope(CcTest::isolate());
20749 CompileRun("1+1;");
20750 }
20751
20752
CallCompletedCallbackException()20753 void CallCompletedCallbackException() {
20754 v8::HandleScope scope(CcTest::isolate());
20755 CompileRun("throw 'second exception';");
20756 }
20757
20758
TEST(CallCompletedCallbackOneException)20759 TEST(CallCompletedCallbackOneException) {
20760 LocalContext env;
20761 v8::HandleScope scope(env->GetIsolate());
20762 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20763 CompileRun("throw 'exception';");
20764 }
20765
20766
TEST(CallCompletedCallbackTwoExceptions)20767 TEST(CallCompletedCallbackTwoExceptions) {
20768 LocalContext env;
20769 v8::HandleScope scope(env->GetIsolate());
20770 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20771 CompileRun("throw 'first exception';");
20772 }
20773
20774
MicrotaskOne(const v8::FunctionCallbackInfo<Value> & info)20775 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20776 v8::HandleScope scope(info.GetIsolate());
20777 CompileRun("ext1Calls++;");
20778 }
20779
20780
MicrotaskTwo(const v8::FunctionCallbackInfo<Value> & info)20781 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20782 v8::HandleScope scope(info.GetIsolate());
20783 CompileRun("ext2Calls++;");
20784 }
20785
20786
20787 void* g_passed_to_three = NULL;
20788
20789
MicrotaskThree(void * data)20790 static void MicrotaskThree(void* data) {
20791 g_passed_to_three = data;
20792 }
20793
20794
TEST(EnqueueMicrotask)20795 TEST(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
MicrotaskExceptionOne(const v8::FunctionCallbackInfo<Value> & info)20850 static 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
MicrotaskExceptionTwo(const v8::FunctionCallbackInfo<Value> & info)20859 static 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
TEST(RunMicrotasksIgnoresThrownExceptions)20868 TEST(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
TEST(SetAutorunMicrotasks)20887 TEST(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
TEST(RunMicrotasksWithoutEnteringContext)20948 TEST(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
DebugEventInObserver(const v8::Debug::EventDetails & event_details)20967 static 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
TEST(Regress385349)20979 TEST(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
20999 static int probes_counter = 0;
21000 static int misses_counter = 0;
21001 static int updates_counter = 0;
21002
21003
LookupCounter(const char * name)21004 static 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
21016 static 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 "}";
21028 #endif
21029
21030
StubCacheHelper(bool primary)21031 static void StubCacheHelper(bool primary) {
21032 #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;
21040 LocalContext env;
21041 env->GetIsolate()->SetCounterFunction(LookupCounter);
21042 v8::HandleScope scope(env->GetIsolate());
21043 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);
21052 // 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);
21057 #endif
21058 }
21059
21060
TEST(SecondaryStubCache)21061 TEST(SecondaryStubCache) {
21062 StubCacheHelper(true);
21063 }
21064
21065
TEST(PrimaryStubCache)21066 TEST(PrimaryStubCache) {
21067 StubCacheHelper(false);
21068 }
21069
21070
21071 #ifdef DEBUG
21072 static int cow_arrays_created_runtime = 0;
21073
21074
LookupCounterCOWArrays(const char * name)21075 static 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
TEST(CheckCOWArraysCreatedRuntimeCounter)21084 TEST(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
TEST(StaticGetters)21101 TEST(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
UNINITIALIZED_TEST(IsolateEmbedderData)21117 UNINITIALIZED_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
TEST(StringEmpty)21149 TEST(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
21159 static int instance_checked_getter_count = 0;
InstanceCheckedGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)21160 static 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
21169 static int instance_checked_setter_count = 0;
InstanceCheckedSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)21170 static 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
CheckInstanceCheckedResult(int getters,int setters,bool expects_callbacks,TryCatch * try_catch)21179 static 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
CheckInstanceCheckedAccessors(bool expects_callbacks)21195 static 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
THREADED_TEST(InstanceCheckOnInstanceAccessor)21238 THREADED_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
THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor)21266 THREADED_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
THREADED_TEST(InstanceCheckOnPrototypeAccessor)21295 THREADED_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
TEST(TryFinallyMessage)21329 TEST(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
Helper137002(bool do_store,bool polymorphic,bool remove_accessor,bool interceptor)21372 static 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
THREADED_TEST(Regress137002a)21419 THREADED_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
THREADED_TEST(Regress137002b)21429 THREADED_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
THREADED_TEST(Regress142088)21498 THREADED_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
THREADED_TEST(Regress3337)21516 THREADED_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
THREADED_TEST(Regress137496)21533 THREADED_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
THREADED_TEST(Regress149912)21547 THREADED_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
THREADED_TEST(Regress157124)21557 THREADED_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
THREADED_TEST(Regress2535)21568 THREADED_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
THREADED_TEST(Regress2746)21580 THREADED_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
THREADED_TEST(Regress260106)21593 THREADED_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
THREADED_TEST(JSONParseObject)21606 THREADED_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
THREADED_TEST(JSONParseNumber)21616 THREADED_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
21627 class ThreadInterruptTest {
21628 public:
ThreadInterruptTest()21629 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
~ThreadInterruptTest()21630 ~ThreadInterruptTest() {}
21631
RunTest()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:
InterruptThread(ThreadInterruptTest * test)21645 explicit InterruptThread(ThreadInterruptTest* test)
21646 : Thread(Options("InterruptThread")), test_(test) {}
21647
Run()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
SignalHandler(int signal)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
THREADED_TEST(SemaphoreInterruption)21682 THREADED_TEST(SemaphoreInterruption) {
21683 ThreadInterruptTest().RunTest();
21684 }
21685
21686
21687 #endif // V8_OS_POSIX
21688
21689
NamedAccessAlwaysBlocked(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)21690 static 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
IndexAccessAlwaysBlocked(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)21699 static 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
UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value> & args)21708 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21709 CHECK(false);
21710 }
21711
21712
TEST(JSONStringifyAccessCheck)21713 TEST(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
21761 bool access_check_fail_thrown = false;
21762 bool catch_callback_called = false;
21763
21764
21765 // Failed access check callback that performs a GC on each invocation.
FailedAccessCheckThrows(Local<v8::Object> target,v8::AccessType type,Local<v8::Value> data)21766 void 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
CatcherCallback(const v8::FunctionCallbackInfo<v8::Value> & args)21776 void 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
HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value> & args)21784 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21785 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21786 }
21787
21788
CheckCorrectThrow(const char * script)21789 void 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
TEST(AccessCheckThrows)21809 TEST(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
THREADED_TEST(Regress256330)21873 THREADED_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
THREADED_TEST(CrankshaftInterceptorSetter)21889 THREADED_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
THREADED_TEST(CrankshaftInterceptorGetter)21915 THREADED_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
THREADED_TEST(CrankshaftInterceptorFieldRead)21938 THREADED_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
THREADED_TEST(CrankshaftInterceptorFieldWrite)21958 THREADED_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
21978 class RequestInterruptTestBase {
21979 public:
RequestInterruptTestBase()21980 RequestInterruptTestBase()
21981 : env_(),
21982 isolate_(env_->GetIsolate()),
21983 sem_(0),
21984 warmup_(20000),
21985 should_continue_(true) {
21986 }
21987
~RequestInterruptTestBase()21988 virtual ~RequestInterruptTestBase() { }
21989
21990 virtual void StartInterruptThread() = 0;
21991
21992 virtual void TestBody() = 0;
21993
RunTest()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
WakeUpInterruptor()22008 void WakeUpInterruptor() {
22009 sem_.Signal();
22010 }
22011
should_continue() const22012 bool should_continue() const { return should_continue_; }
22013
ShouldContinue()22014 bool ShouldContinue() {
22015 if (warmup_ > 0) {
22016 if (--warmup_ == 0) {
22017 WakeUpInterruptor();
22018 }
22019 }
22020
22021 return should_continue_;
22022 }
22023
ShouldContinueCallback(const v8::FunctionCallbackInfo<Value> & info)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
22040 class RequestInterruptTestBaseWithSimpleInterrupt
22041 : public RequestInterruptTestBase {
22042 public:
RequestInterruptTestBaseWithSimpleInterrupt()22043 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22044
StartInterruptThread()22045 virtual void StartInterruptThread() {
22046 i_thread.Start();
22047 }
22048
22049 private:
22050 class InterruptThread : public v8::base::Thread {
22051 public:
InterruptThread(RequestInterruptTestBase * test)22052 explicit InterruptThread(RequestInterruptTestBase* test)
22053 : Thread(Options("RequestInterruptTest")), test_(test) {}
22054
Run()22055 virtual void Run() {
22056 test_->sem_.Wait();
22057 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22058 }
22059
OnInterrupt(v8::Isolate * isolate,void * data)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
22073 class RequestInterruptTestWithFunctionCall
22074 : public RequestInterruptTestBaseWithSimpleInterrupt {
22075 public:
TestBody()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
22086 class RequestInterruptTestWithMethodCall
22087 : public RequestInterruptTestBaseWithSimpleInterrupt {
22088 public:
TestBody()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
22101 class RequestInterruptTestWithAccessor
22102 : public RequestInterruptTestBaseWithSimpleInterrupt {
22103 public:
TestBody()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
22116 class RequestInterruptTestWithNativeAccessor
22117 : public RequestInterruptTestBaseWithSimpleInterrupt {
22118 public:
TestBody()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:
ShouldContinueNativeGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)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
22143 class RequestInterruptTestWithMethodCallAndInterceptor
22144 : public RequestInterruptTestBaseWithSimpleInterrupt {
22145 public:
TestBody()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:
EmptyInterceptor(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)22160 static void EmptyInterceptor(
22161 Local<String> property,
22162 const v8::PropertyCallbackInfo<v8::Value>& info) {
22163 }
22164 };
22165
22166
22167 class RequestInterruptTestWithMathAbs
22168 : public RequestInterruptTestBaseWithSimpleInterrupt {
22169 public:
TestBody()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:
WakeUpInterruptorCallback(const v8::FunctionCallbackInfo<Value> & info)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
ShouldContinueCallback(const v8::FunctionCallbackInfo<Value> & info)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
TEST(RequestInterruptTestWithFunctionCall)22222 TEST(RequestInterruptTestWithFunctionCall) {
22223 RequestInterruptTestWithFunctionCall().RunTest();
22224 }
22225
22226
TEST(RequestInterruptTestWithMethodCall)22227 TEST(RequestInterruptTestWithMethodCall) {
22228 RequestInterruptTestWithMethodCall().RunTest();
22229 }
22230
22231
TEST(RequestInterruptTestWithAccessor)22232 TEST(RequestInterruptTestWithAccessor) {
22233 RequestInterruptTestWithAccessor().RunTest();
22234 }
22235
22236
TEST(RequestInterruptTestWithNativeAccessor)22237 TEST(RequestInterruptTestWithNativeAccessor) {
22238 RequestInterruptTestWithNativeAccessor().RunTest();
22239 }
22240
22241
TEST(RequestInterruptTestWithMethodCallAndInterceptor)22242 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22243 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22244 }
22245
22246
TEST(RequestInterruptTestWithMathAbs)22247 TEST(RequestInterruptTestWithMathAbs) {
22248 RequestInterruptTestWithMathAbs().RunTest();
22249 }
22250
22251
22252 class ClearInterruptFromAnotherThread
22253 : public RequestInterruptTestBase {
22254 public:
ClearInterruptFromAnotherThread()22255 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22256
StartInterruptThread()22257 virtual void StartInterruptThread() {
22258 i_thread.Start();
22259 }
22260
TestBody()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:
InterruptThread(ClearInterruptFromAnotherThread * test)22272 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22273 : Thread(Options("RequestInterruptTest")), test_(test) {}
22274
Run()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
OnInterrupt(v8::Isolate * isolate,void * data)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
TEST(ClearInterruptFromAnotherThread)22302 TEST(ClearInterruptFromAnotherThread) {
22303 ClearInterruptFromAnotherThread().RunTest();
22304 }
22305
22306
22307 static Local<Value> function_new_expected_env;
FunctionNewCallback(const v8::FunctionCallbackInfo<Value> & info)22308 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22309 CHECK_EQ(function_new_expected_env, info.Data());
22310 info.GetReturnValue().Set(17);
22311 }
22312
22313
THREADED_TEST(FunctionNew)22314 THREADED_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
TEST(EscapeableHandleScope)22345 TEST(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
SetterWhichExpectsThisAndHolderToDiffer(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> & info)22367 static void SetterWhichExpectsThisAndHolderToDiffer(
22368 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22369 CHECK(info.Holder() != info.This());
22370 }
22371
22372
TEST(Regress239669)22373 TEST(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
22391 class 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
OptimizationCallback(const v8::FunctionCallbackInfo<v8::Value> & info)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
RunAll()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
Run(SignatureType signature_type,bool global,int key)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
22561 Local<Object> ApiCallOptimizationChecker::data;
22562 Local<Object> ApiCallOptimizationChecker::receiver;
22563 Local<Object> ApiCallOptimizationChecker::holder;
22564 Local<Object> ApiCallOptimizationChecker::callee;
22565 int ApiCallOptimizationChecker::count = 0;
22566
22567
TEST(TestFunctionCallOptimization)22568 TEST(TestFunctionCallOptimization) {
22569 i::FLAG_allow_natives_syntax = true;
22570 ApiCallOptimizationChecker checker;
22571 checker.RunAll();
22572 }
22573
22574
22575 static const char* last_event_message;
22576 static int last_event_status;
StoringEventLoggerCallback(const char * message,int status)22577 void StoringEventLoggerCallback(const char* message, int status) {
22578 last_event_message = message;
22579 last_event_status = status;
22580 }
22581
22582
TEST(EventLogging)22583 TEST(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
TEST(Promises)22598 TEST(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
TEST(PromiseThen)22692 TEST(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
TEST(DisallowJavascriptExecutionScope)22758 TEST(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
TEST(AllowJavascriptExecutionScope)22768 TEST(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
TEST(ThrowOnJavascriptExecution)22782 TEST(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
TEST(Regress354123)22794 TEST(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
TEST(CaptureStackTraceForStackOverflow)22839 TEST(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
TEST(ScriptNameAndLineNumber)22852 TEST(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
SourceURLHelper(const char * source,const char * expected_source_url,const char * expected_source_mapping_url)22871 void 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
TEST(ScriptSourceURLAndSourceMappingURL)22890 TEST(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
TEST(GetOwnPropertyDescriptor)22953 TEST(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
TEST(Regress411877)22981 TEST(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
TEST(GetHiddenPropertyTableAfterAccessCheck)22997 TEST(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
TEST(Regress411793)23016 TEST(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
23033 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23034 public:
TestSourceStream(const char ** chunks)23035 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23036
GetMoreData(const uint8_t ** src)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).
FullSourceString(const char ** chunks)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.
RunStreamingTest(const char ** chunks,v8::ScriptCompiler::StreamedSource::Encoding encoding=v8::ScriptCompiler::StreamedSource::ONE_BYTE,bool expected_success=true)23077 void 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
TEST(StreamingSimpleScript)23117 TEST(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
TEST(StreamingBiggerScript)23126 TEST(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
TEST(StreamingScriptWithParseError)23147 TEST(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
TEST(StreamingUtf8Script)23172 TEST(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
TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck)23187 TEST(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
TEST(StreamingUtf8ScriptWithSplitCharacters)23211 TEST(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
TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases)23232 TEST(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
TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases)23287 TEST(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
TEST(StreamingProducesParserCache)23311 TEST(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
TEST(StreamingScriptWithInvalidUtf8)23339 TEST(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 }
23357