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 "test/cctest/test-api.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/base/smart-pointers.h"
44 #include "src/compilation-cache.h"
45 #include "src/debug/debug.h"
46 #include "src/execution.h"
47 #include "src/futex-emulation.h"
48 #include "src/objects.h"
49 #include "src/parsing/parser.h"
50 #include "src/profiler/cpu-profiler.h"
51 #include "src/unicode-inl.h"
52 #include "src/utils.h"
53 #include "src/vm-state.h"
54 #include "test/cctest/heap/heap-tester.h"
55 #include "test/cctest/heap/heap-utils.h"
56
57 static const bool kLogThreading = false;
58
59 using ::v8::Boolean;
60 using ::v8::BooleanObject;
61 using ::v8::Context;
62 using ::v8::Extension;
63 using ::v8::Function;
64 using ::v8::FunctionTemplate;
65 using ::v8::HandleScope;
66 using ::v8::Local;
67 using ::v8::Maybe;
68 using ::v8::Message;
69 using ::v8::MessageCallback;
70 using ::v8::Name;
71 using ::v8::None;
72 using ::v8::Object;
73 using ::v8::ObjectTemplate;
74 using ::v8::Persistent;
75 using ::v8::PropertyAttribute;
76 using ::v8::Script;
77 using ::v8::StackTrace;
78 using ::v8::String;
79 using ::v8::Symbol;
80 using ::v8::TryCatch;
81 using ::v8::Undefined;
82 using ::v8::UniqueId;
83 using ::v8::V8;
84 using ::v8::Value;
85
86
87 #define THREADED_PROFILED_TEST(Name) \
88 static void Test##Name(); \
89 TEST(Name##WithProfiler) { \
90 RunWithProfiler(&Test##Name); \
91 } \
92 THREADED_TEST(Name)
93
94
RunWithProfiler(void (* test)())95 void RunWithProfiler(void (*test)()) {
96 LocalContext env;
97 v8::HandleScope scope(env->GetIsolate());
98 v8::Local<v8::String> profile_name = v8_str("my_profile1");
99 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
100
101 cpu_profiler->StartProfiling(profile_name);
102 (*test)();
103 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
104 }
105
106
107 static int signature_callback_count;
108 static Local<Value> signature_expected_receiver;
IncrementingSignatureCallback(const v8::FunctionCallbackInfo<v8::Value> & args)109 static void IncrementingSignatureCallback(
110 const v8::FunctionCallbackInfo<v8::Value>& args) {
111 ApiTestFuzzer::Fuzz();
112 signature_callback_count++;
113 CHECK(signature_expected_receiver->Equals(
114 args.GetIsolate()->GetCurrentContext(),
115 args.Holder())
116 .FromJust());
117 CHECK(signature_expected_receiver->Equals(
118 args.GetIsolate()->GetCurrentContext(),
119 args.This())
120 .FromJust());
121 v8::Local<v8::Array> result =
122 v8::Array::New(args.GetIsolate(), args.Length());
123 for (int i = 0; i < args.Length(); i++) {
124 CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
125 v8::Integer::New(args.GetIsolate(), i), args[i])
126 .FromJust());
127 }
128 args.GetReturnValue().Set(result);
129 }
130
131
Returns42(const v8::FunctionCallbackInfo<v8::Value> & info)132 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
133 info.GetReturnValue().Set(42);
134 }
135
136
137 // Tests that call v8::V8::Dispose() cannot be threaded.
UNINITIALIZED_TEST(InitializeAndDisposeOnce)138 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
139 CHECK(v8::V8::Initialize());
140 CHECK(v8::V8::Dispose());
141 }
142
143
144 // Tests that call v8::V8::Dispose() cannot be threaded.
UNINITIALIZED_TEST(InitializeAndDisposeMultiple)145 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
146 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
147 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
148 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
149 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
150 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
151 }
152
153
THREADED_TEST(Handles)154 THREADED_TEST(Handles) {
155 v8::HandleScope scope(CcTest::isolate());
156 Local<Context> local_env;
157 {
158 LocalContext env;
159 local_env = env.local();
160 }
161
162 // Local context should still be live.
163 CHECK(!local_env.IsEmpty());
164 local_env->Enter();
165
166 v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
167 CHECK(!undef.IsEmpty());
168 CHECK(undef->IsUndefined());
169
170 const char* source = "1 + 2 + 3";
171 Local<Script> script = v8_compile(source);
172 CHECK_EQ(6, v8_run_int32value(script));
173
174 local_env->Exit();
175 }
176
177
THREADED_TEST(IsolateOfContext)178 THREADED_TEST(IsolateOfContext) {
179 v8::HandleScope scope(CcTest::isolate());
180 v8::Local<Context> env = Context::New(CcTest::isolate());
181
182 CHECK(!env->GetIsolate()->InContext());
183 CHECK(env->GetIsolate() == CcTest::isolate());
184 env->Enter();
185 CHECK(env->GetIsolate()->InContext());
186 CHECK(env->GetIsolate() == CcTest::isolate());
187 env->Exit();
188 CHECK(!env->GetIsolate()->InContext());
189 CHECK(env->GetIsolate() == CcTest::isolate());
190 }
191
192
TestSignature(const char * loop_js,Local<Value> receiver,v8::Isolate * isolate)193 static void TestSignature(const char* loop_js, Local<Value> receiver,
194 v8::Isolate* isolate) {
195 i::ScopedVector<char> source(200);
196 i::SNPrintF(source,
197 "for (var i = 0; i < 10; i++) {"
198 " %s"
199 "}",
200 loop_js);
201 signature_callback_count = 0;
202 signature_expected_receiver = receiver;
203 bool expected_to_throw = receiver.IsEmpty();
204 v8::TryCatch try_catch(isolate);
205 CompileRun(source.start());
206 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
207 if (!expected_to_throw) {
208 CHECK_EQ(10, signature_callback_count);
209 } else {
210 CHECK(v8_str("TypeError: Illegal invocation")
211 ->Equals(isolate->GetCurrentContext(),
212 try_catch.Exception()
213 ->ToString(isolate->GetCurrentContext())
214 .ToLocalChecked())
215 .FromJust());
216 }
217 }
218
219
THREADED_TEST(ReceiverSignature)220 THREADED_TEST(ReceiverSignature) {
221 LocalContext env;
222 v8::Isolate* isolate = env->GetIsolate();
223 v8::HandleScope scope(isolate);
224 // Setup templates.
225 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
226 v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
227 v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
228 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
229 v8::Local<v8::FunctionTemplate> callback =
230 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
231 v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
232 sub_fun->Inherit(fun);
233 v8::Local<v8::FunctionTemplate> unrel_fun =
234 v8::FunctionTemplate::New(isolate);
235 // Install properties.
236 v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
237 fun_proto->Set(v8_str("prop_sig"), callback_sig);
238 fun_proto->Set(v8_str("prop"), callback);
239 fun_proto->SetAccessorProperty(
240 v8_str("accessor_sig"), callback_sig, callback_sig);
241 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
242 // Instantiate templates.
243 Local<Value> fun_instance =
244 fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
245 Local<Value> sub_fun_instance =
246 sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
247 // Setup global variables.
248 CHECK(env->Global()
249 ->Set(env.local(), v8_str("Fun"),
250 fun->GetFunction(env.local()).ToLocalChecked())
251 .FromJust());
252 CHECK(env->Global()
253 ->Set(env.local(), v8_str("UnrelFun"),
254 unrel_fun->GetFunction(env.local()).ToLocalChecked())
255 .FromJust());
256 CHECK(env->Global()
257 ->Set(env.local(), v8_str("fun_instance"), fun_instance)
258 .FromJust());
259 CHECK(env->Global()
260 ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
261 .FromJust());
262 CompileRun(
263 "var accessor_sig_key = 'accessor_sig';"
264 "var accessor_key = 'accessor';"
265 "var prop_sig_key = 'prop_sig';"
266 "var prop_key = 'prop';"
267 ""
268 "function copy_props(obj) {"
269 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
270 " var source = Fun.prototype;"
271 " for (var i in keys) {"
272 " var key = keys[i];"
273 " var desc = Object.getOwnPropertyDescriptor(source, key);"
274 " Object.defineProperty(obj, key, desc);"
275 " }"
276 "}"
277 ""
278 "var obj = {};"
279 "copy_props(obj);"
280 "var unrel = new UnrelFun();"
281 "copy_props(unrel);");
282 // Test with and without ICs
283 const char* test_objects[] = {
284 "fun_instance", "sub_fun_instance", "obj", "unrel" };
285 unsigned bad_signature_start_offset = 2;
286 for (unsigned i = 0; i < arraysize(test_objects); i++) {
287 i::ScopedVector<char> source(200);
288 i::SNPrintF(
289 source, "var test_object = %s; test_object", test_objects[i]);
290 Local<Value> test_object = CompileRun(source.start());
291 TestSignature("test_object.prop();", test_object, isolate);
292 TestSignature("test_object.accessor;", test_object, isolate);
293 TestSignature("test_object[accessor_key];", test_object, isolate);
294 TestSignature("test_object.accessor = 1;", test_object, isolate);
295 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
296 if (i >= bad_signature_start_offset) test_object = Local<Value>();
297 TestSignature("test_object.prop_sig();", test_object, isolate);
298 TestSignature("test_object.accessor_sig;", test_object, isolate);
299 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
300 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
301 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
302 }
303 }
304
305
THREADED_TEST(HulIgennem)306 THREADED_TEST(HulIgennem) {
307 LocalContext env;
308 v8::Isolate* isolate = env->GetIsolate();
309 v8::HandleScope scope(isolate);
310 v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
311 Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
312 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
313 undef_str->WriteUtf8(value);
314 CHECK_EQ(0, strcmp(value, "undefined"));
315 i::DeleteArray(value);
316 }
317
318
THREADED_TEST(Access)319 THREADED_TEST(Access) {
320 LocalContext env;
321 v8::Isolate* isolate = env->GetIsolate();
322 v8::HandleScope scope(isolate);
323 Local<v8::Object> obj = v8::Object::New(isolate);
324 Local<Value> foo_before =
325 obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
326 CHECK(foo_before->IsUndefined());
327 Local<String> bar_str = v8_str("bar");
328 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
329 Local<Value> foo_after =
330 obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
331 CHECK(!foo_after->IsUndefined());
332 CHECK(foo_after->IsString());
333 CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
334 }
335
336
THREADED_TEST(AccessElement)337 THREADED_TEST(AccessElement) {
338 LocalContext env;
339 v8::HandleScope scope(env->GetIsolate());
340 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
341 Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
342 CHECK(before->IsUndefined());
343 Local<String> bar_str = v8_str("bar");
344 CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
345 Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
346 CHECK(!after->IsUndefined());
347 CHECK(after->IsString());
348 CHECK(bar_str->Equals(env.local(), after).FromJust());
349
350 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
351 CHECK(v8_str("a")
352 ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
353 .FromJust());
354 CHECK(v8_str("b")
355 ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
356 .FromJust());
357 }
358
359
THREADED_TEST(Script)360 THREADED_TEST(Script) {
361 LocalContext env;
362 v8::HandleScope scope(env->GetIsolate());
363 const char* source = "1 + 2 + 3";
364 Local<Script> script = v8_compile(source);
365 CHECK_EQ(6, v8_run_int32value(script));
366 }
367
368
369 class TestResource: public String::ExternalStringResource {
370 public:
TestResource(uint16_t * data,int * counter=NULL,bool owning_data=true)371 explicit TestResource(uint16_t* data, int* counter = NULL,
372 bool owning_data = true)
373 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
374 while (data[length_]) ++length_;
375 }
376
~TestResource()377 ~TestResource() {
378 if (owning_data_) i::DeleteArray(data_);
379 if (counter_ != NULL) ++*counter_;
380 }
381
data() const382 const uint16_t* data() const {
383 return data_;
384 }
385
length() const386 size_t length() const {
387 return length_;
388 }
389
390 private:
391 uint16_t* data_;
392 size_t length_;
393 int* counter_;
394 bool owning_data_;
395 };
396
397
398 class TestOneByteResource : public String::ExternalOneByteStringResource {
399 public:
TestOneByteResource(const char * data,int * counter=NULL,size_t offset=0)400 explicit TestOneByteResource(const char* data, int* counter = NULL,
401 size_t offset = 0)
402 : orig_data_(data),
403 data_(data + offset),
404 length_(strlen(data) - offset),
405 counter_(counter) {}
406
~TestOneByteResource()407 ~TestOneByteResource() {
408 i::DeleteArray(orig_data_);
409 if (counter_ != NULL) ++*counter_;
410 }
411
data() const412 const char* data() const {
413 return data_;
414 }
415
length() const416 size_t length() const {
417 return length_;
418 }
419
420 private:
421 const char* orig_data_;
422 const char* data_;
423 size_t length_;
424 int* counter_;
425 };
426
427
THREADED_TEST(ScriptUsingStringResource)428 THREADED_TEST(ScriptUsingStringResource) {
429 int dispose_count = 0;
430 const char* c_source = "1 + 2 * 3";
431 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
432 {
433 LocalContext env;
434 v8::HandleScope scope(env->GetIsolate());
435 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
436 Local<String> source =
437 String::NewExternalTwoByte(env->GetIsolate(), resource)
438 .ToLocalChecked();
439 Local<Script> script = v8_compile(source);
440 Local<Value> value = script->Run(env.local()).ToLocalChecked();
441 CHECK(value->IsNumber());
442 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
443 CHECK(source->IsExternal());
444 CHECK_EQ(resource,
445 static_cast<TestResource*>(source->GetExternalStringResource()));
446 String::Encoding encoding = String::UNKNOWN_ENCODING;
447 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
448 source->GetExternalStringResourceBase(&encoding));
449 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
450 CcTest::heap()->CollectAllGarbage();
451 CHECK_EQ(0, dispose_count);
452 }
453 CcTest::i_isolate()->compilation_cache()->Clear();
454 CcTest::heap()->CollectAllAvailableGarbage();
455 CHECK_EQ(1, dispose_count);
456 }
457
458
THREADED_TEST(ScriptUsingOneByteStringResource)459 THREADED_TEST(ScriptUsingOneByteStringResource) {
460 int dispose_count = 0;
461 const char* c_source = "1 + 2 * 3";
462 {
463 LocalContext env;
464 v8::HandleScope scope(env->GetIsolate());
465 TestOneByteResource* resource =
466 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
467 Local<String> source =
468 String::NewExternalOneByte(env->GetIsolate(), resource)
469 .ToLocalChecked();
470 CHECK(source->IsExternalOneByte());
471 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
472 source->GetExternalOneByteStringResource());
473 String::Encoding encoding = String::UNKNOWN_ENCODING;
474 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
475 source->GetExternalStringResourceBase(&encoding));
476 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
477 Local<Script> script = v8_compile(source);
478 Local<Value> value = script->Run(env.local()).ToLocalChecked();
479 CHECK(value->IsNumber());
480 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
481 CcTest::heap()->CollectAllGarbage();
482 CHECK_EQ(0, dispose_count);
483 }
484 CcTest::i_isolate()->compilation_cache()->Clear();
485 CcTest::heap()->CollectAllAvailableGarbage();
486 CHECK_EQ(1, dispose_count);
487 }
488
489
THREADED_TEST(ScriptMakingExternalString)490 THREADED_TEST(ScriptMakingExternalString) {
491 int dispose_count = 0;
492 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
493 {
494 LocalContext env;
495 v8::HandleScope scope(env->GetIsolate());
496 Local<String> source =
497 String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
498 v8::NewStringType::kNormal)
499 .ToLocalChecked();
500 // Trigger GCs so that the newly allocated string moves to old gen.
501 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
502 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
503 CHECK_EQ(source->IsExternal(), false);
504 CHECK_EQ(source->IsExternalOneByte(), false);
505 String::Encoding encoding = String::UNKNOWN_ENCODING;
506 CHECK(!source->GetExternalStringResourceBase(&encoding));
507 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
508 bool success = source->MakeExternal(new TestResource(two_byte_source,
509 &dispose_count));
510 CHECK(success);
511 Local<Script> script = v8_compile(source);
512 Local<Value> value = script->Run(env.local()).ToLocalChecked();
513 CHECK(value->IsNumber());
514 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
515 CcTest::heap()->CollectAllGarbage();
516 CHECK_EQ(0, dispose_count);
517 }
518 CcTest::i_isolate()->compilation_cache()->Clear();
519 CcTest::heap()->CollectAllGarbage();
520 CHECK_EQ(1, dispose_count);
521 }
522
523
THREADED_TEST(ScriptMakingExternalOneByteString)524 THREADED_TEST(ScriptMakingExternalOneByteString) {
525 int dispose_count = 0;
526 const char* c_source = "1 + 2 * 3";
527 {
528 LocalContext env;
529 v8::HandleScope scope(env->GetIsolate());
530 Local<String> source = v8_str(c_source);
531 // Trigger GCs so that the newly allocated string moves to old gen.
532 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
533 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
534 bool success = source->MakeExternal(
535 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
536 CHECK(success);
537 Local<Script> script = v8_compile(source);
538 Local<Value> value = script->Run(env.local()).ToLocalChecked();
539 CHECK(value->IsNumber());
540 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
541 CcTest::heap()->CollectAllGarbage();
542 CHECK_EQ(0, dispose_count);
543 }
544 CcTest::i_isolate()->compilation_cache()->Clear();
545 CcTest::heap()->CollectAllGarbage();
546 CHECK_EQ(1, dispose_count);
547 }
548
549
TEST(MakingExternalStringConditions)550 TEST(MakingExternalStringConditions) {
551 LocalContext env;
552 v8::HandleScope scope(env->GetIsolate());
553
554 // Free some space in the new space so that we can check freshness.
555 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
556 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
557
558 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
559 Local<String> local_string =
560 String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
561 v8::NewStringType::kNormal)
562 .ToLocalChecked();
563 i::DeleteArray(two_byte_string);
564
565 // We should refuse to externalize new space strings.
566 CHECK(!local_string->CanMakeExternal());
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 // Old space strings should be accepted.
571 CHECK(local_string->CanMakeExternal());
572 }
573
574
TEST(MakingExternalOneByteStringConditions)575 TEST(MakingExternalOneByteStringConditions) {
576 LocalContext env;
577 v8::HandleScope scope(env->GetIsolate());
578
579 // Free some space in the new space so that we can check freshness.
580 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
581 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
582
583 Local<String> local_string = v8_str("s1");
584 // We should refuse to externalize new space strings.
585 CHECK(!local_string->CanMakeExternal());
586 // Trigger GCs so that the newly allocated string moves to old gen.
587 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
588 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
589 // Old space strings should be accepted.
590 CHECK(local_string->CanMakeExternal());
591 }
592
593
TEST(MakingExternalUnalignedOneByteString)594 TEST(MakingExternalUnalignedOneByteString) {
595 LocalContext env;
596 v8::HandleScope scope(env->GetIsolate());
597
598 CompileRun("function cons(a, b) { return a + b; }"
599 "function slice(a) { return a.substring(1); }");
600 // Create a cons string that will land in old pointer space.
601 Local<String> cons = Local<String>::Cast(CompileRun(
602 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
603 // Create a sliced string that will land in old pointer space.
604 Local<String> slice = Local<String>::Cast(CompileRun(
605 "slice('abcdefghijklmnopqrstuvwxyz');"));
606
607 // Trigger GCs so that the newly allocated string moves to old gen.
608 i::heap::SimulateFullSpace(CcTest::heap()->old_space());
609 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
610 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
611
612 // Turn into external string with unaligned resource data.
613 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
614 bool success =
615 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
616 CHECK(success);
617 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
618 success =
619 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
620 CHECK(success);
621
622 // Trigger GCs and force evacuation.
623 CcTest::heap()->CollectAllGarbage();
624 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
625 }
626
627
THREADED_TEST(UsingExternalString)628 THREADED_TEST(UsingExternalString) {
629 i::Factory* factory = CcTest::i_isolate()->factory();
630 {
631 v8::HandleScope scope(CcTest::isolate());
632 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
633 Local<String> string =
634 String::NewExternalTwoByte(CcTest::isolate(),
635 new TestResource(two_byte_string))
636 .ToLocalChecked();
637 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
638 // Trigger GCs so that the newly allocated string moves to old gen.
639 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
641 i::Handle<i::String> isymbol =
642 factory->InternalizeString(istring);
643 CHECK(isymbol->IsInternalizedString());
644 }
645 CcTest::heap()->CollectAllGarbage();
646 CcTest::heap()->CollectAllGarbage();
647 }
648
649
THREADED_TEST(UsingExternalOneByteString)650 THREADED_TEST(UsingExternalOneByteString) {
651 i::Factory* factory = CcTest::i_isolate()->factory();
652 {
653 v8::HandleScope scope(CcTest::isolate());
654 const char* one_byte_string = "test string";
655 Local<String> string =
656 String::NewExternalOneByte(
657 CcTest::isolate(),
658 new TestOneByteResource(i::StrDup(one_byte_string)))
659 .ToLocalChecked();
660 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
661 // Trigger GCs so that the newly allocated string moves to old gen.
662 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
663 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
664 i::Handle<i::String> isymbol =
665 factory->InternalizeString(istring);
666 CHECK(isymbol->IsInternalizedString());
667 }
668 CcTest::heap()->CollectAllGarbage();
669 CcTest::heap()->CollectAllGarbage();
670 }
671
672
673 class RandomLengthResource : public v8::String::ExternalStringResource {
674 public:
RandomLengthResource(int length)675 explicit RandomLengthResource(int length) : length_(length) {}
data() const676 virtual const uint16_t* data() const { return string_; }
length() const677 virtual size_t length() const { return length_; }
678
679 private:
680 uint16_t string_[10];
681 int length_;
682 };
683
684
685 class RandomLengthOneByteResource
686 : public v8::String::ExternalOneByteStringResource {
687 public:
RandomLengthOneByteResource(int length)688 explicit RandomLengthOneByteResource(int length) : length_(length) {}
data() const689 virtual const char* data() const { return string_; }
length() const690 virtual size_t length() const { return length_; }
691
692 private:
693 char string_[10];
694 int length_;
695 };
696
697
THREADED_TEST(NewExternalForVeryLongString)698 THREADED_TEST(NewExternalForVeryLongString) {
699 auto isolate = CcTest::isolate();
700 {
701 v8::HandleScope scope(isolate);
702 v8::TryCatch try_catch(isolate);
703 RandomLengthOneByteResource r(1 << 30);
704 v8::MaybeLocal<v8::String> maybe_str =
705 v8::String::NewExternalOneByte(isolate, &r);
706 CHECK(maybe_str.IsEmpty());
707 CHECK(!try_catch.HasCaught());
708 }
709
710 {
711 v8::HandleScope scope(isolate);
712 v8::TryCatch try_catch(isolate);
713 RandomLengthResource r(1 << 30);
714 v8::MaybeLocal<v8::String> maybe_str =
715 v8::String::NewExternalTwoByte(isolate, &r);
716 CHECK(maybe_str.IsEmpty());
717 CHECK(!try_catch.HasCaught());
718 }
719 }
720
721
THREADED_TEST(ScavengeExternalString)722 THREADED_TEST(ScavengeExternalString) {
723 i::FLAG_stress_compaction = false;
724 i::FLAG_gc_global = false;
725 int dispose_count = 0;
726 bool in_new_space = false;
727 {
728 v8::HandleScope scope(CcTest::isolate());
729 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
730 Local<String> string =
731 String::NewExternalTwoByte(
732 CcTest::isolate(),
733 new TestResource(two_byte_string, &dispose_count))
734 .ToLocalChecked();
735 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
736 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
737 in_new_space = CcTest::heap()->InNewSpace(*istring);
738 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
739 CHECK_EQ(0, dispose_count);
740 }
741 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
742 CHECK_EQ(1, dispose_count);
743 }
744
745
THREADED_TEST(ScavengeExternalOneByteString)746 THREADED_TEST(ScavengeExternalOneByteString) {
747 i::FLAG_stress_compaction = false;
748 i::FLAG_gc_global = false;
749 int dispose_count = 0;
750 bool in_new_space = false;
751 {
752 v8::HandleScope scope(CcTest::isolate());
753 const char* one_byte_string = "test string";
754 Local<String> string =
755 String::NewExternalOneByte(
756 CcTest::isolate(),
757 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
758 .ToLocalChecked();
759 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
760 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
761 in_new_space = CcTest::heap()->InNewSpace(*istring);
762 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
763 CHECK_EQ(0, dispose_count);
764 }
765 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
766 CHECK_EQ(1, dispose_count);
767 }
768
769
770 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
771 public:
772 // Only used by non-threaded tests, so it can use static fields.
773 static int dispose_calls;
774 static int dispose_count;
775
TestOneByteResourceWithDisposeControl(const char * data,bool dispose)776 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
777 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
778
Dispose()779 void Dispose() {
780 ++dispose_calls;
781 if (dispose_) delete this;
782 }
783 private:
784 bool dispose_;
785 };
786
787
788 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
789 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
790
791
TEST(ExternalStringWithDisposeHandling)792 TEST(ExternalStringWithDisposeHandling) {
793 const char* c_source = "1 + 2 * 3";
794
795 // Use a stack allocated external string resource allocated object.
796 TestOneByteResourceWithDisposeControl::dispose_count = 0;
797 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
798 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
799 {
800 LocalContext env;
801 v8::HandleScope scope(env->GetIsolate());
802 Local<String> source =
803 String::NewExternalOneByte(env->GetIsolate(), &res_stack)
804 .ToLocalChecked();
805 Local<Script> script = v8_compile(source);
806 Local<Value> value = script->Run(env.local()).ToLocalChecked();
807 CHECK(value->IsNumber());
808 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
809 CcTest::heap()->CollectAllAvailableGarbage();
810 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
811 }
812 CcTest::i_isolate()->compilation_cache()->Clear();
813 CcTest::heap()->CollectAllAvailableGarbage();
814 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
815 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
816
817 // Use a heap allocated external string resource allocated object.
818 TestOneByteResourceWithDisposeControl::dispose_count = 0;
819 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
820 TestOneByteResource* res_heap =
821 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
822 {
823 LocalContext env;
824 v8::HandleScope scope(env->GetIsolate());
825 Local<String> source =
826 String::NewExternalOneByte(env->GetIsolate(), res_heap)
827 .ToLocalChecked();
828 Local<Script> script = v8_compile(source);
829 Local<Value> value = script->Run(env.local()).ToLocalChecked();
830 CHECK(value->IsNumber());
831 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
832 CcTest::heap()->CollectAllAvailableGarbage();
833 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
834 }
835 CcTest::i_isolate()->compilation_cache()->Clear();
836 CcTest::heap()->CollectAllAvailableGarbage();
837 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
838 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
839 }
840
841
THREADED_TEST(StringConcat)842 THREADED_TEST(StringConcat) {
843 {
844 LocalContext env;
845 v8::HandleScope scope(env->GetIsolate());
846 const char* one_byte_string_1 = "function a_times_t";
847 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
848 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
849 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
850 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
851 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
852 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
853 Local<String> left = v8_str(one_byte_string_1);
854
855 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
856 Local<String> right =
857 String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
858 v8::NewStringType::kNormal)
859 .ToLocalChecked();
860 i::DeleteArray(two_byte_source);
861
862 Local<String> source = String::Concat(left, right);
863 right = String::NewExternalOneByte(
864 env->GetIsolate(),
865 new TestOneByteResource(i::StrDup(one_byte_extern_1)))
866 .ToLocalChecked();
867 source = String::Concat(source, right);
868 right = String::NewExternalTwoByte(
869 env->GetIsolate(),
870 new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
871 .ToLocalChecked();
872 source = String::Concat(source, right);
873 right = v8_str(one_byte_string_2);
874 source = String::Concat(source, right);
875
876 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
877 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
878 v8::NewStringType::kNormal)
879 .ToLocalChecked();
880 i::DeleteArray(two_byte_source);
881
882 source = String::Concat(source, right);
883 right = String::NewExternalTwoByte(
884 env->GetIsolate(),
885 new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
886 .ToLocalChecked();
887 source = String::Concat(source, right);
888 Local<Script> script = v8_compile(source);
889 Local<Value> value = script->Run(env.local()).ToLocalChecked();
890 CHECK(value->IsNumber());
891 CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
892 }
893 CcTest::i_isolate()->compilation_cache()->Clear();
894 CcTest::heap()->CollectAllGarbage();
895 CcTest::heap()->CollectAllGarbage();
896 }
897
898
THREADED_TEST(GlobalProperties)899 THREADED_TEST(GlobalProperties) {
900 LocalContext env;
901 v8::HandleScope scope(env->GetIsolate());
902 v8::Local<v8::Object> global = env->Global();
903 CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
904 Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
905 CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
906 }
907
908
handle_callback_impl(const v8::FunctionCallbackInfo<Value> & info,i::Address callback)909 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
910 i::Address callback) {
911 ApiTestFuzzer::Fuzz();
912 CheckReturnValue(info, callback);
913 info.GetReturnValue().Set(v8_str("bad value"));
914 info.GetReturnValue().Set(v8_num(102));
915 }
916
917
handle_callback(const v8::FunctionCallbackInfo<Value> & info)918 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
919 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
920 }
921
922
handle_callback_2(const v8::FunctionCallbackInfo<Value> & info)923 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
924 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
925 }
926
construct_callback(const v8::FunctionCallbackInfo<Value> & info)927 static void construct_callback(
928 const v8::FunctionCallbackInfo<Value>& info) {
929 ApiTestFuzzer::Fuzz();
930 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
931 CHECK(
932 info.This()
933 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
934 .FromJust());
935 CHECK(
936 info.This()
937 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
938 .FromJust());
939 info.GetReturnValue().Set(v8_str("bad value"));
940 info.GetReturnValue().Set(info.This());
941 }
942
943
Return239Callback(Local<String> name,const v8::PropertyCallbackInfo<Value> & info)944 static void Return239Callback(
945 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
946 ApiTestFuzzer::Fuzz();
947 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
948 info.GetReturnValue().Set(v8_str("bad value"));
949 info.GetReturnValue().Set(v8_num(239));
950 }
951
952
953 template<typename Handler>
TestFunctionTemplateInitializer(Handler handler,Handler handler_2)954 static void TestFunctionTemplateInitializer(Handler handler,
955 Handler handler_2) {
956 // Test constructor calls.
957 {
958 LocalContext env;
959 v8::Isolate* isolate = env->GetIsolate();
960 v8::HandleScope scope(isolate);
961
962 Local<v8::FunctionTemplate> fun_templ =
963 v8::FunctionTemplate::New(isolate, handler);
964 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
965 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
966 Local<Script> script = v8_compile("obj()");
967 for (int i = 0; i < 30; i++) {
968 CHECK_EQ(102, v8_run_int32value(script));
969 }
970 }
971 // Use SetCallHandler to initialize a function template, should work like
972 // the previous one.
973 {
974 LocalContext env;
975 v8::Isolate* isolate = env->GetIsolate();
976 v8::HandleScope scope(isolate);
977
978 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
979 fun_templ->SetCallHandler(handler_2);
980 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
981 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
982 Local<Script> script = v8_compile("obj()");
983 for (int i = 0; i < 30; i++) {
984 CHECK_EQ(102, v8_run_int32value(script));
985 }
986 }
987 }
988
989
990 template<typename Constructor, typename Accessor>
TestFunctionTemplateAccessor(Constructor constructor,Accessor accessor)991 static void TestFunctionTemplateAccessor(Constructor constructor,
992 Accessor accessor) {
993 LocalContext env;
994 v8::HandleScope scope(env->GetIsolate());
995
996 Local<v8::FunctionTemplate> fun_templ =
997 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
998 fun_templ->SetClassName(v8_str("funky"));
999 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1000 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1001 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1002 Local<Value> result =
1003 v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1004 CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1005 CompileRun("var obj_instance = new obj();");
1006 Local<Script> script;
1007 script = v8_compile("obj_instance.x");
1008 for (int i = 0; i < 30; i++) {
1009 CHECK_EQ(1, v8_run_int32value(script));
1010 }
1011 script = v8_compile("obj_instance.m");
1012 for (int i = 0; i < 30; i++) {
1013 CHECK_EQ(239, v8_run_int32value(script));
1014 }
1015 }
1016
1017
THREADED_PROFILED_TEST(FunctionTemplate)1018 THREADED_PROFILED_TEST(FunctionTemplate) {
1019 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1020 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1021 }
1022
1023
SimpleCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1024 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1025 ApiTestFuzzer::Fuzz();
1026 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1027 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1028 }
1029
1030
1031 template<typename Callback>
TestSimpleCallback(Callback callback)1032 static void TestSimpleCallback(Callback callback) {
1033 LocalContext env;
1034 v8::Isolate* isolate = env->GetIsolate();
1035 v8::HandleScope scope(isolate);
1036
1037 v8::Local<v8::ObjectTemplate> object_template =
1038 v8::ObjectTemplate::New(isolate);
1039 object_template->Set(isolate, "callback",
1040 v8::FunctionTemplate::New(isolate, callback));
1041 v8::Local<v8::Object> object =
1042 object_template->NewInstance(env.local()).ToLocalChecked();
1043 CHECK((*env)
1044 ->Global()
1045 ->Set(env.local(), v8_str("callback_object"), object)
1046 .FromJust());
1047 v8::Local<v8::Script> script;
1048 script = v8_compile("callback_object.callback(17)");
1049 for (int i = 0; i < 30; i++) {
1050 CHECK_EQ(51424, v8_run_int32value(script));
1051 }
1052 script = v8_compile("callback_object.callback(17, 24)");
1053 for (int i = 0; i < 30; i++) {
1054 CHECK_EQ(51425, v8_run_int32value(script));
1055 }
1056 }
1057
1058
THREADED_PROFILED_TEST(SimpleCallback)1059 THREADED_PROFILED_TEST(SimpleCallback) {
1060 TestSimpleCallback(SimpleCallback);
1061 }
1062
1063
1064 template<typename T>
1065 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1066
1067 // constant return values
1068 static int32_t fast_return_value_int32 = 471;
1069 static uint32_t fast_return_value_uint32 = 571;
1070 static const double kFastReturnValueDouble = 2.7;
1071 // variable return values
1072 static bool fast_return_value_bool = false;
1073 enum ReturnValueOddball {
1074 kNullReturnValue,
1075 kUndefinedReturnValue,
1076 kEmptyStringReturnValue
1077 };
1078 static ReturnValueOddball fast_return_value_void;
1079 static bool fast_return_value_object_is_empty = false;
1080
1081 // Helper function to avoid compiler error: insufficient contextual information
1082 // to determine type when applying FUNCTION_ADDR to a template function.
address_of(v8::FunctionCallback callback)1083 static i::Address address_of(v8::FunctionCallback callback) {
1084 return FUNCTION_ADDR(callback);
1085 }
1086
1087 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1088 void FastReturnValueCallback<int32_t>(
1089 const v8::FunctionCallbackInfo<v8::Value>& info) {
1090 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1091 info.GetReturnValue().Set(fast_return_value_int32);
1092 }
1093
1094 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1095 void FastReturnValueCallback<uint32_t>(
1096 const v8::FunctionCallbackInfo<v8::Value>& info) {
1097 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1098 info.GetReturnValue().Set(fast_return_value_uint32);
1099 }
1100
1101 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1102 void FastReturnValueCallback<double>(
1103 const v8::FunctionCallbackInfo<v8::Value>& info) {
1104 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1105 info.GetReturnValue().Set(kFastReturnValueDouble);
1106 }
1107
1108 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1109 void FastReturnValueCallback<bool>(
1110 const v8::FunctionCallbackInfo<v8::Value>& info) {
1111 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1112 info.GetReturnValue().Set(fast_return_value_bool);
1113 }
1114
1115 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1116 void FastReturnValueCallback<void>(
1117 const v8::FunctionCallbackInfo<v8::Value>& info) {
1118 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1119 switch (fast_return_value_void) {
1120 case kNullReturnValue:
1121 info.GetReturnValue().SetNull();
1122 break;
1123 case kUndefinedReturnValue:
1124 info.GetReturnValue().SetUndefined();
1125 break;
1126 case kEmptyStringReturnValue:
1127 info.GetReturnValue().SetEmptyString();
1128 break;
1129 }
1130 }
1131
1132 template<>
FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value> & info)1133 void FastReturnValueCallback<Object>(
1134 const v8::FunctionCallbackInfo<v8::Value>& info) {
1135 v8::Local<v8::Object> object;
1136 if (!fast_return_value_object_is_empty) {
1137 object = Object::New(info.GetIsolate());
1138 }
1139 info.GetReturnValue().Set(object);
1140 }
1141
1142 template <typename T>
TestFastReturnValues()1143 Local<Value> TestFastReturnValues() {
1144 LocalContext env;
1145 v8::Isolate* isolate = env->GetIsolate();
1146 v8::EscapableHandleScope scope(isolate);
1147 v8::Local<v8::ObjectTemplate> object_template =
1148 v8::ObjectTemplate::New(isolate);
1149 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1150 object_template->Set(isolate, "callback",
1151 v8::FunctionTemplate::New(isolate, callback));
1152 v8::Local<v8::Object> object =
1153 object_template->NewInstance(env.local()).ToLocalChecked();
1154 CHECK((*env)
1155 ->Global()
1156 ->Set(env.local(), v8_str("callback_object"), object)
1157 .FromJust());
1158 return scope.Escape(CompileRun("callback_object.callback()"));
1159 }
1160
1161
THREADED_PROFILED_TEST(FastReturnValues)1162 THREADED_PROFILED_TEST(FastReturnValues) {
1163 LocalContext env;
1164 v8::Isolate* isolate = env->GetIsolate();
1165 v8::HandleScope scope(isolate);
1166 v8::Local<v8::Value> value;
1167 // check int32_t and uint32_t
1168 int32_t int_values[] = {
1169 0, 234, -723,
1170 i::Smi::kMinValue, i::Smi::kMaxValue
1171 };
1172 for (size_t i = 0; i < arraysize(int_values); i++) {
1173 for (int modifier = -1; modifier <= 1; modifier++) {
1174 int int_value = int_values[i] + modifier;
1175 // check int32_t
1176 fast_return_value_int32 = int_value;
1177 value = TestFastReturnValues<int32_t>();
1178 CHECK(value->IsInt32());
1179 CHECK_EQ(fast_return_value_int32,
1180 value->Int32Value(env.local()).FromJust());
1181 // check uint32_t
1182 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1183 value = TestFastReturnValues<uint32_t>();
1184 CHECK(value->IsUint32());
1185 CHECK_EQ(fast_return_value_uint32,
1186 value->Uint32Value(env.local()).FromJust());
1187 }
1188 }
1189 // check double
1190 value = TestFastReturnValues<double>();
1191 CHECK(value->IsNumber());
1192 CHECK_EQ(kFastReturnValueDouble,
1193 value->ToNumber(env.local()).ToLocalChecked()->Value());
1194 // check bool values
1195 for (int i = 0; i < 2; i++) {
1196 fast_return_value_bool = i == 0;
1197 value = TestFastReturnValues<bool>();
1198 CHECK(value->IsBoolean());
1199 CHECK_EQ(fast_return_value_bool,
1200 value->ToBoolean(env.local()).ToLocalChecked()->Value());
1201 }
1202 // check oddballs
1203 ReturnValueOddball oddballs[] = {
1204 kNullReturnValue,
1205 kUndefinedReturnValue,
1206 kEmptyStringReturnValue
1207 };
1208 for (size_t i = 0; i < arraysize(oddballs); i++) {
1209 fast_return_value_void = oddballs[i];
1210 value = TestFastReturnValues<void>();
1211 switch (fast_return_value_void) {
1212 case kNullReturnValue:
1213 CHECK(value->IsNull());
1214 break;
1215 case kUndefinedReturnValue:
1216 CHECK(value->IsUndefined());
1217 break;
1218 case kEmptyStringReturnValue:
1219 CHECK(value->IsString());
1220 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1221 break;
1222 }
1223 }
1224 // check handles
1225 fast_return_value_object_is_empty = false;
1226 value = TestFastReturnValues<Object>();
1227 CHECK(value->IsObject());
1228 fast_return_value_object_is_empty = true;
1229 value = TestFastReturnValues<Object>();
1230 CHECK(value->IsUndefined());
1231 }
1232
1233
THREADED_TEST(FunctionTemplateSetLength)1234 THREADED_TEST(FunctionTemplateSetLength) {
1235 LocalContext env;
1236 v8::Isolate* isolate = env->GetIsolate();
1237 v8::HandleScope scope(isolate);
1238 {
1239 Local<v8::FunctionTemplate> fun_templ =
1240 v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1241 Local<v8::Signature>(), 23);
1242 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1243 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1244 Local<Script> script = v8_compile("obj.length");
1245 CHECK_EQ(23, v8_run_int32value(script));
1246 }
1247 {
1248 Local<v8::FunctionTemplate> fun_templ =
1249 v8::FunctionTemplate::New(isolate, handle_callback);
1250 fun_templ->SetLength(22);
1251 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1252 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1253 Local<Script> script = v8_compile("obj.length");
1254 CHECK_EQ(22, v8_run_int32value(script));
1255 }
1256 {
1257 // Without setting length it defaults to 0.
1258 Local<v8::FunctionTemplate> fun_templ =
1259 v8::FunctionTemplate::New(isolate, handle_callback);
1260 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1261 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1262 Local<Script> script = v8_compile("obj.length");
1263 CHECK_EQ(0, v8_run_int32value(script));
1264 }
1265 }
1266
1267
1268 static void* expected_ptr;
callback(const v8::FunctionCallbackInfo<v8::Value> & args)1269 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1270 void* ptr = v8::External::Cast(*args.Data())->Value();
1271 CHECK_EQ(expected_ptr, ptr);
1272 args.GetReturnValue().Set(true);
1273 }
1274
1275
TestExternalPointerWrapping()1276 static void TestExternalPointerWrapping() {
1277 LocalContext env;
1278 v8::Isolate* isolate = env->GetIsolate();
1279 v8::HandleScope scope(isolate);
1280
1281 v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1282
1283 v8::Local<v8::Object> obj = v8::Object::New(isolate);
1284 CHECK(obj->Set(env.local(), v8_str("func"),
1285 v8::FunctionTemplate::New(isolate, callback, data)
1286 ->GetFunction(env.local())
1287 .ToLocalChecked())
1288 .FromJust());
1289 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1290
1291 CHECK(CompileRun("function foo() {\n"
1292 " for (var i = 0; i < 13; i++) obj.func();\n"
1293 "}\n"
1294 "foo(), true")
1295 ->BooleanValue(env.local())
1296 .FromJust());
1297 }
1298
1299
THREADED_TEST(ExternalWrap)1300 THREADED_TEST(ExternalWrap) {
1301 // Check heap allocated object.
1302 int* ptr = new int;
1303 expected_ptr = ptr;
1304 TestExternalPointerWrapping();
1305 delete ptr;
1306
1307 // Check stack allocated object.
1308 int foo;
1309 expected_ptr = &foo;
1310 TestExternalPointerWrapping();
1311
1312 // Check not aligned addresses.
1313 const int n = 100;
1314 char* s = new char[n];
1315 for (int i = 0; i < n; i++) {
1316 expected_ptr = s + i;
1317 TestExternalPointerWrapping();
1318 }
1319
1320 delete[] s;
1321
1322 // Check several invalid addresses.
1323 expected_ptr = reinterpret_cast<void*>(1);
1324 TestExternalPointerWrapping();
1325
1326 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1327 TestExternalPointerWrapping();
1328
1329 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1330 TestExternalPointerWrapping();
1331
1332 #if defined(V8_HOST_ARCH_X64)
1333 // Check a value with a leading 1 bit in x64 Smi encoding.
1334 expected_ptr = reinterpret_cast<void*>(0x400000000);
1335 TestExternalPointerWrapping();
1336
1337 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1338 TestExternalPointerWrapping();
1339
1340 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1341 TestExternalPointerWrapping();
1342 #endif
1343 }
1344
1345
THREADED_TEST(FindInstanceInPrototypeChain)1346 THREADED_TEST(FindInstanceInPrototypeChain) {
1347 LocalContext env;
1348 v8::Isolate* isolate = env->GetIsolate();
1349 v8::HandleScope scope(isolate);
1350
1351 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1352 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1353 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1354 derived->Inherit(base);
1355
1356 Local<v8::Function> base_function =
1357 base->GetFunction(env.local()).ToLocalChecked();
1358 Local<v8::Function> derived_function =
1359 derived->GetFunction(env.local()).ToLocalChecked();
1360 Local<v8::Function> other_function =
1361 other->GetFunction(env.local()).ToLocalChecked();
1362
1363 Local<v8::Object> base_instance =
1364 base_function->NewInstance(env.local()).ToLocalChecked();
1365 Local<v8::Object> derived_instance =
1366 derived_function->NewInstance(env.local()).ToLocalChecked();
1367 Local<v8::Object> derived_instance2 =
1368 derived_function->NewInstance(env.local()).ToLocalChecked();
1369 Local<v8::Object> other_instance =
1370 other_function->NewInstance(env.local()).ToLocalChecked();
1371 CHECK(
1372 derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1373 .FromJust());
1374 CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1375 .FromJust());
1376
1377 // base_instance is only an instance of base.
1378 CHECK(base_instance->Equals(env.local(),
1379 base_instance->FindInstanceInPrototypeChain(base))
1380 .FromJust());
1381 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1382 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1383
1384 // derived_instance is an instance of base and derived.
1385 CHECK(derived_instance->Equals(env.local(),
1386 derived_instance->FindInstanceInPrototypeChain(
1387 base))
1388 .FromJust());
1389 CHECK(derived_instance->Equals(env.local(),
1390 derived_instance->FindInstanceInPrototypeChain(
1391 derived))
1392 .FromJust());
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(derived_instance2->Equals(
1401 env.local(),
1402 other_instance->FindInstanceInPrototypeChain(base))
1403 .FromJust());
1404 CHECK(derived_instance2->Equals(env.local(),
1405 other_instance->FindInstanceInPrototypeChain(
1406 derived))
1407 .FromJust());
1408 CHECK(other_instance->Equals(
1409 env.local(),
1410 other_instance->FindInstanceInPrototypeChain(other))
1411 .FromJust());
1412 }
1413
1414
THREADED_TEST(TinyInteger)1415 THREADED_TEST(TinyInteger) {
1416 LocalContext env;
1417 v8::Isolate* isolate = env->GetIsolate();
1418 v8::HandleScope scope(isolate);
1419
1420 int32_t value = 239;
1421 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1422 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1423
1424 value_obj = v8::Integer::New(isolate, value);
1425 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1426 }
1427
1428
THREADED_TEST(BigSmiInteger)1429 THREADED_TEST(BigSmiInteger) {
1430 LocalContext env;
1431 v8::HandleScope scope(env->GetIsolate());
1432 v8::Isolate* isolate = CcTest::isolate();
1433
1434 int32_t value = i::Smi::kMaxValue;
1435 // We cannot add one to a Smi::kMaxValue without wrapping.
1436 if (i::SmiValuesAre31Bits()) {
1437 CHECK(i::Smi::IsValid(value));
1438 CHECK(!i::Smi::IsValid(value + 1));
1439
1440 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1442
1443 value_obj = v8::Integer::New(isolate, value);
1444 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1445 }
1446 }
1447
1448
THREADED_TEST(BigInteger)1449 THREADED_TEST(BigInteger) {
1450 LocalContext env;
1451 v8::HandleScope scope(env->GetIsolate());
1452 v8::Isolate* isolate = CcTest::isolate();
1453
1454 // We cannot add one to a Smi::kMaxValue without wrapping.
1455 if (i::SmiValuesAre31Bits()) {
1456 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1457 // The code will not be run in that case, due to the "if" guard.
1458 int32_t value =
1459 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1460 CHECK(value > i::Smi::kMaxValue);
1461 CHECK(!i::Smi::IsValid(value));
1462
1463 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1464 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1465
1466 value_obj = v8::Integer::New(isolate, value);
1467 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1468 }
1469 }
1470
1471
THREADED_TEST(TinyUnsignedInteger)1472 THREADED_TEST(TinyUnsignedInteger) {
1473 LocalContext env;
1474 v8::HandleScope scope(env->GetIsolate());
1475 v8::Isolate* isolate = CcTest::isolate();
1476
1477 uint32_t value = 239;
1478
1479 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1480 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1481
1482 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1483 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1484 }
1485
1486
THREADED_TEST(BigUnsignedSmiInteger)1487 THREADED_TEST(BigUnsignedSmiInteger) {
1488 LocalContext env;
1489 v8::HandleScope scope(env->GetIsolate());
1490 v8::Isolate* isolate = CcTest::isolate();
1491
1492 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1493 CHECK(i::Smi::IsValid(value));
1494 CHECK(!i::Smi::IsValid(value + 1));
1495
1496 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1497 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1498
1499 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1500 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1501 }
1502
1503
THREADED_TEST(BigUnsignedInteger)1504 THREADED_TEST(BigUnsignedInteger) {
1505 LocalContext env;
1506 v8::HandleScope scope(env->GetIsolate());
1507 v8::Isolate* isolate = CcTest::isolate();
1508
1509 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1510 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1511 CHECK(!i::Smi::IsValid(value));
1512
1513 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1514 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1515
1516 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1517 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1518 }
1519
1520
THREADED_TEST(OutOfSignedRangeUnsignedInteger)1521 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1522 LocalContext env;
1523 v8::HandleScope scope(env->GetIsolate());
1524 v8::Isolate* isolate = CcTest::isolate();
1525
1526 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1527 uint32_t value = INT32_MAX_AS_UINT + 1;
1528 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1529
1530 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1532
1533 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1534 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1535 }
1536
1537
THREADED_TEST(IsNativeError)1538 THREADED_TEST(IsNativeError) {
1539 LocalContext env;
1540 v8::HandleScope scope(env->GetIsolate());
1541 v8::Local<Value> syntax_error = CompileRun(
1542 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1543 CHECK(syntax_error->IsNativeError());
1544 v8::Local<Value> not_error = CompileRun("{a:42}");
1545 CHECK(!not_error->IsNativeError());
1546 v8::Local<Value> not_object = CompileRun("42");
1547 CHECK(!not_object->IsNativeError());
1548 }
1549
1550
THREADED_TEST(IsGeneratorFunctionOrObject)1551 THREADED_TEST(IsGeneratorFunctionOrObject) {
1552 LocalContext env;
1553 v8::HandleScope scope(env->GetIsolate());
1554
1555 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1556 v8::Local<Value> gen = CompileRun("gen");
1557 v8::Local<Value> genObj = CompileRun("gen()");
1558 v8::Local<Value> object = CompileRun("{a:42}");
1559 v8::Local<Value> func = CompileRun("func");
1560
1561 CHECK(gen->IsGeneratorFunction());
1562 CHECK(gen->IsFunction());
1563 CHECK(!gen->IsGeneratorObject());
1564
1565 CHECK(!genObj->IsGeneratorFunction());
1566 CHECK(!genObj->IsFunction());
1567 CHECK(genObj->IsGeneratorObject());
1568
1569 CHECK(!object->IsGeneratorFunction());
1570 CHECK(!object->IsFunction());
1571 CHECK(!object->IsGeneratorObject());
1572
1573 CHECK(!func->IsGeneratorFunction());
1574 CHECK(func->IsFunction());
1575 CHECK(!func->IsGeneratorObject());
1576 }
1577
1578
THREADED_TEST(ArgumentsObject)1579 THREADED_TEST(ArgumentsObject) {
1580 LocalContext env;
1581 v8::HandleScope scope(env->GetIsolate());
1582 v8::Local<Value> arguments_object =
1583 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1584 CHECK(arguments_object->IsArgumentsObject());
1585 v8::Local<Value> array = CompileRun("[1,2,3]");
1586 CHECK(!array->IsArgumentsObject());
1587 v8::Local<Value> object = CompileRun("{a:42}");
1588 CHECK(!object->IsArgumentsObject());
1589 }
1590
1591
THREADED_TEST(IsMapOrSet)1592 THREADED_TEST(IsMapOrSet) {
1593 LocalContext env;
1594 v8::HandleScope scope(env->GetIsolate());
1595 v8::Local<Value> map = CompileRun("new Map()");
1596 v8::Local<Value> set = CompileRun("new Set()");
1597 v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1598 v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1599 CHECK(map->IsMap());
1600 CHECK(set->IsSet());
1601 CHECK(weak_map->IsWeakMap());
1602 CHECK(weak_set->IsWeakSet());
1603
1604 CHECK(!map->IsSet());
1605 CHECK(!map->IsWeakMap());
1606 CHECK(!map->IsWeakSet());
1607
1608 CHECK(!set->IsMap());
1609 CHECK(!set->IsWeakMap());
1610 CHECK(!set->IsWeakSet());
1611
1612 CHECK(!weak_map->IsMap());
1613 CHECK(!weak_map->IsSet());
1614 CHECK(!weak_map->IsWeakSet());
1615
1616 CHECK(!weak_set->IsMap());
1617 CHECK(!weak_set->IsSet());
1618 CHECK(!weak_set->IsWeakMap());
1619
1620 v8::Local<Value> object = CompileRun("{a:42}");
1621 CHECK(!object->IsMap());
1622 CHECK(!object->IsSet());
1623 CHECK(!object->IsWeakMap());
1624 CHECK(!object->IsWeakSet());
1625 }
1626
1627
THREADED_TEST(StringObject)1628 THREADED_TEST(StringObject) {
1629 LocalContext env;
1630 v8::HandleScope scope(env->GetIsolate());
1631 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1632 CHECK(boxed_string->IsStringObject());
1633 v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1634 CHECK(!unboxed_string->IsStringObject());
1635 v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1636 CHECK(!boxed_not_string->IsStringObject());
1637 v8::Local<Value> not_object = CompileRun("0");
1638 CHECK(!not_object->IsStringObject());
1639 v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1640 CHECK(!as_boxed.IsEmpty());
1641 Local<v8::String> the_string = as_boxed->ValueOf();
1642 CHECK(!the_string.IsEmpty());
1643 ExpectObject("\"test\"", the_string);
1644 v8::Local<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1645 CHECK(new_boxed_string->IsStringObject());
1646 as_boxed = new_boxed_string.As<v8::StringObject>();
1647 the_string = as_boxed->ValueOf();
1648 CHECK(!the_string.IsEmpty());
1649 ExpectObject("\"test\"", the_string);
1650 }
1651
1652
TEST(StringObjectDelete)1653 TEST(StringObjectDelete) {
1654 LocalContext context;
1655 v8::HandleScope scope(context->GetIsolate());
1656 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1657 CHECK(boxed_string->IsStringObject());
1658 v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1659 CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1660 CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1661 }
1662
1663
THREADED_TEST(NumberObject)1664 THREADED_TEST(NumberObject) {
1665 LocalContext env;
1666 v8::HandleScope scope(env->GetIsolate());
1667 v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1668 CHECK(boxed_number->IsNumberObject());
1669 v8::Local<Value> unboxed_number = CompileRun("42");
1670 CHECK(!unboxed_number->IsNumberObject());
1671 v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1672 CHECK(!boxed_not_number->IsNumberObject());
1673 v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1674 CHECK(!as_boxed.IsEmpty());
1675 double the_number = as_boxed->ValueOf();
1676 CHECK_EQ(42.0, the_number);
1677 v8::Local<v8::Value> new_boxed_number =
1678 v8::NumberObject::New(env->GetIsolate(), 43);
1679 CHECK(new_boxed_number->IsNumberObject());
1680 as_boxed = new_boxed_number.As<v8::NumberObject>();
1681 the_number = as_boxed->ValueOf();
1682 CHECK_EQ(43.0, the_number);
1683 }
1684
1685
THREADED_TEST(BooleanObject)1686 THREADED_TEST(BooleanObject) {
1687 LocalContext env;
1688 v8::HandleScope scope(env->GetIsolate());
1689 v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1690 CHECK(boxed_boolean->IsBooleanObject());
1691 v8::Local<Value> unboxed_boolean = CompileRun("true");
1692 CHECK(!unboxed_boolean->IsBooleanObject());
1693 v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1694 CHECK(!boxed_not_boolean->IsBooleanObject());
1695 v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1696 CHECK(!as_boxed.IsEmpty());
1697 bool the_boolean = as_boxed->ValueOf();
1698 CHECK_EQ(true, the_boolean);
1699 v8::Local<v8::Value> boxed_true =
1700 v8::BooleanObject::New(env->GetIsolate(), true);
1701 v8::Local<v8::Value> boxed_false =
1702 v8::BooleanObject::New(env->GetIsolate(), false);
1703 CHECK(boxed_true->IsBooleanObject());
1704 CHECK(boxed_false->IsBooleanObject());
1705 as_boxed = boxed_true.As<v8::BooleanObject>();
1706 CHECK_EQ(true, as_boxed->ValueOf());
1707 as_boxed = boxed_false.As<v8::BooleanObject>();
1708 CHECK_EQ(false, as_boxed->ValueOf());
1709 }
1710
1711
THREADED_TEST(PrimitiveAndWrappedBooleans)1712 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1713 LocalContext env;
1714 v8::HandleScope scope(env->GetIsolate());
1715
1716 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1717 CHECK(primitive_false->IsBoolean());
1718 CHECK(!primitive_false->IsBooleanObject());
1719 CHECK(!primitive_false->BooleanValue(env.local()).FromJust());
1720 CHECK(!primitive_false->IsTrue());
1721 CHECK(primitive_false->IsFalse());
1722
1723 Local<Value> false_value = BooleanObject::New(env->GetIsolate(), false);
1724 CHECK(!false_value->IsBoolean());
1725 CHECK(false_value->IsBooleanObject());
1726 CHECK(false_value->BooleanValue(env.local()).FromJust());
1727 CHECK(!false_value->IsTrue());
1728 CHECK(!false_value->IsFalse());
1729
1730 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1731 CHECK(!false_boolean_object->IsBoolean());
1732 CHECK(false_boolean_object->IsBooleanObject());
1733 CHECK(false_boolean_object->BooleanValue(env.local()).FromJust());
1734 CHECK(!false_boolean_object->ValueOf());
1735 CHECK(!false_boolean_object->IsTrue());
1736 CHECK(!false_boolean_object->IsFalse());
1737
1738 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1739 CHECK(primitive_true->IsBoolean());
1740 CHECK(!primitive_true->IsBooleanObject());
1741 CHECK(primitive_true->BooleanValue(env.local()).FromJust());
1742 CHECK(primitive_true->IsTrue());
1743 CHECK(!primitive_true->IsFalse());
1744
1745 Local<Value> true_value = BooleanObject::New(env->GetIsolate(), true);
1746 CHECK(!true_value->IsBoolean());
1747 CHECK(true_value->IsBooleanObject());
1748 CHECK(true_value->BooleanValue(env.local()).FromJust());
1749 CHECK(!true_value->IsTrue());
1750 CHECK(!true_value->IsFalse());
1751
1752 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1753 CHECK(!true_boolean_object->IsBoolean());
1754 CHECK(true_boolean_object->IsBooleanObject());
1755 CHECK(true_boolean_object->BooleanValue(env.local()).FromJust());
1756 CHECK(true_boolean_object->ValueOf());
1757 CHECK(!true_boolean_object->IsTrue());
1758 CHECK(!true_boolean_object->IsFalse());
1759 }
1760
1761
THREADED_TEST(Number)1762 THREADED_TEST(Number) {
1763 LocalContext env;
1764 v8::HandleScope scope(env->GetIsolate());
1765 double PI = 3.1415926;
1766 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1767 CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1768 }
1769
1770
THREADED_TEST(ToNumber)1771 THREADED_TEST(ToNumber) {
1772 LocalContext env;
1773 v8::Isolate* isolate = CcTest::isolate();
1774 v8::HandleScope scope(isolate);
1775 Local<String> str = v8_str("3.1415926");
1776 CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1777 v8::Local<v8::Boolean> t = v8::True(isolate);
1778 CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1779 v8::Local<v8::Boolean> f = v8::False(isolate);
1780 CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1781 }
1782
1783
THREADED_TEST(Date)1784 THREADED_TEST(Date) {
1785 LocalContext env;
1786 v8::HandleScope scope(env->GetIsolate());
1787 double PI = 3.1415926;
1788 Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1789 CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1790 CHECK(date.As<v8::Date>()
1791 ->Set(env.local(), v8_str("property"),
1792 v8::Integer::New(env->GetIsolate(), 42))
1793 .FromJust());
1794 CHECK_EQ(42, date.As<v8::Date>()
1795 ->Get(env.local(), v8_str("property"))
1796 .ToLocalChecked()
1797 ->Int32Value(env.local())
1798 .FromJust());
1799 }
1800
1801
THREADED_TEST(Boolean)1802 THREADED_TEST(Boolean) {
1803 LocalContext env;
1804 v8::Isolate* isolate = env->GetIsolate();
1805 v8::HandleScope scope(isolate);
1806 v8::Local<v8::Boolean> t = v8::True(isolate);
1807 CHECK(t->Value());
1808 v8::Local<v8::Boolean> f = v8::False(isolate);
1809 CHECK(!f->Value());
1810 v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1811 CHECK(!u->BooleanValue(env.local()).FromJust());
1812 v8::Local<v8::Primitive> n = v8::Null(isolate);
1813 CHECK(!n->BooleanValue(env.local()).FromJust());
1814 v8::Local<String> str1 = v8_str("");
1815 CHECK(!str1->BooleanValue(env.local()).FromJust());
1816 v8::Local<String> str2 = v8_str("x");
1817 CHECK(str2->BooleanValue(env.local()).FromJust());
1818 CHECK(!v8::Number::New(isolate, 0)->BooleanValue(env.local()).FromJust());
1819 CHECK(v8::Number::New(isolate, -1)->BooleanValue(env.local()).FromJust());
1820 CHECK(v8::Number::New(isolate, 1)->BooleanValue(env.local()).FromJust());
1821 CHECK(v8::Number::New(isolate, 42)->BooleanValue(env.local()).FromJust());
1822 CHECK(!v8_compile("NaN")
1823 ->Run(env.local())
1824 .ToLocalChecked()
1825 ->BooleanValue(env.local())
1826 .FromJust());
1827 }
1828
1829
DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value> & args)1830 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1831 ApiTestFuzzer::Fuzz();
1832 args.GetReturnValue().Set(v8_num(13.4));
1833 }
1834
1835
GetM(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1836 static void GetM(Local<String> name,
1837 const v8::PropertyCallbackInfo<v8::Value>& info) {
1838 ApiTestFuzzer::Fuzz();
1839 info.GetReturnValue().Set(v8_num(876));
1840 }
1841
1842
THREADED_TEST(GlobalPrototype)1843 THREADED_TEST(GlobalPrototype) {
1844 v8::Isolate* isolate = CcTest::isolate();
1845 v8::HandleScope scope(isolate);
1846 v8::Local<v8::FunctionTemplate> func_templ =
1847 v8::FunctionTemplate::New(isolate);
1848 func_templ->PrototypeTemplate()->Set(
1849 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1850 v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1851 templ->Set(isolate, "x", v8_num(200));
1852 templ->SetAccessor(v8_str("m"), GetM);
1853 LocalContext env(0, templ);
1854 v8::Local<Script> script(v8_compile("dummy()"));
1855 v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1856 CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
1857 CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
1858 CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
1859 }
1860
1861
THREADED_TEST(ObjectTemplate)1862 THREADED_TEST(ObjectTemplate) {
1863 LocalContext env;
1864 v8::Isolate* isolate = CcTest::isolate();
1865 v8::HandleScope scope(isolate);
1866 Local<v8::FunctionTemplate> acc =
1867 v8::FunctionTemplate::New(isolate, Returns42);
1868 CHECK(env->Global()
1869 ->Set(env.local(), v8_str("acc"),
1870 acc->GetFunction(env.local()).ToLocalChecked())
1871 .FromJust());
1872
1873 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1874 v8::Local<v8::String> class_name = v8_str("the_class_name");
1875 fun->SetClassName(class_name);
1876 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
1877 templ1->Set(isolate, "x", v8_num(10));
1878 templ1->Set(isolate, "y", v8_num(13));
1879 templ1->Set(v8_str("foo"), acc);
1880 Local<v8::Object> instance1 =
1881 templ1->NewInstance(env.local()).ToLocalChecked();
1882 CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
1883 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
1884 CHECK(CompileRun("(p.x == 10)")->BooleanValue(env.local()).FromJust());
1885 CHECK(CompileRun("(p.y == 13)")->BooleanValue(env.local()).FromJust());
1886 CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(env.local()).FromJust());
1887 CHECK(CompileRun("(p.foo == acc)")->BooleanValue(env.local()).FromJust());
1888 // Ensure that foo become a data field.
1889 CompileRun("p.foo = function() {}");
1890 Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
1891 fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1892 Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
1893 templ2->Set(isolate, "a", v8_num(12));
1894 templ2->Set(isolate, "b", templ1);
1895 templ2->Set(v8_str("bar"), acc);
1896 templ2->SetAccessorProperty(v8_str("acc"), acc);
1897 Local<v8::Object> instance2 =
1898 templ2->NewInstance(env.local()).ToLocalChecked();
1899 CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
1900 CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(env.local()).FromJust());
1901 CHECK(CompileRun("(q.a == 12)")->BooleanValue(env.local()).FromJust());
1902 CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(env.local()).FromJust());
1903 CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(env.local()).FromJust());
1904 CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
1905 CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(env.local()).FromJust());
1906 CHECK(CompileRun("(q.b !== p)")->BooleanValue(env.local()).FromJust());
1907 CHECK(CompileRun("(q.acc == 42)")->BooleanValue(env.local()).FromJust());
1908 CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(env.local()).FromJust());
1909 CHECK(CompileRun("(q.bar == acc)")->BooleanValue(env.local()).FromJust());
1910
1911 instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
1912 CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
1913 CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(env.local()).FromJust());
1914 CHECK(CompileRun("(q2.a == 12)")->BooleanValue(env.local()).FromJust());
1915 CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(env.local()).FromJust());
1916 CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(env.local()).FromJust());
1917 CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
1918 CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(env.local()).FromJust());
1919 CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(env.local()).FromJust());
1920 CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(env.local()).FromJust());
1921 CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(env.local()).FromJust());
1922
1923 CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(env.local()).FromJust());
1924 CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")
1925 ->BooleanValue(env.local())
1926 .FromJust());
1927 CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
1928 "(desc1.get === acc)")
1929 ->BooleanValue(env.local())
1930 .FromJust());
1931 CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
1932 "(desc2.get === acc)")
1933 ->BooleanValue(env.local())
1934 .FromJust());
1935 }
1936
THREADED_TEST(IntegerValue)1937 THREADED_TEST(IntegerValue) {
1938 LocalContext env;
1939 v8::Isolate* isolate = CcTest::isolate();
1940 v8::HandleScope scope(isolate);
1941
1942 CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
1943 }
1944
GetNirk(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1945 static void GetNirk(Local<String> name,
1946 const v8::PropertyCallbackInfo<v8::Value>& info) {
1947 ApiTestFuzzer::Fuzz();
1948 info.GetReturnValue().Set(v8_num(900));
1949 }
1950
GetRino(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)1951 static void GetRino(Local<String> name,
1952 const v8::PropertyCallbackInfo<v8::Value>& info) {
1953 ApiTestFuzzer::Fuzz();
1954 info.GetReturnValue().Set(v8_num(560));
1955 }
1956
1957 enum ObjectInstantiationMode {
1958 // Create object using ObjectTemplate::NewInstance.
1959 ObjectTemplate_NewInstance,
1960 // Create object using FunctionTemplate::NewInstance on constructor.
1961 Constructor_GetFunction_NewInstance,
1962 // Create object using new operator on constructor.
1963 Constructor_GetFunction_New
1964 };
1965
1966 // Test object instance creation using a function template with an instance
1967 // template inherited from another function template with accessors and data
1968 // properties in prototype template.
TestObjectTemplateInheritedWithPrototype(ObjectInstantiationMode mode)1969 static void TestObjectTemplateInheritedWithPrototype(
1970 ObjectInstantiationMode mode) {
1971 LocalContext env;
1972 v8::Isolate* isolate = CcTest::isolate();
1973 v8::HandleScope scope(isolate);
1974
1975 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
1976 fun_A->SetClassName(v8_str("A"));
1977 v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
1978 prototype_templ->Set(isolate, "a", v8_num(113));
1979 prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
1980 prototype_templ->Set(isolate, "b", v8_num(153));
1981
1982 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
1983 v8::Local<v8::String> class_name = v8_str("B");
1984 fun_B->SetClassName(class_name);
1985 fun_B->Inherit(fun_A);
1986 prototype_templ = fun_B->PrototypeTemplate();
1987 prototype_templ->Set(isolate, "c", v8_num(713));
1988 prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
1989 prototype_templ->Set(isolate, "d", v8_num(753));
1990
1991 Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
1992 templ->Set(isolate, "x", v8_num(10));
1993 templ->Set(isolate, "y", v8_num(13));
1994
1995 // Perform several iterations to trigger creation from cached boilerplate.
1996 for (int i = 0; i < 3; i++) {
1997 Local<v8::Object> instance;
1998 switch (mode) {
1999 case ObjectTemplate_NewInstance:
2000 instance = templ->NewInstance(env.local()).ToLocalChecked();
2001 break;
2002
2003 case Constructor_GetFunction_NewInstance: {
2004 Local<v8::Function> function_B =
2005 fun_B->GetFunction(env.local()).ToLocalChecked();
2006 instance = function_B->NewInstance(env.local()).ToLocalChecked();
2007 break;
2008 }
2009 case Constructor_GetFunction_New: {
2010 Local<v8::Function> function_B =
2011 fun_B->GetFunction(env.local()).ToLocalChecked();
2012 if (i == 0) {
2013 CHECK(env->Global()
2014 ->Set(env.local(), class_name, function_B)
2015 .FromJust());
2016 }
2017 instance =
2018 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2019 break;
2020 }
2021 default:
2022 UNREACHABLE();
2023 }
2024
2025 CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2026 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2027
2028 CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2029 CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2030
2031 CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2032 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2033 CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2034 CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2035 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2036 CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2037 }
2038 }
2039
THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1)2040 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2041 TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2042 }
2043
THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2)2044 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2045 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2046 }
2047
THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3)2048 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2049 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2050 }
2051
2052 // Test object instance creation using a function template without an instance
2053 // template inherited from another function template.
TestObjectTemplateInheritedWithoutInstanceTemplate(ObjectInstantiationMode mode)2054 static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2055 ObjectInstantiationMode mode) {
2056 LocalContext env;
2057 v8::Isolate* isolate = CcTest::isolate();
2058 v8::HandleScope scope(isolate);
2059
2060 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2061 fun_A->SetClassName(v8_str("A"));
2062
2063 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2064 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2065 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2066
2067 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2068 v8::Local<v8::String> class_name = v8_str("B");
2069 fun_B->SetClassName(class_name);
2070 fun_B->Inherit(fun_A);
2071
2072 // Perform several iterations to trigger creation from cached boilerplate.
2073 for (int i = 0; i < 3; i++) {
2074 Local<v8::Object> instance;
2075 switch (mode) {
2076 case Constructor_GetFunction_NewInstance: {
2077 Local<v8::Function> function_B =
2078 fun_B->GetFunction(env.local()).ToLocalChecked();
2079 instance = function_B->NewInstance(env.local()).ToLocalChecked();
2080 break;
2081 }
2082 case Constructor_GetFunction_New: {
2083 Local<v8::Function> function_B =
2084 fun_B->GetFunction(env.local()).ToLocalChecked();
2085 if (i == 0) {
2086 CHECK(env->Global()
2087 ->Set(env.local(), class_name, function_B)
2088 .FromJust());
2089 }
2090 instance =
2091 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2092 break;
2093 }
2094 default:
2095 UNREACHABLE();
2096 }
2097
2098 CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2099 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2100
2101 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2102 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2103 }
2104 }
2105
THREADED_TEST(TestObjectTemplateInheritedWithPrototype1)2106 THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2107 TestObjectTemplateInheritedWithoutInstanceTemplate(
2108 Constructor_GetFunction_NewInstance);
2109 }
2110
THREADED_TEST(TestObjectTemplateInheritedWithPrototype2)2111 THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2112 TestObjectTemplateInheritedWithoutInstanceTemplate(
2113 Constructor_GetFunction_New);
2114 }
2115
THREADED_TEST(TestObjectTemplateClassInheritance)2116 THREADED_TEST(TestObjectTemplateClassInheritance) {
2117 LocalContext env;
2118 v8::Isolate* isolate = CcTest::isolate();
2119 v8::HandleScope scope(isolate);
2120
2121 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2122 fun_A->SetClassName(v8_str("A"));
2123
2124 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2125 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2126 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2127
2128 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2129 v8::Local<v8::String> class_name = v8_str("B");
2130 fun_B->SetClassName(class_name);
2131 fun_B->Inherit(fun_A);
2132
2133 v8::Local<v8::String> subclass_name = v8_str("C");
2134 v8::Local<v8::Object> b_proto;
2135 v8::Local<v8::Object> c_proto;
2136 // Perform several iterations to make sure the cache doesn't break
2137 // subclassing.
2138 for (int i = 0; i < 3; i++) {
2139 Local<v8::Function> function_B =
2140 fun_B->GetFunction(env.local()).ToLocalChecked();
2141 if (i == 0) {
2142 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2143 CompileRun("class C extends B {}");
2144 b_proto =
2145 CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2146 c_proto =
2147 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2148 CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2149 }
2150 Local<v8::Object> instance =
2151 CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2152 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2153
2154 CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2155 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2156
2157 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2158 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2159 }
2160 }
2161
NamedPropertyGetterWhichReturns42(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2162 static void NamedPropertyGetterWhichReturns42(
2163 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2164 info.GetReturnValue().Set(v8_num(42));
2165 }
2166
THREADED_TEST(TestObjectTemplateReflectConstruct)2167 THREADED_TEST(TestObjectTemplateReflectConstruct) {
2168 LocalContext env;
2169 v8::Isolate* isolate = CcTest::isolate();
2170 v8::HandleScope scope(isolate);
2171
2172 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2173 fun_B->InstanceTemplate()->SetHandler(
2174 v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2175 v8::Local<v8::String> class_name = v8_str("B");
2176 fun_B->SetClassName(class_name);
2177
2178 v8::Local<v8::String> subclass_name = v8_str("C");
2179 v8::Local<v8::Object> b_proto;
2180 v8::Local<v8::Object> c_proto;
2181 // Perform several iterations to make sure the cache doesn't break
2182 // subclassing.
2183 for (int i = 0; i < 3; i++) {
2184 Local<v8::Function> function_B =
2185 fun_B->GetFunction(env.local()).ToLocalChecked();
2186 if (i == 0) {
2187 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2188 CompileRun("function C() {}");
2189 c_proto =
2190 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2191 }
2192 Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2193 ->ToObject(env.local())
2194 .ToLocalChecked();
2195 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2196
2197 CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2198 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2199
2200 CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2201 CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2202 }
2203 }
2204
GetFlabby(const v8::FunctionCallbackInfo<v8::Value> & args)2205 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2206 ApiTestFuzzer::Fuzz();
2207 args.GetReturnValue().Set(v8_num(17.2));
2208 }
2209
2210
GetKnurd(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)2211 static void GetKnurd(Local<String> property,
2212 const v8::PropertyCallbackInfo<v8::Value>& info) {
2213 ApiTestFuzzer::Fuzz();
2214 info.GetReturnValue().Set(v8_num(15.2));
2215 }
2216
2217
THREADED_TEST(DescriptorInheritance)2218 THREADED_TEST(DescriptorInheritance) {
2219 v8::Isolate* isolate = CcTest::isolate();
2220 v8::HandleScope scope(isolate);
2221 v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2222 super->PrototypeTemplate()->Set(isolate, "flabby",
2223 v8::FunctionTemplate::New(isolate,
2224 GetFlabby));
2225 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2226
2227 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2228
2229 v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2230 base1->Inherit(super);
2231 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2232
2233 v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2234 base2->Inherit(super);
2235 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2236
2237 LocalContext env;
2238
2239 CHECK(env->Global()
2240 ->Set(env.local(), v8_str("s"),
2241 super->GetFunction(env.local()).ToLocalChecked())
2242 .FromJust());
2243 CHECK(env->Global()
2244 ->Set(env.local(), v8_str("base1"),
2245 base1->GetFunction(env.local()).ToLocalChecked())
2246 .FromJust());
2247 CHECK(env->Global()
2248 ->Set(env.local(), v8_str("base2"),
2249 base2->GetFunction(env.local()).ToLocalChecked())
2250 .FromJust());
2251
2252 // Checks right __proto__ chain.
2253 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2254 ->BooleanValue(env.local())
2255 .FromJust());
2256 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2257 ->BooleanValue(env.local())
2258 .FromJust());
2259
2260 CHECK(v8_compile("s.prototype.PI == 3.14")
2261 ->Run(env.local())
2262 .ToLocalChecked()
2263 ->BooleanValue(env.local())
2264 .FromJust());
2265
2266 // Instance accessor should not be visible on function object or its prototype
2267 CHECK(
2268 CompileRun("s.knurd == undefined")->BooleanValue(env.local()).FromJust());
2269 CHECK(CompileRun("s.prototype.knurd == undefined")
2270 ->BooleanValue(env.local())
2271 .FromJust());
2272 CHECK(CompileRun("base1.prototype.knurd == undefined")
2273 ->BooleanValue(env.local())
2274 .FromJust());
2275
2276 CHECK(env->Global()
2277 ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2278 .ToLocalChecked()
2279 ->NewInstance(env.local())
2280 .ToLocalChecked())
2281 .FromJust());
2282 CHECK_EQ(17.2,
2283 CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2284 CHECK(CompileRun("'flabby' in obj")->BooleanValue(env.local()).FromJust());
2285 CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2286 CHECK(CompileRun("'knurd' in obj")->BooleanValue(env.local()).FromJust());
2287 CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2288
2289 CHECK(env->Global()
2290 ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2291 .ToLocalChecked()
2292 ->NewInstance(env.local())
2293 .ToLocalChecked())
2294 .FromJust());
2295 CHECK_EQ(17.2,
2296 CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2297 CHECK(CompileRun("'flabby' in obj2")->BooleanValue(env.local()).FromJust());
2298 CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2299 CHECK(CompileRun("'knurd' in obj2")->BooleanValue(env.local()).FromJust());
2300 CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2301
2302 // base1 and base2 cannot cross reference to each's prototype
2303 CHECK(CompileRun("obj.v2")->IsUndefined());
2304 CHECK(CompileRun("obj2.v1")->IsUndefined());
2305 }
2306
THREADED_TEST(DescriptorInheritance2)2307 THREADED_TEST(DescriptorInheritance2) {
2308 LocalContext env;
2309 v8::Isolate* isolate = CcTest::isolate();
2310 v8::HandleScope scope(isolate);
2311 v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2312 fun_A->SetClassName(v8_str("A"));
2313 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2314 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2315 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2316
2317 v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2318 fun_B->SetClassName(v8_str("B"));
2319 fun_B->Inherit(fun_A);
2320
2321 v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2322 fun_C->SetClassName(v8_str("C"));
2323 fun_C->Inherit(fun_B);
2324 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2325 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2326 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2327
2328 v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2329 fun_D->SetClassName(v8_str("D"));
2330 fun_D->Inherit(fun_C);
2331
2332 v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2333 fun_E->SetClassName(v8_str("E"));
2334 fun_E->Inherit(fun_D);
2335 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2336 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2337 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2338
2339 v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2340 fun_F->SetClassName(v8_str("F"));
2341 fun_F->Inherit(fun_E);
2342 v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2343 const int kDataPropertiesNumber = 100;
2344 for (int i = 0; i < kDataPropertiesNumber; i++) {
2345 v8::Local<v8::Value> val = v8_num(i);
2346 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2347 v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
2348
2349 templ->Set(name, val);
2350 templ->Set(val_str, val);
2351 }
2352
2353 CHECK(env->Global()
2354 ->Set(env.local(), v8_str("F"),
2355 fun_F->GetFunction(env.local()).ToLocalChecked())
2356 .FromJust());
2357
2358 v8::Local<v8::Script> script = v8_compile("o = new F()");
2359
2360 for (int i = 0; i < 100; i++) {
2361 v8::HandleScope scope(isolate);
2362 script->Run(env.local()).ToLocalChecked();
2363 }
2364 v8::Local<v8::Object> object = script->Run(env.local())
2365 .ToLocalChecked()
2366 ->ToObject(env.local())
2367 .ToLocalChecked();
2368
2369 CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2370 CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2371 CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2372
2373 CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2374 CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2375 CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2376
2377 CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2378 CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2379 CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2380
2381 for (int i = 0; i < kDataPropertiesNumber; i++) {
2382 v8::Local<v8::Value> val = v8_num(i);
2383 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2384 v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
2385
2386 CHECK_EQ(i, object->Get(env.local(), name)
2387 .ToLocalChecked()
2388 ->IntegerValue(env.local())
2389 .FromJust());
2390 CHECK_EQ(i, object->Get(env.local(), val)
2391 .ToLocalChecked()
2392 ->IntegerValue(env.local())
2393 .FromJust());
2394 }
2395 }
2396
2397
2398 // Helper functions for Interceptor/Accessor interaction tests
2399
SimpleAccessorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)2400 void SimpleAccessorGetter(Local<String> name,
2401 const v8::PropertyCallbackInfo<v8::Value>& info) {
2402 Local<Object> self = Local<Object>::Cast(info.This());
2403 info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(),
2404 String::Concat(v8_str("accessor_"), name))
2405 .ToLocalChecked());
2406 }
2407
SimpleAccessorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)2408 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2409 const v8::PropertyCallbackInfo<void>& info) {
2410 Local<Object> self = Local<Object>::Cast(info.This());
2411 CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2412 String::Concat(v8_str("accessor_"), name), value)
2413 .FromJust());
2414 }
2415
SymbolAccessorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2416 void SymbolAccessorGetter(Local<Name> name,
2417 const v8::PropertyCallbackInfo<v8::Value>& info) {
2418 CHECK(name->IsSymbol());
2419 Local<Symbol> sym = Local<Symbol>::Cast(name);
2420 if (sym->Name()->IsUndefined())
2421 return;
2422 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2423 }
2424
SymbolAccessorSetter(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)2425 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2426 const v8::PropertyCallbackInfo<void>& info) {
2427 CHECK(name->IsSymbol());
2428 Local<Symbol> sym = Local<Symbol>::Cast(name);
2429 if (sym->Name()->IsUndefined())
2430 return;
2431 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2432 }
2433
SymbolAccessorGetterReturnsDefault(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2434 void SymbolAccessorGetterReturnsDefault(
2435 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2436 CHECK(name->IsSymbol());
2437 Local<Symbol> sym = Local<Symbol>::Cast(name);
2438 if (sym->Name()->IsUndefined()) return;
2439 info.GetReturnValue().Set(info.Data());
2440 }
2441
ThrowingSymbolAccessorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)2442 static void ThrowingSymbolAccessorGetter(
2443 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2444 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2445 }
2446
2447
THREADED_TEST(AccessorIsPreservedOnAttributeChange)2448 THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2449 v8::Isolate* isolate = CcTest::isolate();
2450 v8::HandleScope scope(isolate);
2451 LocalContext env;
2452 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2453 i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2454 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2455 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2456 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2457 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2458 // But we should still have an AccessorInfo.
2459 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2460 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2461 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2462 CHECK(it.GetAccessors()->IsAccessorInfo());
2463 }
2464
2465
THREADED_TEST(UndefinedIsNotEnumerable)2466 THREADED_TEST(UndefinedIsNotEnumerable) {
2467 LocalContext env;
2468 v8::HandleScope scope(env->GetIsolate());
2469 v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2470 CHECK(result->IsFalse());
2471 }
2472
2473
2474 v8::Local<Script> call_recursively_script;
2475 static const int kTargetRecursionDepth = 150; // near maximum
2476
2477
CallScriptRecursivelyCall(const v8::FunctionCallbackInfo<v8::Value> & args)2478 static void CallScriptRecursivelyCall(
2479 const v8::FunctionCallbackInfo<v8::Value>& args) {
2480 ApiTestFuzzer::Fuzz();
2481 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2482 int depth = args.This()
2483 ->Get(context, v8_str("depth"))
2484 .ToLocalChecked()
2485 ->Int32Value(context)
2486 .FromJust();
2487 if (depth == kTargetRecursionDepth) return;
2488 CHECK(args.This()
2489 ->Set(context, v8_str("depth"),
2490 v8::Integer::New(args.GetIsolate(), depth + 1))
2491 .FromJust());
2492 args.GetReturnValue().Set(
2493 call_recursively_script->Run(context).ToLocalChecked());
2494 }
2495
2496
CallFunctionRecursivelyCall(const v8::FunctionCallbackInfo<v8::Value> & args)2497 static void CallFunctionRecursivelyCall(
2498 const v8::FunctionCallbackInfo<v8::Value>& args) {
2499 ApiTestFuzzer::Fuzz();
2500 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2501 int depth = args.This()
2502 ->Get(context, v8_str("depth"))
2503 .ToLocalChecked()
2504 ->Int32Value(context)
2505 .FromJust();
2506 if (depth == kTargetRecursionDepth) {
2507 printf("[depth = %d]\n", depth);
2508 return;
2509 }
2510 CHECK(args.This()
2511 ->Set(context, v8_str("depth"),
2512 v8::Integer::New(args.GetIsolate(), depth + 1))
2513 .FromJust());
2514 v8::Local<Value> function =
2515 args.This()
2516 ->Get(context, v8_str("callFunctionRecursively"))
2517 .ToLocalChecked();
2518 args.GetReturnValue().Set(function.As<Function>()
2519 ->Call(context, args.This(), 0, NULL)
2520 .ToLocalChecked());
2521 }
2522
2523
THREADED_TEST(DeepCrossLanguageRecursion)2524 THREADED_TEST(DeepCrossLanguageRecursion) {
2525 v8::Isolate* isolate = CcTest::isolate();
2526 v8::HandleScope scope(isolate);
2527 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2528 global->Set(v8_str("callScriptRecursively"),
2529 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2530 global->Set(v8_str("callFunctionRecursively"),
2531 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2532 LocalContext env(NULL, global);
2533
2534 CHECK(env->Global()
2535 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2536 .FromJust());
2537 call_recursively_script = v8_compile("callScriptRecursively()");
2538 call_recursively_script->Run(env.local()).ToLocalChecked();
2539 call_recursively_script = v8::Local<Script>();
2540
2541 CHECK(env->Global()
2542 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2543 .FromJust());
2544 CompileRun("callFunctionRecursively()");
2545 }
2546
2547
ThrowingPropertyHandlerGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)2548 static void ThrowingPropertyHandlerGet(
2549 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2550 // Since this interceptor is used on "with" objects, the runtime will look up
2551 // @@unscopables. Punt.
2552 if (key->IsSymbol()) return;
2553 ApiTestFuzzer::Fuzz();
2554 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2555 }
2556
2557
ThrowingPropertyHandlerSet(Local<Name> key,Local<Value>,const v8::PropertyCallbackInfo<v8::Value> & info)2558 static void ThrowingPropertyHandlerSet(
2559 Local<Name> key, Local<Value>,
2560 const v8::PropertyCallbackInfo<v8::Value>& info) {
2561 info.GetIsolate()->ThrowException(key);
2562 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2563 }
2564
2565
THREADED_TEST(CallbackExceptionRegression)2566 THREADED_TEST(CallbackExceptionRegression) {
2567 v8::Isolate* isolate = CcTest::isolate();
2568 v8::HandleScope scope(isolate);
2569 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2570 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2571 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2572 LocalContext env;
2573 CHECK(env->Global()
2574 ->Set(env.local(), v8_str("obj"),
2575 obj->NewInstance(env.local()).ToLocalChecked())
2576 .FromJust());
2577 v8::Local<Value> otto =
2578 CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2579 CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2580 v8::Local<Value> netto =
2581 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2582 CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2583 }
2584
2585
THREADED_TEST(FunctionPrototype)2586 THREADED_TEST(FunctionPrototype) {
2587 v8::Isolate* isolate = CcTest::isolate();
2588 v8::HandleScope scope(isolate);
2589 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2590 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2591 LocalContext env;
2592 CHECK(env->Global()
2593 ->Set(env.local(), v8_str("Foo"),
2594 Foo->GetFunction(env.local()).ToLocalChecked())
2595 .FromJust());
2596 Local<Script> script = v8_compile("Foo.prototype.plak");
2597 CHECK_EQ(v8_run_int32value(script), 321);
2598 }
2599
2600
THREADED_TEST(InternalFields)2601 THREADED_TEST(InternalFields) {
2602 LocalContext env;
2603 v8::Isolate* isolate = env->GetIsolate();
2604 v8::HandleScope scope(isolate);
2605
2606 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2607 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2608 instance_templ->SetInternalFieldCount(1);
2609 Local<v8::Object> obj = templ->GetFunction(env.local())
2610 .ToLocalChecked()
2611 ->NewInstance(env.local())
2612 .ToLocalChecked();
2613 CHECK_EQ(1, obj->InternalFieldCount());
2614 CHECK(obj->GetInternalField(0)->IsUndefined());
2615 obj->SetInternalField(0, v8_num(17));
2616 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2617 }
2618
2619
THREADED_TEST(GlobalObjectInternalFields)2620 THREADED_TEST(GlobalObjectInternalFields) {
2621 v8::Isolate* isolate = CcTest::isolate();
2622 v8::HandleScope scope(isolate);
2623 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2624 global_template->SetInternalFieldCount(1);
2625 LocalContext env(NULL, global_template);
2626 v8::Local<v8::Object> global_proxy = env->Global();
2627 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2628 CHECK_EQ(1, global->InternalFieldCount());
2629 CHECK(global->GetInternalField(0)->IsUndefined());
2630 global->SetInternalField(0, v8_num(17));
2631 CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2632 }
2633
2634
THREADED_TEST(GlobalObjectHasRealIndexedProperty)2635 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2636 LocalContext env;
2637 v8::HandleScope scope(CcTest::isolate());
2638
2639 v8::Local<v8::Object> global = env->Global();
2640 CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2641 CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2642 }
2643
2644
CheckAlignedPointerInInternalField(Local<v8::Object> obj,void * value)2645 static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2646 void* value) {
2647 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2648 obj->SetAlignedPointerInInternalField(0, value);
2649 CcTest::heap()->CollectAllGarbage();
2650 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2651 }
2652
2653
THREADED_TEST(InternalFieldsAlignedPointers)2654 THREADED_TEST(InternalFieldsAlignedPointers) {
2655 LocalContext env;
2656 v8::Isolate* isolate = env->GetIsolate();
2657 v8::HandleScope scope(isolate);
2658
2659 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2660 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2661 instance_templ->SetInternalFieldCount(1);
2662 Local<v8::Object> obj = templ->GetFunction(env.local())
2663 .ToLocalChecked()
2664 ->NewInstance(env.local())
2665 .ToLocalChecked();
2666 CHECK_EQ(1, obj->InternalFieldCount());
2667
2668 CheckAlignedPointerInInternalField(obj, NULL);
2669
2670 int* heap_allocated = new int[100];
2671 CheckAlignedPointerInInternalField(obj, heap_allocated);
2672 delete[] heap_allocated;
2673
2674 int stack_allocated[100];
2675 CheckAlignedPointerInInternalField(obj, stack_allocated);
2676
2677 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2678 CheckAlignedPointerInInternalField(obj, huge);
2679
2680 v8::Global<v8::Object> persistent(isolate, obj);
2681 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2682 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2683 }
2684
2685
CheckAlignedPointerInEmbedderData(LocalContext * env,int index,void * value)2686 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2687 void* value) {
2688 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2689 (*env)->SetAlignedPointerInEmbedderData(index, value);
2690 CcTest::heap()->CollectAllGarbage();
2691 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2692 }
2693
2694
AlignedTestPointer(int i)2695 static void* AlignedTestPointer(int i) {
2696 return reinterpret_cast<void*>(i * 1234);
2697 }
2698
2699
THREADED_TEST(EmbedderDataAlignedPointers)2700 THREADED_TEST(EmbedderDataAlignedPointers) {
2701 LocalContext env;
2702 v8::HandleScope scope(env->GetIsolate());
2703
2704 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2705
2706 int* heap_allocated = new int[100];
2707 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2708 delete[] heap_allocated;
2709
2710 int stack_allocated[100];
2711 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2712
2713 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2714 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2715
2716 // Test growing of the embedder data's backing store.
2717 for (int i = 0; i < 100; i++) {
2718 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2719 }
2720 CcTest::heap()->CollectAllGarbage();
2721 for (int i = 0; i < 100; i++) {
2722 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2723 }
2724 }
2725
2726
CheckEmbedderData(LocalContext * env,int index,v8::Local<Value> data)2727 static void CheckEmbedderData(LocalContext* env, int index,
2728 v8::Local<Value> data) {
2729 (*env)->SetEmbedderData(index, data);
2730 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2731 }
2732
2733
THREADED_TEST(EmbedderData)2734 THREADED_TEST(EmbedderData) {
2735 LocalContext env;
2736 v8::Isolate* isolate = env->GetIsolate();
2737 v8::HandleScope scope(isolate);
2738
2739 CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
2740 CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
2741 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2742 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2743 }
2744
2745
THREADED_TEST(IdentityHash)2746 THREADED_TEST(IdentityHash) {
2747 LocalContext env;
2748 v8::Isolate* isolate = env->GetIsolate();
2749 v8::HandleScope scope(isolate);
2750
2751 // Ensure that the test starts with an fresh heap to test whether the hash
2752 // code is based on the address.
2753 CcTest::heap()->CollectAllGarbage();
2754 Local<v8::Object> obj = v8::Object::New(isolate);
2755 int hash = obj->GetIdentityHash();
2756 int hash1 = obj->GetIdentityHash();
2757 CHECK_EQ(hash, hash1);
2758 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2759 // Since the identity hash is essentially a random number two consecutive
2760 // objects should not be assigned the same hash code. If the test below fails
2761 // the random number generator should be evaluated.
2762 CHECK_NE(hash, hash2);
2763 CcTest::heap()->CollectAllGarbage();
2764 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2765 // Make sure that the identity hash is not based on the initial address of
2766 // the object alone. If the test below fails the random number generator
2767 // should be evaluated.
2768 CHECK_NE(hash, hash3);
2769 int hash4 = obj->GetIdentityHash();
2770 CHECK_EQ(hash, hash4);
2771
2772 // Check identity hashes behaviour in the presence of JS accessors.
2773 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2774 {
2775 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2776 Local<v8::Object> o1 = v8::Object::New(isolate);
2777 Local<v8::Object> o2 = v8::Object::New(isolate);
2778 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2779 }
2780 {
2781 CompileRun(
2782 "function cnst() { return 42; };\n"
2783 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2784 Local<v8::Object> o1 = v8::Object::New(isolate);
2785 Local<v8::Object> o2 = v8::Object::New(isolate);
2786 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2787 }
2788 }
2789
2790
GlobalProxyIdentityHash(bool set_in_js)2791 void GlobalProxyIdentityHash(bool set_in_js) {
2792 LocalContext env;
2793 v8::Isolate* isolate = env->GetIsolate();
2794 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2795 v8::HandleScope scope(isolate);
2796 Local<Object> global_proxy = env->Global();
2797 i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
2798 CHECK(env->Global()
2799 ->Set(env.local(), v8_str("global"), global_proxy)
2800 .FromJust());
2801 int32_t hash1;
2802 if (set_in_js) {
2803 CompileRun("var m = new Set(); m.add(global);");
2804 i::Object* original_hash = i_global_proxy->GetHash();
2805 CHECK(original_hash->IsSmi());
2806 hash1 = i::Smi::cast(original_hash)->value();
2807 } else {
2808 hash1 = i::Object::GetOrCreateHash(i_isolate, i_global_proxy)->value();
2809 }
2810 // Hash should be retained after being detached.
2811 env->DetachGlobal();
2812 int hash2 = global_proxy->GetIdentityHash();
2813 CHECK_EQ(hash1, hash2);
2814 {
2815 // Re-attach global proxy to a new context, hash should stay the same.
2816 LocalContext env2(NULL, Local<ObjectTemplate>(), global_proxy);
2817 int hash3 = global_proxy->GetIdentityHash();
2818 CHECK_EQ(hash1, hash3);
2819 }
2820 }
2821
2822
THREADED_TEST(GlobalProxyIdentityHash)2823 THREADED_TEST(GlobalProxyIdentityHash) {
2824 GlobalProxyIdentityHash(true);
2825 GlobalProxyIdentityHash(false);
2826 }
2827
2828
TEST(SymbolIdentityHash)2829 TEST(SymbolIdentityHash) {
2830 LocalContext env;
2831 v8::Isolate* isolate = env->GetIsolate();
2832 v8::HandleScope scope(isolate);
2833
2834 {
2835 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2836 int hash = symbol->GetIdentityHash();
2837 int hash1 = symbol->GetIdentityHash();
2838 CHECK_EQ(hash, hash1);
2839 CcTest::heap()->CollectAllGarbage();
2840 int hash3 = symbol->GetIdentityHash();
2841 CHECK_EQ(hash, hash3);
2842 }
2843
2844 {
2845 v8::Local<v8::Symbol> js_symbol =
2846 CompileRun("Symbol('foo')").As<v8::Symbol>();
2847 int hash = js_symbol->GetIdentityHash();
2848 int hash1 = js_symbol->GetIdentityHash();
2849 CHECK_EQ(hash, hash1);
2850 CcTest::heap()->CollectAllGarbage();
2851 int hash3 = js_symbol->GetIdentityHash();
2852 CHECK_EQ(hash, hash3);
2853 }
2854 }
2855
2856
TEST(StringIdentityHash)2857 TEST(StringIdentityHash) {
2858 LocalContext env;
2859 v8::Isolate* isolate = env->GetIsolate();
2860 v8::HandleScope scope(isolate);
2861
2862 Local<v8::String> str = v8_str("str1");
2863 int hash = str->GetIdentityHash();
2864 int hash1 = str->GetIdentityHash();
2865 CHECK_EQ(hash, hash1);
2866 CcTest::heap()->CollectAllGarbage();
2867 int hash3 = str->GetIdentityHash();
2868 CHECK_EQ(hash, hash3);
2869
2870 Local<v8::String> str2 = v8_str("str1");
2871 int hash4 = str2->GetIdentityHash();
2872 CHECK_EQ(hash, hash4);
2873 }
2874
2875
THREADED_TEST(SymbolProperties)2876 THREADED_TEST(SymbolProperties) {
2877 LocalContext env;
2878 v8::Isolate* isolate = env->GetIsolate();
2879 v8::HandleScope scope(isolate);
2880
2881 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2882 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2883 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2884 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2885
2886 CcTest::heap()->CollectAllGarbage();
2887
2888 // Check basic symbol functionality.
2889 CHECK(sym1->IsSymbol());
2890 CHECK(sym2->IsSymbol());
2891 CHECK(!obj->IsSymbol());
2892
2893 CHECK(sym1->Equals(env.local(), sym1).FromJust());
2894 CHECK(sym2->Equals(env.local(), sym2).FromJust());
2895 CHECK(!sym1->Equals(env.local(), sym2).FromJust());
2896 CHECK(!sym2->Equals(env.local(), sym1).FromJust());
2897 CHECK(sym1->StrictEquals(sym1));
2898 CHECK(sym2->StrictEquals(sym2));
2899 CHECK(!sym1->StrictEquals(sym2));
2900 CHECK(!sym2->StrictEquals(sym1));
2901
2902 CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
2903
2904 v8::Local<v8::Value> sym_val = sym2;
2905 CHECK(sym_val->IsSymbol());
2906 CHECK(sym_val->Equals(env.local(), sym2).FromJust());
2907 CHECK(sym_val->StrictEquals(sym2));
2908 CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
2909
2910 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2911 CHECK(sym_obj->IsSymbolObject());
2912 CHECK(!sym2->IsSymbolObject());
2913 CHECK(!obj->IsSymbolObject());
2914 CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
2915 CHECK(!sym_obj->StrictEquals(sym2));
2916 CHECK(v8::SymbolObject::Cast(*sym_obj)
2917 ->Equals(env.local(), sym_obj)
2918 .FromJust());
2919 CHECK(v8::SymbolObject::Cast(*sym_obj)
2920 ->ValueOf()
2921 ->Equals(env.local(), sym2)
2922 .FromJust());
2923
2924 // Make sure delete of a non-existent symbol property works.
2925 CHECK(obj->Delete(env.local(), sym1).FromJust());
2926 CHECK(!obj->Has(env.local(), sym1).FromJust());
2927
2928 CHECK(
2929 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
2930 CHECK(obj->Has(env.local(), sym1).FromJust());
2931 CHECK_EQ(1503, obj->Get(env.local(), sym1)
2932 .ToLocalChecked()
2933 ->Int32Value(env.local())
2934 .FromJust());
2935 CHECK(
2936 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
2937 CHECK(obj->Has(env.local(), sym1).FromJust());
2938 CHECK_EQ(2002, obj->Get(env.local(), sym1)
2939 .ToLocalChecked()
2940 ->Int32Value(env.local())
2941 .FromJust());
2942 CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
2943
2944 CHECK_EQ(0u,
2945 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
2946 unsigned num_props =
2947 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
2948 CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
2949 .FromJust());
2950 CHECK_EQ(1u,
2951 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
2952 CHECK_EQ(num_props + 1,
2953 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
2954
2955 CcTest::heap()->CollectAllGarbage();
2956
2957 CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
2958 SymbolAccessorSetter)
2959 .FromJust());
2960 CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
2961 CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
2962 CHECK(obj->Get(env.local(), sym3)
2963 .ToLocalChecked()
2964 ->Equals(env.local(), v8::Integer::New(isolate, 42))
2965 .FromJust());
2966 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
2967 .ToLocalChecked()
2968 ->Equals(env.local(), v8::Integer::New(isolate, 42))
2969 .FromJust());
2970
2971 // Add another property and delete it afterwards to force the object in
2972 // slow case.
2973 CHECK(
2974 obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
2975 CHECK_EQ(2002, obj->Get(env.local(), sym1)
2976 .ToLocalChecked()
2977 ->Int32Value(env.local())
2978 .FromJust());
2979 CHECK_EQ(2008, obj->Get(env.local(), sym2)
2980 .ToLocalChecked()
2981 ->Int32Value(env.local())
2982 .FromJust());
2983 CHECK_EQ(2002, obj->Get(env.local(), sym1)
2984 .ToLocalChecked()
2985 ->Int32Value(env.local())
2986 .FromJust());
2987 CHECK_EQ(2u,
2988 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
2989
2990 CHECK(obj->Has(env.local(), sym1).FromJust());
2991 CHECK(obj->Has(env.local(), sym2).FromJust());
2992 CHECK(obj->Has(env.local(), sym3).FromJust());
2993 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
2994 CHECK(obj->Delete(env.local(), sym2).FromJust());
2995 CHECK(obj->Has(env.local(), sym1).FromJust());
2996 CHECK(!obj->Has(env.local(), sym2).FromJust());
2997 CHECK(obj->Has(env.local(), sym3).FromJust());
2998 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
2999 CHECK_EQ(2002, obj->Get(env.local(), sym1)
3000 .ToLocalChecked()
3001 ->Int32Value(env.local())
3002 .FromJust());
3003 CHECK(obj->Get(env.local(), sym3)
3004 .ToLocalChecked()
3005 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3006 .FromJust());
3007 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3008 .ToLocalChecked()
3009 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3010 .FromJust());
3011 CHECK_EQ(2u,
3012 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3013
3014 // Symbol properties are inherited.
3015 v8::Local<v8::Object> child = v8::Object::New(isolate);
3016 CHECK(child->SetPrototype(env.local(), obj).FromJust());
3017 CHECK(child->Has(env.local(), sym1).FromJust());
3018 CHECK_EQ(2002, child->Get(env.local(), sym1)
3019 .ToLocalChecked()
3020 ->Int32Value(env.local())
3021 .FromJust());
3022 CHECK(obj->Get(env.local(), sym3)
3023 .ToLocalChecked()
3024 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3025 .FromJust());
3026 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3027 .ToLocalChecked()
3028 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3029 .FromJust());
3030 CHECK_EQ(0u,
3031 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3032 }
3033
3034
THREADED_TEST(SymbolTemplateProperties)3035 THREADED_TEST(SymbolTemplateProperties) {
3036 LocalContext env;
3037 v8::Isolate* isolate = env->GetIsolate();
3038 v8::HandleScope scope(isolate);
3039 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3040 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3041 CHECK(!name.IsEmpty());
3042 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3043 v8::Local<v8::Object> new_instance =
3044 foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3045 CHECK(!new_instance.IsEmpty());
3046 CHECK(new_instance->Has(env.local(), name).FromJust());
3047 }
3048
3049
THREADED_TEST(PrivatePropertiesOnProxies)3050 THREADED_TEST(PrivatePropertiesOnProxies) {
3051 LocalContext env;
3052 v8::Isolate* isolate = env->GetIsolate();
3053 v8::HandleScope scope(isolate);
3054
3055 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3056 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3057
3058 v8::Local<v8::Proxy> proxy =
3059 v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3060
3061 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3062 v8::Local<v8::Private> priv2 =
3063 v8::Private::New(isolate, v8_str("my-private"));
3064
3065 CcTest::heap()->CollectAllGarbage();
3066
3067 CHECK(priv2->Name()
3068 ->Equals(env.local(),
3069 v8::String::NewFromUtf8(isolate, "my-private",
3070 v8::NewStringType::kNormal)
3071 .ToLocalChecked())
3072 .FromJust());
3073
3074 // Make sure delete of a non-existent private symbol property works.
3075 proxy->DeletePrivate(env.local(), priv1).FromJust();
3076 CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3077
3078 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3079 .FromJust());
3080 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3081 CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3082 .ToLocalChecked()
3083 ->Int32Value(env.local())
3084 .FromJust());
3085 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3086 .FromJust());
3087 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3088 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3089 .ToLocalChecked()
3090 ->Int32Value(env.local())
3091 .FromJust());
3092
3093 CHECK_EQ(0u,
3094 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3095 unsigned num_props =
3096 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3097 CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3098 isolate, "bla", v8::NewStringType::kNormal)
3099 .ToLocalChecked(),
3100 v8::Integer::New(isolate, 20))
3101 .FromJust());
3102 CHECK_EQ(1u,
3103 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3104 CHECK_EQ(num_props + 1,
3105 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3106
3107 CcTest::heap()->CollectAllGarbage();
3108
3109 // Add another property and delete it afterwards to force the object in
3110 // slow case.
3111 CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3112 .FromJust());
3113 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3114 .ToLocalChecked()
3115 ->Int32Value(env.local())
3116 .FromJust());
3117 CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3118 .ToLocalChecked()
3119 ->Int32Value(env.local())
3120 .FromJust());
3121 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3122 .ToLocalChecked()
3123 ->Int32Value(env.local())
3124 .FromJust());
3125 CHECK_EQ(1u,
3126 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3127
3128 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3129 CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3130 CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3131 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3132 CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3133 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3134 .ToLocalChecked()
3135 ->Int32Value(env.local())
3136 .FromJust());
3137 CHECK_EQ(1u,
3138 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3139
3140 // Private properties are not inherited (for the time being).
3141 v8::Local<v8::Object> child = v8::Object::New(isolate);
3142 CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3143 CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3144 CHECK_EQ(0u,
3145 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3146 }
3147
3148
THREADED_TEST(PrivateProperties)3149 THREADED_TEST(PrivateProperties) {
3150 LocalContext env;
3151 v8::Isolate* isolate = env->GetIsolate();
3152 v8::HandleScope scope(isolate);
3153
3154 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3155 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3156 v8::Local<v8::Private> priv2 =
3157 v8::Private::New(isolate, v8_str("my-private"));
3158
3159 CcTest::heap()->CollectAllGarbage();
3160
3161 CHECK(priv2->Name()
3162 ->Equals(env.local(),
3163 v8::String::NewFromUtf8(isolate, "my-private",
3164 v8::NewStringType::kNormal)
3165 .ToLocalChecked())
3166 .FromJust());
3167
3168 // Make sure delete of a non-existent private symbol property works.
3169 obj->DeletePrivate(env.local(), priv1).FromJust();
3170 CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3171
3172 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3173 .FromJust());
3174 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3175 CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3176 .ToLocalChecked()
3177 ->Int32Value(env.local())
3178 .FromJust());
3179 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3180 .FromJust());
3181 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3182 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3183 .ToLocalChecked()
3184 ->Int32Value(env.local())
3185 .FromJust());
3186
3187 CHECK_EQ(0u,
3188 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3189 unsigned num_props =
3190 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3191 CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3192 isolate, "bla", v8::NewStringType::kNormal)
3193 .ToLocalChecked(),
3194 v8::Integer::New(isolate, 20))
3195 .FromJust());
3196 CHECK_EQ(1u,
3197 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3198 CHECK_EQ(num_props + 1,
3199 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3200
3201 CcTest::heap()->CollectAllGarbage();
3202
3203 // Add another property and delete it afterwards to force the object in
3204 // slow case.
3205 CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3206 .FromJust());
3207 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3208 .ToLocalChecked()
3209 ->Int32Value(env.local())
3210 .FromJust());
3211 CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3212 .ToLocalChecked()
3213 ->Int32Value(env.local())
3214 .FromJust());
3215 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3216 .ToLocalChecked()
3217 ->Int32Value(env.local())
3218 .FromJust());
3219 CHECK_EQ(1u,
3220 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3221
3222 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3223 CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3224 CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3225 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3226 CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3227 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3228 .ToLocalChecked()
3229 ->Int32Value(env.local())
3230 .FromJust());
3231 CHECK_EQ(1u,
3232 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3233
3234 // Private properties are not inherited (for the time being).
3235 v8::Local<v8::Object> child = v8::Object::New(isolate);
3236 CHECK(child->SetPrototype(env.local(), obj).FromJust());
3237 CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3238 CHECK_EQ(0u,
3239 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3240 }
3241
3242
THREADED_TEST(GlobalSymbols)3243 THREADED_TEST(GlobalSymbols) {
3244 LocalContext env;
3245 v8::Isolate* isolate = env->GetIsolate();
3246 v8::HandleScope scope(isolate);
3247
3248 v8::Local<String> name = v8_str("my-symbol");
3249 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3250 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3251 CHECK(glob2->SameValue(glob));
3252
3253 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3254 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3255 CHECK(glob_api2->SameValue(glob_api));
3256 CHECK(!glob_api->SameValue(glob));
3257
3258 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3259 CHECK(!sym->SameValue(glob));
3260
3261 CompileRun("var sym2 = Symbol.for('my-symbol')");
3262 v8::Local<Value> sym2 =
3263 env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3264 CHECK(sym2->SameValue(glob));
3265 CHECK(!sym2->SameValue(glob_api));
3266 }
3267
3268
CheckWellKnownSymbol(v8::Local<v8::Symbol> (* getter)(v8::Isolate *),const char * name)3269 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3270 const char* name) {
3271 LocalContext env;
3272 v8::Isolate* isolate = env->GetIsolate();
3273 v8::HandleScope scope(isolate);
3274
3275 v8::Local<v8::Symbol> symbol = getter(isolate);
3276 std::string script = std::string("var sym = ") + name;
3277 CompileRun(script.c_str());
3278 v8::Local<Value> value =
3279 env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3280
3281 CHECK(!value.IsEmpty());
3282 CHECK(!symbol.IsEmpty());
3283 CHECK(value->SameValue(symbol));
3284 }
3285
3286
THREADED_TEST(WellKnownSymbols)3287 THREADED_TEST(WellKnownSymbols) {
3288 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3289 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3290 }
3291
3292
THREADED_TEST(GlobalPrivates)3293 THREADED_TEST(GlobalPrivates) {
3294 i::FLAG_allow_natives_syntax = true;
3295 LocalContext env;
3296 v8::Isolate* isolate = env->GetIsolate();
3297 v8::HandleScope scope(isolate);
3298
3299 v8::Local<String> name = v8_str("my-private");
3300 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3301 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3302 CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3303 .FromJust());
3304
3305 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3306 CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3307
3308 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3309 CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3310
3311 CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3312 v8::Local<Value> intern =
3313 env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3314 CHECK(!obj->Has(env.local(), intern).FromJust());
3315 }
3316
3317
3318 class ScopedArrayBufferContents {
3319 public:
ScopedArrayBufferContents(const v8::ArrayBuffer::Contents & contents)3320 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3321 : contents_(contents) {}
~ScopedArrayBufferContents()3322 ~ScopedArrayBufferContents() { free(contents_.Data()); }
Data() const3323 void* Data() const { return contents_.Data(); }
ByteLength() const3324 size_t ByteLength() const { return contents_.ByteLength(); }
3325
3326 private:
3327 const v8::ArrayBuffer::Contents contents_;
3328 };
3329
3330 template <typename T>
CheckInternalFieldsAreZero(v8::Local<T> value)3331 static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3332 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3333 for (int i = 0; i < value->InternalFieldCount(); i++) {
3334 CHECK_EQ(0, value->GetInternalField(i)
3335 ->Int32Value(CcTest::isolate()->GetCurrentContext())
3336 .FromJust());
3337 }
3338 }
3339
3340
THREADED_TEST(ArrayBuffer_ApiInternalToExternal)3341 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3342 LocalContext env;
3343 v8::Isolate* isolate = env->GetIsolate();
3344 v8::HandleScope handle_scope(isolate);
3345
3346 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3347 CheckInternalFieldsAreZero(ab);
3348 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3349 CHECK(!ab->IsExternal());
3350 CcTest::heap()->CollectAllGarbage();
3351
3352 ScopedArrayBufferContents ab_contents(ab->Externalize());
3353 CHECK(ab->IsExternal());
3354
3355 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3356 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3357 CHECK(data != NULL);
3358 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3359
3360 v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3361 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3362
3363 result = CompileRun(
3364 "var u8 = new Uint8Array(ab);"
3365 "u8[0] = 0xFF;"
3366 "u8[1] = 0xAA;"
3367 "u8.length");
3368 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3369 CHECK_EQ(0xFF, data[0]);
3370 CHECK_EQ(0xAA, data[1]);
3371 data[0] = 0xCC;
3372 data[1] = 0x11;
3373 result = CompileRun("u8[0] + u8[1]");
3374 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3375 }
3376
3377
THREADED_TEST(ArrayBuffer_JSInternalToExternal)3378 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3379 LocalContext env;
3380 v8::Isolate* isolate = env->GetIsolate();
3381 v8::HandleScope handle_scope(isolate);
3382
3383
3384 v8::Local<v8::Value> result = CompileRun(
3385 "var ab1 = new ArrayBuffer(2);"
3386 "var u8_a = new Uint8Array(ab1);"
3387 "u8_a[0] = 0xAA;"
3388 "u8_a[1] = 0xFF; u8_a.buffer");
3389 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3390 CheckInternalFieldsAreZero(ab1);
3391 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3392 CHECK(!ab1->IsExternal());
3393 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3394 CHECK(ab1->IsExternal());
3395
3396 result = CompileRun("ab1.byteLength");
3397 CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3398 result = CompileRun("u8_a[0]");
3399 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3400 result = CompileRun("u8_a[1]");
3401 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3402 result = CompileRun(
3403 "var u8_b = new Uint8Array(ab1);"
3404 "u8_b[0] = 0xBB;"
3405 "u8_a[0]");
3406 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3407 result = CompileRun("u8_b[1]");
3408 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3409
3410 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3411 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3412 CHECK_EQ(0xBB, ab1_data[0]);
3413 CHECK_EQ(0xFF, ab1_data[1]);
3414 ab1_data[0] = 0xCC;
3415 ab1_data[1] = 0x11;
3416 result = CompileRun("u8_a[0] + u8_a[1]");
3417 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3418 }
3419
3420
THREADED_TEST(ArrayBuffer_External)3421 THREADED_TEST(ArrayBuffer_External) {
3422 LocalContext env;
3423 v8::Isolate* isolate = env->GetIsolate();
3424 v8::HandleScope handle_scope(isolate);
3425
3426 i::ScopedVector<uint8_t> my_data(100);
3427 memset(my_data.start(), 0, 100);
3428 Local<v8::ArrayBuffer> ab3 =
3429 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3430 CheckInternalFieldsAreZero(ab3);
3431 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3432 CHECK(ab3->IsExternal());
3433
3434 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3435
3436 v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3437 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3438
3439 result = CompileRun(
3440 "var u8_b = new Uint8Array(ab3);"
3441 "u8_b[0] = 0xBB;"
3442 "u8_b[1] = 0xCC;"
3443 "u8_b.length");
3444 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3445 CHECK_EQ(0xBB, my_data[0]);
3446 CHECK_EQ(0xCC, my_data[1]);
3447 my_data[0] = 0xCC;
3448 my_data[1] = 0x11;
3449 result = CompileRun("u8_b[0] + u8_b[1]");
3450 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3451 }
3452
3453
THREADED_TEST(ArrayBuffer_DisableNeuter)3454 THREADED_TEST(ArrayBuffer_DisableNeuter) {
3455 LocalContext env;
3456 v8::Isolate* isolate = env->GetIsolate();
3457 v8::HandleScope handle_scope(isolate);
3458
3459 i::ScopedVector<uint8_t> my_data(100);
3460 memset(my_data.start(), 0, 100);
3461 Local<v8::ArrayBuffer> ab =
3462 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3463 CHECK(ab->IsNeuterable());
3464
3465 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3466 buf->set_is_neuterable(false);
3467
3468 CHECK(!ab->IsNeuterable());
3469 }
3470
3471
CheckDataViewIsNeutered(v8::Local<v8::DataView> dv)3472 static void CheckDataViewIsNeutered(v8::Local<v8::DataView> dv) {
3473 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3474 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3475 }
3476
3477
CheckIsNeutered(v8::Local<v8::TypedArray> ta)3478 static void CheckIsNeutered(v8::Local<v8::TypedArray> ta) {
3479 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3480 CHECK_EQ(0, static_cast<int>(ta->Length()));
3481 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3482 }
3483
3484
CheckIsTypedArrayVarNeutered(const char * name)3485 static void CheckIsTypedArrayVarNeutered(const char* name) {
3486 i::ScopedVector<char> source(1024);
3487 i::SNPrintF(source,
3488 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3489 name, name, name);
3490 CHECK(CompileRun(source.start())->IsTrue());
3491 v8::Local<v8::TypedArray> ta =
3492 v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3493 CheckIsNeutered(ta);
3494 }
3495
3496
3497 template <typename TypedArray, int kElementSize>
CreateAndCheck(Local<v8::ArrayBuffer> ab,int byteOffset,int length)3498 static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3499 int byteOffset, int length) {
3500 v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3501 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3502 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3503 CHECK_EQ(length, static_cast<int>(ta->Length()));
3504 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3505 return ta;
3506 }
3507
3508
THREADED_TEST(ArrayBuffer_NeuteringApi)3509 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3510 LocalContext env;
3511 v8::Isolate* isolate = env->GetIsolate();
3512 v8::HandleScope handle_scope(isolate);
3513
3514 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3515
3516 v8::Local<v8::Uint8Array> u8a =
3517 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3518 v8::Local<v8::Uint8ClampedArray> u8c =
3519 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3520 v8::Local<v8::Int8Array> i8a =
3521 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3522
3523 v8::Local<v8::Uint16Array> u16a =
3524 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3525 v8::Local<v8::Int16Array> i16a =
3526 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3527
3528 v8::Local<v8::Uint32Array> u32a =
3529 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3530 v8::Local<v8::Int32Array> i32a =
3531 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3532
3533 v8::Local<v8::Float32Array> f32a =
3534 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3535 v8::Local<v8::Float64Array> f64a =
3536 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3537
3538 v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3539 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3540 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3541 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3542
3543 ScopedArrayBufferContents contents(buffer->Externalize());
3544 buffer->Neuter();
3545 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3546 CheckIsNeutered(u8a);
3547 CheckIsNeutered(u8c);
3548 CheckIsNeutered(i8a);
3549 CheckIsNeutered(u16a);
3550 CheckIsNeutered(i16a);
3551 CheckIsNeutered(u32a);
3552 CheckIsNeutered(i32a);
3553 CheckIsNeutered(f32a);
3554 CheckIsNeutered(f64a);
3555 CheckDataViewIsNeutered(dv);
3556 }
3557
3558
THREADED_TEST(ArrayBuffer_NeuteringScript)3559 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3560 LocalContext env;
3561 v8::Isolate* isolate = env->GetIsolate();
3562 v8::HandleScope handle_scope(isolate);
3563
3564 CompileRun(
3565 "var ab = new ArrayBuffer(1024);"
3566 "var u8a = new Uint8Array(ab, 1, 1023);"
3567 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3568 "var i8a = new Int8Array(ab, 1, 1023);"
3569 "var u16a = new Uint16Array(ab, 2, 511);"
3570 "var i16a = new Int16Array(ab, 2, 511);"
3571 "var u32a = new Uint32Array(ab, 4, 255);"
3572 "var i32a = new Int32Array(ab, 4, 255);"
3573 "var f32a = new Float32Array(ab, 4, 255);"
3574 "var f64a = new Float64Array(ab, 8, 127);"
3575 "var dv = new DataView(ab, 1, 1023);");
3576
3577 v8::Local<v8::ArrayBuffer> ab =
3578 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3579
3580 v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3581
3582 ScopedArrayBufferContents contents(ab->Externalize());
3583 ab->Neuter();
3584 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3585 CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3586
3587 CheckIsTypedArrayVarNeutered("u8a");
3588 CheckIsTypedArrayVarNeutered("u8c");
3589 CheckIsTypedArrayVarNeutered("i8a");
3590 CheckIsTypedArrayVarNeutered("u16a");
3591 CheckIsTypedArrayVarNeutered("i16a");
3592 CheckIsTypedArrayVarNeutered("u32a");
3593 CheckIsTypedArrayVarNeutered("i32a");
3594 CheckIsTypedArrayVarNeutered("f32a");
3595 CheckIsTypedArrayVarNeutered("f64a");
3596
3597 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3598 CheckDataViewIsNeutered(dv);
3599 }
3600
3601
3602 class ScopedSharedArrayBufferContents {
3603 public:
ScopedSharedArrayBufferContents(const v8::SharedArrayBuffer::Contents & contents)3604 explicit ScopedSharedArrayBufferContents(
3605 const v8::SharedArrayBuffer::Contents& contents)
3606 : contents_(contents) {}
~ScopedSharedArrayBufferContents()3607 ~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
Data() const3608 void* Data() const { return contents_.Data(); }
ByteLength() const3609 size_t ByteLength() const { return contents_.ByteLength(); }
3610
3611 private:
3612 const v8::SharedArrayBuffer::Contents contents_;
3613 };
3614
3615
THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal)3616 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
3617 i::FLAG_harmony_sharedarraybuffer = true;
3618 LocalContext env;
3619 v8::Isolate* isolate = env->GetIsolate();
3620 v8::HandleScope handle_scope(isolate);
3621
3622 Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
3623 CheckInternalFieldsAreZero(ab);
3624 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3625 CHECK(!ab->IsExternal());
3626 CcTest::heap()->CollectAllGarbage();
3627
3628 ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
3629 CHECK(ab->IsExternal());
3630
3631 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3632 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3633 CHECK(data != NULL);
3634 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3635
3636 v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3637 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3638
3639 result = CompileRun(
3640 "var u8 = new Uint8Array(ab);"
3641 "u8[0] = 0xFF;"
3642 "u8[1] = 0xAA;"
3643 "u8.length");
3644 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3645 CHECK_EQ(0xFF, data[0]);
3646 CHECK_EQ(0xAA, data[1]);
3647 data[0] = 0xCC;
3648 data[1] = 0x11;
3649 result = CompileRun("u8[0] + u8[1]");
3650 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3651 }
3652
3653
THREADED_TEST(SharedArrayBuffer_JSInternalToExternal)3654 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
3655 i::FLAG_harmony_sharedarraybuffer = true;
3656 LocalContext env;
3657 v8::Isolate* isolate = env->GetIsolate();
3658 v8::HandleScope handle_scope(isolate);
3659
3660
3661 v8::Local<v8::Value> result = CompileRun(
3662 "var ab1 = new SharedArrayBuffer(2);"
3663 "var u8_a = new Uint8Array(ab1);"
3664 "u8_a[0] = 0xAA;"
3665 "u8_a[1] = 0xFF; u8_a.buffer");
3666 Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
3667 CheckInternalFieldsAreZero(ab1);
3668 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3669 CHECK(!ab1->IsExternal());
3670 ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
3671 CHECK(ab1->IsExternal());
3672
3673 result = CompileRun("ab1.byteLength");
3674 CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3675 result = CompileRun("u8_a[0]");
3676 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3677 result = CompileRun("u8_a[1]");
3678 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3679 result = CompileRun(
3680 "var u8_b = new Uint8Array(ab1);"
3681 "u8_b[0] = 0xBB;"
3682 "u8_a[0]");
3683 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3684 result = CompileRun("u8_b[1]");
3685 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3686
3687 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3688 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3689 CHECK_EQ(0xBB, ab1_data[0]);
3690 CHECK_EQ(0xFF, ab1_data[1]);
3691 ab1_data[0] = 0xCC;
3692 ab1_data[1] = 0x11;
3693 result = CompileRun("u8_a[0] + u8_a[1]");
3694 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3695 }
3696
3697
THREADED_TEST(SharedArrayBuffer_External)3698 THREADED_TEST(SharedArrayBuffer_External) {
3699 i::FLAG_harmony_sharedarraybuffer = true;
3700 LocalContext env;
3701 v8::Isolate* isolate = env->GetIsolate();
3702 v8::HandleScope handle_scope(isolate);
3703
3704 i::ScopedVector<uint8_t> my_data(100);
3705 memset(my_data.start(), 0, 100);
3706 Local<v8::SharedArrayBuffer> ab3 =
3707 v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
3708 CheckInternalFieldsAreZero(ab3);
3709 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3710 CHECK(ab3->IsExternal());
3711
3712 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3713
3714 v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3715 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3716
3717 result = CompileRun(
3718 "var u8_b = new Uint8Array(ab3);"
3719 "u8_b[0] = 0xBB;"
3720 "u8_b[1] = 0xCC;"
3721 "u8_b.length");
3722 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3723 CHECK_EQ(0xBB, my_data[0]);
3724 CHECK_EQ(0xCC, my_data[1]);
3725 my_data[0] = 0xCC;
3726 my_data[1] = 0x11;
3727 result = CompileRun("u8_b[0] + u8_b[1]");
3728 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3729 }
3730
3731
THREADED_TEST(HiddenProperties)3732 THREADED_TEST(HiddenProperties) {
3733 LocalContext env;
3734 v8::Isolate* isolate = env->GetIsolate();
3735 v8::HandleScope scope(isolate);
3736
3737 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3738 v8::Local<v8::Private> key =
3739 v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
3740 v8::Local<v8::String> empty = v8_str("");
3741 v8::Local<v8::String> prop_name = v8_str("prop_name");
3742
3743 CcTest::heap()->CollectAllGarbage();
3744
3745 // Make sure delete of a non-existent hidden value works
3746 obj->DeletePrivate(env.local(), key).FromJust();
3747
3748 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
3749 .FromJust());
3750 CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
3751 .ToLocalChecked()
3752 ->Int32Value(env.local())
3753 .FromJust());
3754 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
3755 .FromJust());
3756 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3757 .ToLocalChecked()
3758 ->Int32Value(env.local())
3759 .FromJust());
3760
3761 CcTest::heap()->CollectAllGarbage();
3762
3763 // Make sure we do not find the hidden property.
3764 CHECK(!obj->Has(env.local(), empty).FromJust());
3765 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3766 .ToLocalChecked()
3767 ->Int32Value(env.local())
3768 .FromJust());
3769 CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
3770 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3771 .ToLocalChecked()
3772 ->Int32Value(env.local())
3773 .FromJust());
3774 CHECK(
3775 obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
3776 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3777 .ToLocalChecked()
3778 ->Int32Value(env.local())
3779 .FromJust());
3780 CHECK_EQ(2003, obj->Get(env.local(), empty)
3781 .ToLocalChecked()
3782 ->Int32Value(env.local())
3783 .FromJust());
3784
3785 CcTest::heap()->CollectAllGarbage();
3786
3787 // Add another property and delete it afterwards to force the object in
3788 // slow case.
3789 CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
3790 .FromJust());
3791 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3792 .ToLocalChecked()
3793 ->Int32Value(env.local())
3794 .FromJust());
3795 CHECK_EQ(2008, obj->Get(env.local(), prop_name)
3796 .ToLocalChecked()
3797 ->Int32Value(env.local())
3798 .FromJust());
3799 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3800 .ToLocalChecked()
3801 ->Int32Value(env.local())
3802 .FromJust());
3803 CHECK(obj->Delete(env.local(), prop_name).FromJust());
3804 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
3805 .ToLocalChecked()
3806 ->Int32Value(env.local())
3807 .FromJust());
3808
3809 CcTest::heap()->CollectAllGarbage();
3810
3811 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
3812 .FromJust());
3813 CHECK(obj->DeletePrivate(env.local(), key).FromJust());
3814 CHECK(!obj->HasPrivate(env.local(), key).FromJust());
3815 }
3816
3817
THREADED_TEST(Regress97784)3818 THREADED_TEST(Regress97784) {
3819 // Regression test for crbug.com/97784
3820 // Messing with the Object.prototype should not have effect on
3821 // hidden properties.
3822 LocalContext env;
3823 v8::HandleScope scope(env->GetIsolate());
3824
3825 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3826 v8::Local<v8::Private> key =
3827 v8::Private::New(env->GetIsolate(), v8_str("hidden"));
3828
3829 CompileRun(
3830 "set_called = false;"
3831 "Object.defineProperty("
3832 " Object.prototype,"
3833 " 'hidden',"
3834 " {get: function() { return 45; },"
3835 " set: function() { set_called = true; }})");
3836
3837 CHECK(!obj->HasPrivate(env.local(), key).FromJust());
3838 // Make sure that the getter and setter from Object.prototype is not invoked.
3839 // If it did we would have full access to the hidden properties in
3840 // the accessor.
3841 CHECK(
3842 obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
3843 .FromJust());
3844 ExpectFalse("set_called");
3845 CHECK_EQ(42, obj->GetPrivate(env.local(), key)
3846 .ToLocalChecked()
3847 ->Int32Value(env.local())
3848 .FromJust());
3849 }
3850
3851
THREADED_TEST(External)3852 THREADED_TEST(External) {
3853 v8::HandleScope scope(CcTest::isolate());
3854 int x = 3;
3855 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3856 LocalContext env;
3857 CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
3858 Local<Value> reext_obj = CompileRun("this.ext");
3859 v8::Local<v8::External> reext = reext_obj.As<v8::External>();
3860 int* ptr = static_cast<int*>(reext->Value());
3861 CHECK_EQ(x, 3);
3862 *ptr = 10;
3863 CHECK_EQ(x, 10);
3864
3865 // Make sure unaligned pointers are wrapped properly.
3866 char* data = i::StrDup("0123456789");
3867 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3868 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3869 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3870 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3871
3872 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3873 CHECK_EQ('0', *char_ptr);
3874 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3875 CHECK_EQ('1', *char_ptr);
3876 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3877 CHECK_EQ('2', *char_ptr);
3878 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3879 CHECK_EQ('3', *char_ptr);
3880 i::DeleteArray(data);
3881 }
3882
3883
THREADED_TEST(GlobalHandle)3884 THREADED_TEST(GlobalHandle) {
3885 v8::Isolate* isolate = CcTest::isolate();
3886 v8::Persistent<String> global;
3887 {
3888 v8::HandleScope scope(isolate);
3889 global.Reset(isolate, v8_str("str"));
3890 }
3891 {
3892 v8::HandleScope scope(isolate);
3893 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3894 }
3895 global.Reset();
3896 {
3897 v8::HandleScope scope(isolate);
3898 global.Reset(isolate, v8_str("str"));
3899 }
3900 {
3901 v8::HandleScope scope(isolate);
3902 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3903 }
3904 global.Reset();
3905 }
3906
3907
THREADED_TEST(ResettingGlobalHandle)3908 THREADED_TEST(ResettingGlobalHandle) {
3909 v8::Isolate* isolate = CcTest::isolate();
3910 v8::Persistent<String> global;
3911 {
3912 v8::HandleScope scope(isolate);
3913 global.Reset(isolate, v8_str("str"));
3914 }
3915 v8::internal::GlobalHandles* global_handles =
3916 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3917 int initial_handle_count = global_handles->global_handles_count();
3918 {
3919 v8::HandleScope scope(isolate);
3920 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3921 }
3922 {
3923 v8::HandleScope scope(isolate);
3924 global.Reset(isolate, v8_str("longer"));
3925 }
3926 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3927 {
3928 v8::HandleScope scope(isolate);
3929 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3930 }
3931 global.Reset();
3932 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3933 }
3934
3935
THREADED_TEST(ResettingGlobalHandleToEmpty)3936 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3937 v8::Isolate* isolate = CcTest::isolate();
3938 v8::Persistent<String> global;
3939 {
3940 v8::HandleScope scope(isolate);
3941 global.Reset(isolate, v8_str("str"));
3942 }
3943 v8::internal::GlobalHandles* global_handles =
3944 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3945 int initial_handle_count = global_handles->global_handles_count();
3946 {
3947 v8::HandleScope scope(isolate);
3948 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3949 }
3950 {
3951 v8::HandleScope scope(isolate);
3952 Local<String> empty;
3953 global.Reset(isolate, empty);
3954 }
3955 CHECK(global.IsEmpty());
3956 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3957 }
3958
3959
3960 template <class T>
PassUnique(v8::Global<T> unique)3961 static v8::Global<T> PassUnique(v8::Global<T> unique) {
3962 return unique.Pass();
3963 }
3964
3965
3966 template <class T>
ReturnUnique(v8::Isolate * isolate,const v8::Persistent<T> & global)3967 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
3968 const v8::Persistent<T>& global) {
3969 v8::Global<String> unique(isolate, global);
3970 return unique.Pass();
3971 }
3972
3973
THREADED_TEST(Global)3974 THREADED_TEST(Global) {
3975 v8::Isolate* isolate = CcTest::isolate();
3976 v8::Persistent<String> global;
3977 {
3978 v8::HandleScope scope(isolate);
3979 global.Reset(isolate, v8_str("str"));
3980 }
3981 v8::internal::GlobalHandles* global_handles =
3982 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3983 int initial_handle_count = global_handles->global_handles_count();
3984 {
3985 v8::Global<String> unique(isolate, global);
3986 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3987 // Test assignment via Pass
3988 {
3989 v8::Global<String> copy = unique.Pass();
3990 CHECK(unique.IsEmpty());
3991 CHECK(copy == global);
3992 CHECK_EQ(initial_handle_count + 1,
3993 global_handles->global_handles_count());
3994 unique = copy.Pass();
3995 }
3996 // Test ctor via Pass
3997 {
3998 v8::Global<String> copy(unique.Pass());
3999 CHECK(unique.IsEmpty());
4000 CHECK(copy == global);
4001 CHECK_EQ(initial_handle_count + 1,
4002 global_handles->global_handles_count());
4003 unique = copy.Pass();
4004 }
4005 // Test pass through function call
4006 {
4007 v8::Global<String> copy = PassUnique(unique.Pass());
4008 CHECK(unique.IsEmpty());
4009 CHECK(copy == global);
4010 CHECK_EQ(initial_handle_count + 1,
4011 global_handles->global_handles_count());
4012 unique = copy.Pass();
4013 }
4014 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4015 }
4016 // Test pass from function call
4017 {
4018 v8::Global<String> unique = ReturnUnique(isolate, global);
4019 CHECK(unique == global);
4020 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4021 }
4022 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4023 global.Reset();
4024 }
4025
4026
4027 namespace {
4028
4029 class TwoPassCallbackData;
4030 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4031 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4032
4033
4034 class TwoPassCallbackData {
4035 public:
TwoPassCallbackData(v8::Isolate * isolate,int * instance_counter)4036 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4037 : first_pass_called_(false),
4038 second_pass_called_(false),
4039 trigger_gc_(false),
4040 instance_counter_(instance_counter) {
4041 HandleScope scope(isolate);
4042 i::ScopedVector<char> buffer(40);
4043 i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4044 auto string =
4045 v8::String::NewFromUtf8(isolate, buffer.start(),
4046 v8::NewStringType::kNormal).ToLocalChecked();
4047 cell_.Reset(isolate, string);
4048 (*instance_counter_)++;
4049 }
4050
~TwoPassCallbackData()4051 ~TwoPassCallbackData() {
4052 CHECK(first_pass_called_);
4053 CHECK(second_pass_called_);
4054 CHECK(cell_.IsEmpty());
4055 (*instance_counter_)--;
4056 }
4057
FirstPass()4058 void FirstPass() {
4059 CHECK(!first_pass_called_);
4060 CHECK(!second_pass_called_);
4061 CHECK(!cell_.IsEmpty());
4062 cell_.Reset();
4063 first_pass_called_ = true;
4064 }
4065
SecondPass()4066 void SecondPass() {
4067 CHECK(first_pass_called_);
4068 CHECK(!second_pass_called_);
4069 CHECK(cell_.IsEmpty());
4070 second_pass_called_ = true;
4071 delete this;
4072 }
4073
SetWeak()4074 void SetWeak() {
4075 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4076 }
4077
MarkTriggerGc()4078 void MarkTriggerGc() { trigger_gc_ = true; }
trigger_gc()4079 bool trigger_gc() { return trigger_gc_; }
4080
instance_counter()4081 int* instance_counter() { return instance_counter_; }
4082
4083 private:
4084 bool first_pass_called_;
4085 bool second_pass_called_;
4086 bool trigger_gc_;
4087 v8::Global<v8::String> cell_;
4088 int* instance_counter_;
4089 };
4090
4091
SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData> & data)4092 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4093 ApiTestFuzzer::Fuzz();
4094 bool trigger_gc = data.GetParameter()->trigger_gc();
4095 int* instance_counter = data.GetParameter()->instance_counter();
4096 data.GetParameter()->SecondPass();
4097 if (!trigger_gc) return;
4098 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4099 data_2->SetWeak();
4100 CcTest::heap()->CollectAllGarbage();
4101 }
4102
4103
FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData> & data)4104 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4105 data.GetParameter()->FirstPass();
4106 data.SetSecondPassCallback(SecondPassCallback);
4107 }
4108
4109 } // namespace
4110
4111
TEST(TwoPassPhantomCallbacks)4112 TEST(TwoPassPhantomCallbacks) {
4113 auto isolate = CcTest::isolate();
4114 const size_t kLength = 20;
4115 int instance_counter = 0;
4116 for (size_t i = 0; i < kLength; ++i) {
4117 auto data = new TwoPassCallbackData(isolate, &instance_counter);
4118 data->SetWeak();
4119 }
4120 CHECK_EQ(static_cast<int>(kLength), instance_counter);
4121 CcTest::heap()->CollectAllGarbage();
4122 EmptyMessageQueues(isolate);
4123 CHECK_EQ(0, instance_counter);
4124 }
4125
4126
TEST(TwoPassPhantomCallbacksNestedGc)4127 TEST(TwoPassPhantomCallbacksNestedGc) {
4128 auto isolate = CcTest::isolate();
4129 const size_t kLength = 20;
4130 TwoPassCallbackData* array[kLength];
4131 int instance_counter = 0;
4132 for (size_t i = 0; i < kLength; ++i) {
4133 array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4134 array[i]->SetWeak();
4135 }
4136 array[5]->MarkTriggerGc();
4137 array[10]->MarkTriggerGc();
4138 array[15]->MarkTriggerGc();
4139 CHECK_EQ(static_cast<int>(kLength), instance_counter);
4140 CcTest::heap()->CollectAllGarbage();
4141 EmptyMessageQueues(isolate);
4142 CHECK_EQ(0, instance_counter);
4143 }
4144
4145
4146 namespace {
4147
IntKeyToVoidPointer(int key)4148 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4149
4150
NewObjectForIntKey(v8::Isolate * isolate,const v8::Global<v8::ObjectTemplate> & templ,int key)4151 Local<v8::Object> NewObjectForIntKey(
4152 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4153 int key) {
4154 auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4155 auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4156 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4157 return obj;
4158 }
4159
4160
4161 template <typename K, typename V>
4162 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4163 public:
4164 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4165 static const v8::PersistentContainerCallbackType kCallbackType =
4166 v8::kWeakWithInternalFields;
4167 struct WeakCallbackDataType {
4168 MapType* map;
4169 K key;
4170 };
WeakCallbackParameter(MapType * map,const K & key,Local<V> value)4171 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4172 Local<V> value) {
4173 WeakCallbackDataType* data = new WeakCallbackDataType;
4174 data->map = map;
4175 data->key = key;
4176 return data;
4177 }
MapFromWeakCallbackInfo(const v8::WeakCallbackInfo<WeakCallbackDataType> & data)4178 static MapType* MapFromWeakCallbackInfo(
4179 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4180 return data.GetParameter()->map;
4181 }
KeyFromWeakCallbackInfo(const v8::WeakCallbackInfo<WeakCallbackDataType> & data)4182 static K KeyFromWeakCallbackInfo(
4183 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4184 return data.GetParameter()->key;
4185 }
DisposeCallbackData(WeakCallbackDataType * data)4186 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
Dispose(v8::Isolate * isolate,v8::Global<V> value,K key)4187 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4188 CHECK_EQ(IntKeyToVoidPointer(key),
4189 v8::Object::GetAlignedPointerFromInternalField(value, 0));
4190 }
OnWeakCallback(const v8::WeakCallbackInfo<WeakCallbackDataType> &)4191 static void OnWeakCallback(
4192 const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
DisposeWeak(const v8::WeakCallbackInfo<WeakCallbackDataType> & info)4193 static void DisposeWeak(
4194 const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4195 K key = KeyFromWeakCallbackInfo(info);
4196 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4197 DisposeCallbackData(info.GetParameter());
4198 }
4199 };
4200
4201
4202 template <typename Map>
TestGlobalValueMap()4203 void TestGlobalValueMap() {
4204 LocalContext env;
4205 v8::Isolate* isolate = env->GetIsolate();
4206 v8::Global<ObjectTemplate> templ;
4207 {
4208 HandleScope scope(isolate);
4209 auto t = ObjectTemplate::New(isolate);
4210 t->SetInternalFieldCount(1);
4211 templ.Reset(isolate, t);
4212 }
4213 Map map(isolate);
4214 v8::internal::GlobalHandles* global_handles =
4215 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4216 int initial_handle_count = global_handles->global_handles_count();
4217 CHECK_EQ(0, static_cast<int>(map.Size()));
4218 {
4219 HandleScope scope(isolate);
4220 Local<v8::Object> obj = map.Get(7);
4221 CHECK(obj.IsEmpty());
4222 Local<v8::Object> expected = v8::Object::New(isolate);
4223 map.Set(7, expected);
4224 CHECK_EQ(1, static_cast<int>(map.Size()));
4225 obj = map.Get(7);
4226 CHECK(expected->Equals(env.local(), obj).FromJust());
4227 {
4228 typename Map::PersistentValueReference ref = map.GetReference(7);
4229 CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4230 }
4231 v8::Global<v8::Object> removed = map.Remove(7);
4232 CHECK_EQ(0, static_cast<int>(map.Size()));
4233 CHECK(expected == removed);
4234 removed = map.Remove(7);
4235 CHECK(removed.IsEmpty());
4236 map.Set(8, expected);
4237 CHECK_EQ(1, static_cast<int>(map.Size()));
4238 map.Set(8, expected);
4239 CHECK_EQ(1, static_cast<int>(map.Size()));
4240 {
4241 typename Map::PersistentValueReference ref;
4242 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4243 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4244 CHECK_EQ(1, static_cast<int>(map.Size()));
4245 CHECK(expected == removed);
4246 CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4247 }
4248 }
4249 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
4250 if (map.IsWeak()) {
4251 CcTest::i_isolate()->heap()->CollectAllGarbage(
4252 i::Heap::kAbortIncrementalMarkingMask);
4253 } else {
4254 map.Clear();
4255 }
4256 CHECK_EQ(0, static_cast<int>(map.Size()));
4257 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4258 {
4259 HandleScope scope(isolate);
4260 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4261 map.Set(9, value);
4262 map.Clear();
4263 }
4264 CHECK_EQ(0, static_cast<int>(map.Size()));
4265 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
4266 }
4267
4268 } // namespace
4269
4270
TEST(GlobalValueMap)4271 TEST(GlobalValueMap) {
4272 // Default case, w/o weak callbacks:
4273 TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4274
4275 // Custom traits with weak callbacks:
4276 typedef v8::GlobalValueMap<int, v8::Object,
4277 PhantomStdMapTraits<int, v8::Object>> WeakMap;
4278 TestGlobalValueMap<WeakMap>();
4279 }
4280
4281
TEST(PersistentValueVector)4282 TEST(PersistentValueVector) {
4283 LocalContext env;
4284 v8::Isolate* isolate = env->GetIsolate();
4285 v8::internal::GlobalHandles* global_handles =
4286 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4287 int handle_count = global_handles->global_handles_count();
4288 HandleScope scope(isolate);
4289
4290 v8::PersistentValueVector<v8::Object> vector(isolate);
4291
4292 Local<v8::Object> obj1 = v8::Object::New(isolate);
4293 Local<v8::Object> obj2 = v8::Object::New(isolate);
4294 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4295
4296 CHECK(vector.IsEmpty());
4297 CHECK_EQ(0, static_cast<int>(vector.Size()));
4298
4299 vector.ReserveCapacity(3);
4300 CHECK(vector.IsEmpty());
4301
4302 vector.Append(obj1);
4303 vector.Append(obj2);
4304 vector.Append(obj1);
4305 vector.Append(obj3.Pass());
4306 vector.Append(obj1);
4307
4308 CHECK(!vector.IsEmpty());
4309 CHECK_EQ(5, static_cast<int>(vector.Size()));
4310 CHECK(obj3.IsEmpty());
4311 CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4312 CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4313 CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4314 CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4315
4316 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4317
4318 vector.Clear();
4319 CHECK(vector.IsEmpty());
4320 CHECK_EQ(0, static_cast<int>(vector.Size()));
4321 CHECK_EQ(handle_count, global_handles->global_handles_count());
4322 }
4323
4324
THREADED_TEST(GlobalHandleUpcast)4325 THREADED_TEST(GlobalHandleUpcast) {
4326 v8::Isolate* isolate = CcTest::isolate();
4327 v8::HandleScope scope(isolate);
4328 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4329 v8::Persistent<String> global_string(isolate, local);
4330 v8::Persistent<Value>& global_value =
4331 v8::Persistent<Value>::Cast(global_string);
4332 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4333 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4334 global_string.Reset();
4335 }
4336
4337
THREADED_TEST(HandleEquality)4338 THREADED_TEST(HandleEquality) {
4339 v8::Isolate* isolate = CcTest::isolate();
4340 v8::Persistent<String> global1;
4341 v8::Persistent<String> global2;
4342 {
4343 v8::HandleScope scope(isolate);
4344 global1.Reset(isolate, v8_str("str"));
4345 global2.Reset(isolate, v8_str("str2"));
4346 }
4347 CHECK_EQ(global1 == global1, true);
4348 CHECK_EQ(global1 != global1, false);
4349 {
4350 v8::HandleScope scope(isolate);
4351 Local<String> local1 = Local<String>::New(isolate, global1);
4352 Local<String> local2 = Local<String>::New(isolate, global2);
4353
4354 CHECK_EQ(global1 == local1, true);
4355 CHECK_EQ(global1 != local1, false);
4356 CHECK_EQ(local1 == global1, true);
4357 CHECK_EQ(local1 != global1, false);
4358
4359 CHECK_EQ(global1 == local2, false);
4360 CHECK_EQ(global1 != local2, true);
4361 CHECK_EQ(local2 == global1, false);
4362 CHECK_EQ(local2 != global1, true);
4363
4364 CHECK_EQ(local1 == local2, false);
4365 CHECK_EQ(local1 != local2, true);
4366
4367 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4368 CHECK_EQ(local1 == anotherLocal1, true);
4369 CHECK_EQ(local1 != anotherLocal1, false);
4370 }
4371 global1.Reset();
4372 global2.Reset();
4373 }
4374
4375
THREADED_TEST(LocalHandle)4376 THREADED_TEST(LocalHandle) {
4377 v8::HandleScope scope(CcTest::isolate());
4378 v8::Local<String> local =
4379 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4380 CHECK_EQ(local->Length(), 3);
4381 }
4382
4383
4384 class WeakCallCounter {
4385 public:
WeakCallCounter(int id)4386 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
id()4387 int id() { return id_; }
increment()4388 void increment() { number_of_weak_calls_++; }
NumberOfWeakCalls()4389 int NumberOfWeakCalls() { return number_of_weak_calls_; }
4390
4391 private:
4392 int id_;
4393 int number_of_weak_calls_;
4394 };
4395
4396
4397 template <typename T>
4398 struct WeakCallCounterAndPersistent {
WeakCallCounterAndPersistentWeakCallCounterAndPersistent4399 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4400 : counter(counter) {}
4401 WeakCallCounter* counter;
4402 v8::Persistent<T> handle;
4403 };
4404
4405
4406 template <typename T>
WeakPointerCallback(const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>> & data)4407 static void WeakPointerCallback(
4408 const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4409 CHECK_EQ(1234, data.GetParameter()->counter->id());
4410 data.GetParameter()->counter->increment();
4411 data.GetParameter()->handle.Reset();
4412 }
4413
4414
4415 template <typename T>
MakeUniqueId(const Persistent<T> & p)4416 static UniqueId MakeUniqueId(const Persistent<T>& p) {
4417 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
4418 }
4419
4420
THREADED_TEST(ApiObjectGroups)4421 THREADED_TEST(ApiObjectGroups) {
4422 LocalContext env;
4423 v8::Isolate* iso = env->GetIsolate();
4424 HandleScope scope(iso);
4425
4426 WeakCallCounter counter(1234);
4427
4428 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4429 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4430 WeakCallCounterAndPersistent<Value> g1c1(&counter);
4431 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4432 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4433 WeakCallCounterAndPersistent<Value> g2c1(&counter);
4434
4435 {
4436 HandleScope scope(iso);
4437 g1s1.handle.Reset(iso, Object::New(iso));
4438 g1s2.handle.Reset(iso, Object::New(iso));
4439 g1c1.handle.Reset(iso, Object::New(iso));
4440 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
4441 v8::WeakCallbackType::kParameter);
4442 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
4443 v8::WeakCallbackType::kParameter);
4444 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
4445 v8::WeakCallbackType::kParameter);
4446
4447 g2s1.handle.Reset(iso, Object::New(iso));
4448 g2s2.handle.Reset(iso, Object::New(iso));
4449 g2c1.handle.Reset(iso, Object::New(iso));
4450 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
4451 v8::WeakCallbackType::kParameter);
4452 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
4453 v8::WeakCallbackType::kParameter);
4454 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
4455 v8::WeakCallbackType::kParameter);
4456 }
4457
4458 WeakCallCounterAndPersistent<Value> root(&counter);
4459 root.handle.Reset(iso, g1s1.handle); // make a root.
4460
4461 // Connect group 1 and 2, make a cycle.
4462 {
4463 HandleScope scope(iso);
4464 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
4465 ->Set(env.local(), 0, Local<Value>::New(iso, g2s2.handle))
4466 .FromJust());
4467 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
4468 ->Set(env.local(), 0, Local<Value>::New(iso, g1s1.handle))
4469 .FromJust());
4470 }
4471
4472 {
4473 UniqueId id1 = MakeUniqueId(g1s1.handle);
4474 UniqueId id2 = MakeUniqueId(g2s2.handle);
4475 iso->SetObjectGroupId(g1s1.handle, id1);
4476 iso->SetObjectGroupId(g1s2.handle, id1);
4477 iso->SetReferenceFromGroup(id1, g1c1.handle);
4478 iso->SetObjectGroupId(g2s1.handle, id2);
4479 iso->SetObjectGroupId(g2s2.handle, id2);
4480 iso->SetReferenceFromGroup(id2, g2c1.handle);
4481 }
4482 // Do a single full GC, ensure incremental marking is stopped.
4483 v8::internal::Heap* heap =
4484 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
4485 heap->CollectAllGarbage();
4486
4487 // All object should be alive.
4488 CHECK_EQ(0, counter.NumberOfWeakCalls());
4489
4490 // Weaken the root.
4491 root.handle.SetWeak(&root, &WeakPointerCallback,
4492 v8::WeakCallbackType::kParameter);
4493 // But make children strong roots---all the objects (except for children)
4494 // should be collectable now.
4495 g1c1.handle.ClearWeak();
4496 g2c1.handle.ClearWeak();
4497
4498 // Groups are deleted, rebuild groups.
4499 {
4500 UniqueId id1 = MakeUniqueId(g1s1.handle);
4501 UniqueId id2 = MakeUniqueId(g2s2.handle);
4502 iso->SetObjectGroupId(g1s1.handle, id1);
4503 iso->SetObjectGroupId(g1s2.handle, id1);
4504 iso->SetReferenceFromGroup(id1, g1c1.handle);
4505 iso->SetObjectGroupId(g2s1.handle, id2);
4506 iso->SetObjectGroupId(g2s2.handle, id2);
4507 iso->SetReferenceFromGroup(id2, g2c1.handle);
4508 }
4509
4510 heap->CollectAllGarbage();
4511
4512 // All objects should be gone. 5 global handles in total.
4513 CHECK_EQ(5, counter.NumberOfWeakCalls());
4514
4515 // And now make children weak again and collect them.
4516 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
4517 v8::WeakCallbackType::kParameter);
4518 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
4519 v8::WeakCallbackType::kParameter);
4520
4521 heap->CollectAllGarbage();
4522 CHECK_EQ(7, counter.NumberOfWeakCalls());
4523 }
4524
4525
THREADED_TEST(ApiObjectGroupsForSubtypes)4526 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4527 LocalContext env;
4528 v8::Isolate* iso = env->GetIsolate();
4529 HandleScope scope(iso);
4530
4531 WeakCallCounter counter(1234);
4532
4533 WeakCallCounterAndPersistent<Object> g1s1(&counter);
4534 WeakCallCounterAndPersistent<String> g1s2(&counter);
4535 WeakCallCounterAndPersistent<String> g1c1(&counter);
4536 WeakCallCounterAndPersistent<Object> g2s1(&counter);
4537 WeakCallCounterAndPersistent<String> g2s2(&counter);
4538 WeakCallCounterAndPersistent<String> g2c1(&counter);
4539
4540 {
4541 HandleScope scope(iso);
4542 g1s1.handle.Reset(iso, Object::New(iso));
4543 g1s2.handle.Reset(iso, v8_str("foo1"));
4544 g1c1.handle.Reset(iso, v8_str("foo2"));
4545 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
4546 v8::WeakCallbackType::kParameter);
4547 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
4548 v8::WeakCallbackType::kParameter);
4549 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
4550 v8::WeakCallbackType::kParameter);
4551
4552 g2s1.handle.Reset(iso, Object::New(iso));
4553 g2s2.handle.Reset(iso, v8_str("foo3"));
4554 g2c1.handle.Reset(iso, v8_str("foo4"));
4555 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
4556 v8::WeakCallbackType::kParameter);
4557 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
4558 v8::WeakCallbackType::kParameter);
4559 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
4560 v8::WeakCallbackType::kParameter);
4561 }
4562
4563 WeakCallCounterAndPersistent<Value> root(&counter);
4564 root.handle.Reset(iso, g1s1.handle); // make a root.
4565
4566 // Connect group 1 and 2, make a cycle.
4567 {
4568 HandleScope scope(iso);
4569 CHECK(Local<Object>::New(iso, g1s1.handle)
4570 ->Set(env.local(), 0, Local<Object>::New(iso, g2s1.handle))
4571 .FromJust());
4572 CHECK(Local<Object>::New(iso, g2s1.handle)
4573 ->Set(env.local(), 0, Local<Object>::New(iso, g1s1.handle))
4574 .FromJust());
4575 }
4576
4577 {
4578 UniqueId id1 = MakeUniqueId(g1s1.handle);
4579 UniqueId id2 = MakeUniqueId(g2s2.handle);
4580 iso->SetObjectGroupId(g1s1.handle, id1);
4581 iso->SetObjectGroupId(g1s2.handle, id1);
4582 iso->SetReference(g1s1.handle, g1c1.handle);
4583 iso->SetObjectGroupId(g2s1.handle, id2);
4584 iso->SetObjectGroupId(g2s2.handle, id2);
4585 iso->SetReferenceFromGroup(id2, g2c1.handle);
4586 }
4587 // Do a single full GC, ensure incremental marking is stopped.
4588 v8::internal::Heap* heap =
4589 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
4590 heap->CollectAllGarbage();
4591
4592 // All object should be alive.
4593 CHECK_EQ(0, counter.NumberOfWeakCalls());
4594
4595 // Weaken the root.
4596 root.handle.SetWeak(&root, &WeakPointerCallback,
4597 v8::WeakCallbackType::kParameter);
4598 // But make children strong roots---all the objects (except for children)
4599 // should be collectable now.
4600 g1c1.handle.ClearWeak();
4601 g2c1.handle.ClearWeak();
4602
4603 // Groups are deleted, rebuild groups.
4604 {
4605 UniqueId id1 = MakeUniqueId(g1s1.handle);
4606 UniqueId id2 = MakeUniqueId(g2s2.handle);
4607 iso->SetObjectGroupId(g1s1.handle, id1);
4608 iso->SetObjectGroupId(g1s2.handle, id1);
4609 iso->SetReference(g1s1.handle, g1c1.handle);
4610 iso->SetObjectGroupId(g2s1.handle, id2);
4611 iso->SetObjectGroupId(g2s2.handle, id2);
4612 iso->SetReferenceFromGroup(id2, g2c1.handle);
4613 }
4614
4615 heap->CollectAllGarbage();
4616
4617 // All objects should be gone. 5 global handles in total.
4618 CHECK_EQ(5, counter.NumberOfWeakCalls());
4619
4620 // And now make children weak again and collect them.
4621 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
4622 v8::WeakCallbackType::kParameter);
4623 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
4624 v8::WeakCallbackType::kParameter);
4625
4626 heap->CollectAllGarbage();
4627 CHECK_EQ(7, counter.NumberOfWeakCalls());
4628 }
4629
4630
THREADED_TEST(ApiObjectGroupsCycle)4631 THREADED_TEST(ApiObjectGroupsCycle) {
4632 LocalContext env;
4633 v8::Isolate* iso = env->GetIsolate();
4634 HandleScope scope(iso);
4635
4636 WeakCallCounter counter(1234);
4637
4638 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4639 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4640 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4641 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4642 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4643 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4644 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4645 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4646
4647 {
4648 HandleScope scope(iso);
4649 g1s1.handle.Reset(iso, Object::New(iso));
4650 g1s2.handle.Reset(iso, Object::New(iso));
4651 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
4652 v8::WeakCallbackType::kParameter);
4653 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
4654 v8::WeakCallbackType::kParameter);
4655 CHECK(g1s1.handle.IsWeak());
4656 CHECK(g1s2.handle.IsWeak());
4657
4658 g2s1.handle.Reset(iso, Object::New(iso));
4659 g2s2.handle.Reset(iso, Object::New(iso));
4660 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
4661 v8::WeakCallbackType::kParameter);
4662 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
4663 v8::WeakCallbackType::kParameter);
4664 CHECK(g2s1.handle.IsWeak());
4665 CHECK(g2s2.handle.IsWeak());
4666
4667 g3s1.handle.Reset(iso, Object::New(iso));
4668 g3s2.handle.Reset(iso, Object::New(iso));
4669 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
4670 v8::WeakCallbackType::kParameter);
4671 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
4672 v8::WeakCallbackType::kParameter);
4673 CHECK(g3s1.handle.IsWeak());
4674 CHECK(g3s2.handle.IsWeak());
4675
4676 g4s1.handle.Reset(iso, Object::New(iso));
4677 g4s2.handle.Reset(iso, Object::New(iso));
4678 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
4679 v8::WeakCallbackType::kParameter);
4680 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
4681 v8::WeakCallbackType::kParameter);
4682 CHECK(g4s1.handle.IsWeak());
4683 CHECK(g4s2.handle.IsWeak());
4684 }
4685
4686 WeakCallCounterAndPersistent<Value> root(&counter);
4687 root.handle.Reset(iso, g1s1.handle); // make a root.
4688
4689 // Connect groups. We're building the following cycle:
4690 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4691 // groups.
4692 {
4693 UniqueId id1 = MakeUniqueId(g1s1.handle);
4694 UniqueId id2 = MakeUniqueId(g2s1.handle);
4695 UniqueId id3 = MakeUniqueId(g3s1.handle);
4696 UniqueId id4 = MakeUniqueId(g4s1.handle);
4697 iso->SetObjectGroupId(g1s1.handle, id1);
4698 iso->SetObjectGroupId(g1s2.handle, id1);
4699 iso->SetReferenceFromGroup(id1, g2s1.handle);
4700 iso->SetObjectGroupId(g2s1.handle, id2);
4701 iso->SetObjectGroupId(g2s2.handle, id2);
4702 iso->SetReferenceFromGroup(id2, g3s1.handle);
4703 iso->SetObjectGroupId(g3s1.handle, id3);
4704 iso->SetObjectGroupId(g3s2.handle, id3);
4705 iso->SetReferenceFromGroup(id3, g4s1.handle);
4706 iso->SetObjectGroupId(g4s1.handle, id4);
4707 iso->SetObjectGroupId(g4s2.handle, id4);
4708 iso->SetReferenceFromGroup(id4, g1s1.handle);
4709 }
4710 // Do a single full GC
4711 v8::internal::Heap* heap =
4712 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
4713 heap->CollectAllGarbage();
4714
4715 // All object should be alive.
4716 CHECK_EQ(0, counter.NumberOfWeakCalls());
4717
4718 // Weaken the root.
4719 root.handle.SetWeak(&root, &WeakPointerCallback,
4720 v8::WeakCallbackType::kParameter);
4721
4722 // Groups are deleted, rebuild groups.
4723 {
4724 UniqueId id1 = MakeUniqueId(g1s1.handle);
4725 UniqueId id2 = MakeUniqueId(g2s1.handle);
4726 UniqueId id3 = MakeUniqueId(g3s1.handle);
4727 UniqueId id4 = MakeUniqueId(g4s1.handle);
4728 iso->SetObjectGroupId(g1s1.handle, id1);
4729 iso->SetObjectGroupId(g1s2.handle, id1);
4730 iso->SetReferenceFromGroup(id1, g2s1.handle);
4731 iso->SetObjectGroupId(g2s1.handle, id2);
4732 iso->SetObjectGroupId(g2s2.handle, id2);
4733 iso->SetReferenceFromGroup(id2, g3s1.handle);
4734 iso->SetObjectGroupId(g3s1.handle, id3);
4735 iso->SetObjectGroupId(g3s2.handle, id3);
4736 iso->SetReferenceFromGroup(id3, g4s1.handle);
4737 iso->SetObjectGroupId(g4s1.handle, id4);
4738 iso->SetObjectGroupId(g4s2.handle, id4);
4739 iso->SetReferenceFromGroup(id4, g1s1.handle);
4740 }
4741
4742 heap->CollectAllGarbage();
4743
4744 // All objects should be gone. 9 global handles in total.
4745 CHECK_EQ(9, counter.NumberOfWeakCalls());
4746 }
4747
4748
THREADED_TEST(ScriptException)4749 THREADED_TEST(ScriptException) {
4750 LocalContext env;
4751 v8::HandleScope scope(env->GetIsolate());
4752 Local<Script> script = v8_compile("throw 'panama!';");
4753 v8::TryCatch try_catch(env->GetIsolate());
4754 v8::MaybeLocal<Value> result = script->Run(env.local());
4755 CHECK(result.IsEmpty());
4756 CHECK(try_catch.HasCaught());
4757 String::Utf8Value exception_value(try_catch.Exception());
4758 CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4759 }
4760
4761
TEST(TryCatchCustomException)4762 TEST(TryCatchCustomException) {
4763 LocalContext env;
4764 v8::Isolate* isolate = env->GetIsolate();
4765 v8::HandleScope scope(isolate);
4766 v8::TryCatch try_catch(isolate);
4767 CompileRun(
4768 "function CustomError() { this.a = 'b'; }"
4769 "(function f() { throw new CustomError(); })();");
4770 CHECK(try_catch.HasCaught());
4771 CHECK(try_catch.Exception()
4772 ->ToObject(env.local())
4773 .ToLocalChecked()
4774 ->Get(env.local(), v8_str("a"))
4775 .ToLocalChecked()
4776 ->Equals(env.local(), v8_str("b"))
4777 .FromJust());
4778 }
4779
4780
4781 bool message_received;
4782
4783
check_message_0(v8::Local<v8::Message> message,v8::Local<Value> data)4784 static void check_message_0(v8::Local<v8::Message> message,
4785 v8::Local<Value> data) {
4786 CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4787 .FromJust());
4788 CHECK_EQ(6.75, message->GetScriptOrigin()
4789 .ResourceName()
4790 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4791 .FromJust());
4792 CHECK(!message->IsSharedCrossOrigin());
4793 message_received = true;
4794 }
4795
4796
THREADED_TEST(MessageHandler0)4797 THREADED_TEST(MessageHandler0) {
4798 message_received = false;
4799 v8::HandleScope scope(CcTest::isolate());
4800 CHECK(!message_received);
4801 LocalContext context;
4802 CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4803 v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4804 CHECK(script->Run(context.local()).IsEmpty());
4805 CHECK(message_received);
4806 // clear out the message listener
4807 CcTest::isolate()->RemoveMessageListeners(check_message_0);
4808 }
4809
4810
check_message_1(v8::Local<v8::Message> message,v8::Local<Value> data)4811 static void check_message_1(v8::Local<v8::Message> message,
4812 v8::Local<Value> data) {
4813 CHECK(data->IsNumber());
4814 CHECK_EQ(1337,
4815 data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4816 CHECK(!message->IsSharedCrossOrigin());
4817 message_received = true;
4818 }
4819
4820
TEST(MessageHandler1)4821 TEST(MessageHandler1) {
4822 message_received = false;
4823 v8::HandleScope scope(CcTest::isolate());
4824 CHECK(!message_received);
4825 CcTest::isolate()->AddMessageListener(check_message_1);
4826 LocalContext context;
4827 CompileRun("throw 1337;");
4828 CHECK(message_received);
4829 // clear out the message listener
4830 CcTest::isolate()->RemoveMessageListeners(check_message_1);
4831 }
4832
4833
check_message_2(v8::Local<v8::Message> message,v8::Local<Value> data)4834 static void check_message_2(v8::Local<v8::Message> message,
4835 v8::Local<Value> data) {
4836 LocalContext context;
4837 CHECK(data->IsObject());
4838 v8::Local<v8::Value> hidden_property =
4839 v8::Object::Cast(*data)
4840 ->GetPrivate(
4841 context.local(),
4842 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4843 .ToLocalChecked();
4844 CHECK(v8_str("hidden value")
4845 ->Equals(context.local(), hidden_property)
4846 .FromJust());
4847 CHECK(!message->IsSharedCrossOrigin());
4848 message_received = true;
4849 }
4850
4851
TEST(MessageHandler2)4852 TEST(MessageHandler2) {
4853 message_received = false;
4854 v8::HandleScope scope(CcTest::isolate());
4855 CHECK(!message_received);
4856 CcTest::isolate()->AddMessageListener(check_message_2);
4857 LocalContext context;
4858 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4859 v8::Object::Cast(*error)
4860 ->SetPrivate(context.local(),
4861 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4862 v8_str("hidden value"))
4863 .FromJust();
4864 CHECK(context->Global()
4865 ->Set(context.local(), v8_str("error"), error)
4866 .FromJust());
4867 CompileRun("throw error;");
4868 CHECK(message_received);
4869 // clear out the message listener
4870 CcTest::isolate()->RemoveMessageListeners(check_message_2);
4871 }
4872
4873
check_message_3(v8::Local<v8::Message> message,v8::Local<Value> data)4874 static void check_message_3(v8::Local<v8::Message> message,
4875 v8::Local<Value> data) {
4876 CHECK(message->IsSharedCrossOrigin());
4877 CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4878 CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript());
4879 CHECK(message->GetScriptOrigin().Options().IsOpaque());
4880 CHECK_EQ(6.75, message->GetScriptOrigin()
4881 .ResourceName()
4882 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4883 .FromJust());
4884 CHECK_EQ(7.40, message->GetScriptOrigin()
4885 .SourceMapUrl()
4886 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4887 .FromJust());
4888 message_received = true;
4889 }
4890
4891
TEST(MessageHandler3)4892 TEST(MessageHandler3) {
4893 message_received = false;
4894 v8::Isolate* isolate = CcTest::isolate();
4895 v8::HandleScope scope(isolate);
4896 CHECK(!message_received);
4897 isolate->AddMessageListener(check_message_3);
4898 LocalContext context;
4899 v8::ScriptOrigin origin = v8::ScriptOrigin(
4900 v8_str("6.75"), v8::Integer::New(isolate, 1),
4901 v8::Integer::New(isolate, 2), v8::True(isolate), Local<v8::Integer>(),
4902 v8::True(isolate), v8_str("7.40"), v8::True(isolate));
4903 v8::Local<v8::Script> script =
4904 Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4905 .ToLocalChecked();
4906 CHECK(script->Run(context.local()).IsEmpty());
4907 CHECK(message_received);
4908 // clear out the message listener
4909 isolate->RemoveMessageListeners(check_message_3);
4910 }
4911
4912
check_message_4(v8::Local<v8::Message> message,v8::Local<Value> data)4913 static void check_message_4(v8::Local<v8::Message> message,
4914 v8::Local<Value> data) {
4915 CHECK(!message->IsSharedCrossOrigin());
4916 CHECK_EQ(6.75, message->GetScriptOrigin()
4917 .ResourceName()
4918 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4919 .FromJust());
4920 message_received = true;
4921 }
4922
4923
TEST(MessageHandler4)4924 TEST(MessageHandler4) {
4925 message_received = false;
4926 v8::Isolate* isolate = CcTest::isolate();
4927 v8::HandleScope scope(isolate);
4928 CHECK(!message_received);
4929 isolate->AddMessageListener(check_message_4);
4930 LocalContext context;
4931 v8::ScriptOrigin origin =
4932 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4933 v8::Integer::New(isolate, 2), v8::False(isolate));
4934 v8::Local<v8::Script> script =
4935 Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4936 .ToLocalChecked();
4937 CHECK(script->Run(context.local()).IsEmpty());
4938 CHECK(message_received);
4939 // clear out the message listener
4940 isolate->RemoveMessageListeners(check_message_4);
4941 }
4942
4943
check_message_5a(v8::Local<v8::Message> message,v8::Local<Value> data)4944 static void check_message_5a(v8::Local<v8::Message> message,
4945 v8::Local<Value> data) {
4946 CHECK(message->IsSharedCrossOrigin());
4947 CHECK_EQ(6.75, message->GetScriptOrigin()
4948 .ResourceName()
4949 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4950 .FromJust());
4951 message_received = true;
4952 }
4953
4954
check_message_5b(v8::Local<v8::Message> message,v8::Local<Value> data)4955 static void check_message_5b(v8::Local<v8::Message> message,
4956 v8::Local<Value> data) {
4957 CHECK(!message->IsSharedCrossOrigin());
4958 CHECK_EQ(6.75, message->GetScriptOrigin()
4959 .ResourceName()
4960 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4961 .FromJust());
4962 message_received = true;
4963 }
4964
4965
TEST(MessageHandler5)4966 TEST(MessageHandler5) {
4967 message_received = false;
4968 v8::Isolate* isolate = CcTest::isolate();
4969 v8::HandleScope scope(isolate);
4970 CHECK(!message_received);
4971 isolate->AddMessageListener(check_message_5a);
4972 LocalContext context;
4973 v8::ScriptOrigin origin1 =
4974 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4975 v8::Integer::New(isolate, 2), v8::True(isolate));
4976 v8::Local<v8::Script> script =
4977 Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
4978 .ToLocalChecked();
4979 CHECK(script->Run(context.local()).IsEmpty());
4980 CHECK(message_received);
4981 // clear out the message listener
4982 isolate->RemoveMessageListeners(check_message_5a);
4983
4984 message_received = false;
4985 isolate->AddMessageListener(check_message_5b);
4986 v8::ScriptOrigin origin2 =
4987 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4988 v8::Integer::New(isolate, 2), v8::False(isolate));
4989 script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
4990 .ToLocalChecked();
4991 CHECK(script->Run(context.local()).IsEmpty());
4992 CHECK(message_received);
4993 // clear out the message listener
4994 isolate->RemoveMessageListeners(check_message_5b);
4995 }
4996
4997
TEST(NativeWeakMap)4998 TEST(NativeWeakMap) {
4999 v8::Isolate* isolate = CcTest::isolate();
5000 HandleScope scope(isolate);
5001 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
5002 CHECK(!weak_map.IsEmpty());
5003
5004 LocalContext env;
5005 Local<Object> value = v8::Object::New(isolate);
5006
5007 Local<Object> local1 = v8::Object::New(isolate);
5008 CHECK(!weak_map->Has(local1));
5009 CHECK(weak_map->Get(local1)->IsUndefined());
5010 weak_map->Set(local1, value);
5011 CHECK(weak_map->Has(local1));
5012 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
5013
5014 WeakCallCounter counter(1234);
5015 WeakCallCounterAndPersistent<Value> o1(&counter);
5016 WeakCallCounterAndPersistent<Value> o2(&counter);
5017 WeakCallCounterAndPersistent<Value> s1(&counter);
5018 {
5019 HandleScope scope(isolate);
5020 Local<v8::Object> obj1 = v8::Object::New(isolate);
5021 Local<v8::Object> obj2 = v8::Object::New(isolate);
5022 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
5023
5024 weak_map->Set(obj1, value);
5025 weak_map->Set(obj2, value);
5026 weak_map->Set(sym1, value);
5027
5028 o1.handle.Reset(isolate, obj1);
5029 o2.handle.Reset(isolate, obj2);
5030 s1.handle.Reset(isolate, sym1);
5031
5032 CHECK(weak_map->Has(local1));
5033 CHECK(weak_map->Has(obj1));
5034 CHECK(weak_map->Has(obj2));
5035 CHECK(weak_map->Has(sym1));
5036
5037 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
5038 CHECK(value->Equals(env.local(), weak_map->Get(obj1)).FromJust());
5039 CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust());
5040 CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust());
5041 }
5042 CcTest::heap()->CollectAllGarbage();
5043 {
5044 HandleScope scope(isolate);
5045 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
5046 CHECK(value->Equals(env.local(),
5047 weak_map->Get(Local<Value>::New(isolate, o1.handle)))
5048 .FromJust());
5049 CHECK(value->Equals(env.local(),
5050 weak_map->Get(Local<Value>::New(isolate, o2.handle)))
5051 .FromJust());
5052 CHECK(value->Equals(env.local(),
5053 weak_map->Get(Local<Value>::New(isolate, s1.handle)))
5054 .FromJust());
5055 }
5056
5057 o1.handle.SetWeak(&o1, &WeakPointerCallback,
5058 v8::WeakCallbackType::kParameter);
5059 o2.handle.SetWeak(&o2, &WeakPointerCallback,
5060 v8::WeakCallbackType::kParameter);
5061 s1.handle.SetWeak(&s1, &WeakPointerCallback,
5062 v8::WeakCallbackType::kParameter);
5063
5064 CcTest::heap()->CollectAllGarbage();
5065 CHECK_EQ(3, counter.NumberOfWeakCalls());
5066
5067 CHECK(o1.handle.IsEmpty());
5068 CHECK(o2.handle.IsEmpty());
5069 CHECK(s1.handle.IsEmpty());
5070
5071 CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
5072 CHECK(weak_map->Delete(local1));
5073 CHECK(!weak_map->Has(local1));
5074 CHECK(weak_map->Get(local1)->IsUndefined());
5075 }
5076
5077
THREADED_TEST(GetSetProperty)5078 THREADED_TEST(GetSetProperty) {
5079 LocalContext context;
5080 v8::Isolate* isolate = context->GetIsolate();
5081 v8::HandleScope scope(isolate);
5082 CHECK(context->Global()
5083 ->Set(context.local(), v8_str("foo"), v8_num(14))
5084 .FromJust());
5085 CHECK(context->Global()
5086 ->Set(context.local(), v8_str("12"), v8_num(92))
5087 .FromJust());
5088 CHECK(context->Global()
5089 ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
5090 .FromJust());
5091 CHECK(context->Global()
5092 ->Set(context.local(), v8_num(13), v8_num(56))
5093 .FromJust());
5094 Local<Value> foo = CompileRun("this.foo");
5095 CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
5096 Local<Value> twelve = CompileRun("this[12]");
5097 CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
5098 Local<Value> sixteen = CompileRun("this[16]");
5099 CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
5100 Local<Value> thirteen = CompileRun("this[13]");
5101 CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
5102 CHECK_EQ(92, context->Global()
5103 ->Get(context.local(), v8::Integer::New(isolate, 12))
5104 .ToLocalChecked()
5105 ->Int32Value(context.local())
5106 .FromJust());
5107 CHECK_EQ(92, context->Global()
5108 ->Get(context.local(), v8_str("12"))
5109 .ToLocalChecked()
5110 ->Int32Value(context.local())
5111 .FromJust());
5112 CHECK_EQ(92, context->Global()
5113 ->Get(context.local(), v8_num(12))
5114 .ToLocalChecked()
5115 ->Int32Value(context.local())
5116 .FromJust());
5117 CHECK_EQ(32, context->Global()
5118 ->Get(context.local(), v8::Integer::New(isolate, 16))
5119 .ToLocalChecked()
5120 ->Int32Value(context.local())
5121 .FromJust());
5122 CHECK_EQ(32, context->Global()
5123 ->Get(context.local(), v8_str("16"))
5124 .ToLocalChecked()
5125 ->Int32Value(context.local())
5126 .FromJust());
5127 CHECK_EQ(32, context->Global()
5128 ->Get(context.local(), v8_num(16))
5129 .ToLocalChecked()
5130 ->Int32Value(context.local())
5131 .FromJust());
5132 CHECK_EQ(56, context->Global()
5133 ->Get(context.local(), v8::Integer::New(isolate, 13))
5134 .ToLocalChecked()
5135 ->Int32Value(context.local())
5136 .FromJust());
5137 CHECK_EQ(56, context->Global()
5138 ->Get(context.local(), v8_str("13"))
5139 .ToLocalChecked()
5140 ->Int32Value(context.local())
5141 .FromJust());
5142 CHECK_EQ(56, context->Global()
5143 ->Get(context.local(), v8_num(13))
5144 .ToLocalChecked()
5145 ->Int32Value(context.local())
5146 .FromJust());
5147 }
5148
5149
THREADED_TEST(PropertyAttributes)5150 THREADED_TEST(PropertyAttributes) {
5151 LocalContext context;
5152 v8::HandleScope scope(context->GetIsolate());
5153 // none
5154 Local<String> prop = v8_str("none");
5155 CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5156 CHECK_EQ(v8::None, context->Global()
5157 ->GetPropertyAttributes(context.local(), prop)
5158 .FromJust());
5159 // read-only
5160 prop = v8_str("read_only");
5161 context->Global()
5162 ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5163 .FromJust();
5164 CHECK_EQ(7, context->Global()
5165 ->Get(context.local(), prop)
5166 .ToLocalChecked()
5167 ->Int32Value(context.local())
5168 .FromJust());
5169 CHECK_EQ(v8::ReadOnly, context->Global()
5170 ->GetPropertyAttributes(context.local(), prop)
5171 .FromJust());
5172 CompileRun("read_only = 9");
5173 CHECK_EQ(7, context->Global()
5174 ->Get(context.local(), prop)
5175 .ToLocalChecked()
5176 ->Int32Value(context.local())
5177 .FromJust());
5178 CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5179 CHECK_EQ(7, context->Global()
5180 ->Get(context.local(), prop)
5181 .ToLocalChecked()
5182 ->Int32Value(context.local())
5183 .FromJust());
5184 // dont-delete
5185 prop = v8_str("dont_delete");
5186 context->Global()
5187 ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5188 .FromJust();
5189 CHECK_EQ(13, context->Global()
5190 ->Get(context.local(), prop)
5191 .ToLocalChecked()
5192 ->Int32Value(context.local())
5193 .FromJust());
5194 CompileRun("delete dont_delete");
5195 CHECK_EQ(13, context->Global()
5196 ->Get(context.local(), prop)
5197 .ToLocalChecked()
5198 ->Int32Value(context.local())
5199 .FromJust());
5200 CHECK_EQ(v8::DontDelete, context->Global()
5201 ->GetPropertyAttributes(context.local(), prop)
5202 .FromJust());
5203 // dont-enum
5204 prop = v8_str("dont_enum");
5205 context->Global()
5206 ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5207 .FromJust();
5208 CHECK_EQ(v8::DontEnum, context->Global()
5209 ->GetPropertyAttributes(context.local(), prop)
5210 .FromJust());
5211 // absent
5212 prop = v8_str("absent");
5213 CHECK_EQ(v8::None, context->Global()
5214 ->GetPropertyAttributes(context.local(), prop)
5215 .FromJust());
5216 Local<Value> fake_prop = v8_num(1);
5217 CHECK_EQ(v8::None, context->Global()
5218 ->GetPropertyAttributes(context.local(), fake_prop)
5219 .FromJust());
5220 // exception
5221 TryCatch try_catch(context->GetIsolate());
5222 Local<Value> exception =
5223 CompileRun("({ toString: function() { throw 'exception';} })");
5224 CHECK(context->Global()
5225 ->GetPropertyAttributes(context.local(), exception)
5226 .IsNothing());
5227 CHECK(try_catch.HasCaught());
5228 String::Utf8Value exception_value(try_catch.Exception());
5229 CHECK_EQ(0, strcmp("exception", *exception_value));
5230 try_catch.Reset();
5231 }
5232
5233
THREADED_TEST(Array)5234 THREADED_TEST(Array) {
5235 LocalContext context;
5236 v8::HandleScope scope(context->GetIsolate());
5237 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5238 CHECK_EQ(0u, array->Length());
5239 CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5240 CHECK(!array->Has(context.local(), 0).FromJust());
5241 CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5242 CHECK(!array->Has(context.local(), 100).FromJust());
5243 CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5244 CHECK_EQ(3u, array->Length());
5245 CHECK(!array->Has(context.local(), 0).FromJust());
5246 CHECK(!array->Has(context.local(), 1).FromJust());
5247 CHECK(array->Has(context.local(), 2).FromJust());
5248 CHECK_EQ(7, array->Get(context.local(), 2)
5249 .ToLocalChecked()
5250 ->Int32Value(context.local())
5251 .FromJust());
5252 Local<Value> obj = CompileRun("[1, 2, 3]");
5253 Local<v8::Array> arr = obj.As<v8::Array>();
5254 CHECK_EQ(3u, arr->Length());
5255 CHECK_EQ(1, arr->Get(context.local(), 0)
5256 .ToLocalChecked()
5257 ->Int32Value(context.local())
5258 .FromJust());
5259 CHECK_EQ(2, arr->Get(context.local(), 1)
5260 .ToLocalChecked()
5261 ->Int32Value(context.local())
5262 .FromJust());
5263 CHECK_EQ(3, arr->Get(context.local(), 2)
5264 .ToLocalChecked()
5265 ->Int32Value(context.local())
5266 .FromJust());
5267 array = v8::Array::New(context->GetIsolate(), 27);
5268 CHECK_EQ(27u, array->Length());
5269 array = v8::Array::New(context->GetIsolate(), -27);
5270 CHECK_EQ(0u, array->Length());
5271 }
5272
5273
HandleF(const v8::FunctionCallbackInfo<v8::Value> & args)5274 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5275 v8::EscapableHandleScope scope(args.GetIsolate());
5276 ApiTestFuzzer::Fuzz();
5277 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5278 for (int i = 0; i < args.Length(); i++) {
5279 CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5280 .FromJust());
5281 }
5282 args.GetReturnValue().Set(scope.Escape(result));
5283 }
5284
5285
THREADED_TEST(Vector)5286 THREADED_TEST(Vector) {
5287 v8::Isolate* isolate = CcTest::isolate();
5288 v8::HandleScope scope(isolate);
5289 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5290 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5291 LocalContext context(0, global);
5292
5293 const char* fun = "f()";
5294 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5295 CHECK_EQ(0u, a0->Length());
5296
5297 const char* fun2 = "f(11)";
5298 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5299 CHECK_EQ(1u, a1->Length());
5300 CHECK_EQ(11, a1->Get(context.local(), 0)
5301 .ToLocalChecked()
5302 ->Int32Value(context.local())
5303 .FromJust());
5304
5305 const char* fun3 = "f(12, 13)";
5306 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5307 CHECK_EQ(2u, a2->Length());
5308 CHECK_EQ(12, a2->Get(context.local(), 0)
5309 .ToLocalChecked()
5310 ->Int32Value(context.local())
5311 .FromJust());
5312 CHECK_EQ(13, a2->Get(context.local(), 1)
5313 .ToLocalChecked()
5314 ->Int32Value(context.local())
5315 .FromJust());
5316
5317 const char* fun4 = "f(14, 15, 16)";
5318 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5319 CHECK_EQ(3u, a3->Length());
5320 CHECK_EQ(14, a3->Get(context.local(), 0)
5321 .ToLocalChecked()
5322 ->Int32Value(context.local())
5323 .FromJust());
5324 CHECK_EQ(15, a3->Get(context.local(), 1)
5325 .ToLocalChecked()
5326 ->Int32Value(context.local())
5327 .FromJust());
5328 CHECK_EQ(16, a3->Get(context.local(), 2)
5329 .ToLocalChecked()
5330 ->Int32Value(context.local())
5331 .FromJust());
5332
5333 const char* fun5 = "f(17, 18, 19, 20)";
5334 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5335 CHECK_EQ(4u, a4->Length());
5336 CHECK_EQ(17, a4->Get(context.local(), 0)
5337 .ToLocalChecked()
5338 ->Int32Value(context.local())
5339 .FromJust());
5340 CHECK_EQ(18, a4->Get(context.local(), 1)
5341 .ToLocalChecked()
5342 ->Int32Value(context.local())
5343 .FromJust());
5344 CHECK_EQ(19, a4->Get(context.local(), 2)
5345 .ToLocalChecked()
5346 ->Int32Value(context.local())
5347 .FromJust());
5348 CHECK_EQ(20, a4->Get(context.local(), 3)
5349 .ToLocalChecked()
5350 ->Int32Value(context.local())
5351 .FromJust());
5352 }
5353
5354
THREADED_TEST(FunctionCall)5355 THREADED_TEST(FunctionCall) {
5356 LocalContext context;
5357 v8::Isolate* isolate = context->GetIsolate();
5358 v8::HandleScope scope(isolate);
5359 CompileRun(
5360 "function Foo() {"
5361 " var result = [];"
5362 " for (var i = 0; i < arguments.length; i++) {"
5363 " result.push(arguments[i]);"
5364 " }"
5365 " return result;"
5366 "}"
5367 "function ReturnThisSloppy() {"
5368 " return this;"
5369 "}"
5370 "function ReturnThisStrict() {"
5371 " 'use strict';"
5372 " return this;"
5373 "}");
5374 Local<Function> Foo = Local<Function>::Cast(
5375 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5376 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5377 context->Global()
5378 ->Get(context.local(), v8_str("ReturnThisSloppy"))
5379 .ToLocalChecked());
5380 Local<Function> ReturnThisStrict = Local<Function>::Cast(
5381 context->Global()
5382 ->Get(context.local(), v8_str("ReturnThisStrict"))
5383 .ToLocalChecked());
5384
5385 v8::Local<Value>* args0 = NULL;
5386 Local<v8::Array> a0 = Local<v8::Array>::Cast(
5387 Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5388 CHECK_EQ(0u, a0->Length());
5389
5390 v8::Local<Value> args1[] = {v8_num(1.1)};
5391 Local<v8::Array> a1 = Local<v8::Array>::Cast(
5392 Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5393 CHECK_EQ(1u, a1->Length());
5394 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5395 .ToLocalChecked()
5396 ->NumberValue(context.local())
5397 .FromJust());
5398
5399 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5400 Local<v8::Array> a2 = Local<v8::Array>::Cast(
5401 Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5402 CHECK_EQ(2u, a2->Length());
5403 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5404 .ToLocalChecked()
5405 ->NumberValue(context.local())
5406 .FromJust());
5407 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5408 .ToLocalChecked()
5409 ->NumberValue(context.local())
5410 .FromJust());
5411
5412 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5413 Local<v8::Array> a3 = Local<v8::Array>::Cast(
5414 Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5415 CHECK_EQ(3u, a3->Length());
5416 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5417 .ToLocalChecked()
5418 ->NumberValue(context.local())
5419 .FromJust());
5420 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5421 .ToLocalChecked()
5422 ->NumberValue(context.local())
5423 .FromJust());
5424 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5425 .ToLocalChecked()
5426 ->NumberValue(context.local())
5427 .FromJust());
5428
5429 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5430 v8_num(10.11)};
5431 Local<v8::Array> a4 = Local<v8::Array>::Cast(
5432 Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5433 CHECK_EQ(4u, a4->Length());
5434 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5435 .ToLocalChecked()
5436 ->NumberValue(context.local())
5437 .FromJust());
5438 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5439 .ToLocalChecked()
5440 ->NumberValue(context.local())
5441 .FromJust());
5442 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5443 .ToLocalChecked()
5444 ->NumberValue(context.local())
5445 .FromJust());
5446 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5447 .ToLocalChecked()
5448 ->NumberValue(context.local())
5449 .FromJust());
5450
5451 Local<v8::Value> r1 =
5452 ReturnThisSloppy->Call(context.local(), v8::Undefined(isolate), 0, NULL)
5453 .ToLocalChecked();
5454 CHECK(r1->StrictEquals(context->Global()));
5455 Local<v8::Value> r2 =
5456 ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, NULL)
5457 .ToLocalChecked();
5458 CHECK(r2->StrictEquals(context->Global()));
5459 Local<v8::Value> r3 =
5460 ReturnThisSloppy->Call(context.local(), v8_num(42), 0, NULL)
5461 .ToLocalChecked();
5462 CHECK(r3->IsNumberObject());
5463 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5464 Local<v8::Value> r4 =
5465 ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, NULL)
5466 .ToLocalChecked();
5467 CHECK(r4->IsStringObject());
5468 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5469 Local<v8::Value> r5 =
5470 ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, NULL)
5471 .ToLocalChecked();
5472 CHECK(r5->IsBooleanObject());
5473 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5474
5475 Local<v8::Value> r6 =
5476 ReturnThisStrict->Call(context.local(), v8::Undefined(isolate), 0, NULL)
5477 .ToLocalChecked();
5478 CHECK(r6->IsUndefined());
5479 Local<v8::Value> r7 =
5480 ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, NULL)
5481 .ToLocalChecked();
5482 CHECK(r7->IsNull());
5483 Local<v8::Value> r8 =
5484 ReturnThisStrict->Call(context.local(), v8_num(42), 0, NULL)
5485 .ToLocalChecked();
5486 CHECK(r8->StrictEquals(v8_num(42)));
5487 Local<v8::Value> r9 =
5488 ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, NULL)
5489 .ToLocalChecked();
5490 CHECK(r9->StrictEquals(v8_str("hello")));
5491 Local<v8::Value> r10 =
5492 ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, NULL)
5493 .ToLocalChecked();
5494 CHECK(r10->StrictEquals(v8::True(isolate)));
5495 }
5496
5497
THREADED_TEST(ConstructCall)5498 THREADED_TEST(ConstructCall) {
5499 LocalContext context;
5500 v8::Isolate* isolate = context->GetIsolate();
5501 v8::HandleScope scope(isolate);
5502 CompileRun(
5503 "function Foo() {"
5504 " var result = [];"
5505 " for (var i = 0; i < arguments.length; i++) {"
5506 " result.push(arguments[i]);"
5507 " }"
5508 " return result;"
5509 "}");
5510 Local<Function> Foo = Local<Function>::Cast(
5511 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5512
5513 v8::Local<Value>* args0 = NULL;
5514 Local<v8::Array> a0 = Local<v8::Array>::Cast(
5515 Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5516 CHECK_EQ(0u, a0->Length());
5517
5518 v8::Local<Value> args1[] = {v8_num(1.1)};
5519 Local<v8::Array> a1 = Local<v8::Array>::Cast(
5520 Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5521 CHECK_EQ(1u, a1->Length());
5522 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5523 .ToLocalChecked()
5524 ->NumberValue(context.local())
5525 .FromJust());
5526
5527 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5528 Local<v8::Array> a2 = Local<v8::Array>::Cast(
5529 Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5530 CHECK_EQ(2u, a2->Length());
5531 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5532 .ToLocalChecked()
5533 ->NumberValue(context.local())
5534 .FromJust());
5535 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5536 .ToLocalChecked()
5537 ->NumberValue(context.local())
5538 .FromJust());
5539
5540 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5541 Local<v8::Array> a3 = Local<v8::Array>::Cast(
5542 Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5543 CHECK_EQ(3u, a3->Length());
5544 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5545 .ToLocalChecked()
5546 ->NumberValue(context.local())
5547 .FromJust());
5548 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5549 .ToLocalChecked()
5550 ->NumberValue(context.local())
5551 .FromJust());
5552 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5553 .ToLocalChecked()
5554 ->NumberValue(context.local())
5555 .FromJust());
5556
5557 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5558 v8_num(10.11)};
5559 Local<v8::Array> a4 = Local<v8::Array>::Cast(
5560 Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5561 CHECK_EQ(4u, a4->Length());
5562 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5563 .ToLocalChecked()
5564 ->NumberValue(context.local())
5565 .FromJust());
5566 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5567 .ToLocalChecked()
5568 ->NumberValue(context.local())
5569 .FromJust());
5570 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5571 .ToLocalChecked()
5572 ->NumberValue(context.local())
5573 .FromJust());
5574 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5575 .ToLocalChecked()
5576 ->NumberValue(context.local())
5577 .FromJust());
5578 }
5579
5580
THREADED_TEST(ConversionNumber)5581 THREADED_TEST(ConversionNumber) {
5582 LocalContext env;
5583 v8::Isolate* isolate = env->GetIsolate();
5584 v8::HandleScope scope(isolate);
5585 // Very large number.
5586 CompileRun("var obj = Math.pow(2,32) * 1237;");
5587 Local<Value> obj =
5588 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5589 CHECK_EQ(5312874545152.0,
5590 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5591 CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5592 CHECK(0u ==
5593 obj->ToUint32(env.local())
5594 .ToLocalChecked()
5595 ->Value()); // NOLINT - no CHECK_EQ for unsigned.
5596 // Large number.
5597 CompileRun("var obj = -1234567890123;");
5598 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5599 CHECK_EQ(-1234567890123.0,
5600 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5601 CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5602 CHECK(2382691125u ==
5603 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5604 // Small positive integer.
5605 CompileRun("var obj = 42;");
5606 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5607 CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5608 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5609 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5610 // Negative integer.
5611 CompileRun("var obj = -37;");
5612 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5613 CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5614 CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5615 CHECK(4294967259u ==
5616 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5617 // Positive non-int32 integer.
5618 CompileRun("var obj = 0x81234567;");
5619 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5620 CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5621 CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5622 CHECK(2166572391u ==
5623 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5624 // Fraction.
5625 CompileRun("var obj = 42.3;");
5626 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5627 CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5628 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5629 CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5630 // Large negative fraction.
5631 CompileRun("var obj = -5726623061.75;");
5632 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5633 CHECK_EQ(-5726623061.75,
5634 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5635 CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5636 CHECK(2863311531u ==
5637 obj->ToUint32(env.local()).ToLocalChecked()->Value()); // NOLINT
5638 }
5639
5640
THREADED_TEST(isNumberType)5641 THREADED_TEST(isNumberType) {
5642 LocalContext env;
5643 v8::HandleScope scope(env->GetIsolate());
5644 // Very large number.
5645 CompileRun("var obj = Math.pow(2,32) * 1237;");
5646 Local<Value> obj =
5647 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5648 CHECK(!obj->IsInt32());
5649 CHECK(!obj->IsUint32());
5650 // Large negative number.
5651 CompileRun("var obj = -1234567890123;");
5652 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5653 CHECK(!obj->IsInt32());
5654 CHECK(!obj->IsUint32());
5655 // Small positive integer.
5656 CompileRun("var obj = 42;");
5657 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5658 CHECK(obj->IsInt32());
5659 CHECK(obj->IsUint32());
5660 // Negative integer.
5661 CompileRun("var obj = -37;");
5662 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5663 CHECK(obj->IsInt32());
5664 CHECK(!obj->IsUint32());
5665 // Positive non-int32 integer.
5666 CompileRun("var obj = 0x81234567;");
5667 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5668 CHECK(!obj->IsInt32());
5669 CHECK(obj->IsUint32());
5670 // Fraction.
5671 CompileRun("var obj = 42.3;");
5672 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5673 CHECK(!obj->IsInt32());
5674 CHECK(!obj->IsUint32());
5675 // Large negative fraction.
5676 CompileRun("var obj = -5726623061.75;");
5677 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5678 CHECK(!obj->IsInt32());
5679 CHECK(!obj->IsUint32());
5680 // Positive zero
5681 CompileRun("var obj = 0.0;");
5682 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5683 CHECK(obj->IsInt32());
5684 CHECK(obj->IsUint32());
5685 // Positive zero
5686 CompileRun("var obj = -0.0;");
5687 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5688 CHECK(!obj->IsInt32());
5689 CHECK(!obj->IsUint32());
5690 }
5691
5692
CheckUncle(v8::TryCatch * try_catch)5693 static void CheckUncle(v8::TryCatch* try_catch) {
5694 CHECK(try_catch->HasCaught());
5695 String::Utf8Value str_value(try_catch->Exception());
5696 CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5697 try_catch->Reset();
5698 }
5699
5700
THREADED_TEST(ConversionException)5701 THREADED_TEST(ConversionException) {
5702 LocalContext env;
5703 v8::Isolate* isolate = env->GetIsolate();
5704 v8::HandleScope scope(isolate);
5705 CompileRun(
5706 "function TestClass() { };"
5707 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5708 "var obj = new TestClass();");
5709 Local<Value> obj =
5710 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5711
5712 v8::TryCatch try_catch(isolate);
5713
5714 CHECK(obj->ToString(env.local()).IsEmpty());
5715 CheckUncle(&try_catch);
5716
5717 CHECK(obj->ToNumber(env.local()).IsEmpty());
5718 CheckUncle(&try_catch);
5719
5720 CHECK(obj->ToInteger(env.local()).IsEmpty());
5721 CheckUncle(&try_catch);
5722
5723 CHECK(obj->ToUint32(env.local()).IsEmpty());
5724 CheckUncle(&try_catch);
5725
5726 CHECK(obj->ToInt32(env.local()).IsEmpty());
5727 CheckUncle(&try_catch);
5728
5729 CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5730 CHECK(try_catch.HasCaught());
5731 try_catch.Reset();
5732
5733 CHECK(obj->Int32Value(env.local()).IsNothing());
5734 CheckUncle(&try_catch);
5735
5736 CHECK(obj->Uint32Value(env.local()).IsNothing());
5737 CheckUncle(&try_catch);
5738
5739 CHECK(obj->NumberValue(env.local()).IsNothing());
5740 CheckUncle(&try_catch);
5741
5742 CHECK(obj->IntegerValue(env.local()).IsNothing());
5743 CheckUncle(&try_catch);
5744 }
5745
5746
ThrowFromC(const v8::FunctionCallbackInfo<v8::Value> & args)5747 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5748 ApiTestFuzzer::Fuzz();
5749 args.GetIsolate()->ThrowException(v8_str("konto"));
5750 }
5751
5752
CCatcher(const v8::FunctionCallbackInfo<v8::Value> & args)5753 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5754 if (args.Length() < 1) {
5755 args.GetReturnValue().Set(false);
5756 return;
5757 }
5758 v8::HandleScope scope(args.GetIsolate());
5759 v8::TryCatch try_catch(args.GetIsolate());
5760 Local<Value> result =
5761 CompileRun(args[0]
5762 ->ToString(args.GetIsolate()->GetCurrentContext())
5763 .ToLocalChecked());
5764 CHECK(!try_catch.HasCaught() || result.IsEmpty());
5765 args.GetReturnValue().Set(try_catch.HasCaught());
5766 }
5767
5768
THREADED_TEST(APICatch)5769 THREADED_TEST(APICatch) {
5770 v8::Isolate* isolate = CcTest::isolate();
5771 v8::HandleScope scope(isolate);
5772 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5773 templ->Set(v8_str("ThrowFromC"),
5774 v8::FunctionTemplate::New(isolate, ThrowFromC));
5775 LocalContext context(0, templ);
5776 CompileRun(
5777 "var thrown = false;"
5778 "try {"
5779 " ThrowFromC();"
5780 "} catch (e) {"
5781 " thrown = true;"
5782 "}");
5783 Local<Value> thrown = context->Global()
5784 ->Get(context.local(), v8_str("thrown"))
5785 .ToLocalChecked();
5786 CHECK(thrown->BooleanValue(context.local()).FromJust());
5787 }
5788
5789
THREADED_TEST(APIThrowTryCatch)5790 THREADED_TEST(APIThrowTryCatch) {
5791 v8::Isolate* isolate = CcTest::isolate();
5792 v8::HandleScope scope(isolate);
5793 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5794 templ->Set(v8_str("ThrowFromC"),
5795 v8::FunctionTemplate::New(isolate, ThrowFromC));
5796 LocalContext context(0, templ);
5797 v8::TryCatch try_catch(isolate);
5798 CompileRun("ThrowFromC();");
5799 CHECK(try_catch.HasCaught());
5800 }
5801
5802
5803 // Test that a try-finally block doesn't shadow a try-catch block
5804 // when setting up an external handler.
5805 //
5806 // BUG(271): Some of the exception propagation does not work on the
5807 // ARM simulator because the simulator separates the C++ stack and the
5808 // JS stack. This test therefore fails on the simulator. The test is
5809 // not threaded to allow the threading tests to run on the simulator.
TEST(TryCatchInTryFinally)5810 TEST(TryCatchInTryFinally) {
5811 v8::Isolate* isolate = CcTest::isolate();
5812 v8::HandleScope scope(isolate);
5813 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5814 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5815 LocalContext context(0, templ);
5816 Local<Value> result = CompileRun(
5817 "try {"
5818 " try {"
5819 " CCatcher('throw 7;');"
5820 " } finally {"
5821 " }"
5822 "} catch (e) {"
5823 "}");
5824 CHECK(result->IsTrue());
5825 }
5826
5827
check_custom_error_tostring(v8::Local<v8::Message> message,v8::Local<v8::Value> data)5828 static void check_custom_error_tostring(v8::Local<v8::Message> message,
5829 v8::Local<v8::Value> data) {
5830 const char* uncaught_error = "Uncaught MyError toString";
5831 CHECK(message->Get()
5832 ->Equals(CcTest::isolate()->GetCurrentContext(),
5833 v8_str(uncaught_error))
5834 .FromJust());
5835 }
5836
5837
TEST(CustomErrorToString)5838 TEST(CustomErrorToString) {
5839 LocalContext context;
5840 v8::HandleScope scope(context->GetIsolate());
5841 context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5842 CompileRun(
5843 "function MyError(name, message) { "
5844 " this.name = name; "
5845 " this.message = message; "
5846 "} "
5847 "MyError.prototype = Object.create(Error.prototype); "
5848 "MyError.prototype.toString = function() { "
5849 " return 'MyError toString'; "
5850 "}; "
5851 "throw new MyError('my name', 'my message'); ");
5852 context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5853 }
5854
5855
check_custom_error_message(v8::Local<v8::Message> message,v8::Local<v8::Value> data)5856 static void check_custom_error_message(v8::Local<v8::Message> message,
5857 v8::Local<v8::Value> data) {
5858 const char* uncaught_error = "Uncaught MyError: my message";
5859 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5860 CHECK(message->Get()
5861 ->Equals(CcTest::isolate()->GetCurrentContext(),
5862 v8_str(uncaught_error))
5863 .FromJust());
5864 }
5865
5866
TEST(CustomErrorMessage)5867 TEST(CustomErrorMessage) {
5868 LocalContext context;
5869 v8::HandleScope scope(context->GetIsolate());
5870 context->GetIsolate()->AddMessageListener(check_custom_error_message);
5871
5872 // Handlebars.
5873 CompileRun(
5874 "function MyError(msg) { "
5875 " this.name = 'MyError'; "
5876 " this.message = msg; "
5877 "} "
5878 "MyError.prototype = new Error(); "
5879 "throw new MyError('my message'); ");
5880
5881 // Closure.
5882 CompileRun(
5883 "function MyError(msg) { "
5884 " this.name = 'MyError'; "
5885 " this.message = msg; "
5886 "} "
5887 "inherits = function(childCtor, parentCtor) { "
5888 " function tempCtor() {}; "
5889 " tempCtor.prototype = parentCtor.prototype; "
5890 " childCtor.superClass_ = parentCtor.prototype; "
5891 " childCtor.prototype = new tempCtor(); "
5892 " childCtor.prototype.constructor = childCtor; "
5893 "}; "
5894 "inherits(MyError, Error); "
5895 "throw new MyError('my message'); ");
5896
5897 // Object.create.
5898 CompileRun(
5899 "function MyError(msg) { "
5900 " this.name = 'MyError'; "
5901 " this.message = msg; "
5902 "} "
5903 "MyError.prototype = Object.create(Error.prototype); "
5904 "throw new MyError('my message'); ");
5905
5906 context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5907 }
5908
5909
check_custom_rethrowing_message(v8::Local<v8::Message> message,v8::Local<v8::Value> data)5910 static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5911 v8::Local<v8::Value> data) {
5912 const char* uncaught_error = "Uncaught exception";
5913 CHECK(message->Get()
5914 ->Equals(CcTest::isolate()->GetCurrentContext(),
5915 v8_str(uncaught_error))
5916 .FromJust());
5917 }
5918
5919
TEST(CustomErrorRethrowsOnToString)5920 TEST(CustomErrorRethrowsOnToString) {
5921 LocalContext context;
5922 v8::HandleScope scope(context->GetIsolate());
5923 context->GetIsolate()->AddMessageListener(check_custom_rethrowing_message);
5924
5925 CompileRun(
5926 "var e = { toString: function() { throw e; } };"
5927 "try { throw e; } finally {}");
5928
5929 context->GetIsolate()->RemoveMessageListeners(
5930 check_custom_rethrowing_message);
5931 }
5932
5933
receive_message(v8::Local<v8::Message> message,v8::Local<v8::Value> data)5934 static void receive_message(v8::Local<v8::Message> message,
5935 v8::Local<v8::Value> data) {
5936 message->Get();
5937 message_received = true;
5938 }
5939
5940
TEST(APIThrowMessage)5941 TEST(APIThrowMessage) {
5942 message_received = false;
5943 v8::Isolate* isolate = CcTest::isolate();
5944 v8::HandleScope scope(isolate);
5945 isolate->AddMessageListener(receive_message);
5946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5947 templ->Set(v8_str("ThrowFromC"),
5948 v8::FunctionTemplate::New(isolate, ThrowFromC));
5949 LocalContext context(0, templ);
5950 CompileRun("ThrowFromC();");
5951 CHECK(message_received);
5952 isolate->RemoveMessageListeners(receive_message);
5953 }
5954
5955
TEST(APIThrowMessageAndVerboseTryCatch)5956 TEST(APIThrowMessageAndVerboseTryCatch) {
5957 message_received = false;
5958 v8::Isolate* isolate = CcTest::isolate();
5959 v8::HandleScope scope(isolate);
5960 isolate->AddMessageListener(receive_message);
5961 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5962 templ->Set(v8_str("ThrowFromC"),
5963 v8::FunctionTemplate::New(isolate, ThrowFromC));
5964 LocalContext context(0, templ);
5965 v8::TryCatch try_catch(isolate);
5966 try_catch.SetVerbose(true);
5967 Local<Value> result = CompileRun("ThrowFromC();");
5968 CHECK(try_catch.HasCaught());
5969 CHECK(result.IsEmpty());
5970 CHECK(message_received);
5971 isolate->RemoveMessageListeners(receive_message);
5972 }
5973
5974
TEST(APIStackOverflowAndVerboseTryCatch)5975 TEST(APIStackOverflowAndVerboseTryCatch) {
5976 message_received = false;
5977 LocalContext context;
5978 v8::HandleScope scope(context->GetIsolate());
5979 context->GetIsolate()->AddMessageListener(receive_message);
5980 v8::TryCatch try_catch(context->GetIsolate());
5981 try_catch.SetVerbose(true);
5982 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5983 CHECK(try_catch.HasCaught());
5984 CHECK(result.IsEmpty());
5985 CHECK(message_received);
5986 context->GetIsolate()->RemoveMessageListeners(receive_message);
5987 }
5988
5989
THREADED_TEST(ExternalScriptException)5990 THREADED_TEST(ExternalScriptException) {
5991 v8::Isolate* isolate = CcTest::isolate();
5992 v8::HandleScope scope(isolate);
5993 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5994 templ->Set(v8_str("ThrowFromC"),
5995 v8::FunctionTemplate::New(isolate, ThrowFromC));
5996 LocalContext context(0, templ);
5997
5998 v8::TryCatch try_catch(isolate);
5999 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
6000 CHECK(result.IsEmpty());
6001 CHECK(try_catch.HasCaught());
6002 String::Utf8Value exception_value(try_catch.Exception());
6003 CHECK_EQ(0, strcmp("konto", *exception_value));
6004 }
6005
6006
CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value> & args)6007 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
6008 ApiTestFuzzer::Fuzz();
6009 CHECK_EQ(4, args.Length());
6010 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6011 int count = args[0]->Int32Value(context).FromJust();
6012 int cInterval = args[2]->Int32Value(context).FromJust();
6013 if (count == 0) {
6014 args.GetIsolate()->ThrowException(v8_str("FromC"));
6015 return;
6016 } else {
6017 Local<v8::Object> global = context->Global();
6018 Local<Value> fun =
6019 global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
6020 v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
6021 if (count % cInterval == 0) {
6022 v8::TryCatch try_catch(args.GetIsolate());
6023 Local<Value> result = fun.As<Function>()
6024 ->Call(context, global, 4, argv)
6025 .FromMaybe(Local<Value>());
6026 int expected = args[3]->Int32Value(context).FromJust();
6027 if (try_catch.HasCaught()) {
6028 CHECK_EQ(expected, count);
6029 CHECK(result.IsEmpty());
6030 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
6031 } else {
6032 CHECK_NE(expected, count);
6033 }
6034 args.GetReturnValue().Set(result);
6035 return;
6036 } else {
6037 args.GetReturnValue().Set(fun.As<Function>()
6038 ->Call(context, global, 4, argv)
6039 .FromMaybe(v8::Local<v8::Value>()));
6040 return;
6041 }
6042 }
6043 }
6044
6045
JSCheck(const v8::FunctionCallbackInfo<v8::Value> & args)6046 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
6047 ApiTestFuzzer::Fuzz();
6048 CHECK_EQ(3, args.Length());
6049 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6050 bool equality = args[0]->BooleanValue(context).FromJust();
6051 int count = args[1]->Int32Value(context).FromJust();
6052 int expected = args[2]->Int32Value(context).FromJust();
6053 if (equality) {
6054 CHECK_EQ(count, expected);
6055 } else {
6056 CHECK_NE(count, expected);
6057 }
6058 }
6059
6060
THREADED_TEST(EvalInTryFinally)6061 THREADED_TEST(EvalInTryFinally) {
6062 LocalContext context;
6063 v8::HandleScope scope(context->GetIsolate());
6064 v8::TryCatch try_catch(context->GetIsolate());
6065 CompileRun(
6066 "(function() {"
6067 " try {"
6068 " eval('asldkf (*&^&*^');"
6069 " } finally {"
6070 " return;"
6071 " }"
6072 "})()");
6073 CHECK(!try_catch.HasCaught());
6074 }
6075
6076
6077 // This test works by making a stack of alternating JavaScript and C
6078 // activations. These activations set up exception handlers with regular
6079 // intervals, one interval for C activations and another for JavaScript
6080 // activations. When enough activations have been created an exception is
6081 // thrown and we check that the right activation catches the exception and that
6082 // no other activations do. The right activation is always the topmost one with
6083 // a handler, regardless of whether it is in JavaScript or C.
6084 //
6085 // The notation used to describe a test case looks like this:
6086 //
6087 // *JS[4] *C[3] @JS[2] C[1] JS[0]
6088 //
6089 // Each entry is an activation, either JS or C. The index is the count at that
6090 // level. Stars identify activations with exception handlers, the @ identifies
6091 // the exception handler that should catch the exception.
6092 //
6093 // BUG(271): Some of the exception propagation does not work on the
6094 // ARM simulator because the simulator separates the C++ stack and the
6095 // JS stack. This test therefore fails on the simulator. The test is
6096 // not threaded to allow the threading tests to run on the simulator.
TEST(ExceptionOrder)6097 TEST(ExceptionOrder) {
6098 v8::Isolate* isolate = CcTest::isolate();
6099 v8::HandleScope scope(isolate);
6100 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6101 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
6102 templ->Set(v8_str("CThrowCountDown"),
6103 v8::FunctionTemplate::New(isolate, CThrowCountDown));
6104 LocalContext context(0, templ);
6105 CompileRun(
6106 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
6107 " if (count == 0) throw 'FromJS';"
6108 " if (count % jsInterval == 0) {"
6109 " try {"
6110 " var value = CThrowCountDown(count - 1,"
6111 " jsInterval,"
6112 " cInterval,"
6113 " expected);"
6114 " check(false, count, expected);"
6115 " return value;"
6116 " } catch (e) {"
6117 " check(true, count, expected);"
6118 " }"
6119 " } else {"
6120 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
6121 " }"
6122 "}");
6123 Local<Function> fun = Local<Function>::Cast(
6124 context->Global()
6125 ->Get(context.local(), v8_str("JSThrowCountDown"))
6126 .ToLocalChecked());
6127
6128 const int argc = 4;
6129 // count jsInterval cInterval expected
6130
6131 // *JS[4] *C[3] @JS[2] C[1] JS[0]
6132 v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6133 fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6134
6135 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6136 v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6137 fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6138
6139 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6140 v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6141 fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6142
6143 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6144 v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6145 fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6146
6147 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6148 v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6149 fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6150
6151 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6152 v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6153 fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6154 }
6155
6156
ThrowValue(const v8::FunctionCallbackInfo<v8::Value> & args)6157 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6158 ApiTestFuzzer::Fuzz();
6159 CHECK_EQ(1, args.Length());
6160 args.GetIsolate()->ThrowException(args[0]);
6161 }
6162
6163
THREADED_TEST(ThrowValues)6164 THREADED_TEST(ThrowValues) {
6165 v8::Isolate* isolate = CcTest::isolate();
6166 v8::HandleScope scope(isolate);
6167 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6168 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6169 LocalContext context(0, templ);
6170 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6171 CompileRun("function Run(obj) {"
6172 " try {"
6173 " Throw(obj);"
6174 " } catch (e) {"
6175 " return e;"
6176 " }"
6177 " return 'no exception';"
6178 "}"
6179 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6180 CHECK_EQ(5u, result->Length());
6181 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6182 .ToLocalChecked()
6183 ->IsString());
6184 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6185 .ToLocalChecked()
6186 ->IsNumber());
6187 CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6188 .ToLocalChecked()
6189 ->Int32Value(context.local())
6190 .FromJust());
6191 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6192 .ToLocalChecked()
6193 ->IsNumber());
6194 CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6195 .ToLocalChecked()
6196 ->Int32Value(context.local())
6197 .FromJust());
6198 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6199 .ToLocalChecked()
6200 ->IsNull());
6201 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6202 .ToLocalChecked()
6203 ->IsUndefined());
6204 }
6205
6206
THREADED_TEST(CatchZero)6207 THREADED_TEST(CatchZero) {
6208 LocalContext context;
6209 v8::HandleScope scope(context->GetIsolate());
6210 v8::TryCatch try_catch(context->GetIsolate());
6211 CHECK(!try_catch.HasCaught());
6212 CompileRun("throw 10");
6213 CHECK(try_catch.HasCaught());
6214 CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6215 try_catch.Reset();
6216 CHECK(!try_catch.HasCaught());
6217 CompileRun("throw 0");
6218 CHECK(try_catch.HasCaught());
6219 CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6220 }
6221
6222
THREADED_TEST(CatchExceptionFromWith)6223 THREADED_TEST(CatchExceptionFromWith) {
6224 LocalContext context;
6225 v8::HandleScope scope(context->GetIsolate());
6226 v8::TryCatch try_catch(context->GetIsolate());
6227 CHECK(!try_catch.HasCaught());
6228 CompileRun("var o = {}; with (o) { throw 42; }");
6229 CHECK(try_catch.HasCaught());
6230 }
6231
6232
THREADED_TEST(TryCatchAndFinallyHidingException)6233 THREADED_TEST(TryCatchAndFinallyHidingException) {
6234 LocalContext context;
6235 v8::HandleScope scope(context->GetIsolate());
6236 v8::TryCatch try_catch(context->GetIsolate());
6237 CHECK(!try_catch.HasCaught());
6238 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6239 CompileRun("f({toString: function() { throw 42; }});");
6240 CHECK(!try_catch.HasCaught());
6241 }
6242
6243
WithTryCatch(const v8::FunctionCallbackInfo<v8::Value> & args)6244 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6245 v8::TryCatch try_catch(args.GetIsolate());
6246 }
6247
6248
THREADED_TEST(TryCatchAndFinally)6249 THREADED_TEST(TryCatchAndFinally) {
6250 LocalContext context;
6251 v8::Isolate* isolate = context->GetIsolate();
6252 v8::HandleScope scope(isolate);
6253 CHECK(context->Global()
6254 ->Set(context.local(), v8_str("native_with_try_catch"),
6255 v8::FunctionTemplate::New(isolate, WithTryCatch)
6256 ->GetFunction(context.local())
6257 .ToLocalChecked())
6258 .FromJust());
6259 v8::TryCatch try_catch(isolate);
6260 CHECK(!try_catch.HasCaught());
6261 CompileRun(
6262 "try {\n"
6263 " throw new Error('a');\n"
6264 "} finally {\n"
6265 " native_with_try_catch();\n"
6266 "}\n");
6267 CHECK(try_catch.HasCaught());
6268 }
6269
6270
TryCatchNested1Helper(int depth)6271 static void TryCatchNested1Helper(int depth) {
6272 if (depth > 0) {
6273 v8::TryCatch try_catch(CcTest::isolate());
6274 try_catch.SetVerbose(true);
6275 TryCatchNested1Helper(depth - 1);
6276 CHECK(try_catch.HasCaught());
6277 try_catch.ReThrow();
6278 } else {
6279 CcTest::isolate()->ThrowException(v8_str("E1"));
6280 }
6281 }
6282
6283
TryCatchNested2Helper(int depth)6284 static void TryCatchNested2Helper(int depth) {
6285 if (depth > 0) {
6286 v8::TryCatch try_catch(CcTest::isolate());
6287 try_catch.SetVerbose(true);
6288 TryCatchNested2Helper(depth - 1);
6289 CHECK(try_catch.HasCaught());
6290 try_catch.ReThrow();
6291 } else {
6292 CompileRun("throw 'E2';");
6293 }
6294 }
6295
6296
TEST(TryCatchNested)6297 TEST(TryCatchNested) {
6298 v8::V8::Initialize();
6299 LocalContext context;
6300 v8::HandleScope scope(context->GetIsolate());
6301
6302 {
6303 // Test nested try-catch with a native throw in the end.
6304 v8::TryCatch try_catch(context->GetIsolate());
6305 TryCatchNested1Helper(5);
6306 CHECK(try_catch.HasCaught());
6307 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
6308 }
6309
6310 {
6311 // Test nested try-catch with a JavaScript throw in the end.
6312 v8::TryCatch try_catch(context->GetIsolate());
6313 TryCatchNested2Helper(5);
6314 CHECK(try_catch.HasCaught());
6315 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
6316 }
6317 }
6318
6319
TryCatchMixedNestingCheck(v8::TryCatch * try_catch)6320 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6321 CHECK(try_catch->HasCaught());
6322 Local<Message> message = try_catch->Message();
6323 Local<Value> resource = message->GetScriptOrigin().ResourceName();
6324 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
6325 CHECK_EQ(0,
6326 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
6327 CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6328 .FromJust());
6329 CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6330 .FromJust());
6331 }
6332
6333
TryCatchMixedNestingHelper(const v8::FunctionCallbackInfo<v8::Value> & args)6334 void TryCatchMixedNestingHelper(
6335 const v8::FunctionCallbackInfo<v8::Value>& args) {
6336 ApiTestFuzzer::Fuzz();
6337 v8::TryCatch try_catch(args.GetIsolate());
6338 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6339 CHECK(try_catch.HasCaught());
6340 TryCatchMixedNestingCheck(&try_catch);
6341 try_catch.ReThrow();
6342 }
6343
6344
6345 // This test ensures that an outer TryCatch in the following situation:
6346 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6347 // does not clobber the Message object generated for the inner TryCatch.
6348 // This exercises the ability of TryCatch.ReThrow() to restore the
6349 // inner pending Message before throwing the exception again.
TEST(TryCatchMixedNesting)6350 TEST(TryCatchMixedNesting) {
6351 v8::Isolate* isolate = CcTest::isolate();
6352 v8::HandleScope scope(isolate);
6353 v8::V8::Initialize();
6354 v8::TryCatch try_catch(isolate);
6355 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6356 templ->Set(v8_str("TryCatchMixedNestingHelper"),
6357 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6358 LocalContext context(0, templ);
6359 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6360 TryCatchMixedNestingCheck(&try_catch);
6361 }
6362
6363
TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value> & args)6364 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6365 ApiTestFuzzer::Fuzz();
6366 v8::TryCatch try_catch(args.GetIsolate());
6367 args.GetIsolate()->ThrowException(v8_str("boom"));
6368 CHECK(try_catch.HasCaught());
6369 }
6370
6371
TEST(TryCatchNative)6372 TEST(TryCatchNative) {
6373 v8::Isolate* isolate = CcTest::isolate();
6374 v8::HandleScope scope(isolate);
6375 v8::V8::Initialize();
6376 v8::TryCatch try_catch(isolate);
6377 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6378 templ->Set(v8_str("TryCatchNativeHelper"),
6379 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6380 LocalContext context(0, templ);
6381 CompileRun("TryCatchNativeHelper();");
6382 CHECK(!try_catch.HasCaught());
6383 }
6384
6385
TryCatchNativeResetHelper(const v8::FunctionCallbackInfo<v8::Value> & args)6386 void TryCatchNativeResetHelper(
6387 const v8::FunctionCallbackInfo<v8::Value>& args) {
6388 ApiTestFuzzer::Fuzz();
6389 v8::TryCatch try_catch(args.GetIsolate());
6390 args.GetIsolate()->ThrowException(v8_str("boom"));
6391 CHECK(try_catch.HasCaught());
6392 try_catch.Reset();
6393 CHECK(!try_catch.HasCaught());
6394 }
6395
6396
TEST(TryCatchNativeReset)6397 TEST(TryCatchNativeReset) {
6398 v8::Isolate* isolate = CcTest::isolate();
6399 v8::HandleScope scope(isolate);
6400 v8::V8::Initialize();
6401 v8::TryCatch try_catch(isolate);
6402 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6403 templ->Set(v8_str("TryCatchNativeResetHelper"),
6404 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6405 LocalContext context(0, templ);
6406 CompileRun("TryCatchNativeResetHelper();");
6407 CHECK(!try_catch.HasCaught());
6408 }
6409
6410
THREADED_TEST(Equality)6411 THREADED_TEST(Equality) {
6412 LocalContext context;
6413 v8::Isolate* isolate = context->GetIsolate();
6414 v8::HandleScope scope(context->GetIsolate());
6415 // Check that equality works at all before relying on CHECK_EQ
6416 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6417 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6418
6419 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6420 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6421 CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6422 CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6423 CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6424
6425 // Assume String is not internalized.
6426 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6427 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6428 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6429 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6430 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6431 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6432 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6433 CHECK(!not_a_number->StrictEquals(not_a_number));
6434 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6435 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6436
6437 v8::Local<v8::Object> obj = v8::Object::New(isolate);
6438 v8::Persistent<v8::Object> alias(isolate, obj);
6439 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6440 alias.Reset();
6441
6442 CHECK(v8_str("a")->SameValue(v8_str("a")));
6443 CHECK(!v8_str("a")->SameValue(v8_str("b")));
6444 CHECK(!v8_str("5")->SameValue(v8_num(5)));
6445 CHECK(v8_num(1)->SameValue(v8_num(1)));
6446 CHECK(!v8_num(1)->SameValue(v8_num(2)));
6447 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6448 CHECK(not_a_number->SameValue(not_a_number));
6449 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6450 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6451 }
6452
THREADED_TEST(TypeOf)6453 THREADED_TEST(TypeOf) {
6454 LocalContext context;
6455 v8::Isolate* isolate = context->GetIsolate();
6456 v8::HandleScope scope(context->GetIsolate());
6457
6458 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6459 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6460
6461 CHECK(v8::Undefined(isolate)
6462 ->TypeOf(isolate)
6463 ->Equals(context.local(), v8_str("undefined"))
6464 .FromJust());
6465 CHECK(v8::Null(isolate)
6466 ->TypeOf(isolate)
6467 ->Equals(context.local(), v8_str("object"))
6468 .FromJust());
6469 CHECK(v8_str("str")
6470 ->TypeOf(isolate)
6471 ->Equals(context.local(), v8_str("string"))
6472 .FromJust());
6473 CHECK(v8_num(0.0)
6474 ->TypeOf(isolate)
6475 ->Equals(context.local(), v8_str("number"))
6476 .FromJust());
6477 CHECK(v8_num(1)
6478 ->TypeOf(isolate)
6479 ->Equals(context.local(), v8_str("number"))
6480 .FromJust());
6481 CHECK(v8::Object::New(isolate)
6482 ->TypeOf(isolate)
6483 ->Equals(context.local(), v8_str("object"))
6484 .FromJust());
6485 CHECK(v8::Boolean::New(isolate, true)
6486 ->TypeOf(isolate)
6487 ->Equals(context.local(), v8_str("boolean"))
6488 .FromJust());
6489 CHECK(fun->TypeOf(isolate)
6490 ->Equals(context.local(), v8_str("function"))
6491 .FromJust());
6492 }
6493
THREADED_TEST(MultiRun)6494 THREADED_TEST(MultiRun) {
6495 LocalContext context;
6496 v8::HandleScope scope(context->GetIsolate());
6497 Local<Script> script = v8_compile("x");
6498 for (int i = 0; i < 10; i++) {
6499 script->Run(context.local()).IsEmpty();
6500 }
6501 }
6502
6503
GetXValue(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)6504 static void GetXValue(Local<Name> name,
6505 const v8::PropertyCallbackInfo<v8::Value>& info) {
6506 ApiTestFuzzer::Fuzz();
6507 CHECK(info.Data()
6508 ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6509 .FromJust());
6510 CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6511 .FromJust());
6512 info.GetReturnValue().Set(name);
6513 }
6514
6515
THREADED_TEST(SimplePropertyRead)6516 THREADED_TEST(SimplePropertyRead) {
6517 LocalContext context;
6518 v8::Isolate* isolate = context->GetIsolate();
6519 v8::HandleScope scope(isolate);
6520 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6521 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6522 CHECK(context->Global()
6523 ->Set(context.local(), v8_str("obj"),
6524 templ->NewInstance(context.local()).ToLocalChecked())
6525 .FromJust());
6526 Local<Script> script = v8_compile("obj.x");
6527 for (int i = 0; i < 10; i++) {
6528 Local<Value> result = script->Run(context.local()).ToLocalChecked();
6529 CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6530 }
6531 }
6532
6533
THREADED_TEST(DefinePropertyOnAPIAccessor)6534 THREADED_TEST(DefinePropertyOnAPIAccessor) {
6535 LocalContext context;
6536 v8::Isolate* isolate = context->GetIsolate();
6537 v8::HandleScope scope(isolate);
6538 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6539 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6540 CHECK(context->Global()
6541 ->Set(context.local(), v8_str("obj"),
6542 templ->NewInstance(context.local()).ToLocalChecked())
6543 .FromJust());
6544
6545 // Uses getOwnPropertyDescriptor to check the configurable status
6546 Local<Script> script_desc = v8_compile(
6547 "var prop = Object.getOwnPropertyDescriptor( "
6548 "obj, 'x');"
6549 "prop.configurable;");
6550 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6551 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true);
6552
6553 // Redefine get - but still configurable
6554 Local<Script> script_define = v8_compile(
6555 "var desc = { get: function(){return 42; },"
6556 " configurable: true };"
6557 "Object.defineProperty(obj, 'x', desc);"
6558 "obj.x");
6559 result = script_define->Run(context.local()).ToLocalChecked();
6560 CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6561
6562 // Check that the accessor is still configurable
6563 result = script_desc->Run(context.local()).ToLocalChecked();
6564 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true);
6565
6566 // Redefine to a non-configurable
6567 script_define = v8_compile(
6568 "var desc = { get: function(){return 43; },"
6569 " configurable: false };"
6570 "Object.defineProperty(obj, 'x', desc);"
6571 "obj.x");
6572 result = script_define->Run(context.local()).ToLocalChecked();
6573 CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6574 result = script_desc->Run(context.local()).ToLocalChecked();
6575 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false);
6576
6577 // Make sure that it is not possible to redefine again
6578 v8::TryCatch try_catch(isolate);
6579 CHECK(script_define->Run(context.local()).IsEmpty());
6580 CHECK(try_catch.HasCaught());
6581 String::Utf8Value exception_value(try_catch.Exception());
6582 CHECK_EQ(0,
6583 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6584 }
6585
6586
THREADED_TEST(DefinePropertyOnDefineGetterSetter)6587 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6588 v8::Isolate* isolate = CcTest::isolate();
6589 v8::HandleScope scope(isolate);
6590 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6591 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6592 LocalContext context;
6593 CHECK(context->Global()
6594 ->Set(context.local(), v8_str("obj"),
6595 templ->NewInstance(context.local()).ToLocalChecked())
6596 .FromJust());
6597
6598 Local<Script> script_desc = v8_compile(
6599 "var prop ="
6600 "Object.getOwnPropertyDescriptor( "
6601 "obj, 'x');"
6602 "prop.configurable;");
6603 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6604 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true);
6605
6606 Local<Script> script_define = v8_compile(
6607 "var desc = {get: function(){return 42; },"
6608 " configurable: true };"
6609 "Object.defineProperty(obj, 'x', desc);"
6610 "obj.x");
6611 result = script_define->Run(context.local()).ToLocalChecked();
6612 CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6613
6614 result = script_desc->Run(context.local()).ToLocalChecked();
6615 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), true);
6616
6617 script_define = v8_compile(
6618 "var desc = {get: function(){return 43; },"
6619 " configurable: false };"
6620 "Object.defineProperty(obj, 'x', desc);"
6621 "obj.x");
6622 result = script_define->Run(context.local()).ToLocalChecked();
6623 CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6624
6625 result = script_desc->Run(context.local()).ToLocalChecked();
6626 CHECK_EQ(result->BooleanValue(context.local()).FromJust(), false);
6627
6628 v8::TryCatch try_catch(isolate);
6629 CHECK(script_define->Run(context.local()).IsEmpty());
6630 CHECK(try_catch.HasCaught());
6631 String::Utf8Value exception_value(try_catch.Exception());
6632 CHECK_EQ(0,
6633 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6634 }
6635
6636
GetGlobalProperty(LocalContext * context,char const * name)6637 static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6638 char const* name) {
6639 return v8::Local<v8::Object>::Cast(
6640 (*context)
6641 ->Global()
6642 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6643 .ToLocalChecked());
6644 }
6645
6646
THREADED_TEST(DefineAPIAccessorOnObject)6647 THREADED_TEST(DefineAPIAccessorOnObject) {
6648 v8::Isolate* isolate = CcTest::isolate();
6649 v8::HandleScope scope(isolate);
6650 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6651 LocalContext context;
6652
6653 CHECK(context->Global()
6654 ->Set(context.local(), v8_str("obj1"),
6655 templ->NewInstance(context.local()).ToLocalChecked())
6656 .FromJust());
6657 CompileRun("var obj2 = {};");
6658
6659 CHECK(CompileRun("obj1.x")->IsUndefined());
6660 CHECK(CompileRun("obj2.x")->IsUndefined());
6661
6662 CHECK(GetGlobalProperty(&context, "obj1")
6663 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6664 v8_str("donut"))
6665 .FromJust());
6666
6667 ExpectString("obj1.x", "x");
6668 CHECK(CompileRun("obj2.x")->IsUndefined());
6669
6670 CHECK(GetGlobalProperty(&context, "obj2")
6671 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6672 v8_str("donut"))
6673 .FromJust());
6674
6675 ExpectString("obj1.x", "x");
6676 ExpectString("obj2.x", "x");
6677
6678 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6679 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6680
6681 CompileRun(
6682 "Object.defineProperty(obj1, 'x',"
6683 "{ get: function() { return 'y'; }, configurable: true })");
6684
6685 ExpectString("obj1.x", "y");
6686 ExpectString("obj2.x", "x");
6687
6688 CompileRun(
6689 "Object.defineProperty(obj2, 'x',"
6690 "{ get: function() { return 'y'; }, configurable: true })");
6691
6692 ExpectString("obj1.x", "y");
6693 ExpectString("obj2.x", "y");
6694
6695 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6696 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6697
6698 CHECK(GetGlobalProperty(&context, "obj1")
6699 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6700 v8_str("donut"))
6701 .FromJust());
6702 CHECK(GetGlobalProperty(&context, "obj2")
6703 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6704 v8_str("donut"))
6705 .FromJust());
6706
6707 ExpectString("obj1.x", "x");
6708 ExpectString("obj2.x", "x");
6709
6710 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6711 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6712
6713 // Define getters/setters, but now make them not configurable.
6714 CompileRun(
6715 "Object.defineProperty(obj1, 'x',"
6716 "{ get: function() { return 'z'; }, configurable: false })");
6717 CompileRun(
6718 "Object.defineProperty(obj2, 'x',"
6719 "{ get: function() { return 'z'; }, configurable: false })");
6720 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6721 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6722
6723 ExpectString("obj1.x", "z");
6724 ExpectString("obj2.x", "z");
6725
6726 CHECK(GetGlobalProperty(&context, "obj1")
6727 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6728 v8_str("donut"))
6729 .IsNothing());
6730 CHECK(GetGlobalProperty(&context, "obj2")
6731 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6732 v8_str("donut"))
6733 .IsNothing());
6734
6735 ExpectString("obj1.x", "z");
6736 ExpectString("obj2.x", "z");
6737 }
6738
6739
THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden)6740 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6741 v8::Isolate* isolate = CcTest::isolate();
6742 v8::HandleScope scope(isolate);
6743 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6744 LocalContext context;
6745
6746 CHECK(context->Global()
6747 ->Set(context.local(), v8_str("obj1"),
6748 templ->NewInstance(context.local()).ToLocalChecked())
6749 .FromJust());
6750 CompileRun("var obj2 = {};");
6751
6752 CHECK(GetGlobalProperty(&context, "obj1")
6753 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6754 v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6755 .FromJust());
6756 CHECK(GetGlobalProperty(&context, "obj2")
6757 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6758 v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6759 .FromJust());
6760
6761 ExpectString("obj1.x", "x");
6762 ExpectString("obj2.x", "x");
6763
6764 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6765 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6766
6767 CHECK(GetGlobalProperty(&context, "obj1")
6768 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6769 v8_str("donut"))
6770 .IsNothing());
6771 CHECK(GetGlobalProperty(&context, "obj2")
6772 ->SetAccessor(context.local(), v8_str("x"), GetXValue, NULL,
6773 v8_str("donut"))
6774 .IsNothing());
6775
6776 {
6777 v8::TryCatch try_catch(isolate);
6778 CompileRun(
6779 "Object.defineProperty(obj1, 'x',"
6780 "{get: function() { return 'func'; }})");
6781 CHECK(try_catch.HasCaught());
6782 String::Utf8Value exception_value(try_catch.Exception());
6783 CHECK_EQ(
6784 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6785 }
6786 {
6787 v8::TryCatch try_catch(isolate);
6788 CompileRun(
6789 "Object.defineProperty(obj2, 'x',"
6790 "{get: function() { return 'func'; }})");
6791 CHECK(try_catch.HasCaught());
6792 String::Utf8Value exception_value(try_catch.Exception());
6793 CHECK_EQ(
6794 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6795 }
6796 }
6797
6798
Get239Value(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)6799 static void Get239Value(Local<Name> name,
6800 const v8::PropertyCallbackInfo<v8::Value>& info) {
6801 ApiTestFuzzer::Fuzz();
6802 CHECK(info.Data()
6803 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6804 .FromJust());
6805 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6806 .FromJust());
6807 info.GetReturnValue().Set(name);
6808 }
6809
6810
THREADED_TEST(ElementAPIAccessor)6811 THREADED_TEST(ElementAPIAccessor) {
6812 v8::Isolate* isolate = CcTest::isolate();
6813 v8::HandleScope scope(isolate);
6814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6815 LocalContext context;
6816
6817 CHECK(context->Global()
6818 ->Set(context.local(), v8_str("obj1"),
6819 templ->NewInstance(context.local()).ToLocalChecked())
6820 .FromJust());
6821 CompileRun("var obj2 = {};");
6822
6823 CHECK(GetGlobalProperty(&context, "obj1")
6824 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL,
6825 v8_str("donut"))
6826 .FromJust());
6827 CHECK(GetGlobalProperty(&context, "obj2")
6828 ->SetAccessor(context.local(), v8_str("239"), Get239Value, NULL,
6829 v8_str("donut"))
6830 .FromJust());
6831
6832 ExpectString("obj1[239]", "239");
6833 ExpectString("obj2[239]", "239");
6834 ExpectString("obj1['239']", "239");
6835 ExpectString("obj2['239']", "239");
6836 }
6837
6838
6839 v8::Persistent<Value> xValue;
6840
6841
SetXValue(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)6842 static void SetXValue(Local<Name> name, Local<Value> value,
6843 const v8::PropertyCallbackInfo<void>& info) {
6844 Local<Context> context = info.GetIsolate()->GetCurrentContext();
6845 CHECK(value->Equals(context, v8_num(4)).FromJust());
6846 CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6847 CHECK(name->Equals(context, v8_str("x")).FromJust());
6848 CHECK(xValue.IsEmpty());
6849 xValue.Reset(info.GetIsolate(), value);
6850 }
6851
6852
THREADED_TEST(SimplePropertyWrite)6853 THREADED_TEST(SimplePropertyWrite) {
6854 v8::Isolate* isolate = CcTest::isolate();
6855 v8::HandleScope scope(isolate);
6856 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6857 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6858 LocalContext context;
6859 CHECK(context->Global()
6860 ->Set(context.local(), v8_str("obj"),
6861 templ->NewInstance(context.local()).ToLocalChecked())
6862 .FromJust());
6863 Local<Script> script = v8_compile("obj.x = 4");
6864 for (int i = 0; i < 10; i++) {
6865 CHECK(xValue.IsEmpty());
6866 script->Run(context.local()).ToLocalChecked();
6867 CHECK(v8_num(4)
6868 ->Equals(context.local(),
6869 Local<Value>::New(CcTest::isolate(), xValue))
6870 .FromJust());
6871 xValue.Reset();
6872 }
6873 }
6874
6875
THREADED_TEST(SetterOnly)6876 THREADED_TEST(SetterOnly) {
6877 v8::Isolate* isolate = CcTest::isolate();
6878 v8::HandleScope scope(isolate);
6879 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6880 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6881 LocalContext context;
6882 CHECK(context->Global()
6883 ->Set(context.local(), v8_str("obj"),
6884 templ->NewInstance(context.local()).ToLocalChecked())
6885 .FromJust());
6886 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6887 for (int i = 0; i < 10; i++) {
6888 CHECK(xValue.IsEmpty());
6889 script->Run(context.local()).ToLocalChecked();
6890 CHECK(v8_num(4)
6891 ->Equals(context.local(),
6892 Local<Value>::New(CcTest::isolate(), xValue))
6893 .FromJust());
6894 xValue.Reset();
6895 }
6896 }
6897
6898
THREADED_TEST(NoAccessors)6899 THREADED_TEST(NoAccessors) {
6900 v8::Isolate* isolate = CcTest::isolate();
6901 v8::HandleScope scope(isolate);
6902 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6903 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
6904 NULL, v8_str("donut"));
6905 LocalContext context;
6906 CHECK(context->Global()
6907 ->Set(context.local(), v8_str("obj"),
6908 templ->NewInstance(context.local()).ToLocalChecked())
6909 .FromJust());
6910 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6911 for (int i = 0; i < 10; i++) {
6912 script->Run(context.local()).ToLocalChecked();
6913 }
6914 }
6915
6916
THREADED_TEST(MultiContexts)6917 THREADED_TEST(MultiContexts) {
6918 v8::Isolate* isolate = CcTest::isolate();
6919 v8::HandleScope scope(isolate);
6920 v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6921 templ->Set(v8_str("dummy"),
6922 v8::FunctionTemplate::New(isolate, DummyCallHandler));
6923
6924 Local<String> password = v8_str("Password");
6925
6926 // Create an environment
6927 LocalContext context0(0, templ);
6928 context0->SetSecurityToken(password);
6929 v8::Local<v8::Object> global0 = context0->Global();
6930 CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
6931 .FromJust());
6932 CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
6933 .ToLocalChecked()
6934 ->Int32Value(context0.local())
6935 .FromJust());
6936
6937 // Create an independent environment
6938 LocalContext context1(0, templ);
6939 context1->SetSecurityToken(password);
6940 v8::Local<v8::Object> global1 = context1->Global();
6941 CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
6942 .FromJust());
6943 CHECK(!global0->Equals(context1.local(), global1).FromJust());
6944 CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
6945 .ToLocalChecked()
6946 ->Int32Value(context0.local())
6947 .FromJust());
6948 CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
6949 .ToLocalChecked()
6950 ->Int32Value(context1.local())
6951 .FromJust());
6952
6953 // Now create a new context with the old global
6954 LocalContext context2(0, templ, global1);
6955 context2->SetSecurityToken(password);
6956 v8::Local<v8::Object> global2 = context2->Global();
6957 CHECK(global1->Equals(context2.local(), global2).FromJust());
6958 CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
6959 .ToLocalChecked()
6960 ->Int32Value(context1.local())
6961 .FromJust());
6962 CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
6963 .ToLocalChecked()
6964 ->Int32Value(context2.local())
6965 .FromJust());
6966 }
6967
6968
THREADED_TEST(FunctionPrototypeAcrossContexts)6969 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6970 // Make sure that functions created by cloning boilerplates cannot
6971 // communicate through their __proto__ field.
6972
6973 v8::HandleScope scope(CcTest::isolate());
6974
6975 LocalContext env0;
6976 v8::Local<v8::Object> global0 = env0->Global();
6977 v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
6978 .ToLocalChecked()
6979 .As<v8::Object>();
6980 v8::Local<v8::Object> tostring0 =
6981 object0->Get(env0.local(), v8_str("toString"))
6982 .ToLocalChecked()
6983 .As<v8::Object>();
6984 v8::Local<v8::Object> proto0 =
6985 tostring0->Get(env0.local(), v8_str("__proto__"))
6986 .ToLocalChecked()
6987 .As<v8::Object>();
6988 CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
6989
6990 LocalContext env1;
6991 v8::Local<v8::Object> global1 = env1->Global();
6992 v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
6993 .ToLocalChecked()
6994 .As<v8::Object>();
6995 v8::Local<v8::Object> tostring1 =
6996 object1->Get(env1.local(), v8_str("toString"))
6997 .ToLocalChecked()
6998 .As<v8::Object>();
6999 v8::Local<v8::Object> proto1 =
7000 tostring1->Get(env1.local(), v8_str("__proto__"))
7001 .ToLocalChecked()
7002 .As<v8::Object>();
7003 CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
7004 }
7005
7006
THREADED_TEST(Regress892105)7007 THREADED_TEST(Regress892105) {
7008 // Make sure that object and array literals created by cloning
7009 // boilerplates cannot communicate through their __proto__
7010 // field. This is rather difficult to check, but we try to add stuff
7011 // to Object.prototype and Array.prototype and create a new
7012 // environment. This should succeed.
7013
7014 v8::HandleScope scope(CcTest::isolate());
7015
7016 Local<String> source = v8_str(
7017 "Object.prototype.obj = 1234;"
7018 "Array.prototype.arr = 4567;"
7019 "8901");
7020
7021 LocalContext env0;
7022 Local<Script> script0 = v8_compile(source);
7023 CHECK_EQ(8901.0, script0->Run(env0.local())
7024 .ToLocalChecked()
7025 ->NumberValue(env0.local())
7026 .FromJust());
7027
7028 LocalContext env1;
7029 Local<Script> script1 = v8_compile(source);
7030 CHECK_EQ(8901.0, script1->Run(env1.local())
7031 .ToLocalChecked()
7032 ->NumberValue(env1.local())
7033 .FromJust());
7034 }
7035
7036
THREADED_TEST(UndetectableObject)7037 THREADED_TEST(UndetectableObject) {
7038 LocalContext env;
7039 v8::HandleScope scope(env->GetIsolate());
7040
7041 Local<v8::FunctionTemplate> desc =
7042 v8::FunctionTemplate::New(env->GetIsolate());
7043 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7044
7045 Local<v8::Object> obj = desc->GetFunction(env.local())
7046 .ToLocalChecked()
7047 ->NewInstance(env.local())
7048 .ToLocalChecked();
7049 CHECK(
7050 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7051
7052 ExpectString("undetectable.toString()", "[object Object]");
7053 ExpectString("typeof undetectable", "undefined");
7054 ExpectString("typeof(undetectable)", "undefined");
7055 ExpectBoolean("typeof undetectable == 'undefined'", true);
7056 ExpectBoolean("typeof undetectable == 'object'", false);
7057 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7058 ExpectBoolean("!undetectable", true);
7059
7060 ExpectObject("true&&undetectable", obj);
7061 ExpectBoolean("false&&undetectable", false);
7062 ExpectBoolean("true||undetectable", true);
7063 ExpectObject("false||undetectable", obj);
7064
7065 ExpectObject("undetectable&&true", obj);
7066 ExpectObject("undetectable&&false", obj);
7067 ExpectBoolean("undetectable||true", true);
7068 ExpectBoolean("undetectable||false", false);
7069
7070 ExpectBoolean("undetectable==null", true);
7071 ExpectBoolean("null==undetectable", true);
7072 ExpectBoolean("undetectable==undefined", true);
7073 ExpectBoolean("undefined==undetectable", true);
7074 ExpectBoolean("undetectable==undetectable", true);
7075
7076
7077 ExpectBoolean("undetectable===null", false);
7078 ExpectBoolean("null===undetectable", false);
7079 ExpectBoolean("undetectable===undefined", false);
7080 ExpectBoolean("undefined===undetectable", false);
7081 ExpectBoolean("undetectable===undetectable", true);
7082 }
7083
7084
THREADED_TEST(VoidLiteral)7085 THREADED_TEST(VoidLiteral) {
7086 LocalContext env;
7087 v8::Isolate* isolate = env->GetIsolate();
7088 v8::HandleScope scope(isolate);
7089
7090 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7091 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7092
7093 Local<v8::Object> obj = desc->GetFunction(env.local())
7094 .ToLocalChecked()
7095 ->NewInstance(env.local())
7096 .ToLocalChecked();
7097 CHECK(
7098 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7099
7100 ExpectBoolean("undefined == void 0", true);
7101 ExpectBoolean("undetectable == void 0", true);
7102 ExpectBoolean("null == void 0", true);
7103 ExpectBoolean("undefined === void 0", true);
7104 ExpectBoolean("undetectable === void 0", false);
7105 ExpectBoolean("null === void 0", false);
7106
7107 ExpectBoolean("void 0 == undefined", true);
7108 ExpectBoolean("void 0 == undetectable", true);
7109 ExpectBoolean("void 0 == null", true);
7110 ExpectBoolean("void 0 === undefined", true);
7111 ExpectBoolean("void 0 === undetectable", false);
7112 ExpectBoolean("void 0 === null", false);
7113
7114 ExpectString(
7115 "(function() {"
7116 " try {"
7117 " return x === void 0;"
7118 " } catch(e) {"
7119 " return e.toString();"
7120 " }"
7121 "})()",
7122 "ReferenceError: x is not defined");
7123 ExpectString(
7124 "(function() {"
7125 " try {"
7126 " return void 0 === x;"
7127 " } catch(e) {"
7128 " return e.toString();"
7129 " }"
7130 "})()",
7131 "ReferenceError: x is not defined");
7132 }
7133
7134
THREADED_TEST(ExtensibleOnUndetectable)7135 THREADED_TEST(ExtensibleOnUndetectable) {
7136 LocalContext env;
7137 v8::Isolate* isolate = env->GetIsolate();
7138 v8::HandleScope scope(isolate);
7139
7140 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7141 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7142
7143 Local<v8::Object> obj = desc->GetFunction(env.local())
7144 .ToLocalChecked()
7145 ->NewInstance(env.local())
7146 .ToLocalChecked();
7147 CHECK(
7148 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7149
7150 Local<String> source = v8_str(
7151 "undetectable.x = 42;"
7152 "undetectable.x");
7153
7154 Local<Script> script = v8_compile(source);
7155
7156 CHECK(v8::Integer::New(isolate, 42)
7157 ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7158 .FromJust());
7159
7160 ExpectBoolean("Object.isExtensible(undetectable)", true);
7161
7162 source = v8_str("Object.preventExtensions(undetectable);");
7163 script = v8_compile(source);
7164 script->Run(env.local()).ToLocalChecked();
7165 ExpectBoolean("Object.isExtensible(undetectable)", false);
7166
7167 source = v8_str("undetectable.y = 2000;");
7168 script = v8_compile(source);
7169 script->Run(env.local()).ToLocalChecked();
7170 ExpectBoolean("undetectable.y == undefined", true);
7171 }
7172
7173
7174 // The point of this test is type checking. We run it only so compilers
7175 // don't complain about an unused function.
TEST(PersistentHandles)7176 TEST(PersistentHandles) {
7177 LocalContext env;
7178 v8::Isolate* isolate = CcTest::isolate();
7179 v8::HandleScope scope(isolate);
7180 Local<String> str = v8_str("foo");
7181 v8::Persistent<String> p_str(isolate, str);
7182 p_str.Reset();
7183 Local<Script> scr = v8_compile("");
7184 v8::Persistent<Script> p_scr(isolate, scr);
7185 p_scr.Reset();
7186 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7187 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7188 p_templ.Reset();
7189 }
7190
7191
HandleLogDelegator(const v8::FunctionCallbackInfo<v8::Value> & args)7192 static void HandleLogDelegator(
7193 const v8::FunctionCallbackInfo<v8::Value>& args) {
7194 ApiTestFuzzer::Fuzz();
7195 }
7196
7197
THREADED_TEST(GlobalObjectTemplate)7198 THREADED_TEST(GlobalObjectTemplate) {
7199 v8::Isolate* isolate = CcTest::isolate();
7200 v8::HandleScope handle_scope(isolate);
7201 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7202 global_template->Set(v8_str("JSNI_Log"),
7203 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7204 v8::Local<Context> context = Context::New(isolate, 0, global_template);
7205 Context::Scope context_scope(context);
7206 CompileRun("JSNI_Log('LOG')");
7207 }
7208
7209
7210 static const char* kSimpleExtensionSource =
7211 "function Foo() {"
7212 " return 4;"
7213 "}";
7214
7215
TEST(SimpleExtensions)7216 TEST(SimpleExtensions) {
7217 v8::HandleScope handle_scope(CcTest::isolate());
7218 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7219 const char* extension_names[] = {"simpletest"};
7220 v8::ExtensionConfiguration extensions(1, extension_names);
7221 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7222 Context::Scope lock(context);
7223 v8::Local<Value> result = CompileRun("Foo()");
7224 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7225 .FromJust());
7226 }
7227
7228
7229 static const char* kStackTraceFromExtensionSource =
7230 "function foo() {"
7231 " throw new Error();"
7232 "}"
7233 "function bar() {"
7234 " foo();"
7235 "}";
7236
7237
TEST(StackTraceInExtension)7238 TEST(StackTraceInExtension) {
7239 v8::HandleScope handle_scope(CcTest::isolate());
7240 v8::RegisterExtension(
7241 new Extension("stacktracetest", kStackTraceFromExtensionSource));
7242 const char* extension_names[] = {"stacktracetest"};
7243 v8::ExtensionConfiguration extensions(1, extension_names);
7244 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7245 Context::Scope lock(context);
7246 CompileRun(
7247 "function user() { bar(); }"
7248 "var error;"
7249 "try{ user(); } catch (e) { error = e; }");
7250 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7251 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7252 CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7253 }
7254
7255
TEST(NullExtensions)7256 TEST(NullExtensions) {
7257 v8::HandleScope handle_scope(CcTest::isolate());
7258 v8::RegisterExtension(new Extension("nulltest", NULL));
7259 const char* extension_names[] = {"nulltest"};
7260 v8::ExtensionConfiguration extensions(1, extension_names);
7261 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7262 Context::Scope lock(context);
7263 v8::Local<Value> result = CompileRun("1+3");
7264 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7265 .FromJust());
7266 }
7267
7268
7269 static const char* kEmbeddedExtensionSource =
7270 "function Ret54321(){return 54321;}~~@@$"
7271 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7272 static const int kEmbeddedExtensionSourceValidLen = 34;
7273
7274
TEST(ExtensionMissingSourceLength)7275 TEST(ExtensionMissingSourceLength) {
7276 v8::HandleScope handle_scope(CcTest::isolate());
7277 v8::RegisterExtension(
7278 new Extension("srclentest_fail", kEmbeddedExtensionSource));
7279 const char* extension_names[] = {"srclentest_fail"};
7280 v8::ExtensionConfiguration extensions(1, extension_names);
7281 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7282 CHECK(0 == *context);
7283 }
7284
7285
TEST(ExtensionWithSourceLength)7286 TEST(ExtensionWithSourceLength) {
7287 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7288 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7289 v8::HandleScope handle_scope(CcTest::isolate());
7290 i::ScopedVector<char> extension_name(32);
7291 i::SNPrintF(extension_name, "ext #%d", source_len);
7292 v8::RegisterExtension(new Extension(
7293 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
7294 const char* extension_names[1] = {extension_name.start()};
7295 v8::ExtensionConfiguration extensions(1, extension_names);
7296 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7297 if (source_len == kEmbeddedExtensionSourceValidLen) {
7298 Context::Scope lock(context);
7299 v8::Local<Value> result = CompileRun("Ret54321()");
7300 CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7301 ->Equals(context, result)
7302 .FromJust());
7303 } else {
7304 // Anything but exactly the right length should fail to compile.
7305 CHECK(0 == *context);
7306 }
7307 }
7308 }
7309
7310
7311 static const char* kEvalExtensionSource1 =
7312 "function UseEval1() {"
7313 " var x = 42;"
7314 " return eval('x');"
7315 "}";
7316
7317
7318 static const char* kEvalExtensionSource2 =
7319 "(function() {"
7320 " var x = 42;"
7321 " function e() {"
7322 " return eval('x');"
7323 " }"
7324 " this.UseEval2 = e;"
7325 "})()";
7326
7327
TEST(UseEvalFromExtension)7328 TEST(UseEvalFromExtension) {
7329 v8::HandleScope handle_scope(CcTest::isolate());
7330 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7331 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7332 const char* extension_names[] = {"evaltest1", "evaltest2"};
7333 v8::ExtensionConfiguration extensions(2, extension_names);
7334 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7335 Context::Scope lock(context);
7336 v8::Local<Value> result = CompileRun("UseEval1()");
7337 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7338 .FromJust());
7339 result = CompileRun("UseEval2()");
7340 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7341 .FromJust());
7342 }
7343
7344
7345 static const char* kWithExtensionSource1 =
7346 "function UseWith1() {"
7347 " var x = 42;"
7348 " with({x:87}) { return x; }"
7349 "}";
7350
7351
7352 static const char* kWithExtensionSource2 =
7353 "(function() {"
7354 " var x = 42;"
7355 " function e() {"
7356 " with ({x:87}) { return x; }"
7357 " }"
7358 " this.UseWith2 = e;"
7359 "})()";
7360
7361
TEST(UseWithFromExtension)7362 TEST(UseWithFromExtension) {
7363 v8::HandleScope handle_scope(CcTest::isolate());
7364 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7365 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7366 const char* extension_names[] = {"withtest1", "withtest2"};
7367 v8::ExtensionConfiguration extensions(2, extension_names);
7368 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7369 Context::Scope lock(context);
7370 v8::Local<Value> result = CompileRun("UseWith1()");
7371 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7372 .FromJust());
7373 result = CompileRun("UseWith2()");
7374 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7375 .FromJust());
7376 }
7377
7378
TEST(AutoExtensions)7379 TEST(AutoExtensions) {
7380 v8::HandleScope handle_scope(CcTest::isolate());
7381 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7382 extension->set_auto_enable(true);
7383 v8::RegisterExtension(extension);
7384 v8::Local<Context> context = Context::New(CcTest::isolate());
7385 Context::Scope lock(context);
7386 v8::Local<Value> result = CompileRun("Foo()");
7387 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7388 .FromJust());
7389 }
7390
7391
7392 static const char* kSyntaxErrorInExtensionSource = "[";
7393
7394
7395 // Test that a syntax error in an extension does not cause a fatal
7396 // error but results in an empty context.
TEST(SyntaxErrorExtensions)7397 TEST(SyntaxErrorExtensions) {
7398 v8::HandleScope handle_scope(CcTest::isolate());
7399 v8::RegisterExtension(
7400 new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
7401 const char* extension_names[] = {"syntaxerror"};
7402 v8::ExtensionConfiguration extensions(1, extension_names);
7403 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7404 CHECK(context.IsEmpty());
7405 }
7406
7407
7408 static const char* kExceptionInExtensionSource = "throw 42";
7409
7410
7411 // Test that an exception when installing an extension does not cause
7412 // a fatal error but results in an empty context.
TEST(ExceptionExtensions)7413 TEST(ExceptionExtensions) {
7414 v8::HandleScope handle_scope(CcTest::isolate());
7415 v8::RegisterExtension(
7416 new Extension("exception", kExceptionInExtensionSource));
7417 const char* extension_names[] = {"exception"};
7418 v8::ExtensionConfiguration extensions(1, extension_names);
7419 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7420 CHECK(context.IsEmpty());
7421 }
7422
7423
7424 static const char* kNativeCallInExtensionSource =
7425 "function call_runtime_last_index_of(x) {"
7426 " return %StringLastIndexOf(x, 'bob', 10);"
7427 "}";
7428
7429
7430 static const char* kNativeCallTest =
7431 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7432
7433 // Test that a native runtime calls are supported in extensions.
TEST(NativeCallInExtensions)7434 TEST(NativeCallInExtensions) {
7435 v8::HandleScope handle_scope(CcTest::isolate());
7436 v8::RegisterExtension(
7437 new Extension("nativecall", kNativeCallInExtensionSource));
7438 const char* extension_names[] = {"nativecall"};
7439 v8::ExtensionConfiguration extensions(1, extension_names);
7440 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7441 Context::Scope lock(context);
7442 v8::Local<Value> result = CompileRun(kNativeCallTest);
7443 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 3))
7444 .FromJust());
7445 }
7446
7447
7448 class NativeFunctionExtension : public Extension {
7449 public:
NativeFunctionExtension(const char * name,const char * source,v8::FunctionCallback fun=& Echo)7450 NativeFunctionExtension(const char* name, const char* source,
7451 v8::FunctionCallback fun = &Echo)
7452 : Extension(name, source), function_(fun) {}
7453
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Local<v8::String> name)7454 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7455 v8::Isolate* isolate, v8::Local<v8::String> name) {
7456 return v8::FunctionTemplate::New(isolate, function_);
7457 }
7458
Echo(const v8::FunctionCallbackInfo<v8::Value> & args)7459 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7460 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7461 }
7462
7463 private:
7464 v8::FunctionCallback function_;
7465 };
7466
7467
TEST(NativeFunctionDeclaration)7468 TEST(NativeFunctionDeclaration) {
7469 v8::HandleScope handle_scope(CcTest::isolate());
7470 const char* name = "nativedecl";
7471 v8::RegisterExtension(
7472 new NativeFunctionExtension(name, "native function foo();"));
7473 const char* extension_names[] = {name};
7474 v8::ExtensionConfiguration extensions(1, extension_names);
7475 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7476 Context::Scope lock(context);
7477 v8::Local<Value> result = CompileRun("foo(42);");
7478 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7479 .FromJust());
7480 }
7481
7482
TEST(NativeFunctionDeclarationError)7483 TEST(NativeFunctionDeclarationError) {
7484 v8::HandleScope handle_scope(CcTest::isolate());
7485 const char* name = "nativedeclerr";
7486 // Syntax error in extension code.
7487 v8::RegisterExtension(
7488 new NativeFunctionExtension(name, "native\nfunction foo();"));
7489 const char* extension_names[] = {name};
7490 v8::ExtensionConfiguration extensions(1, extension_names);
7491 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7492 CHECK(context.IsEmpty());
7493 }
7494
7495
TEST(NativeFunctionDeclarationErrorEscape)7496 TEST(NativeFunctionDeclarationErrorEscape) {
7497 v8::HandleScope handle_scope(CcTest::isolate());
7498 const char* name = "nativedeclerresc";
7499 // Syntax error in extension code - escape code in "native" means that
7500 // it's not treated as a keyword.
7501 v8::RegisterExtension(
7502 new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
7503 const char* extension_names[] = {name};
7504 v8::ExtensionConfiguration extensions(1, extension_names);
7505 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7506 CHECK(context.IsEmpty());
7507 }
7508
7509
CheckDependencies(const char * name,const char * expected)7510 static void CheckDependencies(const char* name, const char* expected) {
7511 v8::HandleScope handle_scope(CcTest::isolate());
7512 v8::ExtensionConfiguration config(1, &name);
7513 LocalContext context(&config);
7514 CHECK(
7515 v8_str(expected)
7516 ->Equals(context.local(), context->Global()
7517 ->Get(context.local(), v8_str("loaded"))
7518 .ToLocalChecked())
7519 .FromJust());
7520 }
7521
7522
7523 /*
7524 * Configuration:
7525 *
7526 * /-- B <--\
7527 * A <- -- D <-- E
7528 * \-- C <--/
7529 */
THREADED_TEST(ExtensionDependency)7530 THREADED_TEST(ExtensionDependency) {
7531 static const char* kEDeps[] = {"D"};
7532 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7533 static const char* kDDeps[] = {"B", "C"};
7534 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7535 static const char* kBCDeps[] = {"A"};
7536 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7537 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7538 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7539 CheckDependencies("A", "undefinedA");
7540 CheckDependencies("B", "undefinedAB");
7541 CheckDependencies("C", "undefinedAC");
7542 CheckDependencies("D", "undefinedABCD");
7543 CheckDependencies("E", "undefinedABCDE");
7544 v8::HandleScope handle_scope(CcTest::isolate());
7545 static const char* exts[2] = {"C", "E"};
7546 v8::ExtensionConfiguration config(2, exts);
7547 LocalContext context(&config);
7548 CHECK(
7549 v8_str("undefinedACBDE")
7550 ->Equals(context.local(), context->Global()
7551 ->Get(context.local(), v8_str("loaded"))
7552 .ToLocalChecked())
7553 .FromJust());
7554 }
7555
7556
7557 static const char* kExtensionTestScript =
7558 "native function A();"
7559 "native function B();"
7560 "native function C();"
7561 "function Foo(i) {"
7562 " if (i == 0) return A();"
7563 " if (i == 1) return B();"
7564 " if (i == 2) return C();"
7565 "}";
7566
7567
CallFun(const v8::FunctionCallbackInfo<v8::Value> & args)7568 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7569 ApiTestFuzzer::Fuzz();
7570 if (args.IsConstructCall()) {
7571 CHECK(args.This()
7572 ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7573 args.Data())
7574 .FromJust());
7575 args.GetReturnValue().SetNull();
7576 return;
7577 }
7578 args.GetReturnValue().Set(args.Data());
7579 }
7580
7581
7582 class FunctionExtension : public Extension {
7583 public:
FunctionExtension()7584 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7585 virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7586 v8::Isolate* isolate, v8::Local<String> name);
7587 };
7588
7589
7590 static int lookup_count = 0;
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Local<String> name)7591 v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7592 v8::Isolate* isolate, v8::Local<String> name) {
7593 lookup_count++;
7594 if (name->Equals(isolate->GetCurrentContext(), v8_str("A")).FromJust()) {
7595 return v8::FunctionTemplate::New(isolate, CallFun,
7596 v8::Integer::New(isolate, 8));
7597 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("B"))
7598 .FromJust()) {
7599 return v8::FunctionTemplate::New(isolate, CallFun,
7600 v8::Integer::New(isolate, 7));
7601 } else if (name->Equals(isolate->GetCurrentContext(), v8_str("C"))
7602 .FromJust()) {
7603 return v8::FunctionTemplate::New(isolate, CallFun,
7604 v8::Integer::New(isolate, 6));
7605 } else {
7606 return v8::Local<v8::FunctionTemplate>();
7607 }
7608 }
7609
7610
THREADED_TEST(FunctionLookup)7611 THREADED_TEST(FunctionLookup) {
7612 v8::RegisterExtension(new FunctionExtension());
7613 v8::HandleScope handle_scope(CcTest::isolate());
7614 static const char* exts[1] = {"functiontest"};
7615 v8::ExtensionConfiguration config(1, exts);
7616 LocalContext context(&config);
7617 CHECK_EQ(3, lookup_count);
7618 CHECK(v8::Integer::New(CcTest::isolate(), 8)
7619 ->Equals(context.local(), CompileRun("Foo(0)"))
7620 .FromJust());
7621 CHECK(v8::Integer::New(CcTest::isolate(), 7)
7622 ->Equals(context.local(), CompileRun("Foo(1)"))
7623 .FromJust());
7624 CHECK(v8::Integer::New(CcTest::isolate(), 6)
7625 ->Equals(context.local(), CompileRun("Foo(2)"))
7626 .FromJust());
7627 }
7628
7629
THREADED_TEST(NativeFunctionConstructCall)7630 THREADED_TEST(NativeFunctionConstructCall) {
7631 v8::RegisterExtension(new FunctionExtension());
7632 v8::HandleScope handle_scope(CcTest::isolate());
7633 static const char* exts[1] = {"functiontest"};
7634 v8::ExtensionConfiguration config(1, exts);
7635 LocalContext context(&config);
7636 for (int i = 0; i < 10; i++) {
7637 // Run a few times to ensure that allocation of objects doesn't
7638 // change behavior of a constructor function.
7639 CHECK(v8::Integer::New(CcTest::isolate(), 8)
7640 ->Equals(context.local(), CompileRun("(new A()).data"))
7641 .FromJust());
7642 CHECK(v8::Integer::New(CcTest::isolate(), 7)
7643 ->Equals(context.local(), CompileRun("(new B()).data"))
7644 .FromJust());
7645 CHECK(v8::Integer::New(CcTest::isolate(), 6)
7646 ->Equals(context.local(), CompileRun("(new C()).data"))
7647 .FromJust());
7648 }
7649 }
7650
7651
7652 static const char* last_location;
7653 static const char* last_message;
StoringErrorCallback(const char * location,const char * message)7654 void StoringErrorCallback(const char* location, const char* message) {
7655 if (last_location == NULL) {
7656 last_location = location;
7657 last_message = message;
7658 }
7659 }
7660
7661
7662 // ErrorReporting creates a circular extensions configuration and
7663 // tests that the fatal error handler gets called. This renders V8
7664 // unusable and therefore this test cannot be run in parallel.
TEST(ErrorReporting)7665 TEST(ErrorReporting) {
7666 CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7667 static const char* aDeps[] = {"B"};
7668 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7669 static const char* bDeps[] = {"A"};
7670 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7671 last_location = NULL;
7672 v8::ExtensionConfiguration config(1, bDeps);
7673 v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7674 CHECK(context.IsEmpty());
7675 CHECK(last_location);
7676 }
7677
7678
MissingScriptInfoMessageListener(v8::Local<v8::Message> message,v8::Local<Value> data)7679 static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7680 v8::Local<Value> data) {
7681 v8::Isolate* isolate = CcTest::isolate();
7682 Local<Context> context = isolate->GetCurrentContext();
7683 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7684 CHECK(v8::Undefined(isolate)
7685 ->Equals(context, message->GetScriptOrigin().ResourceName())
7686 .FromJust());
7687 message->GetLineNumber(context).FromJust();
7688 message->GetSourceLine(context).ToLocalChecked();
7689 }
7690
7691
THREADED_TEST(ErrorWithMissingScriptInfo)7692 THREADED_TEST(ErrorWithMissingScriptInfo) {
7693 LocalContext context;
7694 v8::HandleScope scope(context->GetIsolate());
7695 context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7696 CompileRun("throw Error()");
7697 context->GetIsolate()->RemoveMessageListeners(
7698 MissingScriptInfoMessageListener);
7699 }
7700
7701
7702 struct FlagAndPersistent {
7703 bool flag;
7704 v8::Global<v8::Object> handle;
7705 };
7706
7707
SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7708 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7709 data.GetParameter()->flag = true;
7710 data.GetParameter()->handle.Reset();
7711 }
7712
7713
IndependentWeakHandle(bool global_gc,bool interlinked)7714 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7715 v8::Isolate* iso = CcTest::isolate();
7716 v8::HandleScope scope(iso);
7717 v8::Local<Context> context = Context::New(iso);
7718 Context::Scope context_scope(context);
7719
7720 FlagAndPersistent object_a, object_b;
7721
7722 intptr_t big_heap_size;
7723
7724 {
7725 v8::HandleScope handle_scope(iso);
7726 Local<Object> a(v8::Object::New(iso));
7727 Local<Object> b(v8::Object::New(iso));
7728 object_a.handle.Reset(iso, a);
7729 object_b.handle.Reset(iso, b);
7730 if (interlinked) {
7731 a->Set(context, v8_str("x"), b).FromJust();
7732 b->Set(context, v8_str("x"), a).FromJust();
7733 }
7734 if (global_gc) {
7735 CcTest::heap()->CollectAllGarbage();
7736 } else {
7737 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7738 }
7739 // We are relying on this creating a big flag array and reserving the space
7740 // up front.
7741 v8::Local<Value> big_array = CompileRun("new Array(5000)");
7742 a->Set(context, v8_str("y"), big_array).FromJust();
7743 big_heap_size = CcTest::heap()->SizeOfObjects();
7744 }
7745
7746 object_a.flag = false;
7747 object_b.flag = false;
7748 object_a.handle.SetWeak(&object_a, &SetFlag,
7749 v8::WeakCallbackType::kParameter);
7750 object_b.handle.SetWeak(&object_b, &SetFlag,
7751 v8::WeakCallbackType::kParameter);
7752 CHECK(!object_b.handle.IsIndependent());
7753 object_a.handle.MarkIndependent();
7754 object_b.handle.MarkIndependent();
7755 CHECK(object_b.handle.IsIndependent());
7756 if (global_gc) {
7757 CcTest::heap()->CollectAllGarbage();
7758 } else {
7759 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7760 }
7761 // A single GC should be enough to reclaim the memory, since we are using
7762 // phantom handles.
7763 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 20000);
7764 CHECK(object_a.flag);
7765 CHECK(object_b.flag);
7766 }
7767
7768
TEST(IndependentWeakHandle)7769 TEST(IndependentWeakHandle) {
7770 IndependentWeakHandle(false, false);
7771 IndependentWeakHandle(false, true);
7772 IndependentWeakHandle(true, false);
7773 IndependentWeakHandle(true, true);
7774 }
7775
7776
7777 class Trivial {
7778 public:
Trivial(int x)7779 explicit Trivial(int x) : x_(x) {}
7780
x()7781 int x() { return x_; }
set_x(int x)7782 void set_x(int x) { x_ = x; }
7783
7784 private:
7785 int x_;
7786 };
7787
7788
7789 class Trivial2 {
7790 public:
Trivial2(int x,int y)7791 Trivial2(int x, int y) : y_(y), x_(x) {}
7792
x()7793 int x() { return x_; }
set_x(int x)7794 void set_x(int x) { x_ = x; }
7795
y()7796 int y() { return y_; }
set_y(int y)7797 void set_y(int y) { y_ = y; }
7798
7799 private:
7800 int y_;
7801 int x_;
7802 };
7803
7804
CheckInternalFields(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)7805 void CheckInternalFields(
7806 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
7807 v8::Persistent<v8::Object>* handle = data.GetParameter();
7808 handle->Reset();
7809 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
7810 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
7811 CHECK_EQ(42, t1->x());
7812 CHECK_EQ(103, t2->x());
7813 t1->set_x(1729);
7814 t2->set_x(33550336);
7815 }
7816
7817
InternalFieldCallback(bool global_gc)7818 void InternalFieldCallback(bool global_gc) {
7819 LocalContext env;
7820 v8::Isolate* isolate = env->GetIsolate();
7821 v8::HandleScope scope(isolate);
7822
7823 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
7824 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
7825 Trivial* t1;
7826 Trivial2* t2;
7827 instance_templ->SetInternalFieldCount(2);
7828 {
7829 v8::HandleScope scope(isolate);
7830 Local<v8::Object> obj = templ->GetFunction(env.local())
7831 .ToLocalChecked()
7832 ->NewInstance(env.local())
7833 .ToLocalChecked();
7834 v8::Persistent<v8::Object> handle(isolate, obj);
7835 CHECK_EQ(2, obj->InternalFieldCount());
7836 CHECK(obj->GetInternalField(0)->IsUndefined());
7837 t1 = new Trivial(42);
7838 t2 = new Trivial2(103, 9);
7839
7840 obj->SetAlignedPointerInInternalField(0, t1);
7841 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
7842 CHECK_EQ(42, t1->x());
7843
7844 obj->SetAlignedPointerInInternalField(1, t2);
7845 t2 =
7846 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
7847 CHECK_EQ(103, t2->x());
7848
7849 handle.SetWeak<v8::Persistent<v8::Object>>(
7850 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
7851 if (!global_gc) {
7852 handle.MarkIndependent();
7853 }
7854 }
7855 if (global_gc) {
7856 CcTest::heap()->CollectAllGarbage();
7857 } else {
7858 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7859 }
7860
7861 CHECK_EQ(1729, t1->x());
7862 CHECK_EQ(33550336, t2->x());
7863
7864 delete t1;
7865 delete t2;
7866 }
7867
7868
THREADED_TEST(InternalFieldCallback)7869 THREADED_TEST(InternalFieldCallback) {
7870 InternalFieldCallback(false);
7871 InternalFieldCallback(true);
7872 }
7873
7874
ResetUseValueAndSetFlag(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7875 static void ResetUseValueAndSetFlag(
7876 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7877 // Blink will reset the handle, and then use the other handle, so they
7878 // can't use the same backing slot.
7879 data.GetParameter()->handle.Reset();
7880 data.GetParameter()->flag = true;
7881 }
7882
7883
ResetWeakHandle(bool global_gc)7884 void v8::internal::HeapTester::ResetWeakHandle(bool global_gc) {
7885 using v8::Context;
7886 using v8::Local;
7887 using v8::Object;
7888
7889 v8::Isolate* iso = CcTest::isolate();
7890 v8::HandleScope scope(iso);
7891 v8::Local<Context> context = Context::New(iso);
7892 Context::Scope context_scope(context);
7893
7894 FlagAndPersistent object_a, object_b;
7895
7896 {
7897 v8::HandleScope handle_scope(iso);
7898 Local<Object> a(v8::Object::New(iso));
7899 Local<Object> b(v8::Object::New(iso));
7900 object_a.handle.Reset(iso, a);
7901 object_b.handle.Reset(iso, b);
7902 if (global_gc) {
7903 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
7904 } else {
7905 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7906 }
7907 }
7908
7909 object_a.flag = false;
7910 object_b.flag = false;
7911 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
7912 v8::WeakCallbackType::kParameter);
7913 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
7914 v8::WeakCallbackType::kParameter);
7915 if (!global_gc) {
7916 object_a.handle.MarkIndependent();
7917 object_b.handle.MarkIndependent();
7918 CHECK(object_b.handle.IsIndependent());
7919 }
7920 if (global_gc) {
7921 CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
7922 } else {
7923 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7924 }
7925 CHECK(object_a.flag);
7926 CHECK(object_b.flag);
7927 }
7928
7929
THREADED_HEAP_TEST(ResetWeakHandle)7930 THREADED_HEAP_TEST(ResetWeakHandle) {
7931 v8::internal::HeapTester::ResetWeakHandle(false);
7932 v8::internal::HeapTester::ResetWeakHandle(true);
7933 }
7934
7935
InvokeScavenge()7936 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
7937
7938
InvokeMarkSweep()7939 static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); }
7940
7941
ForceScavenge2(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7942 static void ForceScavenge2(
7943 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7944 data.GetParameter()->flag = true;
7945 InvokeScavenge();
7946 }
7947
ForceScavenge1(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7948 static void ForceScavenge1(
7949 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7950 data.GetParameter()->handle.Reset();
7951 data.SetSecondPassCallback(ForceScavenge2);
7952 }
7953
7954
ForceMarkSweep2(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7955 static void ForceMarkSweep2(
7956 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7957 data.GetParameter()->flag = true;
7958 InvokeMarkSweep();
7959 }
7960
ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndPersistent> & data)7961 static void ForceMarkSweep1(
7962 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7963 data.GetParameter()->handle.Reset();
7964 data.SetSecondPassCallback(ForceMarkSweep2);
7965 }
7966
7967
THREADED_TEST(GCFromWeakCallbacks)7968 THREADED_TEST(GCFromWeakCallbacks) {
7969 v8::Isolate* isolate = CcTest::isolate();
7970 v8::Locker locker(CcTest::isolate());
7971 v8::HandleScope scope(isolate);
7972 v8::Local<Context> context = Context::New(isolate);
7973 Context::Scope context_scope(context);
7974
7975 static const int kNumberOfGCTypes = 2;
7976 typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
7977 Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
7978 &ForceMarkSweep1};
7979
7980 typedef void (*GCInvoker)();
7981 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7982
7983 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7984 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7985 FlagAndPersistent object;
7986 {
7987 v8::HandleScope handle_scope(isolate);
7988 object.handle.Reset(isolate, v8::Object::New(isolate));
7989 }
7990 object.flag = false;
7991 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
7992 v8::WeakCallbackType::kParameter);
7993 object.handle.MarkIndependent();
7994 invoke_gc[outer_gc]();
7995 EmptyMessageQueues(isolate);
7996 CHECK(object.flag);
7997 }
7998 }
7999 }
8000
8001
8002 v8::Local<Function> args_fun;
8003
8004
ArgumentsTestCallback(const v8::FunctionCallbackInfo<v8::Value> & args)8005 static void ArgumentsTestCallback(
8006 const v8::FunctionCallbackInfo<v8::Value>& args) {
8007 ApiTestFuzzer::Fuzz();
8008 v8::Isolate* isolate = args.GetIsolate();
8009 Local<Context> context = isolate->GetCurrentContext();
8010 CHECK_EQ(3, args.Length());
8011 CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
8012 CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
8013 CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
8014 CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
8015 v8::HandleScope scope(args.GetIsolate());
8016 CcTest::heap()->CollectAllGarbage();
8017 }
8018
8019
THREADED_TEST(Arguments)8020 THREADED_TEST(Arguments) {
8021 v8::Isolate* isolate = CcTest::isolate();
8022 v8::HandleScope scope(isolate);
8023 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8024 global->Set(v8_str("f"),
8025 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8026 LocalContext context(NULL, global);
8027 args_fun = context->Global()
8028 ->Get(context.local(), v8_str("f"))
8029 .ToLocalChecked()
8030 .As<Function>();
8031 v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
8032 }
8033
8034
8035 static int p_getter_count;
8036 static int p_getter_count2;
8037
8038
PGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)8039 static void PGetter(Local<Name> name,
8040 const v8::PropertyCallbackInfo<v8::Value>& info) {
8041 ApiTestFuzzer::Fuzz();
8042 p_getter_count++;
8043 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8044 v8::Local<v8::Object> global = context->Global();
8045 CHECK(
8046 info.Holder()
8047 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8048 .FromJust());
8049 if (name->Equals(context, v8_str("p1")).FromJust()) {
8050 CHECK(info.This()
8051 ->Equals(context,
8052 global->Get(context, v8_str("o1")).ToLocalChecked())
8053 .FromJust());
8054 } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8055 CHECK(info.This()
8056 ->Equals(context,
8057 global->Get(context, v8_str("o2")).ToLocalChecked())
8058 .FromJust());
8059 } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8060 CHECK(info.This()
8061 ->Equals(context,
8062 global->Get(context, v8_str("o3")).ToLocalChecked())
8063 .FromJust());
8064 } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8065 CHECK(info.This()
8066 ->Equals(context,
8067 global->Get(context, v8_str("o4")).ToLocalChecked())
8068 .FromJust());
8069 }
8070 }
8071
8072
RunHolderTest(v8::Local<v8::ObjectTemplate> obj)8073 static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8074 ApiTestFuzzer::Fuzz();
8075 LocalContext context;
8076 CHECK(context->Global()
8077 ->Set(context.local(), v8_str("o1"),
8078 obj->NewInstance(context.local()).ToLocalChecked())
8079 .FromJust());
8080 CompileRun(
8081 "o1.__proto__ = { };"
8082 "var o2 = { __proto__: o1 };"
8083 "var o3 = { __proto__: o2 };"
8084 "var o4 = { __proto__: o3 };"
8085 "for (var i = 0; i < 10; i++) o4.p4;"
8086 "for (var i = 0; i < 10; i++) o3.p3;"
8087 "for (var i = 0; i < 10; i++) o2.p2;"
8088 "for (var i = 0; i < 10; i++) o1.p1;");
8089 }
8090
8091
PGetter2(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)8092 static void PGetter2(Local<Name> name,
8093 const v8::PropertyCallbackInfo<v8::Value>& info) {
8094 ApiTestFuzzer::Fuzz();
8095 p_getter_count2++;
8096 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8097 v8::Local<v8::Object> global = context->Global();
8098 CHECK(
8099 info.Holder()
8100 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8101 .FromJust());
8102 if (name->Equals(context, v8_str("p1")).FromJust()) {
8103 CHECK(info.This()
8104 ->Equals(context,
8105 global->Get(context, v8_str("o1")).ToLocalChecked())
8106 .FromJust());
8107 } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8108 CHECK(info.This()
8109 ->Equals(context,
8110 global->Get(context, v8_str("o2")).ToLocalChecked())
8111 .FromJust());
8112 } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8113 CHECK(info.This()
8114 ->Equals(context,
8115 global->Get(context, v8_str("o3")).ToLocalChecked())
8116 .FromJust());
8117 } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8118 CHECK(info.This()
8119 ->Equals(context,
8120 global->Get(context, v8_str("o4")).ToLocalChecked())
8121 .FromJust());
8122 }
8123 }
8124
8125
THREADED_TEST(GetterHolders)8126 THREADED_TEST(GetterHolders) {
8127 v8::Isolate* isolate = CcTest::isolate();
8128 v8::HandleScope scope(isolate);
8129 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8130 obj->SetAccessor(v8_str("p1"), PGetter);
8131 obj->SetAccessor(v8_str("p2"), PGetter);
8132 obj->SetAccessor(v8_str("p3"), PGetter);
8133 obj->SetAccessor(v8_str("p4"), PGetter);
8134 p_getter_count = 0;
8135 RunHolderTest(obj);
8136 CHECK_EQ(40, p_getter_count);
8137 }
8138
8139
THREADED_TEST(PreInterceptorHolders)8140 THREADED_TEST(PreInterceptorHolders) {
8141 v8::Isolate* isolate = CcTest::isolate();
8142 v8::HandleScope scope(isolate);
8143 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8144 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8145 p_getter_count2 = 0;
8146 RunHolderTest(obj);
8147 CHECK_EQ(40, p_getter_count2);
8148 }
8149
8150
THREADED_TEST(ObjectInstantiation)8151 THREADED_TEST(ObjectInstantiation) {
8152 v8::Isolate* isolate = CcTest::isolate();
8153 v8::HandleScope scope(isolate);
8154 v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8155 templ->SetAccessor(v8_str("t"), PGetter2);
8156 LocalContext context;
8157 CHECK(context->Global()
8158 ->Set(context.local(), v8_str("o"),
8159 templ->NewInstance(context.local()).ToLocalChecked())
8160 .FromJust());
8161 for (int i = 0; i < 100; i++) {
8162 v8::HandleScope inner_scope(CcTest::isolate());
8163 v8::Local<v8::Object> obj =
8164 templ->NewInstance(context.local()).ToLocalChecked();
8165 CHECK(!obj->Equals(context.local(), context->Global()
8166 ->Get(context.local(), v8_str("o"))
8167 .ToLocalChecked())
8168 .FromJust());
8169 CHECK(
8170 context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8171 v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8172 CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8173 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8174 }
8175 }
8176
8177
StrCmp16(uint16_t * a,uint16_t * b)8178 static int StrCmp16(uint16_t* a, uint16_t* b) {
8179 while (true) {
8180 if (*a == 0 && *b == 0) return 0;
8181 if (*a != *b) return 0 + *a - *b;
8182 a++;
8183 b++;
8184 }
8185 }
8186
8187
StrNCmp16(uint16_t * a,uint16_t * b,int n)8188 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8189 while (true) {
8190 if (n-- == 0) return 0;
8191 if (*a == 0 && *b == 0) return 0;
8192 if (*a != *b) return 0 + *a - *b;
8193 a++;
8194 b++;
8195 }
8196 }
8197
8198
GetUtf8Length(Local<String> str)8199 int GetUtf8Length(Local<String> str) {
8200 int len = str->Utf8Length();
8201 if (len < 0) {
8202 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8203 i::String::Flatten(istr);
8204 len = str->Utf8Length();
8205 }
8206 return len;
8207 }
8208
8209
THREADED_TEST(StringWrite)8210 THREADED_TEST(StringWrite) {
8211 LocalContext context;
8212 v8::HandleScope scope(context->GetIsolate());
8213 v8::Local<String> str = v8_str("abcde");
8214 // abc<Icelandic eth><Unicode snowman>.
8215 v8::Local<String> str2 = v8_str("abc\303\260\342\230\203");
8216 v8::Local<String> str3 =
8217 v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8218 v8::NewStringType::kNormal, 7)
8219 .ToLocalChecked();
8220 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8221 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8222 v8::Local<String> orphans_str =
8223 v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8224 v8::NewStringType::kNormal, 8)
8225 .ToLocalChecked();
8226 // single lead surrogate
8227 uint16_t lead[1] = { 0xd800 };
8228 v8::Local<String> lead_str =
8229 v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8230 v8::NewStringType::kNormal, 1)
8231 .ToLocalChecked();
8232 // single trail surrogate
8233 uint16_t trail[1] = { 0xdc00 };
8234 v8::Local<String> trail_str =
8235 v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8236 v8::NewStringType::kNormal, 1)
8237 .ToLocalChecked();
8238 // surrogate pair
8239 uint16_t pair[2] = { 0xd800, 0xdc00 };
8240 v8::Local<String> pair_str =
8241 v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8242 v8::NewStringType::kNormal, 2)
8243 .ToLocalChecked();
8244 const int kStride = 4; // Must match stride in for loops in JS below.
8245 CompileRun(
8246 "var left = '';"
8247 "for (var i = 0; i < 0xd800; i += 4) {"
8248 " left = left + String.fromCharCode(i);"
8249 "}");
8250 CompileRun(
8251 "var right = '';"
8252 "for (var i = 0; i < 0xd800; i += 4) {"
8253 " right = String.fromCharCode(i) + right;"
8254 "}");
8255 v8::Local<v8::Object> global = context->Global();
8256 Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8257 .ToLocalChecked()
8258 .As<String>();
8259 Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8260 .ToLocalChecked()
8261 .As<String>();
8262
8263 CHECK_EQ(5, str2->Length());
8264 CHECK_EQ(0xd800 / kStride, left_tree->Length());
8265 CHECK_EQ(0xd800 / kStride, right_tree->Length());
8266
8267 char buf[100];
8268 char utf8buf[0xd800 * 3];
8269 uint16_t wbuf[100];
8270 int len;
8271 int charlen;
8272
8273 memset(utf8buf, 0x1, 1000);
8274 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8275 CHECK_EQ(9, len);
8276 CHECK_EQ(5, charlen);
8277 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8278
8279 memset(utf8buf, 0x1, 1000);
8280 len = str2->WriteUtf8(utf8buf, 8, &charlen);
8281 CHECK_EQ(8, len);
8282 CHECK_EQ(5, charlen);
8283 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8284
8285 memset(utf8buf, 0x1, 1000);
8286 len = str2->WriteUtf8(utf8buf, 7, &charlen);
8287 CHECK_EQ(5, len);
8288 CHECK_EQ(4, charlen);
8289 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8290
8291 memset(utf8buf, 0x1, 1000);
8292 len = str2->WriteUtf8(utf8buf, 6, &charlen);
8293 CHECK_EQ(5, len);
8294 CHECK_EQ(4, charlen);
8295 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8296
8297 memset(utf8buf, 0x1, 1000);
8298 len = str2->WriteUtf8(utf8buf, 5, &charlen);
8299 CHECK_EQ(5, len);
8300 CHECK_EQ(4, charlen);
8301 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8302
8303 memset(utf8buf, 0x1, 1000);
8304 len = str2->WriteUtf8(utf8buf, 4, &charlen);
8305 CHECK_EQ(3, len);
8306 CHECK_EQ(3, charlen);
8307 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8308
8309 memset(utf8buf, 0x1, 1000);
8310 len = str2->WriteUtf8(utf8buf, 3, &charlen);
8311 CHECK_EQ(3, len);
8312 CHECK_EQ(3, charlen);
8313 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8314
8315 memset(utf8buf, 0x1, 1000);
8316 len = str2->WriteUtf8(utf8buf, 2, &charlen);
8317 CHECK_EQ(2, len);
8318 CHECK_EQ(2, charlen);
8319 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8320
8321 // allow orphan surrogates by default
8322 memset(utf8buf, 0x1, 1000);
8323 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8324 CHECK_EQ(13, len);
8325 CHECK_EQ(8, charlen);
8326 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8327
8328 // replace orphan surrogates with unicode replacement character
8329 memset(utf8buf, 0x1, 1000);
8330 len = orphans_str->WriteUtf8(utf8buf,
8331 sizeof(utf8buf),
8332 &charlen,
8333 String::REPLACE_INVALID_UTF8);
8334 CHECK_EQ(13, len);
8335 CHECK_EQ(8, charlen);
8336 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8337
8338 // replace single lead surrogate with unicode replacement character
8339 memset(utf8buf, 0x1, 1000);
8340 len = lead_str->WriteUtf8(utf8buf,
8341 sizeof(utf8buf),
8342 &charlen,
8343 String::REPLACE_INVALID_UTF8);
8344 CHECK_EQ(4, len);
8345 CHECK_EQ(1, charlen);
8346 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8347
8348 // replace single trail surrogate with unicode replacement character
8349 memset(utf8buf, 0x1, 1000);
8350 len = trail_str->WriteUtf8(utf8buf,
8351 sizeof(utf8buf),
8352 &charlen,
8353 String::REPLACE_INVALID_UTF8);
8354 CHECK_EQ(4, len);
8355 CHECK_EQ(1, charlen);
8356 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8357
8358 // do not replace / write anything if surrogate pair does not fit the buffer
8359 // space
8360 memset(utf8buf, 0x1, 1000);
8361 len = pair_str->WriteUtf8(utf8buf,
8362 3,
8363 &charlen,
8364 String::REPLACE_INVALID_UTF8);
8365 CHECK_EQ(0, len);
8366 CHECK_EQ(0, charlen);
8367
8368 memset(utf8buf, 0x1, sizeof(utf8buf));
8369 len = GetUtf8Length(left_tree);
8370 int utf8_expected =
8371 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8372 CHECK_EQ(utf8_expected, len);
8373 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8374 CHECK_EQ(utf8_expected, len);
8375 CHECK_EQ(0xd800 / kStride, charlen);
8376 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8377 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8378 CHECK_EQ(0xc0 - kStride,
8379 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8380 CHECK_EQ(1, utf8buf[utf8_expected]);
8381
8382 memset(utf8buf, 0x1, sizeof(utf8buf));
8383 len = GetUtf8Length(right_tree);
8384 CHECK_EQ(utf8_expected, len);
8385 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8386 CHECK_EQ(utf8_expected, len);
8387 CHECK_EQ(0xd800 / kStride, charlen);
8388 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8389 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8390 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8391 CHECK_EQ(1, utf8buf[utf8_expected]);
8392
8393 memset(buf, 0x1, sizeof(buf));
8394 memset(wbuf, 0x1, sizeof(wbuf));
8395 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8396 CHECK_EQ(5, len);
8397 len = str->Write(wbuf);
8398 CHECK_EQ(5, len);
8399 CHECK_EQ(0, strcmp("abcde", buf));
8400 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8401 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8402
8403 memset(buf, 0x1, sizeof(buf));
8404 memset(wbuf, 0x1, sizeof(wbuf));
8405 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8406 CHECK_EQ(4, len);
8407 len = str->Write(wbuf, 0, 4);
8408 CHECK_EQ(4, len);
8409 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8410 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8411 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8412
8413 memset(buf, 0x1, sizeof(buf));
8414 memset(wbuf, 0x1, sizeof(wbuf));
8415 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8416 CHECK_EQ(5, len);
8417 len = str->Write(wbuf, 0, 5);
8418 CHECK_EQ(5, len);
8419 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8420 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8421 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8422
8423 memset(buf, 0x1, sizeof(buf));
8424 memset(wbuf, 0x1, sizeof(wbuf));
8425 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8426 CHECK_EQ(5, len);
8427 len = str->Write(wbuf, 0, 6);
8428 CHECK_EQ(5, len);
8429 CHECK_EQ(0, strcmp("abcde", buf));
8430 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8431 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8432
8433 memset(buf, 0x1, sizeof(buf));
8434 memset(wbuf, 0x1, sizeof(wbuf));
8435 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8436 CHECK_EQ(1, len);
8437 len = str->Write(wbuf, 4, -1);
8438 CHECK_EQ(1, len);
8439 CHECK_EQ(0, strcmp("e", buf));
8440 uint16_t answer5[] = {'e', '\0'};
8441 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8442
8443 memset(buf, 0x1, sizeof(buf));
8444 memset(wbuf, 0x1, sizeof(wbuf));
8445 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8446 CHECK_EQ(1, len);
8447 len = str->Write(wbuf, 4, 6);
8448 CHECK_EQ(1, len);
8449 CHECK_EQ(0, strcmp("e", buf));
8450 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8451
8452 memset(buf, 0x1, sizeof(buf));
8453 memset(wbuf, 0x1, sizeof(wbuf));
8454 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8455 CHECK_EQ(1, len);
8456 len = str->Write(wbuf, 4, 1);
8457 CHECK_EQ(1, len);
8458 CHECK_EQ(0, strncmp("e\1", buf, 2));
8459 uint16_t answer6[] = {'e', 0x101};
8460 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8461
8462 memset(buf, 0x1, sizeof(buf));
8463 memset(wbuf, 0x1, sizeof(wbuf));
8464 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8465 CHECK_EQ(1, len);
8466 len = str->Write(wbuf, 3, 1);
8467 CHECK_EQ(1, len);
8468 CHECK_EQ(0, strncmp("d\1", buf, 2));
8469 uint16_t answer7[] = {'d', 0x101};
8470 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8471
8472 memset(wbuf, 0x1, sizeof(wbuf));
8473 wbuf[5] = 'X';
8474 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8475 CHECK_EQ(5, len);
8476 CHECK_EQ('X', wbuf[5]);
8477 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8478 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8479 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8480 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8481 wbuf[5] = '\0';
8482 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8483
8484 memset(buf, 0x1, sizeof(buf));
8485 buf[5] = 'X';
8486 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8487 0,
8488 6,
8489 String::NO_NULL_TERMINATION);
8490 CHECK_EQ(5, len);
8491 CHECK_EQ('X', buf[5]);
8492 CHECK_EQ(0, strncmp("abcde", buf, 5));
8493 CHECK_NE(0, strcmp("abcde", buf));
8494 buf[5] = '\0';
8495 CHECK_EQ(0, strcmp("abcde", buf));
8496
8497 memset(utf8buf, 0x1, sizeof(utf8buf));
8498 utf8buf[8] = 'X';
8499 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8500 String::NO_NULL_TERMINATION);
8501 CHECK_EQ(8, len);
8502 CHECK_EQ('X', utf8buf[8]);
8503 CHECK_EQ(5, charlen);
8504 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8505 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8506 utf8buf[8] = '\0';
8507 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8508
8509 memset(utf8buf, 0x1, sizeof(utf8buf));
8510 utf8buf[5] = 'X';
8511 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8512 String::NO_NULL_TERMINATION);
8513 CHECK_EQ(5, len);
8514 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8515 CHECK_EQ(5, charlen);
8516 utf8buf[5] = '\0';
8517 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8518
8519 memset(buf, 0x1, sizeof(buf));
8520 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8521 CHECK_EQ(7, len);
8522 CHECK_EQ(0, strcmp("abc", buf));
8523 CHECK_EQ(0, buf[3]);
8524 CHECK_EQ(0, strcmp("def", buf + 4));
8525
8526 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8527 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8528 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8529 }
8530
8531
Utf16Helper(LocalContext & context,const char * name,const char * lengths_name,int len)8532 static void Utf16Helper(
8533 LocalContext& context, // NOLINT
8534 const char* name,
8535 const char* lengths_name,
8536 int len) {
8537 Local<v8::Array> a = Local<v8::Array>::Cast(
8538 context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8539 Local<v8::Array> alens =
8540 Local<v8::Array>::Cast(context->Global()
8541 ->Get(context.local(), v8_str(lengths_name))
8542 .ToLocalChecked());
8543 for (int i = 0; i < len; i++) {
8544 Local<v8::String> string =
8545 Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8546 Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8547 alens->Get(context.local(), i).ToLocalChecked());
8548 int length = GetUtf8Length(string);
8549 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8550 }
8551 }
8552
8553
THREADED_TEST(Utf16)8554 THREADED_TEST(Utf16) {
8555 LocalContext context;
8556 v8::HandleScope scope(context->GetIsolate());
8557 CompileRun(
8558 "var pad = '01234567890123456789';"
8559 "var p = [];"
8560 "var plens = [20, 3, 3];"
8561 "p.push('01234567890123456789');"
8562 "var lead = 0xd800;"
8563 "var trail = 0xdc00;"
8564 "p.push(String.fromCharCode(0xd800));"
8565 "p.push(String.fromCharCode(0xdc00));"
8566 "var a = [];"
8567 "var b = [];"
8568 "var c = [];"
8569 "var alens = [];"
8570 "for (var i = 0; i < 3; i++) {"
8571 " p[1] = String.fromCharCode(lead++);"
8572 " for (var j = 0; j < 3; j++) {"
8573 " p[2] = String.fromCharCode(trail++);"
8574 " a.push(p[i] + p[j]);"
8575 " b.push(p[i] + p[j]);"
8576 " c.push(p[i] + p[j]);"
8577 " alens.push(plens[i] + plens[j]);"
8578 " }"
8579 "}"
8580 "alens[5] -= 2;" // Here the surrogate pairs match up.
8581 "var a2 = [];"
8582 "var b2 = [];"
8583 "var c2 = [];"
8584 "var a2lens = [];"
8585 "for (var m = 0; m < 9; m++) {"
8586 " for (var n = 0; n < 9; n++) {"
8587 " a2.push(a[m] + a[n]);"
8588 " b2.push(b[m] + b[n]);"
8589 " var newc = 'x' + c[m] + c[n] + 'y';"
8590 " c2.push(newc.substring(1, newc.length - 1));"
8591 " var utf = alens[m] + alens[n];" // And here.
8592 // The 'n's that start with 0xdc.. are 6-8
8593 // The 'm's that end with 0xd8.. are 1, 4 and 7
8594 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8595 " a2lens.push(utf);"
8596 " }"
8597 "}");
8598 Utf16Helper(context, "a", "alens", 9);
8599 Utf16Helper(context, "a2", "a2lens", 81);
8600 }
8601
8602
SameSymbol(Local<String> s1,Local<String> s2)8603 static bool SameSymbol(Local<String> s1, Local<String> s2) {
8604 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8605 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8606 return *is1 == *is2;
8607 }
8608
8609
THREADED_TEST(Utf16Symbol)8610 THREADED_TEST(Utf16Symbol) {
8611 LocalContext context;
8612 v8::HandleScope scope(context->GetIsolate());
8613
8614 Local<String> symbol1 =
8615 v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8616 v8::NewStringType::kInternalized)
8617 .ToLocalChecked();
8618 Local<String> symbol2 =
8619 v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8620 v8::NewStringType::kInternalized)
8621 .ToLocalChecked();
8622 CHECK(SameSymbol(symbol1, symbol2));
8623
8624 CompileRun(
8625 "var sym0 = 'benedictus';"
8626 "var sym0b = 'S\303\270ren';"
8627 "var sym1 = '\355\240\201\355\260\207';"
8628 "var sym2 = '\360\220\220\210';"
8629 "var sym3 = 'x\355\240\201\355\260\207';"
8630 "var sym4 = 'x\360\220\220\210';"
8631 "if (sym1.length != 2) throw sym1;"
8632 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8633 "if (sym2.length != 2) throw sym2;"
8634 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8635 "if (sym3.length != 3) throw sym3;"
8636 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8637 "if (sym4.length != 3) throw sym4;"
8638 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8639 Local<String> sym0 =
8640 v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8641 v8::NewStringType::kInternalized)
8642 .ToLocalChecked();
8643 Local<String> sym0b =
8644 v8::String::NewFromUtf8(context->GetIsolate(), "S\303\270ren",
8645 v8::NewStringType::kInternalized)
8646 .ToLocalChecked();
8647 Local<String> sym1 =
8648 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8649 v8::NewStringType::kInternalized)
8650 .ToLocalChecked();
8651 Local<String> sym2 =
8652 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8653 v8::NewStringType::kInternalized)
8654 .ToLocalChecked();
8655 Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8656 "x\355\240\201\355\260\207",
8657 v8::NewStringType::kInternalized)
8658 .ToLocalChecked();
8659 Local<String> sym4 =
8660 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8661 v8::NewStringType::kInternalized)
8662 .ToLocalChecked();
8663 v8::Local<v8::Object> global = context->Global();
8664 Local<Value> s0 =
8665 global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8666 Local<Value> s0b =
8667 global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8668 Local<Value> s1 =
8669 global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8670 Local<Value> s2 =
8671 global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8672 Local<Value> s3 =
8673 global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8674 Local<Value> s4 =
8675 global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8676 CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8677 CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8678 CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8679 CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8680 CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8681 CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8682 }
8683
8684
THREADED_TEST(Utf16MissingTrailing)8685 THREADED_TEST(Utf16MissingTrailing) {
8686 LocalContext context;
8687 v8::HandleScope scope(context->GetIsolate());
8688
8689 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8690 int size = 1024 * 64;
8691 uint8_t* buffer = new uint8_t[size];
8692 for (int i = 0; i < size; i += 4) {
8693 buffer[i] = 0xf0;
8694 buffer[i + 1] = 0x9d;
8695 buffer[i + 2] = 0x80;
8696 buffer[i + 3] = 0x9e;
8697 }
8698
8699 // Now invoke the decoder without last 3 bytes
8700 v8::Local<v8::String> str =
8701 v8::String::NewFromUtf8(
8702 context->GetIsolate(), reinterpret_cast<char*>(buffer),
8703 v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8704 USE(str);
8705 delete[] buffer;
8706 }
8707
8708
THREADED_TEST(Utf16Trailing3Byte)8709 THREADED_TEST(Utf16Trailing3Byte) {
8710 LocalContext context;
8711 v8::HandleScope scope(context->GetIsolate());
8712
8713 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8714 int size = 1024 * 63;
8715 uint8_t* buffer = new uint8_t[size];
8716 for (int i = 0; i < size; i += 3) {
8717 buffer[i] = 0xe2;
8718 buffer[i + 1] = 0x80;
8719 buffer[i + 2] = 0xa6;
8720 }
8721
8722 // Now invoke the decoder without last 3 bytes
8723 v8::Local<v8::String> str =
8724 v8::String::NewFromUtf8(
8725 context->GetIsolate(), reinterpret_cast<char*>(buffer),
8726 v8::NewStringType::kNormal, size).ToLocalChecked();
8727
8728 v8::String::Value value(str);
8729 CHECK_EQ(value.length(), size / 3);
8730 CHECK_EQ((*value)[value.length() - 1], 0x2026);
8731
8732 delete[] buffer;
8733 }
8734
8735
THREADED_TEST(ToArrayIndex)8736 THREADED_TEST(ToArrayIndex) {
8737 LocalContext context;
8738 v8::Isolate* isolate = context->GetIsolate();
8739 v8::HandleScope scope(isolate);
8740
8741 v8::Local<String> str = v8_str("42");
8742 v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
8743 CHECK(!index.IsEmpty());
8744 CHECK_EQ(42.0,
8745 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8746 str = v8_str("42asdf");
8747 index = str->ToArrayIndex(context.local());
8748 CHECK(index.IsEmpty());
8749 str = v8_str("-42");
8750 index = str->ToArrayIndex(context.local());
8751 CHECK(index.IsEmpty());
8752 str = v8_str("4294967294");
8753 index = str->ToArrayIndex(context.local());
8754 CHECK(!index.IsEmpty());
8755 CHECK_EQ(4294967294.0,
8756 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8757 v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
8758 index = num->ToArrayIndex(context.local());
8759 CHECK(!index.IsEmpty());
8760 CHECK_EQ(1.0,
8761 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
8762 num = v8::Number::New(isolate, -1);
8763 index = num->ToArrayIndex(context.local());
8764 CHECK(index.IsEmpty());
8765 v8::Local<v8::Object> obj = v8::Object::New(isolate);
8766 index = obj->ToArrayIndex(context.local());
8767 CHECK(index.IsEmpty());
8768 }
8769
8770
THREADED_TEST(ErrorConstruction)8771 THREADED_TEST(ErrorConstruction) {
8772 LocalContext context;
8773 v8::HandleScope scope(context->GetIsolate());
8774
8775 v8::Local<String> foo = v8_str("foo");
8776 v8::Local<String> message = v8_str("message");
8777 v8::Local<Value> range_error = v8::Exception::RangeError(foo);
8778 CHECK(range_error->IsObject());
8779 CHECK(range_error.As<v8::Object>()
8780 ->Get(context.local(), message)
8781 .ToLocalChecked()
8782 ->Equals(context.local(), foo)
8783 .FromJust());
8784 v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
8785 CHECK(reference_error->IsObject());
8786 CHECK(reference_error.As<v8::Object>()
8787 ->Get(context.local(), message)
8788 .ToLocalChecked()
8789 ->Equals(context.local(), foo)
8790 .FromJust());
8791 v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
8792 CHECK(syntax_error->IsObject());
8793 CHECK(syntax_error.As<v8::Object>()
8794 ->Get(context.local(), message)
8795 .ToLocalChecked()
8796 ->Equals(context.local(), foo)
8797 .FromJust());
8798 v8::Local<Value> type_error = v8::Exception::TypeError(foo);
8799 CHECK(type_error->IsObject());
8800 CHECK(type_error.As<v8::Object>()
8801 ->Get(context.local(), message)
8802 .ToLocalChecked()
8803 ->Equals(context.local(), foo)
8804 .FromJust());
8805 v8::Local<Value> error = v8::Exception::Error(foo);
8806 CHECK(error->IsObject());
8807 CHECK(error.As<v8::Object>()
8808 ->Get(context.local(), message)
8809 .ToLocalChecked()
8810 ->Equals(context.local(), foo)
8811 .FromJust());
8812 }
8813
8814
ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value> & info)8815 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8816 ApiTestFuzzer::Fuzz();
8817 v8::Local<String> foo = v8_str("foo");
8818 v8::Local<String> message = v8_str("message");
8819 v8::Local<Value> error = v8::Exception::Error(foo);
8820 CHECK(error->IsObject());
8821 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8822 CHECK(error.As<v8::Object>()
8823 ->Get(context, message)
8824 .ToLocalChecked()
8825 ->Equals(context, foo)
8826 .FromJust());
8827 info.GetIsolate()->ThrowException(error);
8828 info.GetReturnValue().SetUndefined();
8829 }
8830
8831
THREADED_TEST(ExceptionCreateMessage)8832 THREADED_TEST(ExceptionCreateMessage) {
8833 LocalContext context;
8834 v8::HandleScope scope(context->GetIsolate());
8835 v8::Local<String> foo_str = v8_str("foo");
8836 v8::Local<String> message_str = v8_str("message");
8837
8838 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
8839
8840 Local<v8::FunctionTemplate> fun =
8841 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8842 v8::Local<v8::Object> global = context->Global();
8843 CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
8844 fun->GetFunction(context.local()).ToLocalChecked())
8845 .FromJust());
8846
8847 TryCatch try_catch(context->GetIsolate());
8848 CompileRun(
8849 "function f1() {\n"
8850 " throwV8Exception();\n"
8851 "};\n"
8852 "f1();");
8853 CHECK(try_catch.HasCaught());
8854
8855 v8::Local<v8::Value> error = try_catch.Exception();
8856 CHECK(error->IsObject());
8857 CHECK(error.As<v8::Object>()
8858 ->Get(context.local(), message_str)
8859 .ToLocalChecked()
8860 ->Equals(context.local(), foo_str)
8861 .FromJust());
8862
8863 v8::Local<v8::Message> message =
8864 v8::Exception::CreateMessage(context->GetIsolate(), error);
8865 CHECK(!message.IsEmpty());
8866 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
8867 CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
8868
8869 v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
8870 CHECK(!stackTrace.IsEmpty());
8871 CHECK_EQ(2, stackTrace->GetFrameCount());
8872
8873 stackTrace = v8::Exception::GetStackTrace(error);
8874 CHECK(!stackTrace.IsEmpty());
8875 CHECK_EQ(2, stackTrace->GetFrameCount());
8876
8877 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
8878
8879 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8880 // is false.
8881 try_catch.Reset();
8882
8883 CompileRun(
8884 "function f2() {\n"
8885 " return throwV8Exception();\n"
8886 "};\n"
8887 "f2();");
8888 CHECK(try_catch.HasCaught());
8889
8890 error = try_catch.Exception();
8891 CHECK(error->IsObject());
8892 CHECK(error.As<v8::Object>()
8893 ->Get(context.local(), message_str)
8894 .ToLocalChecked()
8895 ->Equals(context.local(), foo_str)
8896 .FromJust());
8897
8898 message = v8::Exception::CreateMessage(context->GetIsolate(), error);
8899 CHECK(!message.IsEmpty());
8900 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
8901 CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust());
8902
8903 // Should be empty stack trace.
8904 stackTrace = message->GetStackTrace();
8905 CHECK(stackTrace.IsEmpty());
8906 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
8907 }
8908
8909
THREADED_TEST(ExceptionCreateMessageLength)8910 THREADED_TEST(ExceptionCreateMessageLength) {
8911 LocalContext context;
8912 v8::HandleScope scope(context->GetIsolate());
8913
8914 // Test that the message is not truncated.
8915 TryCatch try_catch(context->GetIsolate());
8916 CompileRun(
8917 "var message = 'm';"
8918 "while (message.length < 1000) message += message;"
8919 "throw message;");
8920 CHECK(try_catch.HasCaught());
8921
8922 CHECK_LT(1000, try_catch.Message()->Get()->Length());
8923 }
8924
8925
YGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)8926 static void YGetter(Local<String> name,
8927 const v8::PropertyCallbackInfo<v8::Value>& info) {
8928 ApiTestFuzzer::Fuzz();
8929 info.GetReturnValue().Set(v8_num(10));
8930 }
8931
8932
YSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)8933 static void YSetter(Local<String> name,
8934 Local<Value> value,
8935 const v8::PropertyCallbackInfo<void>& info) {
8936 Local<Object> this_obj = Local<Object>::Cast(info.This());
8937 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8938 if (this_obj->Has(context, name).FromJust())
8939 this_obj->Delete(context, name).FromJust();
8940 CHECK(this_obj->Set(context, name, value).FromJust());
8941 }
8942
8943
THREADED_TEST(DeleteAccessor)8944 THREADED_TEST(DeleteAccessor) {
8945 v8::Isolate* isolate = CcTest::isolate();
8946 v8::HandleScope scope(isolate);
8947 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8948 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8949 LocalContext context;
8950 v8::Local<v8::Object> holder =
8951 obj->NewInstance(context.local()).ToLocalChecked();
8952 CHECK(context->Global()
8953 ->Set(context.local(), v8_str("holder"), holder)
8954 .FromJust());
8955 v8::Local<Value> result =
8956 CompileRun("holder.y = 11; holder.y = 12; holder.y");
8957 CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
8958 }
8959
8960
8961 static int trouble_nesting = 0;
TroubleCallback(const v8::FunctionCallbackInfo<v8::Value> & args)8962 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8963 ApiTestFuzzer::Fuzz();
8964 trouble_nesting++;
8965
8966 // Call a JS function that throws an uncaught exception.
8967 Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
8968 Local<v8::Object> arg_this = context->Global();
8969 Local<Value> trouble_callee =
8970 (trouble_nesting == 3)
8971 ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
8972 : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
8973 CHECK(trouble_callee->IsFunction());
8974 args.GetReturnValue().Set(Function::Cast(*trouble_callee)
8975 ->Call(context, arg_this, 0, NULL)
8976 .FromMaybe(v8::Local<v8::Value>()));
8977 }
8978
8979
8980 static int report_count = 0;
ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,v8::Local<Value>)8981 static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
8982 v8::Local<Value>) {
8983 report_count++;
8984 }
8985
8986
8987 // Counts uncaught exceptions, but other tests running in parallel
8988 // also have uncaught exceptions.
TEST(ApiUncaughtException)8989 TEST(ApiUncaughtException) {
8990 report_count = 0;
8991 LocalContext env;
8992 v8::Isolate* isolate = env->GetIsolate();
8993 v8::HandleScope scope(isolate);
8994 isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
8995
8996 Local<v8::FunctionTemplate> fun =
8997 v8::FunctionTemplate::New(isolate, TroubleCallback);
8998 v8::Local<v8::Object> global = env->Global();
8999 CHECK(global->Set(env.local(), v8_str("trouble"),
9000 fun->GetFunction(env.local()).ToLocalChecked())
9001 .FromJust());
9002
9003 CompileRun(
9004 "function trouble_callee() {"
9005 " var x = null;"
9006 " return x.foo;"
9007 "};"
9008 "function trouble_caller() {"
9009 " trouble();"
9010 "};");
9011 Local<Value> trouble =
9012 global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9013 CHECK(trouble->IsFunction());
9014 Local<Value> trouble_callee =
9015 global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9016 CHECK(trouble_callee->IsFunction());
9017 Local<Value> trouble_caller =
9018 global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9019 CHECK(trouble_caller->IsFunction());
9020 Function::Cast(*trouble_caller)
9021 ->Call(env.local(), global, 0, NULL)
9022 .FromMaybe(v8::Local<v8::Value>());
9023 CHECK_EQ(1, report_count);
9024 isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9025 }
9026
9027
9028 static const char* script_resource_name = "ExceptionInNativeScript.js";
ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,v8::Local<Value>)9029 static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9030 v8::Local<Value>) {
9031 v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9032 CHECK(!name_val.IsEmpty() && name_val->IsString());
9033 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
9034 CHECK_EQ(0, strcmp(script_resource_name, *name));
9035 v8::Local<v8::Context> context =
9036 v8::Isolate::GetCurrent()->GetCurrentContext();
9037 CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9038 v8::String::Utf8Value source_line(
9039 message->GetSourceLine(context).ToLocalChecked());
9040 CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9041 }
9042
9043
TEST(ExceptionInNativeScript)9044 TEST(ExceptionInNativeScript) {
9045 LocalContext env;
9046 v8::Isolate* isolate = env->GetIsolate();
9047 v8::HandleScope scope(isolate);
9048 isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9049
9050 Local<v8::FunctionTemplate> fun =
9051 v8::FunctionTemplate::New(isolate, TroubleCallback);
9052 v8::Local<v8::Object> global = env->Global();
9053 CHECK(global->Set(env.local(), v8_str("trouble"),
9054 fun->GetFunction(env.local()).ToLocalChecked())
9055 .FromJust());
9056
9057 CompileRunWithOrigin(
9058 "function trouble() {\n"
9059 " var o = {};\n"
9060 " new o.foo();\n"
9061 "};",
9062 script_resource_name);
9063 Local<Value> trouble =
9064 global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9065 CHECK(trouble->IsFunction());
9066 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty());
9067 isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9068 }
9069
9070
TEST(CompilationErrorUsingTryCatchHandler)9071 TEST(CompilationErrorUsingTryCatchHandler) {
9072 LocalContext env;
9073 v8::HandleScope scope(env->GetIsolate());
9074 v8::TryCatch try_catch(env->GetIsolate());
9075 v8_compile("This doesn't &*&@#$&*^ compile.");
9076 CHECK(*try_catch.Exception());
9077 CHECK(try_catch.HasCaught());
9078 }
9079
9080
TEST(TryCatchFinallyUsingTryCatchHandler)9081 TEST(TryCatchFinallyUsingTryCatchHandler) {
9082 LocalContext env;
9083 v8::HandleScope scope(env->GetIsolate());
9084 v8::TryCatch try_catch(env->GetIsolate());
9085 CompileRun("try { throw ''; } catch (e) {}");
9086 CHECK(!try_catch.HasCaught());
9087 CompileRun("try { throw ''; } finally {}");
9088 CHECK(try_catch.HasCaught());
9089 try_catch.Reset();
9090 CompileRun(
9091 "(function() {"
9092 "try { throw ''; } finally { return; }"
9093 "})()");
9094 CHECK(!try_catch.HasCaught());
9095 CompileRun(
9096 "(function()"
9097 " { try { throw ''; } finally { throw 0; }"
9098 "})()");
9099 CHECK(try_catch.HasCaught());
9100 }
9101
9102
CEvaluate(const v8::FunctionCallbackInfo<v8::Value> & args)9103 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9104 v8::HandleScope scope(args.GetIsolate());
9105 CompileRun(args[0]
9106 ->ToString(args.GetIsolate()->GetCurrentContext())
9107 .ToLocalChecked());
9108 }
9109
9110
TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler)9111 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9112 v8::Isolate* isolate = CcTest::isolate();
9113 v8::HandleScope scope(isolate);
9114 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9115 templ->Set(v8_str("CEvaluate"),
9116 v8::FunctionTemplate::New(isolate, CEvaluate));
9117 LocalContext context(0, templ);
9118 v8::TryCatch try_catch(isolate);
9119 CompileRun("try {"
9120 " CEvaluate('throw 1;');"
9121 "} finally {"
9122 "}");
9123 CHECK(try_catch.HasCaught());
9124 CHECK(!try_catch.Message().IsEmpty());
9125 String::Utf8Value exception_value(try_catch.Exception());
9126 CHECK_EQ(0, strcmp(*exception_value, "1"));
9127 try_catch.Reset();
9128 CompileRun("try {"
9129 " CEvaluate('throw 1;');"
9130 "} finally {"
9131 " throw 2;"
9132 "}");
9133 CHECK(try_catch.HasCaught());
9134 CHECK(!try_catch.Message().IsEmpty());
9135 String::Utf8Value finally_exception_value(try_catch.Exception());
9136 CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9137 }
9138
9139
9140 // For use within the TestSecurityHandler() test.
9141 static bool g_security_callback_result = false;
SecurityTestCallback(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)9142 static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9143 Local<v8::Object> accessed_object,
9144 Local<v8::Value> data) {
9145 printf("a\n");
9146 CHECK(!data.IsEmpty() && data->IsInt32());
9147 CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9148 return g_security_callback_result;
9149 }
9150
9151
9152 // SecurityHandler can't be run twice
TEST(SecurityHandler)9153 TEST(SecurityHandler) {
9154 v8::Isolate* isolate = CcTest::isolate();
9155 v8::HandleScope scope0(isolate);
9156 v8::Local<v8::ObjectTemplate> global_template =
9157 v8::ObjectTemplate::New(isolate);
9158 global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9159 // Create an environment
9160 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9161 context0->Enter();
9162
9163 v8::Local<v8::Object> global0 = context0->Global();
9164 v8::Local<Script> script0 = v8_compile("foo = 111");
9165 script0->Run(context0).ToLocalChecked();
9166 CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9167 v8::Local<Value> foo0 =
9168 global0->Get(context0, v8_str("foo")).ToLocalChecked();
9169 CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9170 v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9171 CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9172
9173 // Create another environment, should fail security checks.
9174 v8::HandleScope scope1(isolate);
9175
9176 v8::Local<Context> context1 = Context::New(isolate, NULL, global_template);
9177 context1->Enter();
9178
9179 v8::Local<v8::Object> global1 = context1->Global();
9180 global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9181 // This set will fail the security check.
9182 v8::Local<Script> script1 =
9183 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9184 CHECK(script1->Run(context1).IsEmpty());
9185 g_security_callback_result = true;
9186 // This read will pass the security check.
9187 v8::Local<Value> foo1 =
9188 global0->Get(context1, v8_str("foo")).ToLocalChecked();
9189 CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9190 // This read will pass the security check.
9191 v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9192 CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9193
9194 // Create another environment, should pass security checks.
9195 {
9196 v8::HandleScope scope2(isolate);
9197 LocalContext context2;
9198 v8::Local<v8::Object> global2 = context2->Global();
9199 CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9200 .FromJust());
9201 v8::Local<Script> script2 =
9202 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9203 script2->Run(context2.local()).ToLocalChecked();
9204 v8::Local<Value> foo2 =
9205 global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9206 CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9207 v8::Local<Value> z2 =
9208 global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9209 CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9210 }
9211
9212 context1->Exit();
9213 context0->Exit();
9214 }
9215
9216
THREADED_TEST(SecurityChecks)9217 THREADED_TEST(SecurityChecks) {
9218 LocalContext env1;
9219 v8::HandleScope handle_scope(env1->GetIsolate());
9220 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9221
9222 Local<Value> foo = v8_str("foo");
9223 Local<Value> bar = v8_str("bar");
9224
9225 // Set to the same domain.
9226 env1->SetSecurityToken(foo);
9227
9228 // Create a function in env1.
9229 CompileRun("spy=function(){return spy;}");
9230 Local<Value> spy =
9231 env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9232 CHECK(spy->IsFunction());
9233
9234 // Create another function accessing global objects.
9235 CompileRun("spy2=function(){return new this.Array();}");
9236 Local<Value> spy2 =
9237 env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9238 CHECK(spy2->IsFunction());
9239
9240 // Switch to env2 in the same domain and invoke spy on env2.
9241 {
9242 env2->SetSecurityToken(foo);
9243 // Enter env2
9244 Context::Scope scope_env2(env2);
9245 Local<Value> result = Function::Cast(*spy)
9246 ->Call(env2, env2->Global(), 0, NULL)
9247 .ToLocalChecked();
9248 CHECK(result->IsFunction());
9249 }
9250
9251 {
9252 env2->SetSecurityToken(bar);
9253 Context::Scope scope_env2(env2);
9254
9255 // Call cross_domain_call, it should throw an exception
9256 v8::TryCatch try_catch(env1->GetIsolate());
9257 CHECK(Function::Cast(*spy2)->Call(env2, env2->Global(), 0, NULL).IsEmpty());
9258 CHECK(try_catch.HasCaught());
9259 }
9260 }
9261
9262
9263 // Regression test case for issue 1183439.
THREADED_TEST(SecurityChecksForPrototypeChain)9264 THREADED_TEST(SecurityChecksForPrototypeChain) {
9265 LocalContext current;
9266 v8::HandleScope scope(current->GetIsolate());
9267 v8::Local<Context> other = Context::New(current->GetIsolate());
9268
9269 // Change context to be able to get to the Object function in the
9270 // other context without hitting the security checks.
9271 v8::Local<Value> other_object;
9272 { Context::Scope scope(other);
9273 other_object =
9274 other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9275 CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9276 }
9277
9278 CHECK(current->Global()
9279 ->Set(current.local(), v8_str("other"), other->Global())
9280 .FromJust());
9281 CHECK(v8_compile("other")
9282 ->Run(current.local())
9283 .ToLocalChecked()
9284 ->Equals(current.local(), other->Global())
9285 .FromJust());
9286
9287 // Make sure the security check fails here and we get an undefined
9288 // result instead of getting the Object function. Repeat in a loop
9289 // to make sure to exercise the IC code.
9290 v8::Local<Script> access_other0 = v8_compile("other.Object");
9291 v8::Local<Script> access_other1 = v8_compile("other[42]");
9292 for (int i = 0; i < 5; i++) {
9293 CHECK(access_other0->Run(current.local()).IsEmpty());
9294 CHECK(access_other1->Run(current.local()).IsEmpty());
9295 }
9296
9297 // Create an object that has 'other' in its prototype chain and make
9298 // sure we cannot access the Object function indirectly through
9299 // that. Repeat in a loop to make sure to exercise the IC code.
9300 v8_compile(
9301 "function F() { };"
9302 "F.prototype = other;"
9303 "var f = new F();")
9304 ->Run(current.local())
9305 .ToLocalChecked();
9306 v8::Local<Script> access_f0 = v8_compile("f.Object");
9307 v8::Local<Script> access_f1 = v8_compile("f[42]");
9308 for (int j = 0; j < 5; j++) {
9309 CHECK(access_f0->Run(current.local()).IsEmpty());
9310 CHECK(access_f1->Run(current.local()).IsEmpty());
9311 }
9312
9313 // Now it gets hairy: Set the prototype for the other global object
9314 // to be the current global object. The prototype chain for 'f' now
9315 // goes through 'other' but ends up in the current global object.
9316 { Context::Scope scope(other);
9317 CHECK(other->Global()
9318 ->Set(other, v8_str("__proto__"), current->Global())
9319 .FromJust());
9320 }
9321 // Set a named and an index property on the current global
9322 // object. To force the lookup to go through the other global object,
9323 // the properties must not exist in the other global object.
9324 CHECK(current->Global()
9325 ->Set(current.local(), v8_str("foo"), v8_num(100))
9326 .FromJust());
9327 CHECK(current->Global()
9328 ->Set(current.local(), v8_num(99), v8_num(101))
9329 .FromJust());
9330 // Try to read the properties from f and make sure that the access
9331 // gets stopped by the security checks on the other global object.
9332 Local<Script> access_f2 = v8_compile("f.foo");
9333 Local<Script> access_f3 = v8_compile("f[99]");
9334 for (int k = 0; k < 5; k++) {
9335 CHECK(access_f2->Run(current.local()).IsEmpty());
9336 CHECK(access_f3->Run(current.local()).IsEmpty());
9337 }
9338 }
9339
9340
9341 static bool security_check_with_gc_called;
9342
SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)9343 static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9344 Local<v8::Object> accessed_object,
9345 Local<v8::Value> data) {
9346 CcTest::heap()->CollectAllGarbage();
9347 security_check_with_gc_called = true;
9348 return true;
9349 }
9350
9351
TEST(SecurityTestGCAllowed)9352 TEST(SecurityTestGCAllowed) {
9353 v8::Isolate* isolate = CcTest::isolate();
9354 v8::HandleScope handle_scope(isolate);
9355 v8::Local<v8::ObjectTemplate> object_template =
9356 v8::ObjectTemplate::New(isolate);
9357 object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9358
9359 v8::Local<Context> context = Context::New(isolate);
9360 v8::Context::Scope context_scope(context);
9361
9362 CHECK(context->Global()
9363 ->Set(context, v8_str("obj"),
9364 object_template->NewInstance(context).ToLocalChecked())
9365 .FromJust());
9366
9367 security_check_with_gc_called = false;
9368 CompileRun("obj[0] = new String(1002);");
9369 CHECK(security_check_with_gc_called);
9370
9371 security_check_with_gc_called = false;
9372 CHECK(CompileRun("obj[0]")
9373 ->ToString(context)
9374 .ToLocalChecked()
9375 ->Equals(context, v8_str("1002"))
9376 .FromJust());
9377 CHECK(security_check_with_gc_called);
9378 }
9379
9380
THREADED_TEST(CrossDomainDelete)9381 THREADED_TEST(CrossDomainDelete) {
9382 LocalContext env1;
9383 v8::HandleScope handle_scope(env1->GetIsolate());
9384 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9385
9386 Local<Value> foo = v8_str("foo");
9387 Local<Value> bar = v8_str("bar");
9388
9389 // Set to the same domain.
9390 env1->SetSecurityToken(foo);
9391 env2->SetSecurityToken(foo);
9392
9393 CHECK(
9394 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9395 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9396
9397 // Change env2 to a different domain and delete env1.prop.
9398 env2->SetSecurityToken(bar);
9399 {
9400 Context::Scope scope_env2(env2);
9401 Local<Value> result =
9402 CompileRun("delete env1.prop");
9403 CHECK(result.IsEmpty());
9404 }
9405
9406 // Check that env1.prop still exists.
9407 Local<Value> v =
9408 env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9409 CHECK(v->IsNumber());
9410 CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9411 }
9412
9413
THREADED_TEST(CrossDomainPropertyIsEnumerable)9414 THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9415 LocalContext env1;
9416 v8::HandleScope handle_scope(env1->GetIsolate());
9417 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9418
9419 Local<Value> foo = v8_str("foo");
9420 Local<Value> bar = v8_str("bar");
9421
9422 // Set to the same domain.
9423 env1->SetSecurityToken(foo);
9424 env2->SetSecurityToken(foo);
9425
9426 CHECK(
9427 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9428 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9429
9430 // env1.prop is enumerable in env2.
9431 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9432 {
9433 Context::Scope scope_env2(env2);
9434 Local<Value> result = CompileRun(test);
9435 CHECK(result->IsTrue());
9436 }
9437
9438 // Change env2 to a different domain and test again.
9439 env2->SetSecurityToken(bar);
9440 {
9441 Context::Scope scope_env2(env2);
9442 Local<Value> result = CompileRun(test);
9443 CHECK(result.IsEmpty());
9444 }
9445 }
9446
9447
THREADED_TEST(CrossDomainFor)9448 THREADED_TEST(CrossDomainFor) {
9449 LocalContext env1;
9450 v8::HandleScope handle_scope(env1->GetIsolate());
9451 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9452
9453 Local<Value> foo = v8_str("foo");
9454 Local<Value> bar = v8_str("bar");
9455
9456 // Set to the same domain.
9457 env1->SetSecurityToken(foo);
9458 env2->SetSecurityToken(foo);
9459
9460 CHECK(
9461 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9462 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9463
9464 // Change env2 to a different domain and set env1's global object
9465 // as the __proto__ of an object in env2 and enumerate properties
9466 // in for-in. It shouldn't enumerate properties on env1's global
9467 // object. It shouldn't throw either, just silently ignore them.
9468 env2->SetSecurityToken(bar);
9469 {
9470 Context::Scope scope_env2(env2);
9471 Local<Value> result = CompileRun(
9472 "(function() {"
9473 " try {"
9474 " for (var p in env1) {"
9475 " if (p == 'prop') return false;"
9476 " }"
9477 " return true;"
9478 " } catch (e) {"
9479 " return false;"
9480 " }"
9481 "})()");
9482 CHECK(result->IsTrue());
9483 }
9484 }
9485
9486
THREADED_TEST(CrossDomainForInOnPrototype)9487 THREADED_TEST(CrossDomainForInOnPrototype) {
9488 LocalContext env1;
9489 v8::HandleScope handle_scope(env1->GetIsolate());
9490 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9491
9492 Local<Value> foo = v8_str("foo");
9493 Local<Value> bar = v8_str("bar");
9494
9495 // Set to the same domain.
9496 env1->SetSecurityToken(foo);
9497 env2->SetSecurityToken(foo);
9498
9499 CHECK(
9500 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9501 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9502
9503 // Change env2 to a different domain and set env1's global object
9504 // as the __proto__ of an object in env2 and enumerate properties
9505 // in for-in. It shouldn't enumerate properties on env1's global
9506 // object.
9507 env2->SetSecurityToken(bar);
9508 {
9509 Context::Scope scope_env2(env2);
9510 Local<Value> result = CompileRun(
9511 "(function() {"
9512 " var obj = { '__proto__': env1 };"
9513 " try {"
9514 " for (var p in obj) {"
9515 " if (p == 'prop') return false;"
9516 " }"
9517 " return true;"
9518 " } catch (e) {"
9519 " return false;"
9520 " }"
9521 "})()");
9522 CHECK(result->IsTrue());
9523 }
9524 }
9525
9526
TEST(ContextDetachGlobal)9527 TEST(ContextDetachGlobal) {
9528 LocalContext env1;
9529 v8::HandleScope handle_scope(env1->GetIsolate());
9530 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9531
9532
9533 Local<Value> foo = v8_str("foo");
9534
9535 // Set to the same domain.
9536 env1->SetSecurityToken(foo);
9537 env2->SetSecurityToken(foo);
9538
9539 // Enter env2
9540 env2->Enter();
9541
9542 // Create a function in env2 and add a reference to it in env1.
9543 Local<v8::Object> global2 = env2->Global();
9544 CHECK(global2->Set(env2, v8_str("prop"),
9545 v8::Integer::New(env2->GetIsolate(), 1))
9546 .FromJust());
9547 CompileRun("function getProp() {return prop;}");
9548
9549 CHECK(env1->Global()
9550 ->Set(env1.local(), v8_str("getProp"),
9551 global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9552 .FromJust());
9553
9554 // Detach env2's global, and reuse the global object of env2
9555 env2->Exit();
9556 env2->DetachGlobal();
9557
9558 v8::Local<Context> env3 = Context::New(
9559 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2);
9560 env3->SetSecurityToken(v8_str("bar"));
9561
9562 env3->Enter();
9563 Local<v8::Object> global3 = env3->Global();
9564 CHECK(global2->Equals(env3, global3).FromJust());
9565 CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9566 CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9567 CHECK(global3->Set(env3, v8_str("prop"),
9568 v8::Integer::New(env3->GetIsolate(), -1))
9569 .FromJust());
9570 CHECK(global3->Set(env3, v8_str("prop2"),
9571 v8::Integer::New(env3->GetIsolate(), 2))
9572 .FromJust());
9573 env3->Exit();
9574
9575 // Call getProp in env1, and it should return the value 1
9576 {
9577 Local<v8::Object> global1 = env1->Global();
9578 Local<Value> get_prop =
9579 global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9580 CHECK(get_prop->IsFunction());
9581 v8::TryCatch try_catch(env1->GetIsolate());
9582 Local<Value> r = Function::Cast(*get_prop)
9583 ->Call(env1.local(), global1, 0, NULL)
9584 .ToLocalChecked();
9585 CHECK(!try_catch.HasCaught());
9586 CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9587 }
9588
9589 // Check that env3 is not accessible from env1
9590 {
9591 v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9592 CHECK(r.IsEmpty());
9593 }
9594 }
9595
9596
TEST(DetachGlobal)9597 TEST(DetachGlobal) {
9598 LocalContext env1;
9599 v8::HandleScope scope(env1->GetIsolate());
9600
9601 // Create second environment.
9602 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9603
9604 Local<Value> foo = v8_str("foo");
9605
9606 // Set same security token for env1 and env2.
9607 env1->SetSecurityToken(foo);
9608 env2->SetSecurityToken(foo);
9609
9610 // Create a property on the global object in env2.
9611 {
9612 v8::Context::Scope scope(env2);
9613 CHECK(env2->Global()
9614 ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9615 .FromJust());
9616 }
9617
9618 // Create a reference to env2 global from env1 global.
9619 CHECK(env1->Global()
9620 ->Set(env1.local(), v8_str("other"), env2->Global())
9621 .FromJust());
9622
9623 // Check that we have access to other.p in env2 from env1.
9624 Local<Value> result = CompileRun("other.p");
9625 CHECK(result->IsInt32());
9626 CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9627
9628 // Hold on to global from env2 and detach global from env2.
9629 Local<v8::Object> global2 = env2->Global();
9630 env2->DetachGlobal();
9631
9632 // Check that the global has been detached. No other.p property can
9633 // be found.
9634 result = CompileRun("other.p");
9635 CHECK(result.IsEmpty());
9636
9637 // Reuse global2 for env3.
9638 v8::Local<Context> env3 = Context::New(
9639 env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(), global2);
9640 CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9641
9642 // Start by using the same security token for env3 as for env1 and env2.
9643 env3->SetSecurityToken(foo);
9644
9645 // Create a property on the global object in env3.
9646 {
9647 v8::Context::Scope scope(env3);
9648 CHECK(env3->Global()
9649 ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9650 .FromJust());
9651 }
9652
9653 // Check that other.p is now the property in env3 and that we have access.
9654 result = CompileRun("other.p");
9655 CHECK(result->IsInt32());
9656 CHECK_EQ(24, result->Int32Value(env3).FromJust());
9657
9658 // Change security token for env3 to something different from env1 and env2.
9659 env3->SetSecurityToken(v8_str("bar"));
9660
9661 // Check that we do not have access to other.p in env1. |other| is now
9662 // the global object for env3 which has a different security token,
9663 // so access should be blocked.
9664 result = CompileRun("other.p");
9665 CHECK(result.IsEmpty());
9666 }
9667
9668
GetThisX(const v8::FunctionCallbackInfo<v8::Value> & info)9669 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9670 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9671 info.GetReturnValue().Set(
9672 context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9673 }
9674
9675
TEST(DetachedAccesses)9676 TEST(DetachedAccesses) {
9677 LocalContext env1;
9678 v8::HandleScope scope(env1->GetIsolate());
9679
9680 // Create second environment.
9681 Local<ObjectTemplate> inner_global_template =
9682 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9683 inner_global_template ->SetAccessorProperty(
9684 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9685 v8::Local<Context> env2 =
9686 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9687
9688 Local<Value> foo = v8_str("foo");
9689
9690 // Set same security token for env1 and env2.
9691 env1->SetSecurityToken(foo);
9692 env2->SetSecurityToken(foo);
9693
9694 CHECK(env1->Global()
9695 ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
9696 .FromJust());
9697
9698 {
9699 v8::Context::Scope scope(env2);
9700 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
9701 CompileRun(
9702 "function bound_x() { return x; }"
9703 "function get_x() { return this.x; }"
9704 "function get_x_w() { return (function() {return this.x;})(); }");
9705 CHECK(env1->Global()
9706 ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
9707 .FromJust());
9708 CHECK(env1->Global()
9709 ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
9710 .FromJust());
9711 CHECK(env1->Global()
9712 ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
9713 .FromJust());
9714 env1->Global()
9715 ->Set(env1.local(), v8_str("this_x"),
9716 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
9717 .FromJust();
9718 }
9719
9720 Local<Object> env2_global = env2->Global();
9721 env2->DetachGlobal();
9722
9723 Local<Value> result;
9724 result = CompileRun("bound_x()");
9725 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
9726 result = CompileRun("get_x()");
9727 CHECK(result.IsEmpty());
9728 result = CompileRun("get_x_w()");
9729 CHECK(result.IsEmpty());
9730 result = CompileRun("this_x()");
9731 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
9732
9733 // Reattach env2's proxy
9734 env2 = Context::New(env1->GetIsolate(), 0, v8::Local<v8::ObjectTemplate>(),
9735 env2_global);
9736 env2->SetSecurityToken(foo);
9737 {
9738 v8::Context::Scope scope(env2);
9739 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
9740 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9741 result = CompileRun(
9742 "results = [];"
9743 "for (var i = 0; i < 4; i++ ) {"
9744 " results.push(env1.bound_x());"
9745 " results.push(env1.get_x());"
9746 " results.push(env1.get_x_w());"
9747 " results.push(env1.this_x());"
9748 "}"
9749 "results");
9750 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9751 CHECK_EQ(16u, results->Length());
9752 for (int i = 0; i < 16; i += 4) {
9753 CHECK(v8_str("env2_x")
9754 ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
9755 .FromJust());
9756 CHECK(v8_str("env1_x")
9757 ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
9758 .FromJust());
9759 CHECK(v8_str("env3_x")
9760 ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
9761 .FromJust());
9762 CHECK(v8_str("env2_x")
9763 ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
9764 .FromJust());
9765 }
9766 }
9767
9768 result = CompileRun(
9769 "results = [];"
9770 "for (var i = 0; i < 4; i++ ) {"
9771 " results.push(bound_x());"
9772 " results.push(get_x());"
9773 " results.push(get_x_w());"
9774 " results.push(this_x());"
9775 "}"
9776 "results");
9777 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9778 CHECK_EQ(16u, results->Length());
9779 for (int i = 0; i < 16; i += 4) {
9780 CHECK(v8_str("env2_x")
9781 ->Equals(env1.local(),
9782 results->Get(env1.local(), i + 0).ToLocalChecked())
9783 .FromJust());
9784 CHECK(v8_str("env3_x")
9785 ->Equals(env1.local(),
9786 results->Get(env1.local(), i + 1).ToLocalChecked())
9787 .FromJust());
9788 CHECK(v8_str("env3_x")
9789 ->Equals(env1.local(),
9790 results->Get(env1.local(), i + 2).ToLocalChecked())
9791 .FromJust());
9792 CHECK(v8_str("env2_x")
9793 ->Equals(env1.local(),
9794 results->Get(env1.local(), i + 3).ToLocalChecked())
9795 .FromJust());
9796 }
9797
9798 result = CompileRun(
9799 "results = [];"
9800 "for (var i = 0; i < 4; i++ ) {"
9801 " results.push(this.bound_x());"
9802 " results.push(this.get_x());"
9803 " results.push(this.get_x_w());"
9804 " results.push(this.this_x());"
9805 "}"
9806 "results");
9807 results = Local<v8::Array>::Cast(result);
9808 CHECK_EQ(16u, results->Length());
9809 for (int i = 0; i < 16; i += 4) {
9810 CHECK(v8_str("env2_x")
9811 ->Equals(env1.local(),
9812 results->Get(env1.local(), i + 0).ToLocalChecked())
9813 .FromJust());
9814 CHECK(v8_str("env1_x")
9815 ->Equals(env1.local(),
9816 results->Get(env1.local(), i + 1).ToLocalChecked())
9817 .FromJust());
9818 CHECK(v8_str("env3_x")
9819 ->Equals(env1.local(),
9820 results->Get(env1.local(), i + 2).ToLocalChecked())
9821 .FromJust());
9822 CHECK(v8_str("env2_x")
9823 ->Equals(env1.local(),
9824 results->Get(env1.local(), i + 3).ToLocalChecked())
9825 .FromJust());
9826 }
9827 }
9828
9829
9830 static bool allowed_access = false;
AccessBlocker(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)9831 static bool AccessBlocker(Local<v8::Context> accessing_context,
9832 Local<v8::Object> accessed_object,
9833 Local<v8::Value> data) {
9834 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
9835 return context->Global()->Equals(context, accessed_object).FromJust() ||
9836 allowed_access;
9837 }
9838
9839
9840 static int g_echo_value = -1;
9841
9842
EchoGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)9843 static void EchoGetter(
9844 Local<String> name,
9845 const v8::PropertyCallbackInfo<v8::Value>& info) {
9846 info.GetReturnValue().Set(v8_num(g_echo_value));
9847 }
9848
9849
EchoSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & args)9850 static void EchoSetter(Local<String> name, Local<Value> value,
9851 const v8::PropertyCallbackInfo<void>& args) {
9852 if (value->IsNumber())
9853 g_echo_value =
9854 value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
9855 }
9856
9857
UnreachableGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)9858 static void UnreachableGetter(
9859 Local<String> name,
9860 const v8::PropertyCallbackInfo<v8::Value>& info) {
9861 CHECK(false); // This function should not be called..
9862 }
9863
9864
UnreachableSetter(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> &)9865 static void UnreachableSetter(Local<String>,
9866 Local<Value>,
9867 const v8::PropertyCallbackInfo<void>&) {
9868 CHECK(false); // This function should nto be called.
9869 }
9870
9871
UnreachableFunction(const v8::FunctionCallbackInfo<v8::Value> & info)9872 static void UnreachableFunction(
9873 const v8::FunctionCallbackInfo<v8::Value>& info) {
9874 CHECK(false); // This function should not be called..
9875 }
9876
9877
TEST(AccessControl)9878 TEST(AccessControl) {
9879 v8::Isolate* isolate = CcTest::isolate();
9880 v8::HandleScope handle_scope(isolate);
9881 v8::Local<v8::ObjectTemplate> global_template =
9882 v8::ObjectTemplate::New(isolate);
9883
9884 global_template->SetAccessCheckCallback(AccessBlocker);
9885
9886 // Add an accessor accessible by cross-domain JS code.
9887 global_template->SetAccessor(
9888 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
9889 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9890
9891
9892 // Add an accessor that is not accessible by cross-domain JS code.
9893 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
9894 UnreachableSetter, v8::Local<Value>(),
9895 v8::DEFAULT);
9896
9897 global_template->SetAccessorProperty(
9898 v8_str("blocked_js_prop"),
9899 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9900 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9901 v8::None,
9902 v8::DEFAULT);
9903
9904 // Create an environment
9905 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9906 context0->Enter();
9907
9908 v8::Local<v8::Object> global0 = context0->Global();
9909
9910 // Define a property with JS getter and setter.
9911 CompileRun(
9912 "function getter() { return 'getter'; };\n"
9913 "function setter() { return 'setter'; }\n"
9914 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9915
9916 Local<Value> getter =
9917 global0->Get(context0, v8_str("getter")).ToLocalChecked();
9918 Local<Value> setter =
9919 global0->Get(context0, v8_str("setter")).ToLocalChecked();
9920
9921 // And define normal element.
9922 CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
9923
9924 // Define an element with JS getter and setter.
9925 CompileRun(
9926 "function el_getter() { return 'el_getter'; };\n"
9927 "function el_setter() { return 'el_setter'; };\n"
9928 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9929
9930 Local<Value> el_getter =
9931 global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
9932 Local<Value> el_setter =
9933 global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
9934
9935 v8::HandleScope scope1(isolate);
9936
9937 v8::Local<Context> context1 = Context::New(isolate);
9938 context1->Enter();
9939
9940 v8::Local<v8::Object> global1 = context1->Global();
9941 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
9942
9943 // Access blocked property.
9944 CompileRun("other.blocked_prop = 1");
9945
9946 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9947 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9948 .IsEmpty());
9949 CHECK(
9950 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9951
9952 // Access blocked element.
9953 CHECK(CompileRun("other[239] = 1").IsEmpty());
9954
9955 CHECK(CompileRun("other[239]").IsEmpty());
9956 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9957 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9958
9959 allowed_access = true;
9960 // Now we can enumerate the property.
9961 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9962 allowed_access = false;
9963
9964 // Access a property with JS accessor.
9965 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9966
9967 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9968 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9969 .IsEmpty());
9970
9971 allowed_access = true;
9972
9973 ExpectString("other.js_accessor_p", "getter");
9974 ExpectObject(
9975 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9976 ExpectObject(
9977 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9978 ExpectUndefined(
9979 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9980
9981 allowed_access = false;
9982
9983 // Access an element with JS accessor.
9984 CHECK(CompileRun("other[42] = 2").IsEmpty());
9985
9986 CHECK(CompileRun("other[42]").IsEmpty());
9987 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9988
9989 allowed_access = true;
9990
9991 ExpectString("other[42]", "el_getter");
9992 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9993 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9994 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9995
9996 allowed_access = false;
9997
9998 v8::Local<Value> value;
9999
10000 // Access accessible property
10001 value = CompileRun("other.accessible_prop = 3");
10002 CHECK(value->IsNumber());
10003 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10004 CHECK_EQ(3, g_echo_value);
10005
10006 value = CompileRun("other.accessible_prop");
10007 CHECK(value->IsNumber());
10008 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10009
10010 value = CompileRun(
10011 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10012 CHECK(value->IsNumber());
10013 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10014
10015 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10016 CHECK(value->IsTrue());
10017
10018 // Enumeration doesn't enumerate accessors from inaccessible objects in
10019 // the prototype chain even if the accessors are in themselves accessible.
10020 // Enumeration doesn't throw, it silently ignores what it can't access.
10021 value = CompileRun(
10022 "(function() {"
10023 " var obj = { '__proto__': other };"
10024 " try {"
10025 " for (var p in obj) {"
10026 " if (p == 'accessible_prop' ||"
10027 " p == 'blocked_js_prop' ||"
10028 " p == 'blocked_js_prop') {"
10029 " return false;"
10030 " }"
10031 " }"
10032 " return true;"
10033 " } catch (e) {"
10034 " return false;"
10035 " }"
10036 "})()");
10037 CHECK(value->IsTrue());
10038
10039 // Test that preventExtensions fails on a non-accessible object even if that
10040 // object is already non-extensible.
10041 CHECK(global1->Set(context1, v8_str("checked_object"),
10042 global_template->NewInstance(context1).ToLocalChecked())
10043 .FromJust());
10044 allowed_access = true;
10045 CompileRun("Object.preventExtensions(checked_object)");
10046 ExpectFalse("Object.isExtensible(checked_object)");
10047 allowed_access = false;
10048 CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10049
10050 context1->Exit();
10051 context0->Exit();
10052 }
10053
10054
TEST(AccessControlES5)10055 TEST(AccessControlES5) {
10056 v8::Isolate* isolate = CcTest::isolate();
10057 v8::HandleScope handle_scope(isolate);
10058 v8::Local<v8::ObjectTemplate> global_template =
10059 v8::ObjectTemplate::New(isolate);
10060
10061 global_template->SetAccessCheckCallback(AccessBlocker);
10062
10063 // Add accessible accessor.
10064 global_template->SetAccessor(
10065 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10066 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10067
10068
10069 // Add an accessor that is not accessible by cross-domain JS code.
10070 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10071 UnreachableSetter, v8::Local<Value>(),
10072 v8::DEFAULT);
10073
10074 // Create an environment
10075 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10076 context0->Enter();
10077
10078 v8::Local<v8::Object> global0 = context0->Global();
10079
10080 v8::Local<Context> context1 = Context::New(isolate);
10081 context1->Enter();
10082 v8::Local<v8::Object> global1 = context1->Global();
10083 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10084
10085 // Regression test for issue 1154.
10086 CHECK(CompileRun("Object.keys(other).length == 1")
10087 ->BooleanValue(context1)
10088 .FromJust());
10089 CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10090 ->BooleanValue(context1)
10091 .FromJust());
10092 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10093
10094 // Regression test for issue 1027.
10095 CompileRun("Object.defineProperty(\n"
10096 " other, 'blocked_prop', {configurable: false})");
10097 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10098 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10099 .IsEmpty());
10100
10101 // Regression test for issue 1171.
10102 ExpectTrue("Object.isExtensible(other)");
10103 CompileRun("Object.preventExtensions(other)");
10104 ExpectTrue("Object.isExtensible(other)");
10105
10106 // Object.seal and Object.freeze.
10107 CompileRun("Object.freeze(other)");
10108 ExpectTrue("Object.isExtensible(other)");
10109
10110 CompileRun("Object.seal(other)");
10111 ExpectTrue("Object.isExtensible(other)");
10112
10113 // Regression test for issue 1250.
10114 // Make sure that we can set the accessible accessors value using normal
10115 // assignment.
10116 CompileRun("other.accessible_prop = 42");
10117 CHECK_EQ(42, g_echo_value);
10118
10119 // [[DefineOwnProperty]] always throws for access-checked objects.
10120 CHECK(
10121 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10122 .IsEmpty());
10123 CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10124 CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10125 }
10126
AccessAlwaysBlocked(Local<v8::Context> accessing_context,Local<v8::Object> global,Local<v8::Value> data)10127 static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10128 Local<v8::Object> global,
10129 Local<v8::Value> data) {
10130 i::PrintF("Access blocked.\n");
10131 return false;
10132 }
10133
10134
THREADED_TEST(AccessControlGetOwnPropertyNames)10135 THREADED_TEST(AccessControlGetOwnPropertyNames) {
10136 v8::Isolate* isolate = CcTest::isolate();
10137 v8::HandleScope handle_scope(isolate);
10138 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10139
10140 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10141 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10142
10143 // Add an accessor accessible by cross-domain JS code.
10144 obj_template->SetAccessor(
10145 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10146 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10147
10148 // Create an environment
10149 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
10150 context0->Enter();
10151
10152 v8::Local<v8::Object> global0 = context0->Global();
10153
10154 v8::HandleScope scope1(CcTest::isolate());
10155
10156 v8::Local<Context> context1 = Context::New(isolate);
10157 context1->Enter();
10158
10159 v8::Local<v8::Object> global1 = context1->Global();
10160 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10161 CHECK(global1->Set(context1, v8_str("object"),
10162 obj_template->NewInstance(context1).ToLocalChecked())
10163 .FromJust());
10164
10165 v8::Local<Value> value;
10166
10167 // Attempt to get the property names of the other global object and
10168 // of an object that requires access checks. Accessing the other
10169 // global object should be blocked by access checks on the global
10170 // proxy object. Accessing the object that requires access checks
10171 // is blocked by the access checks on the object itself.
10172 value = CompileRun(
10173 "var names = Object.getOwnPropertyNames(other);"
10174 "names.length == 1 && names[0] == 'accessible_prop';");
10175 CHECK(value->BooleanValue(context1).FromJust());
10176
10177 value = CompileRun(
10178 "var names = Object.getOwnPropertyNames(object);"
10179 "names.length == 1 && names[0] == 'accessible_prop';");
10180 CHECK(value->BooleanValue(context1).FromJust());
10181
10182 context1->Exit();
10183 context0->Exit();
10184 }
10185
10186
TEST(Regress470113)10187 TEST(Regress470113) {
10188 v8::Isolate* isolate = CcTest::isolate();
10189 v8::HandleScope handle_scope(isolate);
10190 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10191 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10192 LocalContext env;
10193 CHECK(env->Global()
10194 ->Set(env.local(), v8_str("prohibited"),
10195 obj_template->NewInstance(env.local()).ToLocalChecked())
10196 .FromJust());
10197
10198 {
10199 v8::TryCatch try_catch(isolate);
10200 CompileRun(
10201 "'use strict';\n"
10202 "class C extends Object {\n"
10203 " m() { super.powned = 'Powned!'; }\n"
10204 "}\n"
10205 "let c = new C();\n"
10206 "c.m.call(prohibited)");
10207
10208 CHECK(try_catch.HasCaught());
10209 }
10210 }
10211
10212
ConstTenGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)10213 static void ConstTenGetter(Local<String> name,
10214 const v8::PropertyCallbackInfo<v8::Value>& info) {
10215 info.GetReturnValue().Set(v8_num(10));
10216 }
10217
10218
THREADED_TEST(CrossDomainAccessors)10219 THREADED_TEST(CrossDomainAccessors) {
10220 v8::Isolate* isolate = CcTest::isolate();
10221 v8::HandleScope handle_scope(isolate);
10222
10223 v8::Local<v8::FunctionTemplate> func_template =
10224 v8::FunctionTemplate::New(isolate);
10225
10226 v8::Local<v8::ObjectTemplate> global_template =
10227 func_template->InstanceTemplate();
10228
10229 v8::Local<v8::ObjectTemplate> proto_template =
10230 func_template->PrototypeTemplate();
10231
10232 // Add an accessor to proto that's accessible by cross-domain JS code.
10233 proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, 0,
10234 v8::Local<Value>(), v8::ALL_CAN_READ);
10235
10236 // Add an accessor that is not accessible by cross-domain JS code.
10237 global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter, 0,
10238 v8::Local<Value>(), v8::DEFAULT);
10239
10240 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10241 context0->Enter();
10242
10243 Local<v8::Object> global = context0->Global();
10244 // Add a normal property that shadows 'accessible'
10245 CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10246
10247 // Enter a new context.
10248 v8::HandleScope scope1(CcTest::isolate());
10249 v8::Local<Context> context1 = Context::New(isolate);
10250 context1->Enter();
10251
10252 v8::Local<v8::Object> global1 = context1->Global();
10253 CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10254
10255 // Should return 10, instead of 11
10256 v8::Local<Value> value =
10257 v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10258 CHECK(value->IsNumber());
10259 CHECK_EQ(10, value->Int32Value(context1).FromJust());
10260
10261 v8::MaybeLocal<v8::Value> maybe_value =
10262 v8_compile("other.unreachable")->Run(context1);
10263 CHECK(maybe_value.IsEmpty());
10264
10265 context1->Exit();
10266 context0->Exit();
10267 }
10268
10269
10270 static int access_count = 0;
10271
AccessCounter(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object,Local<v8::Value> data)10272 static bool AccessCounter(Local<v8::Context> accessing_context,
10273 Local<v8::Object> accessed_object,
10274 Local<v8::Value> data) {
10275 access_count++;
10276 return true;
10277 }
10278
10279
10280 // This one is too easily disturbed by other tests.
TEST(AccessControlIC)10281 TEST(AccessControlIC) {
10282 access_count = 0;
10283
10284 v8::Isolate* isolate = CcTest::isolate();
10285 v8::HandleScope handle_scope(isolate);
10286
10287 // Create an environment.
10288 v8::Local<Context> context0 = Context::New(isolate);
10289 context0->Enter();
10290
10291 // Create an object that requires access-check functions to be
10292 // called for cross-domain access.
10293 v8::Local<v8::ObjectTemplate> object_template =
10294 v8::ObjectTemplate::New(isolate);
10295 object_template->SetAccessCheckCallback(AccessCounter);
10296 Local<v8::Object> object =
10297 object_template->NewInstance(context0).ToLocalChecked();
10298
10299 v8::HandleScope scope1(isolate);
10300
10301 // Create another environment.
10302 v8::Local<Context> context1 = Context::New(isolate);
10303 context1->Enter();
10304
10305 // Make easy access to the object from the other environment.
10306 v8::Local<v8::Object> global1 = context1->Global();
10307 CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10308
10309 v8::Local<Value> value;
10310
10311 // Check that the named access-control function is called every time.
10312 CompileRun("function testProp(obj) {"
10313 " for (var i = 0; i < 10; i++) obj.prop = 1;"
10314 " for (var j = 0; j < 10; j++) obj.prop;"
10315 " return obj.prop"
10316 "}");
10317 value = CompileRun("testProp(obj)");
10318 CHECK(value->IsNumber());
10319 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10320 CHECK_EQ(21, access_count);
10321
10322 // Check that the named access-control function is called every time.
10323 CompileRun("var p = 'prop';"
10324 "function testKeyed(obj) {"
10325 " for (var i = 0; i < 10; i++) obj[p] = 1;"
10326 " for (var j = 0; j < 10; j++) obj[p];"
10327 " return obj[p];"
10328 "}");
10329 // Use obj which requires access checks. No inline caching is used
10330 // in that case.
10331 value = CompileRun("testKeyed(obj)");
10332 CHECK(value->IsNumber());
10333 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10334 CHECK_EQ(42, access_count);
10335 // Force the inline caches into generic state and try again.
10336 CompileRun("testKeyed({ a: 0 })");
10337 CompileRun("testKeyed({ b: 0 })");
10338 value = CompileRun("testKeyed(obj)");
10339 CHECK(value->IsNumber());
10340 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10341 CHECK_EQ(63, access_count);
10342
10343 // Check that the indexed access-control function is called every time.
10344 access_count = 0;
10345
10346 CompileRun("function testIndexed(obj) {"
10347 " for (var i = 0; i < 10; i++) obj[0] = 1;"
10348 " for (var j = 0; j < 10; j++) obj[0];"
10349 " return obj[0]"
10350 "}");
10351 value = CompileRun("testIndexed(obj)");
10352 CHECK(value->IsNumber());
10353 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10354 CHECK_EQ(21, access_count);
10355 // Force the inline caches into generic state.
10356 CompileRun("testIndexed(new Array(1))");
10357 // Test that the indexed access check is called.
10358 value = CompileRun("testIndexed(obj)");
10359 CHECK(value->IsNumber());
10360 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10361 CHECK_EQ(42, access_count);
10362
10363 access_count = 0;
10364 // Check that the named access check is called when invoking
10365 // functions on an object that requires access checks.
10366 CompileRun("obj.f = function() {}");
10367 CompileRun("function testCallNormal(obj) {"
10368 " for (var i = 0; i < 10; i++) obj.f();"
10369 "}");
10370 CompileRun("testCallNormal(obj)");
10371 printf("%i\n", access_count);
10372 CHECK_EQ(11, access_count);
10373
10374 // Force obj into slow case.
10375 value = CompileRun("delete obj.prop");
10376 CHECK(value->BooleanValue(context1).FromJust());
10377 // Force inline caches into dictionary probing mode.
10378 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10379 // Test that the named access check is called.
10380 value = CompileRun("testProp(obj);");
10381 CHECK(value->IsNumber());
10382 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10383 CHECK_EQ(33, access_count);
10384
10385 // Force the call inline cache into dictionary probing mode.
10386 CompileRun("o.f = function() {}; testCallNormal(o)");
10387 // Test that the named access check is still called for each
10388 // invocation of the function.
10389 value = CompileRun("testCallNormal(obj)");
10390 CHECK_EQ(43, access_count);
10391
10392 context1->Exit();
10393 context0->Exit();
10394 }
10395
10396
THREADED_TEST(Version)10397 THREADED_TEST(Version) { v8::V8::GetVersion(); }
10398
10399
InstanceFunctionCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10400 static void InstanceFunctionCallback(
10401 const v8::FunctionCallbackInfo<v8::Value>& args) {
10402 ApiTestFuzzer::Fuzz();
10403 args.GetReturnValue().Set(v8_num(12));
10404 }
10405
10406
THREADED_TEST(InstanceProperties)10407 THREADED_TEST(InstanceProperties) {
10408 LocalContext context;
10409 v8::Isolate* isolate = context->GetIsolate();
10410 v8::HandleScope handle_scope(isolate);
10411
10412 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10413 Local<ObjectTemplate> instance = t->InstanceTemplate();
10414
10415 instance->Set(v8_str("x"), v8_num(42));
10416 instance->Set(v8_str("f"),
10417 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10418
10419 Local<Value> o = t->GetFunction(context.local())
10420 .ToLocalChecked()
10421 ->NewInstance(context.local())
10422 .ToLocalChecked();
10423
10424 CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10425 Local<Value> value = CompileRun("i.x");
10426 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10427
10428 value = CompileRun("i.f()");
10429 CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10430 }
10431
10432
GlobalObjectInstancePropertiesGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> &)10433 static void GlobalObjectInstancePropertiesGet(
10434 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10435 ApiTestFuzzer::Fuzz();
10436 }
10437
10438
THREADED_TEST(GlobalObjectInstanceProperties)10439 THREADED_TEST(GlobalObjectInstanceProperties) {
10440 v8::Isolate* isolate = CcTest::isolate();
10441 v8::HandleScope handle_scope(isolate);
10442
10443 Local<Value> global_object;
10444
10445 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10446 t->InstanceTemplate()->SetHandler(
10447 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10448 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10449 instance_template->Set(v8_str("x"), v8_num(42));
10450 instance_template->Set(v8_str("f"),
10451 v8::FunctionTemplate::New(isolate,
10452 InstanceFunctionCallback));
10453
10454 // The script to check how Crankshaft compiles missing global function
10455 // invocations. function g is not defined and should throw on call.
10456 const char* script =
10457 "function wrapper(call) {"
10458 " var x = 0, y = 1;"
10459 " for (var i = 0; i < 1000; i++) {"
10460 " x += i * 100;"
10461 " y += i * 100;"
10462 " }"
10463 " if (call) g();"
10464 "}"
10465 "for (var i = 0; i < 17; i++) wrapper(false);"
10466 "var thrown = 0;"
10467 "try { wrapper(true); } catch (e) { thrown = 1; };"
10468 "thrown";
10469
10470 {
10471 LocalContext env(NULL, instance_template);
10472 // Hold on to the global object so it can be used again in another
10473 // environment initialization.
10474 global_object = env->Global();
10475
10476 Local<Value> value = CompileRun("x");
10477 CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10478 value = CompileRun("f()");
10479 CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10480 value = CompileRun(script);
10481 CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10482 }
10483
10484 {
10485 // Create new environment reusing the global object.
10486 LocalContext env(NULL, instance_template, global_object);
10487 Local<Value> value = CompileRun("x");
10488 CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10489 value = CompileRun("f()");
10490 CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10491 value = CompileRun(script);
10492 CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10493 }
10494 }
10495
THREADED_TEST(ObjectGetOwnPropertyNames)10496 THREADED_TEST(ObjectGetOwnPropertyNames) {
10497 LocalContext context;
10498 v8::Isolate* isolate = context->GetIsolate();
10499 v8::HandleScope handle_scope(isolate);
10500
10501 v8::Local<v8::Object> value =
10502 v8::Local<v8::Object>::Cast(v8::StringObject::New(v8_str("test")));
10503 v8::Local<v8::Array> properties;
10504
10505 CHECK(value
10506 ->GetOwnPropertyNames(context.local(),
10507 static_cast<v8::PropertyFilter>(
10508 v8::PropertyFilter::ALL_PROPERTIES |
10509 v8::PropertyFilter::SKIP_SYMBOLS))
10510 .ToLocal(&properties));
10511 CHECK_EQ(5, properties->Length());
10512 v8::Local<v8::Value> property;
10513 CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10514 property->IsString());
10515 CHECK(property.As<v8::String>()
10516 ->Equals(context.local(), v8_str("length"))
10517 .FromMaybe(false));
10518 for (int i = 0; i < 4; ++i) {
10519 v8::Local<v8::Value> property;
10520 CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10521 property->IsInt32());
10522 CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10523 }
10524
10525 CHECK(value->GetOwnPropertyNames(context.local(), v8::ONLY_ENUMERABLE)
10526 .ToLocal(&properties));
10527 CHECK_EQ(4, properties->Length());
10528 for (int i = 0; i < 4; ++i) {
10529 v8::Local<v8::Value> property;
10530 CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10531 property->IsInt32());
10532 CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10533 }
10534
10535 value = value->GetPrototype().As<v8::Object>();
10536 CHECK(value
10537 ->GetOwnPropertyNames(context.local(),
10538 static_cast<v8::PropertyFilter>(
10539 v8::PropertyFilter::ALL_PROPERTIES |
10540 v8::PropertyFilter::SKIP_SYMBOLS))
10541 .ToLocal(&properties));
10542 bool concat_found = false;
10543 bool starts_with_found = false;
10544 for (uint32_t i = 0; i < properties->Length(); ++i) {
10545 v8::Local<v8::Value> property;
10546 CHECK(properties->Get(context.local(), i).ToLocal(&property));
10547 if (!property->IsString()) continue;
10548 if (!concat_found)
10549 concat_found = property.As<v8::String>()
10550 ->Equals(context.local(), v8_str("concat"))
10551 .FromMaybe(false);
10552 if (!starts_with_found)
10553 starts_with_found = property.As<v8::String>()
10554 ->Equals(context.local(), v8_str("startsWith"))
10555 .FromMaybe(false);
10556 }
10557 CHECK(concat_found && starts_with_found);
10558 }
10559
THREADED_TEST(CallKnownGlobalReceiver)10560 THREADED_TEST(CallKnownGlobalReceiver) {
10561 v8::Isolate* isolate = CcTest::isolate();
10562 v8::HandleScope handle_scope(isolate);
10563
10564 Local<Value> global_object;
10565
10566 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10567 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10568
10569 // The script to check that we leave global object not
10570 // global object proxy on stack when we deoptimize from inside
10571 // arguments evaluation.
10572 // To provoke error we need to both force deoptimization
10573 // from arguments evaluation and to force CallIC to take
10574 // CallIC_Miss code path that can't cope with global proxy.
10575 const char* script =
10576 "function bar(x, y) { try { } finally { } }"
10577 "function baz(x) { try { } finally { } }"
10578 "function bom(x) { try { } finally { } }"
10579 "function foo(x) { bar([x], bom(2)); }"
10580 "for (var i = 0; i < 10000; i++) foo(1);"
10581 "foo";
10582
10583 Local<Value> foo;
10584 {
10585 LocalContext env(NULL, instance_template);
10586 // Hold on to the global object so it can be used again in another
10587 // environment initialization.
10588 global_object = env->Global();
10589 foo = CompileRun(script);
10590 }
10591
10592 {
10593 // Create new environment reusing the global object.
10594 LocalContext env(NULL, instance_template, global_object);
10595 CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10596 CompileRun("foo()");
10597 }
10598 }
10599
10600
ShadowFunctionCallback(const v8::FunctionCallbackInfo<v8::Value> & args)10601 static void ShadowFunctionCallback(
10602 const v8::FunctionCallbackInfo<v8::Value>& args) {
10603 ApiTestFuzzer::Fuzz();
10604 args.GetReturnValue().Set(v8_num(42));
10605 }
10606
10607
10608 static int shadow_y;
10609 static int shadow_y_setter_call_count;
10610 static int shadow_y_getter_call_count;
10611
10612
ShadowYSetter(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> &)10613 static void ShadowYSetter(Local<String>,
10614 Local<Value>,
10615 const v8::PropertyCallbackInfo<void>&) {
10616 shadow_y_setter_call_count++;
10617 shadow_y = 42;
10618 }
10619
10620
ShadowYGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)10621 static void ShadowYGetter(Local<String> name,
10622 const v8::PropertyCallbackInfo<v8::Value>& info) {
10623 ApiTestFuzzer::Fuzz();
10624 shadow_y_getter_call_count++;
10625 info.GetReturnValue().Set(v8_num(shadow_y));
10626 }
10627
10628
ShadowIndexedGet(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> &)10629 static void ShadowIndexedGet(uint32_t index,
10630 const v8::PropertyCallbackInfo<v8::Value>&) {
10631 }
10632
10633
ShadowNamedGet(Local<Name> key,const v8::PropertyCallbackInfo<v8::Value> &)10634 static void ShadowNamedGet(Local<Name> key,
10635 const v8::PropertyCallbackInfo<v8::Value>&) {}
10636
10637
THREADED_TEST(ShadowObject)10638 THREADED_TEST(ShadowObject) {
10639 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10640 v8::Isolate* isolate = CcTest::isolate();
10641 v8::HandleScope handle_scope(isolate);
10642
10643 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10644 LocalContext context(NULL, global_template);
10645
10646 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10647 t->InstanceTemplate()->SetHandler(
10648 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10649 t->InstanceTemplate()->SetHandler(
10650 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10651 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10652 Local<ObjectTemplate> instance = t->InstanceTemplate();
10653
10654 proto->Set(v8_str("f"),
10655 v8::FunctionTemplate::New(isolate,
10656 ShadowFunctionCallback,
10657 Local<Value>()));
10658 proto->Set(v8_str("x"), v8_num(12));
10659
10660 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10661
10662 Local<Value> o = t->GetFunction(context.local())
10663 .ToLocalChecked()
10664 ->NewInstance(context.local())
10665 .ToLocalChecked();
10666 CHECK(context->Global()
10667 ->Set(context.local(), v8_str("__proto__"), o)
10668 .FromJust());
10669
10670 Local<Value> value =
10671 CompileRun("this.propertyIsEnumerable(0)");
10672 CHECK(value->IsBoolean());
10673 CHECK(!value->BooleanValue(context.local()).FromJust());
10674
10675 value = CompileRun("x");
10676 CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10677
10678 value = CompileRun("f()");
10679 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10680
10681 CompileRun("y = 43");
10682 CHECK_EQ(1, shadow_y_setter_call_count);
10683 value = CompileRun("y");
10684 CHECK_EQ(1, shadow_y_getter_call_count);
10685 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10686 }
10687
10688
THREADED_TEST(HiddenPrototype)10689 THREADED_TEST(HiddenPrototype) {
10690 LocalContext context;
10691 v8::Isolate* isolate = context->GetIsolate();
10692 v8::HandleScope handle_scope(isolate);
10693
10694 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10695 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10696 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10697 t1->SetHiddenPrototype(true);
10698 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10699 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10700 t2->SetHiddenPrototype(true);
10701 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10702 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10703 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10704
10705 Local<v8::Object> o0 = t0->GetFunction(context.local())
10706 .ToLocalChecked()
10707 ->NewInstance(context.local())
10708 .ToLocalChecked();
10709 Local<v8::Object> o1 = t1->GetFunction(context.local())
10710 .ToLocalChecked()
10711 ->NewInstance(context.local())
10712 .ToLocalChecked();
10713 Local<v8::Object> o2 = t2->GetFunction(context.local())
10714 .ToLocalChecked()
10715 ->NewInstance(context.local())
10716 .ToLocalChecked();
10717 Local<v8::Object> o3 = t3->GetFunction(context.local())
10718 .ToLocalChecked()
10719 ->NewInstance(context.local())
10720 .ToLocalChecked();
10721
10722 // Setting the prototype on an object skips hidden prototypes.
10723 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10724 .ToLocalChecked()
10725 ->Int32Value(context.local())
10726 .FromJust());
10727 CHECK(o0->Set(context.local(), v8_str("__proto__"), o1).FromJust());
10728 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10729 .ToLocalChecked()
10730 ->Int32Value(context.local())
10731 .FromJust());
10732 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10733 .ToLocalChecked()
10734 ->Int32Value(context.local())
10735 .FromJust());
10736 CHECK(o0->Set(context.local(), v8_str("__proto__"), o2).FromJust());
10737 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10738 .ToLocalChecked()
10739 ->Int32Value(context.local())
10740 .FromJust());
10741 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10742 .ToLocalChecked()
10743 ->Int32Value(context.local())
10744 .FromJust());
10745 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10746 .ToLocalChecked()
10747 ->Int32Value(context.local())
10748 .FromJust());
10749 CHECK(o0->Set(context.local(), v8_str("__proto__"), o3).FromJust());
10750 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10751 .ToLocalChecked()
10752 ->Int32Value(context.local())
10753 .FromJust());
10754 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10755 .ToLocalChecked()
10756 ->Int32Value(context.local())
10757 .FromJust());
10758 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10759 .ToLocalChecked()
10760 ->Int32Value(context.local())
10761 .FromJust());
10762 CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
10763 .ToLocalChecked()
10764 ->Int32Value(context.local())
10765 .FromJust());
10766
10767 // Getting the prototype of o0 should get the first visible one
10768 // which is o3. Therefore, z should not be defined on the prototype
10769 // object.
10770 Local<Value> proto =
10771 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
10772 CHECK(proto->IsObject());
10773 CHECK(proto.As<v8::Object>()
10774 ->Get(context.local(), v8_str("z"))
10775 .ToLocalChecked()
10776 ->IsUndefined());
10777 }
10778
10779
THREADED_TEST(HiddenPrototypeSet)10780 THREADED_TEST(HiddenPrototypeSet) {
10781 LocalContext context;
10782 v8::Isolate* isolate = context->GetIsolate();
10783 v8::HandleScope handle_scope(isolate);
10784
10785 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10786 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10787 ht->SetHiddenPrototype(true);
10788 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10789 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10790
10791 Local<v8::Object> o = ot->GetFunction(context.local())
10792 .ToLocalChecked()
10793 ->NewInstance(context.local())
10794 .ToLocalChecked();
10795 Local<v8::Object> h = ht->GetFunction(context.local())
10796 .ToLocalChecked()
10797 ->NewInstance(context.local())
10798 .ToLocalChecked();
10799 Local<v8::Object> p = pt->GetFunction(context.local())
10800 .ToLocalChecked()
10801 ->NewInstance(context.local())
10802 .ToLocalChecked();
10803 CHECK(o->Set(context.local(), v8_str("__proto__"), h).FromJust());
10804 CHECK(h->Set(context.local(), v8_str("__proto__"), p).FromJust());
10805
10806 // Setting a property that exists on the hidden prototype goes there.
10807 CHECK(o->Set(context.local(), v8_str("x"), v8_num(7)).FromJust());
10808 CHECK_EQ(7, o->Get(context.local(), v8_str("x"))
10809 .ToLocalChecked()
10810 ->Int32Value(context.local())
10811 .FromJust());
10812 CHECK_EQ(7, h->Get(context.local(), v8_str("x"))
10813 .ToLocalChecked()
10814 ->Int32Value(context.local())
10815 .FromJust());
10816 CHECK(p->Get(context.local(), v8_str("x")).ToLocalChecked()->IsUndefined());
10817
10818 // Setting a new property should not be forwarded to the hidden prototype.
10819 CHECK(o->Set(context.local(), v8_str("y"), v8_num(6)).FromJust());
10820 CHECK_EQ(6, o->Get(context.local(), v8_str("y"))
10821 .ToLocalChecked()
10822 ->Int32Value(context.local())
10823 .FromJust());
10824 CHECK(h->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
10825 CHECK(p->Get(context.local(), v8_str("y")).ToLocalChecked()->IsUndefined());
10826
10827 // Setting a property that only exists on a prototype of the hidden prototype
10828 // is treated normally again.
10829 CHECK(p->Set(context.local(), v8_str("z"), v8_num(8)).FromJust());
10830 CHECK_EQ(8, o->Get(context.local(), v8_str("z"))
10831 .ToLocalChecked()
10832 ->Int32Value(context.local())
10833 .FromJust());
10834 CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
10835 .ToLocalChecked()
10836 ->Int32Value(context.local())
10837 .FromJust());
10838 CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
10839 .ToLocalChecked()
10840 ->Int32Value(context.local())
10841 .FromJust());
10842 CHECK(o->Set(context.local(), v8_str("z"), v8_num(9)).FromJust());
10843 CHECK_EQ(9, o->Get(context.local(), v8_str("z"))
10844 .ToLocalChecked()
10845 ->Int32Value(context.local())
10846 .FromJust());
10847 CHECK_EQ(8, h->Get(context.local(), v8_str("z"))
10848 .ToLocalChecked()
10849 ->Int32Value(context.local())
10850 .FromJust());
10851 CHECK_EQ(8, p->Get(context.local(), v8_str("z"))
10852 .ToLocalChecked()
10853 ->Int32Value(context.local())
10854 .FromJust());
10855 }
10856
10857
10858 // Regression test for issue 2457.
THREADED_TEST(HiddenPrototypeIdentityHash)10859 THREADED_TEST(HiddenPrototypeIdentityHash) {
10860 LocalContext context;
10861 v8::HandleScope handle_scope(context->GetIsolate());
10862
10863 Local<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10864 t->SetHiddenPrototype(true);
10865 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10866 Local<Object> p = t->GetFunction(context.local())
10867 .ToLocalChecked()
10868 ->NewInstance(context.local())
10869 .ToLocalChecked();
10870 Local<Object> o = Object::New(context->GetIsolate());
10871 CHECK(o->SetPrototype(context.local(), p).FromJust());
10872
10873 int hash = o->GetIdentityHash();
10874 USE(hash);
10875 CHECK(o->Set(context.local(), v8_str("foo"), v8_num(42)).FromJust());
10876 CHECK_EQ(hash, o->GetIdentityHash());
10877 }
10878
10879
THREADED_TEST(SetPrototype)10880 THREADED_TEST(SetPrototype) {
10881 LocalContext context;
10882 v8::Isolate* isolate = context->GetIsolate();
10883 v8::HandleScope handle_scope(isolate);
10884
10885 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10886 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10887 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10888 t1->SetHiddenPrototype(true);
10889 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10890 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10891 t2->SetHiddenPrototype(true);
10892 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10893 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10894 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10895
10896 Local<v8::Object> o0 = t0->GetFunction(context.local())
10897 .ToLocalChecked()
10898 ->NewInstance(context.local())
10899 .ToLocalChecked();
10900 Local<v8::Object> o1 = t1->GetFunction(context.local())
10901 .ToLocalChecked()
10902 ->NewInstance(context.local())
10903 .ToLocalChecked();
10904 Local<v8::Object> o2 = t2->GetFunction(context.local())
10905 .ToLocalChecked()
10906 ->NewInstance(context.local())
10907 .ToLocalChecked();
10908 Local<v8::Object> o3 = t3->GetFunction(context.local())
10909 .ToLocalChecked()
10910 ->NewInstance(context.local())
10911 .ToLocalChecked();
10912
10913 // Setting the prototype on an object does not skip hidden prototypes.
10914 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10915 .ToLocalChecked()
10916 ->Int32Value(context.local())
10917 .FromJust());
10918 CHECK(o0->SetPrototype(context.local(), o1).FromJust());
10919 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10920 .ToLocalChecked()
10921 ->Int32Value(context.local())
10922 .FromJust());
10923 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10924 .ToLocalChecked()
10925 ->Int32Value(context.local())
10926 .FromJust());
10927 CHECK(o1->SetPrototype(context.local(), o2).FromJust());
10928 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10929 .ToLocalChecked()
10930 ->Int32Value(context.local())
10931 .FromJust());
10932 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10933 .ToLocalChecked()
10934 ->Int32Value(context.local())
10935 .FromJust());
10936 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10937 .ToLocalChecked()
10938 ->Int32Value(context.local())
10939 .FromJust());
10940 CHECK(o2->SetPrototype(context.local(), o3).FromJust());
10941 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
10942 .ToLocalChecked()
10943 ->Int32Value(context.local())
10944 .FromJust());
10945 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
10946 .ToLocalChecked()
10947 ->Int32Value(context.local())
10948 .FromJust());
10949 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
10950 .ToLocalChecked()
10951 ->Int32Value(context.local())
10952 .FromJust());
10953 CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
10954 .ToLocalChecked()
10955 ->Int32Value(context.local())
10956 .FromJust());
10957
10958 // Getting the prototype of o0 should get the first visible one
10959 // which is o3. Therefore, z should not be defined on the prototype
10960 // object.
10961 Local<Value> proto =
10962 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
10963 CHECK(proto->IsObject());
10964 CHECK(proto.As<v8::Object>()->Equals(context.local(), o3).FromJust());
10965
10966 // However, Object::GetPrototype ignores hidden prototype.
10967 Local<Value> proto0 = o0->GetPrototype();
10968 CHECK(proto0->IsObject());
10969 CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
10970
10971 Local<Value> proto1 = o1->GetPrototype();
10972 CHECK(proto1->IsObject());
10973 CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
10974
10975 Local<Value> proto2 = o2->GetPrototype();
10976 CHECK(proto2->IsObject());
10977 CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
10978 }
10979
10980
10981 // Getting property names of an object with a prototype chain that
10982 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10983 // crash the runtime.
THREADED_TEST(Regress91517)10984 THREADED_TEST(Regress91517) {
10985 i::FLAG_allow_natives_syntax = true;
10986 LocalContext context;
10987 v8::Isolate* isolate = context->GetIsolate();
10988 v8::HandleScope handle_scope(isolate);
10989
10990 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10991 t1->SetHiddenPrototype(true);
10992 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10993 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10994 t2->SetHiddenPrototype(true);
10995 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10996 t2->InstanceTemplate()->Set(v8_str("objects"),
10997 v8::ObjectTemplate::New(isolate));
10998 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10999 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11000 t3->SetHiddenPrototype(true);
11001 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11002 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11003 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11004
11005 // Force dictionary-based properties.
11006 i::ScopedVector<char> name_buf(1024);
11007 for (int i = 1; i <= 1000; i++) {
11008 i::SNPrintF(name_buf, "sdf%d", i);
11009 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11010 }
11011
11012 Local<v8::Object> o1 = t1->GetFunction(context.local())
11013 .ToLocalChecked()
11014 ->NewInstance(context.local())
11015 .ToLocalChecked();
11016 Local<v8::Object> o2 = t2->GetFunction(context.local())
11017 .ToLocalChecked()
11018 ->NewInstance(context.local())
11019 .ToLocalChecked();
11020 Local<v8::Object> o3 = t3->GetFunction(context.local())
11021 .ToLocalChecked()
11022 ->NewInstance(context.local())
11023 .ToLocalChecked();
11024 Local<v8::Object> o4 = t4->GetFunction(context.local())
11025 .ToLocalChecked()
11026 ->NewInstance(context.local())
11027 .ToLocalChecked();
11028
11029 // Create prototype chain of hidden prototypes.
11030 CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11031 CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11032 CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11033
11034 // Call the runtime version of GetOwnPropertyNames() on the natively
11035 // created object through JavaScript.
11036 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11037 // PROPERTY_FILTER_NONE = 0
11038 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11039
11040 ExpectInt32("names.length", 1006);
11041 ExpectTrue("names.indexOf(\"baz\") >= 0");
11042 ExpectTrue("names.indexOf(\"boo\") >= 0");
11043 ExpectTrue("names.indexOf(\"foo\") >= 0");
11044 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11045 ExpectTrue("names.indexOf(\"objects\") >= 0");
11046 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11047 ExpectFalse("names[1005] == undefined");
11048 }
11049
11050
11051 // Getting property names of an object with a hidden and inherited
11052 // prototype should not duplicate the accessor properties inherited.
THREADED_TEST(Regress269562)11053 THREADED_TEST(Regress269562) {
11054 i::FLAG_allow_natives_syntax = true;
11055 LocalContext context;
11056 v8::HandleScope handle_scope(context->GetIsolate());
11057
11058 Local<v8::FunctionTemplate> t1 =
11059 v8::FunctionTemplate::New(context->GetIsolate());
11060 t1->SetHiddenPrototype(true);
11061
11062 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11063 i1->SetAccessor(v8_str("foo"),
11064 SimpleAccessorGetter, SimpleAccessorSetter);
11065 i1->SetAccessor(v8_str("bar"),
11066 SimpleAccessorGetter, SimpleAccessorSetter);
11067 i1->SetAccessor(v8_str("baz"),
11068 SimpleAccessorGetter, SimpleAccessorSetter);
11069 i1->Set(v8_str("n1"), v8_num(1));
11070 i1->Set(v8_str("n2"), v8_num(2));
11071
11072 Local<v8::Object> o1 = t1->GetFunction(context.local())
11073 .ToLocalChecked()
11074 ->NewInstance(context.local())
11075 .ToLocalChecked();
11076 Local<v8::FunctionTemplate> t2 =
11077 v8::FunctionTemplate::New(context->GetIsolate());
11078 t2->SetHiddenPrototype(true);
11079
11080 // Inherit from t1 and mark prototype as hidden.
11081 t2->Inherit(t1);
11082 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11083
11084 Local<v8::Object> o2 = t2->GetFunction(context.local())
11085 .ToLocalChecked()
11086 ->NewInstance(context.local())
11087 .ToLocalChecked();
11088 CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11089
11090 v8::Local<v8::Symbol> sym =
11091 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11092 CHECK(o1->Set(context.local(), sym, v8_num(3)).FromJust());
11093 o1->SetPrivate(context.local(),
11094 v8::Private::New(context->GetIsolate(), v8_str("h1")),
11095 v8::Integer::New(context->GetIsolate(), 2013))
11096 .FromJust();
11097
11098 // Call the runtime version of GetOwnPropertyNames() on
11099 // the natively created object through JavaScript.
11100 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o2).FromJust());
11101 CHECK(context->Global()->Set(context.local(), v8_str("sym"), sym).FromJust());
11102 // PROPERTY_FILTER_NONE = 0
11103 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11104
11105 ExpectInt32("names.length", 7);
11106 ExpectTrue("names.indexOf(\"foo\") >= 0");
11107 ExpectTrue("names.indexOf(\"bar\") >= 0");
11108 ExpectTrue("names.indexOf(\"baz\") >= 0");
11109 ExpectTrue("names.indexOf(\"n1\") >= 0");
11110 ExpectTrue("names.indexOf(\"n2\") >= 0");
11111 ExpectTrue("names.indexOf(sym) >= 0");
11112 ExpectTrue("names.indexOf(\"mine\") >= 0");
11113 }
11114
11115
THREADED_TEST(FunctionReadOnlyPrototype)11116 THREADED_TEST(FunctionReadOnlyPrototype) {
11117 LocalContext context;
11118 v8::Isolate* isolate = context->GetIsolate();
11119 v8::HandleScope handle_scope(isolate);
11120
11121 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11122 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11123 t1->ReadOnlyPrototype();
11124 CHECK(context->Global()
11125 ->Set(context.local(), v8_str("func1"),
11126 t1->GetFunction(context.local()).ToLocalChecked())
11127 .FromJust());
11128 // Configured value of ReadOnly flag.
11129 CHECK(
11130 CompileRun(
11131 "(function() {"
11132 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11133 " return (descriptor['writable'] == false);"
11134 "})()")
11135 ->BooleanValue(context.local())
11136 .FromJust());
11137 CHECK_EQ(
11138 42,
11139 CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11140 CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11141 ->Int32Value(context.local())
11142 .FromJust());
11143
11144 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11145 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11146 CHECK(context->Global()
11147 ->Set(context.local(), v8_str("func2"),
11148 t2->GetFunction(context.local()).ToLocalChecked())
11149 .FromJust());
11150 // Default value of ReadOnly flag.
11151 CHECK(
11152 CompileRun(
11153 "(function() {"
11154 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11155 " return (descriptor['writable'] == true);"
11156 "})()")
11157 ->BooleanValue(context.local())
11158 .FromJust());
11159 CHECK_EQ(
11160 42,
11161 CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11162 }
11163
11164
THREADED_TEST(SetPrototypeThrows)11165 THREADED_TEST(SetPrototypeThrows) {
11166 LocalContext context;
11167 v8::Isolate* isolate = context->GetIsolate();
11168 v8::HandleScope handle_scope(isolate);
11169
11170 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11171
11172 Local<v8::Object> o0 = t->GetFunction(context.local())
11173 .ToLocalChecked()
11174 ->NewInstance(context.local())
11175 .ToLocalChecked();
11176 Local<v8::Object> o1 = t->GetFunction(context.local())
11177 .ToLocalChecked()
11178 ->NewInstance(context.local())
11179 .ToLocalChecked();
11180
11181 CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11182 // If setting the prototype leads to the cycle, SetPrototype should
11183 // return false and keep VM in sane state.
11184 v8::TryCatch try_catch(isolate);
11185 CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11186 CHECK(!try_catch.HasCaught());
11187 CHECK(!CcTest::i_isolate()->has_pending_exception());
11188
11189 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11190 ->Int32Value(context.local())
11191 .FromJust());
11192 }
11193
11194
THREADED_TEST(FunctionRemovePrototype)11195 THREADED_TEST(FunctionRemovePrototype) {
11196 LocalContext context;
11197 v8::Isolate* isolate = context->GetIsolate();
11198 v8::HandleScope handle_scope(isolate);
11199
11200 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11201 t1->RemovePrototype();
11202 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11203 CHECK(!fun->IsConstructor());
11204 CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11205 CHECK(!CompileRun("'prototype' in fun")
11206 ->BooleanValue(context.local())
11207 .FromJust());
11208
11209 v8::TryCatch try_catch(isolate);
11210 CompileRun("new fun()");
11211 CHECK(try_catch.HasCaught());
11212
11213 try_catch.Reset();
11214 CHECK(fun->NewInstance(context.local()).IsEmpty());
11215 CHECK(try_catch.HasCaught());
11216 }
11217
11218
THREADED_TEST(GetterSetterExceptions)11219 THREADED_TEST(GetterSetterExceptions) {
11220 LocalContext context;
11221 v8::Isolate* isolate = context->GetIsolate();
11222 v8::HandleScope handle_scope(isolate);
11223 CompileRun(
11224 "function Foo() { };"
11225 "function Throw() { throw 5; };"
11226 "var x = { };"
11227 "x.__defineSetter__('set', Throw);"
11228 "x.__defineGetter__('get', Throw);");
11229 Local<v8::Object> x = Local<v8::Object>::Cast(
11230 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11231 v8::TryCatch try_catch(isolate);
11232 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11233 .IsNothing());
11234 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11235 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11236 .IsNothing());
11237 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11238 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11239 .IsNothing());
11240 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11241 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11242 .IsNothing());
11243 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11244 }
11245
11246
THREADED_TEST(Constructor)11247 THREADED_TEST(Constructor) {
11248 LocalContext context;
11249 v8::Isolate* isolate = context->GetIsolate();
11250 v8::HandleScope handle_scope(isolate);
11251 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11252 templ->SetClassName(v8_str("Fun"));
11253 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11254 CHECK(
11255 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11256 Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11257 i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11258 CHECK(obj->IsJSObject());
11259 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11260 CHECK(value->BooleanValue(context.local()).FromJust());
11261 }
11262
11263
ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value> & args)11264 static void ConstructorCallback(
11265 const v8::FunctionCallbackInfo<v8::Value>& args) {
11266 ApiTestFuzzer::Fuzz();
11267 Local<Object> This;
11268
11269 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
11270 if (args.IsConstructCall()) {
11271 Local<Object> Holder = args.Holder();
11272 This = Object::New(args.GetIsolate());
11273 Local<Value> proto = Holder->GetPrototype();
11274 if (proto->IsObject()) {
11275 This->SetPrototype(context, proto).FromJust();
11276 }
11277 } else {
11278 This = args.This();
11279 }
11280
11281 This->Set(context, v8_str("a"), args[0]).FromJust();
11282 args.GetReturnValue().Set(This);
11283 }
11284
11285
FakeConstructorCallback(const v8::FunctionCallbackInfo<v8::Value> & args)11286 static void FakeConstructorCallback(
11287 const v8::FunctionCallbackInfo<v8::Value>& args) {
11288 ApiTestFuzzer::Fuzz();
11289 args.GetReturnValue().Set(args[0]);
11290 }
11291
11292
THREADED_TEST(ConstructorForObject)11293 THREADED_TEST(ConstructorForObject) {
11294 LocalContext context;
11295 v8::Isolate* isolate = context->GetIsolate();
11296 v8::HandleScope handle_scope(isolate);
11297
11298 {
11299 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11300 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
11301 Local<Object> instance =
11302 instance_template->NewInstance(context.local()).ToLocalChecked();
11303 CHECK(context->Global()
11304 ->Set(context.local(), v8_str("obj"), instance)
11305 .FromJust());
11306 v8::TryCatch try_catch(isolate);
11307 Local<Value> value;
11308 CHECK(!try_catch.HasCaught());
11309
11310 // Call the Object's constructor with a 32-bit signed integer.
11311 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11312 CHECK(!try_catch.HasCaught());
11313 CHECK(value->IsInt32());
11314 CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11315
11316 Local<Value> args1[] = {v8_num(28)};
11317 Local<Value> value_obj1 =
11318 instance->CallAsConstructor(context.local(), 1, args1).ToLocalChecked();
11319 CHECK(value_obj1->IsObject());
11320 Local<Object> object1 = Local<Object>::Cast(value_obj1);
11321 value = object1->Get(context.local(), v8_str("a")).ToLocalChecked();
11322 CHECK(value->IsInt32());
11323 CHECK(!try_catch.HasCaught());
11324 CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11325
11326 // Call the Object's constructor with a String.
11327 value =
11328 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
11329 CHECK(!try_catch.HasCaught());
11330 CHECK(value->IsString());
11331 String::Utf8Value string_value1(
11332 value->ToString(context.local()).ToLocalChecked());
11333 CHECK_EQ(0, strcmp("tipli", *string_value1));
11334
11335 Local<Value> args2[] = {v8_str("tipli")};
11336 Local<Value> value_obj2 =
11337 instance->CallAsConstructor(context.local(), 1, args2).ToLocalChecked();
11338 CHECK(value_obj2->IsObject());
11339 Local<Object> object2 = Local<Object>::Cast(value_obj2);
11340 value = object2->Get(context.local(), v8_str("a")).ToLocalChecked();
11341 CHECK(!try_catch.HasCaught());
11342 CHECK(value->IsString());
11343 String::Utf8Value string_value2(
11344 value->ToString(context.local()).ToLocalChecked());
11345 CHECK_EQ(0, strcmp("tipli", *string_value2));
11346
11347 // Call the Object's constructor with a Boolean.
11348 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11349 CHECK(!try_catch.HasCaught());
11350 CHECK(value->IsBoolean());
11351 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
11352
11353 Local<Value> args3[] = {v8::True(isolate)};
11354 Local<Value> value_obj3 =
11355 instance->CallAsConstructor(context.local(), 1, args3).ToLocalChecked();
11356 CHECK(value_obj3->IsObject());
11357 Local<Object> object3 = Local<Object>::Cast(value_obj3);
11358 value = object3->Get(context.local(), v8_str("a")).ToLocalChecked();
11359 CHECK(!try_catch.HasCaught());
11360 CHECK(value->IsBoolean());
11361 CHECK_EQ(true, value->BooleanValue(context.local()).FromJust());
11362
11363 // Call the Object's constructor with undefined.
11364 Local<Value> args4[] = {v8::Undefined(isolate)};
11365 Local<Value> value_obj4 =
11366 instance->CallAsConstructor(context.local(), 1, args4).ToLocalChecked();
11367 CHECK(value_obj4->IsObject());
11368 Local<Object> object4 = Local<Object>::Cast(value_obj4);
11369 value = object4->Get(context.local(), v8_str("a")).ToLocalChecked();
11370 CHECK(!try_catch.HasCaught());
11371 CHECK(value->IsUndefined());
11372
11373 // Call the Object's constructor with null.
11374 Local<Value> args5[] = {v8::Null(isolate)};
11375 Local<Value> value_obj5 =
11376 instance->CallAsConstructor(context.local(), 1, args5).ToLocalChecked();
11377 CHECK(value_obj5->IsObject());
11378 Local<Object> object5 = Local<Object>::Cast(value_obj5);
11379 value = object5->Get(context.local(), v8_str("a")).ToLocalChecked();
11380 CHECK(!try_catch.HasCaught());
11381 CHECK(value->IsNull());
11382 }
11383
11384 // Check exception handling when there is no constructor set for the Object.
11385 {
11386 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11387 Local<Object> instance =
11388 instance_template->NewInstance(context.local()).ToLocalChecked();
11389 CHECK(context->Global()
11390 ->Set(context.local(), v8_str("obj2"), instance)
11391 .FromJust());
11392 v8::TryCatch try_catch(isolate);
11393 Local<Value> value;
11394 CHECK(!try_catch.HasCaught());
11395
11396 value = CompileRun("new obj2(28)");
11397 CHECK(try_catch.HasCaught());
11398 String::Utf8Value exception_value1(try_catch.Exception());
11399 CHECK_EQ(0,
11400 strcmp("TypeError: obj2 is not a constructor", *exception_value1));
11401 try_catch.Reset();
11402
11403 Local<Value> args[] = {v8_num(29)};
11404 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
11405 CHECK(try_catch.HasCaught());
11406 String::Utf8Value exception_value2(try_catch.Exception());
11407 CHECK_EQ(
11408 0, strcmp("TypeError: object is not a constructor", *exception_value2));
11409 try_catch.Reset();
11410 }
11411
11412 // Check the case when constructor throws exception.
11413 {
11414 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11415 instance_template->SetCallAsFunctionHandler(ThrowValue);
11416 Local<Object> instance =
11417 instance_template->NewInstance(context.local()).ToLocalChecked();
11418 CHECK(context->Global()
11419 ->Set(context.local(), v8_str("obj3"), instance)
11420 .FromJust());
11421 v8::TryCatch try_catch(isolate);
11422 Local<Value> value;
11423 CHECK(!try_catch.HasCaught());
11424
11425 value = CompileRun("new obj3(22)");
11426 CHECK(try_catch.HasCaught());
11427 String::Utf8Value exception_value1(try_catch.Exception());
11428 CHECK_EQ(0, strcmp("22", *exception_value1));
11429 try_catch.Reset();
11430
11431 Local<Value> args[] = {v8_num(23)};
11432 CHECK(instance->CallAsConstructor(context.local(), 1, args).IsEmpty());
11433 CHECK(try_catch.HasCaught());
11434 String::Utf8Value exception_value2(try_catch.Exception());
11435 CHECK_EQ(0, strcmp("23", *exception_value2));
11436 try_catch.Reset();
11437 }
11438
11439 // Check whether constructor returns with an object or non-object.
11440 {
11441 Local<FunctionTemplate> function_template =
11442 FunctionTemplate::New(isolate, FakeConstructorCallback);
11443 Local<Function> function =
11444 function_template->GetFunction(context.local()).ToLocalChecked();
11445 Local<Object> instance1 = function;
11446 CHECK(context->Global()
11447 ->Set(context.local(), v8_str("obj4"), instance1)
11448 .FromJust());
11449 v8::TryCatch try_catch(isolate);
11450 Local<Value> value;
11451 CHECK(!try_catch.HasCaught());
11452
11453 CHECK(instance1->IsObject());
11454 CHECK(instance1->IsFunction());
11455
11456 value = CompileRun("new obj4(28)");
11457 CHECK(!try_catch.HasCaught());
11458 CHECK(value->IsObject());
11459
11460 Local<Value> args1[] = {v8_num(28)};
11461 value = instance1->CallAsConstructor(context.local(), 1, args1)
11462 .ToLocalChecked();
11463 CHECK(!try_catch.HasCaught());
11464 CHECK(value->IsObject());
11465
11466 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11467 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11468 Local<Object> instance2 =
11469 instance_template->NewInstance(context.local()).ToLocalChecked();
11470 CHECK(context->Global()
11471 ->Set(context.local(), v8_str("obj5"), instance2)
11472 .FromJust());
11473 CHECK(!try_catch.HasCaught());
11474
11475 CHECK(instance2->IsObject());
11476 CHECK(instance2->IsFunction());
11477
11478 value = CompileRun("new obj5(28)");
11479 CHECK(!try_catch.HasCaught());
11480 CHECK(!value->IsObject());
11481
11482 Local<Value> args2[] = {v8_num(28)};
11483 value = instance2->CallAsConstructor(context.local(), 1, args2)
11484 .ToLocalChecked();
11485 CHECK(!try_catch.HasCaught());
11486 CHECK(!value->IsObject());
11487 }
11488 }
11489
11490
THREADED_TEST(FunctionDescriptorException)11491 THREADED_TEST(FunctionDescriptorException) {
11492 LocalContext context;
11493 v8::Isolate* isolate = context->GetIsolate();
11494 v8::HandleScope handle_scope(isolate);
11495 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11496 templ->SetClassName(v8_str("Fun"));
11497 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11498 CHECK(
11499 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11500 Local<Value> value = CompileRun(
11501 "function test() {"
11502 " try {"
11503 " (new Fun()).blah()"
11504 " } catch (e) {"
11505 " var str = String(e);"
11506 // " if (str.indexOf('TypeError') == -1) return 1;"
11507 // " if (str.indexOf('[object Fun]') != -1) return 2;"
11508 // " if (str.indexOf('#<Fun>') == -1) return 3;"
11509 " return 0;"
11510 " }"
11511 " return 4;"
11512 "}"
11513 "test();");
11514 CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11515 }
11516
11517
THREADED_TEST(EvalAliasedDynamic)11518 THREADED_TEST(EvalAliasedDynamic) {
11519 LocalContext current;
11520 v8::HandleScope scope(current->GetIsolate());
11521
11522 // Tests where aliased eval can only be resolved dynamically.
11523 Local<Script> script = v8_compile(
11524 "function f(x) { "
11525 " var foo = 2;"
11526 " with (x) { return eval('foo'); }"
11527 "}"
11528 "foo = 0;"
11529 "result1 = f(new Object());"
11530 "result2 = f(this);"
11531 "var x = new Object();"
11532 "x.eval = function(x) { return 1; };"
11533 "result3 = f(x);");
11534 script->Run(current.local()).ToLocalChecked();
11535 CHECK_EQ(2, current->Global()
11536 ->Get(current.local(), v8_str("result1"))
11537 .ToLocalChecked()
11538 ->Int32Value(current.local())
11539 .FromJust());
11540 CHECK_EQ(0, current->Global()
11541 ->Get(current.local(), v8_str("result2"))
11542 .ToLocalChecked()
11543 ->Int32Value(current.local())
11544 .FromJust());
11545 CHECK_EQ(1, current->Global()
11546 ->Get(current.local(), v8_str("result3"))
11547 .ToLocalChecked()
11548 ->Int32Value(current.local())
11549 .FromJust());
11550
11551 v8::TryCatch try_catch(current->GetIsolate());
11552 script = v8_compile(
11553 "function f(x) { "
11554 " var bar = 2;"
11555 " with (x) { return eval('bar'); }"
11556 "}"
11557 "result4 = f(this)");
11558 script->Run(current.local()).ToLocalChecked();
11559 CHECK(!try_catch.HasCaught());
11560 CHECK_EQ(2, current->Global()
11561 ->Get(current.local(), v8_str("result4"))
11562 .ToLocalChecked()
11563 ->Int32Value(current.local())
11564 .FromJust());
11565
11566 try_catch.Reset();
11567 }
11568
11569
THREADED_TEST(CrossEval)11570 THREADED_TEST(CrossEval) {
11571 v8::HandleScope scope(CcTest::isolate());
11572 LocalContext other;
11573 LocalContext current;
11574
11575 Local<String> token = v8_str("<security token>");
11576 other->SetSecurityToken(token);
11577 current->SetSecurityToken(token);
11578
11579 // Set up reference from current to other.
11580 CHECK(current->Global()
11581 ->Set(current.local(), v8_str("other"), other->Global())
11582 .FromJust());
11583
11584 // Check that new variables are introduced in other context.
11585 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11586 script->Run(current.local()).ToLocalChecked();
11587 Local<Value> foo =
11588 other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11589 CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11590 CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11591
11592 // Check that writing to non-existing properties introduces them in
11593 // the other context.
11594 script = v8_compile("other.eval('na = 1234')");
11595 script->Run(current.local()).ToLocalChecked();
11596 CHECK_EQ(1234, other->Global()
11597 ->Get(current.local(), v8_str("na"))
11598 .ToLocalChecked()
11599 ->Int32Value(other.local())
11600 .FromJust());
11601 CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11602
11603 // Check that global variables in current context are not visible in other
11604 // context.
11605 v8::TryCatch try_catch(CcTest::isolate());
11606 script = v8_compile("var bar = 42; other.eval('bar');");
11607 CHECK(script->Run(current.local()).IsEmpty());
11608 CHECK(try_catch.HasCaught());
11609 try_catch.Reset();
11610
11611 // Check that local variables in current context are not visible in other
11612 // context.
11613 script = v8_compile(
11614 "(function() { "
11615 " var baz = 87;"
11616 " return other.eval('baz');"
11617 "})();");
11618 CHECK(script->Run(current.local()).IsEmpty());
11619 CHECK(try_catch.HasCaught());
11620 try_catch.Reset();
11621
11622 // Check that global variables in the other environment are visible
11623 // when evaluting code.
11624 CHECK(other->Global()
11625 ->Set(other.local(), v8_str("bis"), v8_num(1234))
11626 .FromJust());
11627 script = v8_compile("other.eval('bis')");
11628 CHECK_EQ(1234, script->Run(current.local())
11629 .ToLocalChecked()
11630 ->Int32Value(current.local())
11631 .FromJust());
11632 CHECK(!try_catch.HasCaught());
11633
11634 // Check that the 'this' pointer points to the global object evaluating
11635 // code.
11636 CHECK(other->Global()
11637 ->Set(current.local(), v8_str("t"), other->Global())
11638 .FromJust());
11639 script = v8_compile("other.eval('this == t')");
11640 Local<Value> result = script->Run(current.local()).ToLocalChecked();
11641 CHECK(result->IsTrue());
11642 CHECK(!try_catch.HasCaught());
11643
11644 // Check that variables introduced in with-statement are not visible in
11645 // other context.
11646 script = v8_compile("with({x:2}){other.eval('x')}");
11647 CHECK(script->Run(current.local()).IsEmpty());
11648 CHECK(try_catch.HasCaught());
11649 try_catch.Reset();
11650
11651 // Check that you cannot use 'eval.call' with another object than the
11652 // current global object.
11653 script = v8_compile("other.y = 1; eval.call(other, 'y')");
11654 CHECK(script->Run(current.local()).IsEmpty());
11655 CHECK(try_catch.HasCaught());
11656 }
11657
11658
11659 // Test that calling eval in a context which has been detached from
11660 // its global proxy works.
THREADED_TEST(EvalInDetachedGlobal)11661 THREADED_TEST(EvalInDetachedGlobal) {
11662 v8::Isolate* isolate = CcTest::isolate();
11663 v8::HandleScope scope(isolate);
11664
11665 v8::Local<Context> context0 = Context::New(isolate);
11666 v8::Local<Context> context1 = Context::New(isolate);
11667
11668 // Set up function in context0 that uses eval from context0.
11669 context0->Enter();
11670 v8::Local<v8::Value> fun = CompileRun(
11671 "var x = 42;"
11672 "(function() {"
11673 " var e = eval;"
11674 " return function(s) { return e(s); }"
11675 "})()");
11676 context0->Exit();
11677
11678 // Put the function into context1 and call it before and after
11679 // detaching the global. Before detaching, the call succeeds and
11680 // after detaching and exception is thrown.
11681 context1->Enter();
11682 CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11683 v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11684 CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11685 context0->DetachGlobal();
11686 v8::TryCatch catcher(isolate);
11687 x_value = CompileRun("fun('x')");
11688 CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11689 context1->Exit();
11690 }
11691
11692
THREADED_TEST(CrossLazyLoad)11693 THREADED_TEST(CrossLazyLoad) {
11694 v8::HandleScope scope(CcTest::isolate());
11695 LocalContext other;
11696 LocalContext current;
11697
11698 Local<String> token = v8_str("<security token>");
11699 other->SetSecurityToken(token);
11700 current->SetSecurityToken(token);
11701
11702 // Set up reference from current to other.
11703 CHECK(current->Global()
11704 ->Set(current.local(), v8_str("other"), other->Global())
11705 .FromJust());
11706
11707 // Trigger lazy loading in other context.
11708 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11709 Local<Value> value = script->Run(current.local()).ToLocalChecked();
11710 CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11711 }
11712
11713
call_as_function(const v8::FunctionCallbackInfo<v8::Value> & args)11714 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11715 ApiTestFuzzer::Fuzz();
11716 if (args.IsConstructCall()) {
11717 if (args[0]->IsInt32()) {
11718 args.GetReturnValue().Set(
11719 v8_num(-args[0]
11720 ->Int32Value(args.GetIsolate()->GetCurrentContext())
11721 .FromJust()));
11722 return;
11723 }
11724 }
11725
11726 args.GetReturnValue().Set(args[0]);
11727 }
11728
11729
ReturnThis(const v8::FunctionCallbackInfo<v8::Value> & args)11730 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11731 args.GetReturnValue().Set(args.This());
11732 }
11733
11734
11735 // Test that a call handler can be set for objects which will allow
11736 // non-function objects created through the API to be called as
11737 // functions.
THREADED_TEST(CallAsFunction)11738 THREADED_TEST(CallAsFunction) {
11739 LocalContext context;
11740 v8::Isolate* isolate = context->GetIsolate();
11741 v8::HandleScope scope(isolate);
11742
11743 {
11744 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11745 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11746 instance_template->SetCallAsFunctionHandler(call_as_function);
11747 Local<v8::Object> instance = t->GetFunction(context.local())
11748 .ToLocalChecked()
11749 ->NewInstance(context.local())
11750 .ToLocalChecked();
11751 CHECK(context->Global()
11752 ->Set(context.local(), v8_str("obj"), instance)
11753 .FromJust());
11754 v8::TryCatch try_catch(isolate);
11755 Local<Value> value;
11756 CHECK(!try_catch.HasCaught());
11757
11758 value = CompileRun("obj(42)");
11759 CHECK(!try_catch.HasCaught());
11760 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11761
11762 value = CompileRun("(function(o){return o(49)})(obj)");
11763 CHECK(!try_catch.HasCaught());
11764 CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11765
11766 // test special case of call as function
11767 value = CompileRun("[obj]['0'](45)");
11768 CHECK(!try_catch.HasCaught());
11769 CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11770
11771 value = CompileRun(
11772 "obj.call = Function.prototype.call;"
11773 "obj.call(null, 87)");
11774 CHECK(!try_catch.HasCaught());
11775 CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11776
11777 // Regression tests for bug #1116356: Calling call through call/apply
11778 // must work for non-function receivers.
11779 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11780 value = CompileRun(apply_99);
11781 CHECK(!try_catch.HasCaught());
11782 CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11783
11784 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11785 value = CompileRun(call_17);
11786 CHECK(!try_catch.HasCaught());
11787 CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11788
11789 // Check that the call-as-function handler can be called through
11790 // new.
11791 value = CompileRun("new obj(43)");
11792 CHECK(!try_catch.HasCaught());
11793 CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11794
11795 // Check that the call-as-function handler can be called through
11796 // the API.
11797 v8::Local<Value> args[] = {v8_num(28)};
11798 value = instance->CallAsFunction(context.local(), instance, 1, args)
11799 .ToLocalChecked();
11800 CHECK(!try_catch.HasCaught());
11801 CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11802 }
11803
11804 {
11805 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11806 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11807 USE(instance_template);
11808 Local<v8::Object> instance = t->GetFunction(context.local())
11809 .ToLocalChecked()
11810 ->NewInstance(context.local())
11811 .ToLocalChecked();
11812 CHECK(context->Global()
11813 ->Set(context.local(), v8_str("obj2"), instance)
11814 .FromJust());
11815 v8::TryCatch try_catch(isolate);
11816 Local<Value> value;
11817 CHECK(!try_catch.HasCaught());
11818
11819 // Call an object without call-as-function handler through the JS
11820 value = CompileRun("obj2(28)");
11821 CHECK(value.IsEmpty());
11822 CHECK(try_catch.HasCaught());
11823 String::Utf8Value exception_value1(try_catch.Exception());
11824 // TODO(verwaest): Better message
11825 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11826 try_catch.Reset();
11827
11828 // Call an object without call-as-function handler through the API
11829 value = CompileRun("obj2(28)");
11830 v8::Local<Value> args[] = {v8_num(28)};
11831 CHECK(
11832 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11833 CHECK(try_catch.HasCaught());
11834 String::Utf8Value exception_value2(try_catch.Exception());
11835 CHECK_EQ(0,
11836 strcmp("TypeError: object is not a function", *exception_value2));
11837 try_catch.Reset();
11838 }
11839
11840 {
11841 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11842 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11843 instance_template->SetCallAsFunctionHandler(ThrowValue);
11844 Local<v8::Object> instance = t->GetFunction(context.local())
11845 .ToLocalChecked()
11846 ->NewInstance(context.local())
11847 .ToLocalChecked();
11848 CHECK(context->Global()
11849 ->Set(context.local(), v8_str("obj3"), instance)
11850 .FromJust());
11851 v8::TryCatch try_catch(isolate);
11852 Local<Value> value;
11853 CHECK(!try_catch.HasCaught());
11854
11855 // Catch the exception which is thrown by call-as-function handler
11856 value = CompileRun("obj3(22)");
11857 CHECK(try_catch.HasCaught());
11858 String::Utf8Value exception_value1(try_catch.Exception());
11859 CHECK_EQ(0, strcmp("22", *exception_value1));
11860 try_catch.Reset();
11861
11862 v8::Local<Value> args[] = {v8_num(23)};
11863 CHECK(
11864 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11865 CHECK(try_catch.HasCaught());
11866 String::Utf8Value exception_value2(try_catch.Exception());
11867 CHECK_EQ(0, strcmp("23", *exception_value2));
11868 try_catch.Reset();
11869 }
11870
11871 {
11872 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11873 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11874 instance_template->SetCallAsFunctionHandler(ReturnThis);
11875 Local<v8::Object> instance = t->GetFunction(context.local())
11876 .ToLocalChecked()
11877 ->NewInstance(context.local())
11878 .ToLocalChecked();
11879
11880 Local<v8::Value> a1 =
11881 instance->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11882 NULL)
11883 .ToLocalChecked();
11884 CHECK(a1->StrictEquals(instance));
11885 Local<v8::Value> a2 =
11886 instance->CallAsFunction(context.local(), v8::Null(isolate), 0, NULL)
11887 .ToLocalChecked();
11888 CHECK(a2->StrictEquals(instance));
11889 Local<v8::Value> a3 =
11890 instance->CallAsFunction(context.local(), v8_num(42), 0, NULL)
11891 .ToLocalChecked();
11892 CHECK(a3->StrictEquals(instance));
11893 Local<v8::Value> a4 =
11894 instance->CallAsFunction(context.local(), v8_str("hello"), 0, NULL)
11895 .ToLocalChecked();
11896 CHECK(a4->StrictEquals(instance));
11897 Local<v8::Value> a5 =
11898 instance->CallAsFunction(context.local(), v8::True(isolate), 0, NULL)
11899 .ToLocalChecked();
11900 CHECK(a5->StrictEquals(instance));
11901 }
11902
11903 {
11904 CompileRun(
11905 "function ReturnThisSloppy() {"
11906 " return this;"
11907 "}"
11908 "function ReturnThisStrict() {"
11909 " 'use strict';"
11910 " return this;"
11911 "}");
11912 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11913 context->Global()
11914 ->Get(context.local(), v8_str("ReturnThisSloppy"))
11915 .ToLocalChecked());
11916 Local<Function> ReturnThisStrict = Local<Function>::Cast(
11917 context->Global()
11918 ->Get(context.local(), v8_str("ReturnThisStrict"))
11919 .ToLocalChecked());
11920
11921 Local<v8::Value> a1 =
11922 ReturnThisSloppy->CallAsFunction(context.local(),
11923 v8::Undefined(isolate), 0, NULL)
11924 .ToLocalChecked();
11925 CHECK(a1->StrictEquals(context->Global()));
11926 Local<v8::Value> a2 =
11927 ReturnThisSloppy->CallAsFunction(context.local(), v8::Null(isolate), 0,
11928 NULL)
11929 .ToLocalChecked();
11930 CHECK(a2->StrictEquals(context->Global()));
11931 Local<v8::Value> a3 =
11932 ReturnThisSloppy->CallAsFunction(context.local(), v8_num(42), 0, NULL)
11933 .ToLocalChecked();
11934 CHECK(a3->IsNumberObject());
11935 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11936 Local<v8::Value> a4 =
11937 ReturnThisSloppy->CallAsFunction(context.local(), v8_str("hello"), 0,
11938 NULL)
11939 .ToLocalChecked();
11940 CHECK(a4->IsStringObject());
11941 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11942 Local<v8::Value> a5 =
11943 ReturnThisSloppy->CallAsFunction(context.local(), v8::True(isolate), 0,
11944 NULL)
11945 .ToLocalChecked();
11946 CHECK(a5->IsBooleanObject());
11947 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11948
11949 Local<v8::Value> a6 =
11950 ReturnThisStrict->CallAsFunction(context.local(),
11951 v8::Undefined(isolate), 0, NULL)
11952 .ToLocalChecked();
11953 CHECK(a6->IsUndefined());
11954 Local<v8::Value> a7 =
11955 ReturnThisStrict->CallAsFunction(context.local(), v8::Null(isolate), 0,
11956 NULL)
11957 .ToLocalChecked();
11958 CHECK(a7->IsNull());
11959 Local<v8::Value> a8 =
11960 ReturnThisStrict->CallAsFunction(context.local(), v8_num(42), 0, NULL)
11961 .ToLocalChecked();
11962 CHECK(a8->StrictEquals(v8_num(42)));
11963 Local<v8::Value> a9 =
11964 ReturnThisStrict->CallAsFunction(context.local(), v8_str("hello"), 0,
11965 NULL)
11966 .ToLocalChecked();
11967 CHECK(a9->StrictEquals(v8_str("hello")));
11968 Local<v8::Value> a10 =
11969 ReturnThisStrict->CallAsFunction(context.local(), v8::True(isolate), 0,
11970 NULL)
11971 .ToLocalChecked();
11972 CHECK(a10->StrictEquals(v8::True(isolate)));
11973 }
11974 }
11975
11976
11977 // Check whether a non-function object is callable.
THREADED_TEST(CallableObject)11978 THREADED_TEST(CallableObject) {
11979 LocalContext context;
11980 v8::Isolate* isolate = context->GetIsolate();
11981 v8::HandleScope scope(isolate);
11982
11983 {
11984 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11985 instance_template->SetCallAsFunctionHandler(call_as_function);
11986 Local<Object> instance =
11987 instance_template->NewInstance(context.local()).ToLocalChecked();
11988 v8::TryCatch try_catch(isolate);
11989
11990 CHECK(instance->IsCallable());
11991 CHECK(!try_catch.HasCaught());
11992 }
11993
11994 {
11995 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11996 Local<Object> instance =
11997 instance_template->NewInstance(context.local()).ToLocalChecked();
11998 v8::TryCatch try_catch(isolate);
11999
12000 CHECK(!instance->IsCallable());
12001 CHECK(!try_catch.HasCaught());
12002 }
12003
12004 {
12005 Local<FunctionTemplate> function_template =
12006 FunctionTemplate::New(isolate, call_as_function);
12007 Local<Function> function =
12008 function_template->GetFunction(context.local()).ToLocalChecked();
12009 Local<Object> instance = function;
12010 v8::TryCatch try_catch(isolate);
12011
12012 CHECK(instance->IsCallable());
12013 CHECK(!try_catch.HasCaught());
12014 }
12015
12016 {
12017 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
12018 Local<Function> function =
12019 function_template->GetFunction(context.local()).ToLocalChecked();
12020 Local<Object> instance = function;
12021 v8::TryCatch try_catch(isolate);
12022
12023 CHECK(instance->IsCallable());
12024 CHECK(!try_catch.HasCaught());
12025 }
12026 }
12027
12028
THREADED_TEST(Regress567998)12029 THREADED_TEST(Regress567998) {
12030 LocalContext env;
12031 v8::HandleScope scope(env->GetIsolate());
12032
12033 Local<v8::FunctionTemplate> desc =
12034 v8::FunctionTemplate::New(env->GetIsolate());
12035 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
12036 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
12037
12038 Local<v8::Object> obj = desc->GetFunction(env.local())
12039 .ToLocalChecked()
12040 ->NewInstance(env.local())
12041 .ToLocalChecked();
12042 CHECK(
12043 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
12044
12045 ExpectString("undetectable.toString()", "[object Object]");
12046 ExpectString("typeof undetectable", "undefined");
12047 ExpectString("typeof(undetectable)", "undefined");
12048 ExpectBoolean("typeof undetectable == 'undefined'", true);
12049 ExpectBoolean("typeof undetectable == 'object'", false);
12050 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
12051 ExpectBoolean("!undetectable", true);
12052
12053 ExpectObject("true&&undetectable", obj);
12054 ExpectBoolean("false&&undetectable", false);
12055 ExpectBoolean("true||undetectable", true);
12056 ExpectObject("false||undetectable", obj);
12057
12058 ExpectObject("undetectable&&true", obj);
12059 ExpectObject("undetectable&&false", obj);
12060 ExpectBoolean("undetectable||true", true);
12061 ExpectBoolean("undetectable||false", false);
12062
12063 ExpectBoolean("undetectable==null", true);
12064 ExpectBoolean("null==undetectable", true);
12065 ExpectBoolean("undetectable==undefined", true);
12066 ExpectBoolean("undefined==undetectable", true);
12067 ExpectBoolean("undetectable==undetectable", true);
12068
12069 ExpectBoolean("undetectable===null", false);
12070 ExpectBoolean("null===undetectable", false);
12071 ExpectBoolean("undetectable===undefined", false);
12072 ExpectBoolean("undefined===undetectable", false);
12073 ExpectBoolean("undetectable===undetectable", true);
12074 }
12075
12076
Recurse(v8::Isolate * isolate,int depth,int iterations)12077 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
12078 v8::HandleScope scope(isolate);
12079 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
12080 for (int i = 0; i < iterations; i++) {
12081 Local<v8::Number> n(v8::Integer::New(isolate, 42));
12082 }
12083 return Recurse(isolate, depth - 1, iterations);
12084 }
12085
12086
THREADED_TEST(HandleIteration)12087 THREADED_TEST(HandleIteration) {
12088 static const int kIterations = 500;
12089 static const int kNesting = 200;
12090 LocalContext context;
12091 v8::Isolate* isolate = context->GetIsolate();
12092 v8::HandleScope scope0(isolate);
12093 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12094 {
12095 v8::HandleScope scope1(isolate);
12096 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12097 for (int i = 0; i < kIterations; i++) {
12098 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12099 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12100 }
12101
12102 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12103 {
12104 v8::HandleScope scope2(CcTest::isolate());
12105 for (int j = 0; j < kIterations; j++) {
12106 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12107 CHECK_EQ(j + 1 + kIterations,
12108 v8::HandleScope::NumberOfHandles(isolate));
12109 }
12110 }
12111 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12112 }
12113 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12114 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12115 }
12116
12117
InterceptorCallICFastApi(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)12118 static void InterceptorCallICFastApi(
12119 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12120 ApiTestFuzzer::Fuzz();
12121 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12122 int* call_count =
12123 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12124 ++(*call_count);
12125 if ((*call_count) % 20 == 0) {
12126 CcTest::heap()->CollectAllGarbage();
12127 }
12128 }
12129
FastApiCallback_TrivialSignature(const v8::FunctionCallbackInfo<v8::Value> & args)12130 static void FastApiCallback_TrivialSignature(
12131 const v8::FunctionCallbackInfo<v8::Value>& args) {
12132 ApiTestFuzzer::Fuzz();
12133 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12134 v8::Isolate* isolate = CcTest::isolate();
12135 CHECK_EQ(isolate, args.GetIsolate());
12136 CHECK(args.This()
12137 ->Equals(isolate->GetCurrentContext(), args.Holder())
12138 .FromJust());
12139 CHECK(args.Data()
12140 ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12141 .FromJust());
12142 args.GetReturnValue().Set(
12143 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12144 }
12145
FastApiCallback_SimpleSignature(const v8::FunctionCallbackInfo<v8::Value> & args)12146 static void FastApiCallback_SimpleSignature(
12147 const v8::FunctionCallbackInfo<v8::Value>& args) {
12148 ApiTestFuzzer::Fuzz();
12149 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12150 v8::Isolate* isolate = CcTest::isolate();
12151 CHECK_EQ(isolate, args.GetIsolate());
12152 CHECK(args.This()
12153 ->GetPrototype()
12154 ->Equals(isolate->GetCurrentContext(), args.Holder())
12155 .FromJust());
12156 CHECK(args.Data()
12157 ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12158 .FromJust());
12159 // Note, we're using HasRealNamedProperty instead of Has to avoid
12160 // invoking the interceptor again.
12161 CHECK(args.Holder()
12162 ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12163 .FromJust());
12164 args.GetReturnValue().Set(
12165 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12166 }
12167
12168
12169 // Helper to maximize the odds of object moving.
GenerateSomeGarbage()12170 static void GenerateSomeGarbage() {
12171 CompileRun(
12172 "var garbage;"
12173 "for (var i = 0; i < 1000; i++) {"
12174 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12175 "}"
12176 "garbage = undefined;");
12177 }
12178
12179
DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value> & args)12180 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12181 static int count = 0;
12182 if (count++ % 3 == 0) {
12183 CcTest::heap()->CollectAllGarbage();
12184 // This should move the stub
12185 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12186 }
12187 }
12188
12189
THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub)12190 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12191 LocalContext context;
12192 v8::Isolate* isolate = context->GetIsolate();
12193 v8::HandleScope scope(isolate);
12194 v8::Local<v8::ObjectTemplate> nativeobject_templ =
12195 v8::ObjectTemplate::New(isolate);
12196 nativeobject_templ->Set(isolate, "callback",
12197 v8::FunctionTemplate::New(isolate,
12198 DirectApiCallback));
12199 v8::Local<v8::Object> nativeobject_obj =
12200 nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12201 CHECK(context->Global()
12202 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12203 .FromJust());
12204 // call the api function multiple times to ensure direct call stub creation.
12205 CompileRun(
12206 "function f() {"
12207 " for (var i = 1; i <= 30; i++) {"
12208 " nativeobject.callback();"
12209 " }"
12210 "}"
12211 "f();");
12212 }
12213
12214
ThrowingDirectApiCallback(const v8::FunctionCallbackInfo<v8::Value> & args)12215 void ThrowingDirectApiCallback(
12216 const v8::FunctionCallbackInfo<v8::Value>& args) {
12217 args.GetIsolate()->ThrowException(v8_str("g"));
12218 }
12219
12220
THREADED_TEST(CallICFastApi_DirectCall_Throw)12221 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12222 LocalContext context;
12223 v8::Isolate* isolate = context->GetIsolate();
12224 v8::HandleScope scope(isolate);
12225 v8::Local<v8::ObjectTemplate> nativeobject_templ =
12226 v8::ObjectTemplate::New(isolate);
12227 nativeobject_templ->Set(isolate, "callback",
12228 v8::FunctionTemplate::New(isolate,
12229 ThrowingDirectApiCallback));
12230 v8::Local<v8::Object> nativeobject_obj =
12231 nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12232 CHECK(context->Global()
12233 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12234 .FromJust());
12235 // call the api function multiple times to ensure direct call stub creation.
12236 v8::Local<Value> result = CompileRun(
12237 "var result = '';"
12238 "function f() {"
12239 " for (var i = 1; i <= 5; i++) {"
12240 " try { nativeobject.callback(); } catch (e) { result += e; }"
12241 " }"
12242 "}"
12243 "f(); result;");
12244 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12245 }
12246
12247
12248 static int p_getter_count_3;
12249
12250
DoDirectGetter()12251 static Local<Value> DoDirectGetter() {
12252 if (++p_getter_count_3 % 3 == 0) {
12253 CcTest::heap()->CollectAllGarbage();
12254 GenerateSomeGarbage();
12255 }
12256 return v8_str("Direct Getter Result");
12257 }
12258
12259
DirectGetterCallback(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12260 static void DirectGetterCallback(
12261 Local<String> name,
12262 const v8::PropertyCallbackInfo<v8::Value>& info) {
12263 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12264 info.GetReturnValue().Set(DoDirectGetter());
12265 }
12266
12267
12268 template<typename Accessor>
LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor)12269 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12270 LocalContext context;
12271 v8::Isolate* isolate = context->GetIsolate();
12272 v8::HandleScope scope(isolate);
12273 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12274 obj->SetAccessor(v8_str("p1"), accessor);
12275 CHECK(context->Global()
12276 ->Set(context.local(), v8_str("o1"),
12277 obj->NewInstance(context.local()).ToLocalChecked())
12278 .FromJust());
12279 p_getter_count_3 = 0;
12280 v8::Local<v8::Value> result = CompileRun(
12281 "function f() {"
12282 " for (var i = 0; i < 30; i++) o1.p1;"
12283 " return o1.p1"
12284 "}"
12285 "f();");
12286 CHECK(v8_str("Direct Getter Result")
12287 ->Equals(context.local(), result)
12288 .FromJust());
12289 CHECK_EQ(31, p_getter_count_3);
12290 }
12291
12292
THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub)12293 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12294 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12295 }
12296
12297
ThrowingDirectGetterCallback(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12298 void ThrowingDirectGetterCallback(
12299 Local<String> name,
12300 const v8::PropertyCallbackInfo<v8::Value>& info) {
12301 info.GetIsolate()->ThrowException(v8_str("g"));
12302 }
12303
12304
THREADED_TEST(LoadICFastApi_DirectCall_Throw)12305 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12306 LocalContext context;
12307 v8::Isolate* isolate = context->GetIsolate();
12308 v8::HandleScope scope(isolate);
12309 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12310 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12311 CHECK(context->Global()
12312 ->Set(context.local(), v8_str("o1"),
12313 obj->NewInstance(context.local()).ToLocalChecked())
12314 .FromJust());
12315 v8::Local<Value> result = CompileRun(
12316 "var result = '';"
12317 "for (var i = 0; i < 5; i++) {"
12318 " try { o1.p1; } catch (e) { result += e; }"
12319 "}"
12320 "result;");
12321 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12322 }
12323
12324
THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature)12325 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12326 int interceptor_call_count = 0;
12327 v8::Isolate* isolate = CcTest::isolate();
12328 v8::HandleScope scope(isolate);
12329 v8::Local<v8::FunctionTemplate> fun_templ =
12330 v8::FunctionTemplate::New(isolate);
12331 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12332 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12333 v8::Local<v8::Signature>());
12334 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12335 proto_templ->Set(v8_str("method"), method_templ);
12336 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12337 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12338 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12339 v8::External::New(isolate, &interceptor_call_count)));
12340 LocalContext context;
12341 v8::Local<v8::Function> fun =
12342 fun_templ->GetFunction(context.local()).ToLocalChecked();
12343 GenerateSomeGarbage();
12344 CHECK(context->Global()
12345 ->Set(context.local(), v8_str("o"),
12346 fun->NewInstance(context.local()).ToLocalChecked())
12347 .FromJust());
12348 CompileRun(
12349 "var result = 0;"
12350 "for (var i = 0; i < 100; i++) {"
12351 " result = o.method(41);"
12352 "}");
12353 CHECK_EQ(42, context->Global()
12354 ->Get(context.local(), v8_str("result"))
12355 .ToLocalChecked()
12356 ->Int32Value(context.local())
12357 .FromJust());
12358 CHECK_EQ(100, interceptor_call_count);
12359 }
12360
12361
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature)12362 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12363 int interceptor_call_count = 0;
12364 v8::Isolate* isolate = CcTest::isolate();
12365 v8::HandleScope scope(isolate);
12366 v8::Local<v8::FunctionTemplate> fun_templ =
12367 v8::FunctionTemplate::New(isolate);
12368 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12369 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12370 v8::Signature::New(isolate, fun_templ));
12371 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12372 proto_templ->Set(v8_str("method"), method_templ);
12373 fun_templ->SetHiddenPrototype(true);
12374 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12375 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12376 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12377 v8::External::New(isolate, &interceptor_call_count)));
12378 LocalContext context;
12379 v8::Local<v8::Function> fun =
12380 fun_templ->GetFunction(context.local()).ToLocalChecked();
12381 GenerateSomeGarbage();
12382 CHECK(context->Global()
12383 ->Set(context.local(), v8_str("o"),
12384 fun->NewInstance(context.local()).ToLocalChecked())
12385 .FromJust());
12386 CompileRun(
12387 "o.foo = 17;"
12388 "var receiver = {};"
12389 "receiver.__proto__ = o;"
12390 "var result = 0;"
12391 "for (var i = 0; i < 100; i++) {"
12392 " result = receiver.method(41);"
12393 "}");
12394 CHECK_EQ(42, context->Global()
12395 ->Get(context.local(), v8_str("result"))
12396 .ToLocalChecked()
12397 ->Int32Value(context.local())
12398 .FromJust());
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::Local<v8::FunctionTemplate> fun_templ =
12408 v8::FunctionTemplate::New(isolate);
12409 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12410 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12411 v8::Signature::New(isolate, fun_templ));
12412 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12413 proto_templ->Set(v8_str("method"), method_templ);
12414 fun_templ->SetHiddenPrototype(true);
12415 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12416 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12417 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12418 v8::External::New(isolate, &interceptor_call_count)));
12419 LocalContext context;
12420 v8::Local<v8::Function> fun =
12421 fun_templ->GetFunction(context.local()).ToLocalChecked();
12422 GenerateSomeGarbage();
12423 CHECK(context->Global()
12424 ->Set(context.local(), v8_str("o"),
12425 fun->NewInstance(context.local()).ToLocalChecked())
12426 .FromJust());
12427 CompileRun(
12428 "o.foo = 17;"
12429 "var receiver = {};"
12430 "receiver.__proto__ = o;"
12431 "var result = 0;"
12432 "var saved_result = 0;"
12433 "for (var i = 0; i < 100; i++) {"
12434 " result = receiver.method(41);"
12435 " if (i == 50) {"
12436 " saved_result = result;"
12437 " receiver = {method: function(x) { return x - 1 }};"
12438 " }"
12439 "}");
12440 CHECK_EQ(40, context->Global()
12441 ->Get(context.local(), v8_str("result"))
12442 .ToLocalChecked()
12443 ->Int32Value(context.local())
12444 .FromJust());
12445 CHECK_EQ(42, context->Global()
12446 ->Get(context.local(), v8_str("saved_result"))
12447 .ToLocalChecked()
12448 ->Int32Value(context.local())
12449 .FromJust());
12450 CHECK_GE(interceptor_call_count, 50);
12451 }
12452
12453
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2)12454 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12455 int interceptor_call_count = 0;
12456 v8::Isolate* isolate = CcTest::isolate();
12457 v8::HandleScope scope(isolate);
12458 v8::Local<v8::FunctionTemplate> fun_templ =
12459 v8::FunctionTemplate::New(isolate);
12460 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12461 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12462 v8::Signature::New(isolate, fun_templ));
12463 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12464 proto_templ->Set(v8_str("method"), method_templ);
12465 fun_templ->SetHiddenPrototype(true);
12466 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12467 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12468 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12469 v8::External::New(isolate, &interceptor_call_count)));
12470 LocalContext context;
12471 v8::Local<v8::Function> fun =
12472 fun_templ->GetFunction(context.local()).ToLocalChecked();
12473 GenerateSomeGarbage();
12474 CHECK(context->Global()
12475 ->Set(context.local(), v8_str("o"),
12476 fun->NewInstance(context.local()).ToLocalChecked())
12477 .FromJust());
12478 CompileRun(
12479 "o.foo = 17;"
12480 "var receiver = {};"
12481 "receiver.__proto__ = o;"
12482 "var result = 0;"
12483 "var saved_result = 0;"
12484 "for (var i = 0; i < 100; i++) {"
12485 " result = receiver.method(41);"
12486 " if (i == 50) {"
12487 " saved_result = result;"
12488 " o.method = function(x) { return x - 1 };"
12489 " }"
12490 "}");
12491 CHECK_EQ(40, context->Global()
12492 ->Get(context.local(), v8_str("result"))
12493 .ToLocalChecked()
12494 ->Int32Value(context.local())
12495 .FromJust());
12496 CHECK_EQ(42, context->Global()
12497 ->Get(context.local(), v8_str("saved_result"))
12498 .ToLocalChecked()
12499 ->Int32Value(context.local())
12500 .FromJust());
12501 CHECK_GE(interceptor_call_count, 50);
12502 }
12503
12504
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3)12505 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12506 int interceptor_call_count = 0;
12507 v8::Isolate* isolate = CcTest::isolate();
12508 v8::HandleScope scope(isolate);
12509 v8::Local<v8::FunctionTemplate> fun_templ =
12510 v8::FunctionTemplate::New(isolate);
12511 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12512 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12513 v8::Signature::New(isolate, fun_templ));
12514 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12515 proto_templ->Set(v8_str("method"), method_templ);
12516 fun_templ->SetHiddenPrototype(true);
12517 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12518 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12519 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12520 v8::External::New(isolate, &interceptor_call_count)));
12521 LocalContext context;
12522 v8::Local<v8::Function> fun =
12523 fun_templ->GetFunction(context.local()).ToLocalChecked();
12524 GenerateSomeGarbage();
12525 CHECK(context->Global()
12526 ->Set(context.local(), v8_str("o"),
12527 fun->NewInstance(context.local()).ToLocalChecked())
12528 .FromJust());
12529 v8::TryCatch try_catch(isolate);
12530 CompileRun(
12531 "o.foo = 17;"
12532 "var receiver = {};"
12533 "receiver.__proto__ = o;"
12534 "var result = 0;"
12535 "var saved_result = 0;"
12536 "for (var i = 0; i < 100; i++) {"
12537 " result = receiver.method(41);"
12538 " if (i == 50) {"
12539 " saved_result = result;"
12540 " receiver = 333;"
12541 " }"
12542 "}");
12543 CHECK(try_catch.HasCaught());
12544 // TODO(verwaest): Adjust message.
12545 CHECK(
12546 v8_str("TypeError: receiver.method is not a function")
12547 ->Equals(
12548 context.local(),
12549 try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12550 .FromJust());
12551 CHECK_EQ(42, context->Global()
12552 ->Get(context.local(), v8_str("saved_result"))
12553 .ToLocalChecked()
12554 ->Int32Value(context.local())
12555 .FromJust());
12556 CHECK_GE(interceptor_call_count, 50);
12557 }
12558
12559
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError)12560 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12561 int interceptor_call_count = 0;
12562 v8::Isolate* isolate = CcTest::isolate();
12563 v8::HandleScope scope(isolate);
12564 v8::Local<v8::FunctionTemplate> fun_templ =
12565 v8::FunctionTemplate::New(isolate);
12566 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12567 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12568 v8::Signature::New(isolate, fun_templ));
12569 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12570 proto_templ->Set(v8_str("method"), method_templ);
12571 fun_templ->SetHiddenPrototype(true);
12572 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12573 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12574 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12575 v8::External::New(isolate, &interceptor_call_count)));
12576 LocalContext context;
12577 v8::Local<v8::Function> fun =
12578 fun_templ->GetFunction(context.local()).ToLocalChecked();
12579 GenerateSomeGarbage();
12580 CHECK(context->Global()
12581 ->Set(context.local(), v8_str("o"),
12582 fun->NewInstance(context.local()).ToLocalChecked())
12583 .FromJust());
12584 v8::TryCatch try_catch(isolate);
12585 CompileRun(
12586 "o.foo = 17;"
12587 "var receiver = {};"
12588 "receiver.__proto__ = o;"
12589 "var result = 0;"
12590 "var saved_result = 0;"
12591 "for (var i = 0; i < 100; i++) {"
12592 " result = receiver.method(41);"
12593 " if (i == 50) {"
12594 " saved_result = result;"
12595 " receiver = {method: receiver.method};"
12596 " }"
12597 "}");
12598 CHECK(try_catch.HasCaught());
12599 CHECK(
12600 v8_str("TypeError: Illegal invocation")
12601 ->Equals(
12602 context.local(),
12603 try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12604 .FromJust());
12605 CHECK_EQ(42, context->Global()
12606 ->Get(context.local(), v8_str("saved_result"))
12607 .ToLocalChecked()
12608 ->Int32Value(context.local())
12609 .FromJust());
12610 CHECK_GE(interceptor_call_count, 50);
12611 }
12612
12613
THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature)12614 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12615 v8::Isolate* isolate = CcTest::isolate();
12616 v8::HandleScope scope(isolate);
12617 v8::Local<v8::FunctionTemplate> fun_templ =
12618 v8::FunctionTemplate::New(isolate);
12619 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12620 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12621 v8::Local<v8::Signature>());
12622 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12623 proto_templ->Set(v8_str("method"), method_templ);
12624 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12625 USE(templ);
12626 LocalContext context;
12627 v8::Local<v8::Function> fun =
12628 fun_templ->GetFunction(context.local()).ToLocalChecked();
12629 GenerateSomeGarbage();
12630 CHECK(context->Global()
12631 ->Set(context.local(), v8_str("o"),
12632 fun->NewInstance(context.local()).ToLocalChecked())
12633 .FromJust());
12634 CompileRun(
12635 "var result = 0;"
12636 "for (var i = 0; i < 100; i++) {"
12637 " result = o.method(41);"
12638 "}");
12639
12640 CHECK_EQ(42, context->Global()
12641 ->Get(context.local(), v8_str("result"))
12642 .ToLocalChecked()
12643 ->Int32Value(context.local())
12644 .FromJust());
12645 }
12646
12647
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature)12648 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12649 v8::Isolate* isolate = CcTest::isolate();
12650 v8::HandleScope scope(isolate);
12651 v8::Local<v8::FunctionTemplate> fun_templ =
12652 v8::FunctionTemplate::New(isolate);
12653 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12654 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12655 v8::Signature::New(isolate, fun_templ));
12656 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12657 proto_templ->Set(v8_str("method"), method_templ);
12658 fun_templ->SetHiddenPrototype(true);
12659 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12660 CHECK(!templ.IsEmpty());
12661 LocalContext context;
12662 v8::Local<v8::Function> fun =
12663 fun_templ->GetFunction(context.local()).ToLocalChecked();
12664 GenerateSomeGarbage();
12665 CHECK(context->Global()
12666 ->Set(context.local(), v8_str("o"),
12667 fun->NewInstance(context.local()).ToLocalChecked())
12668 .FromJust());
12669 CompileRun(
12670 "o.foo = 17;"
12671 "var receiver = {};"
12672 "receiver.__proto__ = o;"
12673 "var result = 0;"
12674 "for (var i = 0; i < 100; i++) {"
12675 " result = receiver.method(41);"
12676 "}");
12677
12678 CHECK_EQ(42, context->Global()
12679 ->Get(context.local(), v8_str("result"))
12680 .ToLocalChecked()
12681 ->Int32Value(context.local())
12682 .FromJust());
12683 }
12684
12685
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1)12686 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12687 v8::Isolate* isolate = CcTest::isolate();
12688 v8::HandleScope scope(isolate);
12689 v8::Local<v8::FunctionTemplate> fun_templ =
12690 v8::FunctionTemplate::New(isolate);
12691 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12692 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12693 v8::Signature::New(isolate, fun_templ));
12694 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12695 proto_templ->Set(v8_str("method"), method_templ);
12696 fun_templ->SetHiddenPrototype(true);
12697 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12698 CHECK(!templ.IsEmpty());
12699 LocalContext context;
12700 v8::Local<v8::Function> fun =
12701 fun_templ->GetFunction(context.local()).ToLocalChecked();
12702 GenerateSomeGarbage();
12703 CHECK(context->Global()
12704 ->Set(context.local(), v8_str("o"),
12705 fun->NewInstance(context.local()).ToLocalChecked())
12706 .FromJust());
12707 CompileRun(
12708 "o.foo = 17;"
12709 "var receiver = {};"
12710 "receiver.__proto__ = o;"
12711 "var result = 0;"
12712 "var saved_result = 0;"
12713 "for (var i = 0; i < 100; i++) {"
12714 " result = receiver.method(41);"
12715 " if (i == 50) {"
12716 " saved_result = result;"
12717 " receiver = {method: function(x) { return x - 1 }};"
12718 " }"
12719 "}");
12720 CHECK_EQ(40, context->Global()
12721 ->Get(context.local(), v8_str("result"))
12722 .ToLocalChecked()
12723 ->Int32Value(context.local())
12724 .FromJust());
12725 CHECK_EQ(42, context->Global()
12726 ->Get(context.local(), v8_str("saved_result"))
12727 .ToLocalChecked()
12728 ->Int32Value(context.local())
12729 .FromJust());
12730 }
12731
12732
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2)12733 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12734 v8::Isolate* isolate = CcTest::isolate();
12735 v8::HandleScope scope(isolate);
12736 v8::Local<v8::FunctionTemplate> fun_templ =
12737 v8::FunctionTemplate::New(isolate);
12738 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12739 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12740 v8::Signature::New(isolate, fun_templ));
12741 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12742 proto_templ->Set(v8_str("method"), method_templ);
12743 fun_templ->SetHiddenPrototype(true);
12744 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12745 CHECK(!templ.IsEmpty());
12746 LocalContext context;
12747 v8::Local<v8::Function> fun =
12748 fun_templ->GetFunction(context.local()).ToLocalChecked();
12749 GenerateSomeGarbage();
12750 CHECK(context->Global()
12751 ->Set(context.local(), v8_str("o"),
12752 fun->NewInstance(context.local()).ToLocalChecked())
12753 .FromJust());
12754 v8::TryCatch try_catch(isolate);
12755 CompileRun(
12756 "o.foo = 17;"
12757 "var receiver = {};"
12758 "receiver.__proto__ = o;"
12759 "var result = 0;"
12760 "var saved_result = 0;"
12761 "for (var i = 0; i < 100; i++) {"
12762 " result = receiver.method(41);"
12763 " if (i == 50) {"
12764 " saved_result = result;"
12765 " receiver = 333;"
12766 " }"
12767 "}");
12768 CHECK(try_catch.HasCaught());
12769 // TODO(verwaest): Adjust message.
12770 CHECK(
12771 v8_str("TypeError: receiver.method is not a function")
12772 ->Equals(
12773 context.local(),
12774 try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12775 .FromJust());
12776 CHECK_EQ(42, context->Global()
12777 ->Get(context.local(), v8_str("saved_result"))
12778 .ToLocalChecked()
12779 ->Int32Value(context.local())
12780 .FromJust());
12781 }
12782
12783
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError)12784 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12785 v8::Isolate* isolate = CcTest::isolate();
12786 v8::HandleScope scope(isolate);
12787 v8::Local<v8::FunctionTemplate> fun_templ =
12788 v8::FunctionTemplate::New(isolate);
12789 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12790 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12791 v8::Signature::New(isolate, fun_templ));
12792 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12793 proto_templ->Set(v8_str("method"), method_templ);
12794 fun_templ->SetHiddenPrototype(true);
12795 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12796 CHECK(!templ.IsEmpty());
12797 LocalContext context;
12798 v8::Local<v8::Function> fun =
12799 fun_templ->GetFunction(context.local()).ToLocalChecked();
12800 GenerateSomeGarbage();
12801 CHECK(context->Global()
12802 ->Set(context.local(), v8_str("o"),
12803 fun->NewInstance(context.local()).ToLocalChecked())
12804 .FromJust());
12805 v8::TryCatch try_catch(isolate);
12806 CompileRun(
12807 "o.foo = 17;"
12808 "var receiver = {};"
12809 "receiver.__proto__ = o;"
12810 "var result = 0;"
12811 "var saved_result = 0;"
12812 "for (var i = 0; i < 100; i++) {"
12813 " result = receiver.method(41);"
12814 " if (i == 50) {"
12815 " saved_result = result;"
12816 " receiver = Object.create(receiver);"
12817 " }"
12818 "}");
12819 CHECK(try_catch.HasCaught());
12820 CHECK(
12821 v8_str("TypeError: Illegal invocation")
12822 ->Equals(
12823 context.local(),
12824 try_catch.Exception()->ToString(context.local()).ToLocalChecked())
12825 .FromJust());
12826 CHECK_EQ(42, context->Global()
12827 ->Get(context.local(), v8_str("saved_result"))
12828 .ToLocalChecked()
12829 ->Int32Value(context.local())
12830 .FromJust());
12831 }
12832
12833
ThrowingGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)12834 static void ThrowingGetter(Local<String> name,
12835 const v8::PropertyCallbackInfo<v8::Value>& info) {
12836 ApiTestFuzzer::Fuzz();
12837 info.GetIsolate()->ThrowException(Local<Value>());
12838 info.GetReturnValue().SetUndefined();
12839 }
12840
12841
THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks)12842 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12843 LocalContext context;
12844 HandleScope scope(context->GetIsolate());
12845
12846 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12847 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12848 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12849
12850 Local<Object> instance = templ->GetFunction(context.local())
12851 .ToLocalChecked()
12852 ->NewInstance(context.local())
12853 .ToLocalChecked();
12854
12855 Local<Object> another = Object::New(context->GetIsolate());
12856 CHECK(another->SetPrototype(context.local(), instance).FromJust());
12857
12858 Local<Object> with_js_getter = CompileRun(
12859 "o = {};\n"
12860 "o.__defineGetter__('f', function() { throw undefined; });\n"
12861 "o\n").As<Object>();
12862 CHECK(!with_js_getter.IsEmpty());
12863
12864 TryCatch try_catch(context->GetIsolate());
12865
12866 v8::MaybeLocal<Value> result =
12867 instance->GetRealNamedProperty(context.local(), v8_str("f"));
12868 CHECK(try_catch.HasCaught());
12869 try_catch.Reset();
12870 CHECK(result.IsEmpty());
12871
12872 Maybe<PropertyAttribute> attr =
12873 instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12874 CHECK(!try_catch.HasCaught());
12875 CHECK(Just(None) == attr);
12876
12877 result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12878 CHECK(try_catch.HasCaught());
12879 try_catch.Reset();
12880 CHECK(result.IsEmpty());
12881
12882 attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12883 CHECK(!try_catch.HasCaught());
12884 CHECK(Just(None) == attr);
12885
12886 result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12887 v8_str("f"));
12888 CHECK(try_catch.HasCaught());
12889 try_catch.Reset();
12890 CHECK(result.IsEmpty());
12891
12892 attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12893 context.local(), v8_str("f"));
12894 CHECK(!try_catch.HasCaught());
12895 CHECK(Just(None) == attr);
12896
12897 result = another->Get(context.local(), v8_str("f"));
12898 CHECK(try_catch.HasCaught());
12899 try_catch.Reset();
12900 CHECK(result.IsEmpty());
12901
12902 result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12903 CHECK(try_catch.HasCaught());
12904 try_catch.Reset();
12905 CHECK(result.IsEmpty());
12906
12907 attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12908 v8_str("f"));
12909 CHECK(!try_catch.HasCaught());
12910 CHECK(Just(None) == attr);
12911
12912 result = with_js_getter->Get(context.local(), v8_str("f"));
12913 CHECK(try_catch.HasCaught());
12914 try_catch.Reset();
12915 CHECK(result.IsEmpty());
12916
12917 Local<Object> target = CompileRun("({})").As<Object>();
12918 Local<Object> handler = CompileRun("({})").As<Object>();
12919 Local<v8::Proxy> proxy =
12920 v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12921
12922 result = target->GetRealNamedProperty(context.local(), v8_str("f"));
12923 CHECK(!try_catch.HasCaught());
12924 CHECK(result.IsEmpty());
12925
12926 result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
12927 CHECK(!try_catch.HasCaught());
12928 CHECK(result.IsEmpty());
12929 }
12930
12931
ThrowingCallbackWithTryCatch(const v8::FunctionCallbackInfo<v8::Value> & args)12932 static void ThrowingCallbackWithTryCatch(
12933 const v8::FunctionCallbackInfo<v8::Value>& args) {
12934 TryCatch try_catch(args.GetIsolate());
12935 // Verboseness is important: it triggers message delivery which can call into
12936 // external code.
12937 try_catch.SetVerbose(true);
12938 CompileRun("throw 'from JS';");
12939 CHECK(try_catch.HasCaught());
12940 CHECK(!CcTest::i_isolate()->has_pending_exception());
12941 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12942 }
12943
12944
12945 static int call_depth;
12946
12947
WithTryCatch(Local<Message> message,Local<Value> data)12948 static void WithTryCatch(Local<Message> message, Local<Value> data) {
12949 TryCatch try_catch(CcTest::isolate());
12950 }
12951
12952
ThrowFromJS(Local<Message> message,Local<Value> data)12953 static void ThrowFromJS(Local<Message> message, Local<Value> data) {
12954 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12955 }
12956
12957
ThrowViaApi(Local<Message> message,Local<Value> data)12958 static void ThrowViaApi(Local<Message> message, Local<Value> data) {
12959 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12960 }
12961
12962
WebKitLike(Local<Message> message,Local<Value> data)12963 static void WebKitLike(Local<Message> message, Local<Value> data) {
12964 Local<String> errorMessageString = message->Get();
12965 CHECK(!errorMessageString.IsEmpty());
12966 message->GetStackTrace();
12967 message->GetScriptOrigin().ResourceName();
12968 }
12969
12970
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch)12971 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12972 LocalContext context;
12973 v8::Isolate* isolate = context->GetIsolate();
12974 HandleScope scope(isolate);
12975
12976 Local<Function> func =
12977 FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
12978 ->GetFunction(context.local())
12979 .ToLocalChecked();
12980 CHECK(
12981 context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
12982
12983 MessageCallback callbacks[] =
12984 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12985 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12986 MessageCallback callback = callbacks[i];
12987 if (callback != NULL) {
12988 isolate->AddMessageListener(callback);
12989 }
12990 // Some small number to control number of times message handler should
12991 // throw an exception.
12992 call_depth = 5;
12993 ExpectFalse(
12994 "var thrown = false;\n"
12995 "try { func(); } catch(e) { thrown = true; }\n"
12996 "thrown\n");
12997 if (callback != NULL) {
12998 isolate->RemoveMessageListeners(callback);
12999 }
13000 }
13001 }
13002
13003
ParentGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)13004 static void ParentGetter(Local<String> name,
13005 const v8::PropertyCallbackInfo<v8::Value>& info) {
13006 ApiTestFuzzer::Fuzz();
13007 info.GetReturnValue().Set(v8_num(1));
13008 }
13009
13010
ChildGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)13011 static void ChildGetter(Local<String> name,
13012 const v8::PropertyCallbackInfo<v8::Value>& info) {
13013 ApiTestFuzzer::Fuzz();
13014 info.GetReturnValue().Set(v8_num(42));
13015 }
13016
13017
THREADED_TEST(Overriding)13018 THREADED_TEST(Overriding) {
13019 LocalContext context;
13020 v8::Isolate* isolate = context->GetIsolate();
13021 v8::HandleScope scope(isolate);
13022
13023 // Parent template.
13024 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13025 Local<ObjectTemplate> parent_instance_templ =
13026 parent_templ->InstanceTemplate();
13027 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13028
13029 // Template that inherits from the parent template.
13030 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13031 Local<ObjectTemplate> child_instance_templ =
13032 child_templ->InstanceTemplate();
13033 child_templ->Inherit(parent_templ);
13034 // Override 'f'. The child version of 'f' should get called for child
13035 // instances.
13036 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13037 // Add 'g' twice. The 'g' added last should get called for instances.
13038 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13039 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13040
13041 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13042 // so 'h' can be shadowed on the instance object.
13043 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13044 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13045 v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
13046
13047 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13048 // but the attribute does not have effect because it is duplicated with
13049 // NULL setter.
13050 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13051 v8::Local<Value>(), v8::DEFAULT,
13052 v8::ReadOnly);
13053
13054
13055 // Instantiate the child template.
13056 Local<v8::Object> instance = child_templ->GetFunction(context.local())
13057 .ToLocalChecked()
13058 ->NewInstance(context.local())
13059 .ToLocalChecked();
13060
13061 // Check that the child function overrides the parent one.
13062 CHECK(context->Global()
13063 ->Set(context.local(), v8_str("o"), instance)
13064 .FromJust());
13065 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13066 // Check that the 'g' that was added last is hit.
13067 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13068 value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
13069 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13070
13071 // Check that 'h' cannot be shadowed.
13072 value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
13073 CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
13074
13075 // Check that 'i' cannot be shadowed or changed.
13076 value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
13077 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
13078 }
13079
13080
ShouldThrowOnErrorGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)13081 static void ShouldThrowOnErrorGetter(
13082 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13083 ApiTestFuzzer::Fuzz();
13084 v8::Isolate* isolate = info.GetIsolate();
13085 Local<Boolean> should_throw_on_error =
13086 Boolean::New(isolate, info.ShouldThrowOnError());
13087 info.GetReturnValue().Set(should_throw_on_error);
13088 }
13089
13090
13091 template <typename T>
ShouldThrowOnErrorSetter(Local<Name> name,Local<v8::Value> value,const v8::PropertyCallbackInfo<T> & info)13092 static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
13093 const v8::PropertyCallbackInfo<T>& info) {
13094 ApiTestFuzzer::Fuzz();
13095 v8::Isolate* isolate = info.GetIsolate();
13096 auto context = isolate->GetCurrentContext();
13097 Local<Boolean> should_throw_on_error_value =
13098 Boolean::New(isolate, info.ShouldThrowOnError());
13099 CHECK(context->Global()
13100 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
13101 should_throw_on_error_value)
13102 .FromJust());
13103 }
13104
13105
THREADED_TEST(AccessorShouldThrowOnError)13106 THREADED_TEST(AccessorShouldThrowOnError) {
13107 LocalContext context;
13108 v8::Isolate* isolate = context->GetIsolate();
13109 v8::HandleScope scope(isolate);
13110 Local<Object> global = context->Global();
13111
13112 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13113 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13114 instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
13115 ShouldThrowOnErrorSetter<void>);
13116
13117 Local<v8::Object> instance = templ->GetFunction(context.local())
13118 .ToLocalChecked()
13119 ->NewInstance(context.local())
13120 .ToLocalChecked();
13121
13122 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13123
13124 // SLOPPY mode
13125 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13126 CHECK(value->IsFalse());
13127 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13128 value = global->Get(context.local(), v8_str("should_throw_setter"))
13129 .ToLocalChecked();
13130 CHECK(value->IsFalse());
13131
13132 // STRICT mode
13133 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13134 CHECK(value->IsFalse());
13135 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13136 value = global->Get(context.local(), v8_str("should_throw_setter"))
13137 .ToLocalChecked();
13138 CHECK(value->IsTrue());
13139 }
13140
13141
ShouldThrowOnErrorQuery(Local<Name> name,const v8::PropertyCallbackInfo<v8::Integer> & info)13142 static void ShouldThrowOnErrorQuery(
13143 Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
13144 ApiTestFuzzer::Fuzz();
13145 v8::Isolate* isolate = info.GetIsolate();
13146 info.GetReturnValue().Set(v8::None);
13147
13148 auto context = isolate->GetCurrentContext();
13149 Local<Boolean> should_throw_on_error_value =
13150 Boolean::New(isolate, info.ShouldThrowOnError());
13151 CHECK(context->Global()
13152 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
13153 should_throw_on_error_value)
13154 .FromJust());
13155 }
13156
13157
ShouldThrowOnErrorDeleter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Boolean> & info)13158 static void ShouldThrowOnErrorDeleter(
13159 Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
13160 ApiTestFuzzer::Fuzz();
13161 v8::Isolate* isolate = info.GetIsolate();
13162 info.GetReturnValue().Set(v8::True(isolate));
13163
13164 auto context = isolate->GetCurrentContext();
13165 Local<Boolean> should_throw_on_error_value =
13166 Boolean::New(isolate, info.ShouldThrowOnError());
13167 CHECK(context->Global()
13168 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
13169 should_throw_on_error_value)
13170 .FromJust());
13171 }
13172
13173
ShouldThrowOnErrorPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)13174 static void ShouldThrowOnErrorPropertyEnumerator(
13175 const v8::PropertyCallbackInfo<v8::Array>& info) {
13176 ApiTestFuzzer::Fuzz();
13177 v8::Isolate* isolate = info.GetIsolate();
13178 Local<v8::Array> names = v8::Array::New(isolate, 1);
13179 CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
13180 info.GetReturnValue().Set(names);
13181
13182 auto context = isolate->GetCurrentContext();
13183 Local<Boolean> should_throw_on_error_value =
13184 Boolean::New(isolate, info.ShouldThrowOnError());
13185 CHECK(context->Global()
13186 ->Set(isolate->GetCurrentContext(),
13187 v8_str("should_throw_enumerator"),
13188 should_throw_on_error_value)
13189 .FromJust());
13190 }
13191
13192
THREADED_TEST(InterceptorShouldThrowOnError)13193 THREADED_TEST(InterceptorShouldThrowOnError) {
13194 LocalContext context;
13195 v8::Isolate* isolate = context->GetIsolate();
13196 v8::HandleScope scope(isolate);
13197 Local<Object> global = context->Global();
13198
13199 auto interceptor_templ = v8::ObjectTemplate::New(isolate);
13200 v8::NamedPropertyHandlerConfiguration handler(
13201 ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
13202 ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
13203 ShouldThrowOnErrorPropertyEnumerator);
13204 interceptor_templ->SetHandler(handler);
13205
13206 Local<v8::Object> instance =
13207 interceptor_templ->NewInstance(context.local()).ToLocalChecked();
13208
13209 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
13210
13211 // SLOPPY mode
13212 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
13213 CHECK(value->IsFalse());
13214 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
13215 value = global->Get(context.local(), v8_str("should_throw_setter"))
13216 .ToLocalChecked();
13217 CHECK(value->IsFalse());
13218
13219 v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
13220 value = global->Get(context.local(), v8_str("should_throw_deleter"))
13221 .ToLocalChecked();
13222 CHECK(value->IsFalse());
13223
13224 v8_compile("Object.getOwnPropertyNames(o)")
13225 ->Run(context.local())
13226 .ToLocalChecked();
13227 value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13228 .ToLocalChecked();
13229 CHECK(value->IsFalse());
13230
13231 // STRICT mode
13232 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
13233 CHECK(value->IsFalse());
13234 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
13235 value = global->Get(context.local(), v8_str("should_throw_setter"))
13236 .ToLocalChecked();
13237 CHECK(value->IsTrue());
13238
13239 v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
13240 value = global->Get(context.local(), v8_str("should_throw_deleter"))
13241 .ToLocalChecked();
13242 CHECK(value->IsTrue());
13243
13244 v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
13245 ->Run(context.local())
13246 .ToLocalChecked();
13247 value = global->Get(context.local(), v8_str("should_throw_enumerator"))
13248 .ToLocalChecked();
13249 CHECK(value->IsFalse());
13250 }
13251
13252
IsConstructHandler(const v8::FunctionCallbackInfo<v8::Value> & args)13253 static void IsConstructHandler(
13254 const v8::FunctionCallbackInfo<v8::Value>& args) {
13255 ApiTestFuzzer::Fuzz();
13256 args.GetReturnValue().Set(args.IsConstructCall());
13257 }
13258
13259
THREADED_TEST(IsConstructCall)13260 THREADED_TEST(IsConstructCall) {
13261 v8::Isolate* isolate = CcTest::isolate();
13262 v8::HandleScope scope(isolate);
13263
13264 // Function template with call handler.
13265 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13266 templ->SetCallHandler(IsConstructHandler);
13267
13268 LocalContext context;
13269
13270 CHECK(context->Global()
13271 ->Set(context.local(), v8_str("f"),
13272 templ->GetFunction(context.local()).ToLocalChecked())
13273 .FromJust());
13274 Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
13275 CHECK(!value->BooleanValue(context.local()).FromJust());
13276 value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
13277 CHECK(value->BooleanValue(context.local()).FromJust());
13278 }
13279
NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value> & args)13280 static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
13281 ApiTestFuzzer::Fuzz();
13282 args.GetReturnValue().Set(args.NewTarget());
13283 }
13284
THREADED_TEST(NewTargetHandler)13285 THREADED_TEST(NewTargetHandler) {
13286 v8::Isolate* isolate = CcTest::isolate();
13287 v8::HandleScope scope(isolate);
13288
13289 // Function template with call handler.
13290 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13291 templ->SetCallHandler(NewTargetHandler);
13292
13293 LocalContext context;
13294
13295 Local<Function> function =
13296 templ->GetFunction(context.local()).ToLocalChecked();
13297 CHECK(context->Global()
13298 ->Set(context.local(), v8_str("f"), function)
13299 .FromJust());
13300 Local<Value> value = CompileRun("f()");
13301 CHECK(value->IsUndefined());
13302 value = CompileRun("new f()");
13303 CHECK(value->IsFunction());
13304 CHECK(value == function);
13305 Local<Value> subclass = CompileRun("var g = class extends f { }; g");
13306 CHECK(subclass->IsFunction());
13307 value = CompileRun("new g()");
13308 CHECK(value->IsFunction());
13309 CHECK(value == subclass);
13310 value = CompileRun("Reflect.construct(f, [], Array)");
13311 CHECK(value->IsFunction());
13312 CHECK(value ==
13313 context->Global()
13314 ->Get(context.local(), v8_str("Array"))
13315 .ToLocalChecked());
13316 }
13317
THREADED_TEST(ObjectProtoToString)13318 THREADED_TEST(ObjectProtoToString) {
13319 v8::Isolate* isolate = CcTest::isolate();
13320 v8::HandleScope scope(isolate);
13321 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13322 templ->SetClassName(v8_str("MyClass"));
13323
13324 LocalContext context;
13325
13326 Local<String> customized_tostring = v8_str("customized toString");
13327
13328 // Replace Object.prototype.toString
13329 v8_compile(
13330 "Object.prototype.toString = function() {"
13331 " return 'customized toString';"
13332 "}")
13333 ->Run(context.local())
13334 .ToLocalChecked();
13335
13336 // Normal ToString call should call replaced Object.prototype.toString
13337 Local<v8::Object> instance = templ->GetFunction(context.local())
13338 .ToLocalChecked()
13339 ->NewInstance(context.local())
13340 .ToLocalChecked();
13341 Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13342 CHECK(value->IsString() &&
13343 value->Equals(context.local(), customized_tostring).FromJust());
13344
13345 // ObjectProtoToString should not call replace toString function.
13346 value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13347 CHECK(value->IsString() &&
13348 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13349
13350 // Check global
13351 value =
13352 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13353 CHECK(value->IsString() &&
13354 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13355
13356 // Check ordinary object
13357 Local<Value> object =
13358 v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13359 value = object.As<v8::Object>()
13360 ->ObjectProtoToString(context.local())
13361 .ToLocalChecked();
13362 CHECK(value->IsString() &&
13363 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13364 }
13365
13366
TEST(ObjectProtoToStringES6)13367 TEST(ObjectProtoToStringES6) {
13368 LocalContext context;
13369 v8::Isolate* isolate = CcTest::isolate();
13370 v8::HandleScope scope(isolate);
13371 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13372 templ->SetClassName(v8_str("MyClass"));
13373
13374 Local<String> customized_tostring = v8_str("customized toString");
13375
13376 // Replace Object.prototype.toString
13377 CompileRun(
13378 "Object.prototype.toString = function() {"
13379 " return 'customized toString';"
13380 "}");
13381
13382 // Normal ToString call should call replaced Object.prototype.toString
13383 Local<v8::Object> instance = templ->GetFunction(context.local())
13384 .ToLocalChecked()
13385 ->NewInstance(context.local())
13386 .ToLocalChecked();
13387 Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13388 CHECK(value->IsString() &&
13389 value->Equals(context.local(), customized_tostring).FromJust());
13390
13391 // ObjectProtoToString should not call replace toString function.
13392 value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13393 CHECK(value->IsString() &&
13394 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13395
13396 // Check global
13397 value =
13398 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13399 CHECK(value->IsString() &&
13400 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13401
13402 // Check ordinary object
13403 Local<Value> object = CompileRun("new Object()");
13404 value = object.As<v8::Object>()
13405 ->ObjectProtoToString(context.local())
13406 .ToLocalChecked();
13407 CHECK(value->IsString() &&
13408 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13409
13410 // Check that ES6 semantics using @@toStringTag work
13411 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13412
13413 #define TEST_TOSTRINGTAG(type, tag, expected) \
13414 do { \
13415 object = CompileRun("new " #type "()"); \
13416 CHECK(object.As<v8::Object>() \
13417 ->Set(context.local(), toStringTag, v8_str(#tag)) \
13418 .FromJust()); \
13419 value = object.As<v8::Object>() \
13420 ->ObjectProtoToString(context.local()) \
13421 .ToLocalChecked(); \
13422 CHECK(value->IsString() && \
13423 value->Equals(context.local(), v8_str("[object " #expected "]")) \
13424 .FromJust()); \
13425 } while (0)
13426
13427 TEST_TOSTRINGTAG(Array, Object, Object);
13428 TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13429 TEST_TOSTRINGTAG(Object, Array, Array);
13430 TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13431 TEST_TOSTRINGTAG(Object, Date, Date);
13432 TEST_TOSTRINGTAG(Object, Error, Error);
13433 TEST_TOSTRINGTAG(Object, Function, Function);
13434 TEST_TOSTRINGTAG(Object, Number, Number);
13435 TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13436 TEST_TOSTRINGTAG(Object, String, String);
13437 TEST_TOSTRINGTAG(Object, Foo, Foo);
13438
13439 #undef TEST_TOSTRINGTAG
13440
13441 Local<v8::RegExp> valueRegExp =
13442 v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13443 .ToLocalChecked();
13444 Local<Value> valueNumber = v8_num(123);
13445 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13446 Local<v8::Function> valueFunction =
13447 CompileRun("(function fn() {})").As<v8::Function>();
13448 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13449 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13450 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13451
13452 #define TEST_TOSTRINGTAG(type, tagValue, expected) \
13453 do { \
13454 object = CompileRun("new " #type "()"); \
13455 CHECK(object.As<v8::Object>() \
13456 ->Set(context.local(), toStringTag, tagValue) \
13457 .FromJust()); \
13458 value = object.As<v8::Object>() \
13459 ->ObjectProtoToString(context.local()) \
13460 .ToLocalChecked(); \
13461 CHECK(value->IsString() && \
13462 value->Equals(context.local(), v8_str("[object " #expected "]")) \
13463 .FromJust()); \
13464 } while (0)
13465
13466 #define TEST_TOSTRINGTAG_TYPES(tagValue) \
13467 TEST_TOSTRINGTAG(Array, tagValue, Array); \
13468 TEST_TOSTRINGTAG(Object, tagValue, Object); \
13469 TEST_TOSTRINGTAG(Function, tagValue, Function); \
13470 TEST_TOSTRINGTAG(Date, tagValue, Date); \
13471 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13472 TEST_TOSTRINGTAG(Error, tagValue, Error); \
13473
13474 // Test non-String-valued @@toStringTag
13475 TEST_TOSTRINGTAG_TYPES(valueRegExp);
13476 TEST_TOSTRINGTAG_TYPES(valueNumber);
13477 TEST_TOSTRINGTAG_TYPES(valueSymbol);
13478 TEST_TOSTRINGTAG_TYPES(valueFunction);
13479 TEST_TOSTRINGTAG_TYPES(valueObject);
13480 TEST_TOSTRINGTAG_TYPES(valueNull);
13481 TEST_TOSTRINGTAG_TYPES(valueUndef);
13482
13483 #undef TEST_TOSTRINGTAG
13484 #undef TEST_TOSTRINGTAG_TYPES
13485
13486 // @@toStringTag getter throws
13487 Local<Value> obj = v8::Object::New(isolate);
13488 obj.As<v8::Object>()
13489 ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13490 .FromJust();
13491 {
13492 TryCatch try_catch(isolate);
13493 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13494 CHECK(try_catch.HasCaught());
13495 }
13496
13497 // @@toStringTag getter does not throw
13498 obj = v8::Object::New(isolate);
13499 obj.As<v8::Object>()
13500 ->SetAccessor(context.local(), toStringTag,
13501 SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"))
13502 .FromJust();
13503 {
13504 TryCatch try_catch(isolate);
13505 value = obj.As<v8::Object>()
13506 ->ObjectProtoToString(context.local())
13507 .ToLocalChecked();
13508 CHECK(value->IsString() &&
13509 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13510 CHECK(!try_catch.HasCaught());
13511 }
13512
13513 // JS @@toStringTag value
13514 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13515 {
13516 TryCatch try_catch(isolate);
13517 value = obj.As<v8::Object>()
13518 ->ObjectProtoToString(context.local())
13519 .ToLocalChecked();
13520 CHECK(value->IsString() &&
13521 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13522 CHECK(!try_catch.HasCaught());
13523 }
13524
13525 // JS @@toStringTag getter throws
13526 obj = CompileRun(
13527 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13528 " get: function() { throw 'Test'; }"
13529 "}); obj");
13530 {
13531 TryCatch try_catch(isolate);
13532 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13533 CHECK(try_catch.HasCaught());
13534 }
13535
13536 // JS @@toStringTag getter does not throw
13537 obj = CompileRun(
13538 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13539 " get: function() { return 'Test'; }"
13540 "}); obj");
13541 {
13542 TryCatch try_catch(isolate);
13543 value = obj.As<v8::Object>()
13544 ->ObjectProtoToString(context.local())
13545 .ToLocalChecked();
13546 CHECK(value->IsString() &&
13547 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13548 CHECK(!try_catch.HasCaught());
13549 }
13550 }
13551
13552
THREADED_TEST(ObjectGetConstructorName)13553 THREADED_TEST(ObjectGetConstructorName) {
13554 v8::Isolate* isolate = CcTest::isolate();
13555 LocalContext context;
13556 v8::HandleScope scope(isolate);
13557 v8_compile(
13558 "function Parent() {};"
13559 "function Child() {};"
13560 "Child.prototype = new Parent();"
13561 "Child.prototype.constructor = Child;"
13562 "var outer = { inner: (0, function() { }) };"
13563 "var p = new Parent();"
13564 "var c = new Child();"
13565 "var x = new outer.inner();"
13566 "var proto = Child.prototype;")
13567 ->Run(context.local())
13568 .ToLocalChecked();
13569
13570 Local<v8::Value> p =
13571 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13572 CHECK(p->IsObject() &&
13573 p->ToObject(context.local())
13574 .ToLocalChecked()
13575 ->GetConstructorName()
13576 ->Equals(context.local(), v8_str("Parent"))
13577 .FromJust());
13578
13579 Local<v8::Value> c =
13580 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13581 CHECK(c->IsObject() &&
13582 c->ToObject(context.local())
13583 .ToLocalChecked()
13584 ->GetConstructorName()
13585 ->Equals(context.local(), v8_str("Child"))
13586 .FromJust());
13587
13588 Local<v8::Value> x =
13589 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13590 CHECK(x->IsObject() &&
13591 x->ToObject(context.local())
13592 .ToLocalChecked()
13593 ->GetConstructorName()
13594 ->Equals(context.local(), v8_str("outer.inner"))
13595 .FromJust());
13596
13597 Local<v8::Value> child_prototype =
13598 context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13599 CHECK(child_prototype->IsObject() &&
13600 child_prototype->ToObject(context.local())
13601 .ToLocalChecked()
13602 ->GetConstructorName()
13603 ->Equals(context.local(), v8_str("Parent"))
13604 .FromJust());
13605 }
13606
13607
THREADED_TEST(SubclassGetConstructorName)13608 THREADED_TEST(SubclassGetConstructorName) {
13609 v8::Isolate* isolate = CcTest::isolate();
13610 LocalContext context;
13611 v8::HandleScope scope(isolate);
13612 v8_compile(
13613 "\"use strict\";"
13614 "class Parent {}"
13615 "class Child extends Parent {}"
13616 "var p = new Parent();"
13617 "var c = new Child();")
13618 ->Run(context.local())
13619 .ToLocalChecked();
13620
13621 Local<v8::Value> p =
13622 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13623 CHECK(p->IsObject() &&
13624 p->ToObject(context.local())
13625 .ToLocalChecked()
13626 ->GetConstructorName()
13627 ->Equals(context.local(), v8_str("Parent"))
13628 .FromJust());
13629
13630 Local<v8::Value> c =
13631 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13632 CHECK(c->IsObject() &&
13633 c->ToObject(context.local())
13634 .ToLocalChecked()
13635 ->GetConstructorName()
13636 ->Equals(context.local(), v8_str("Child"))
13637 .FromJust());
13638 }
13639
13640
13641 bool ApiTestFuzzer::fuzzing_ = false;
13642 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13643 int ApiTestFuzzer::active_tests_;
13644 int ApiTestFuzzer::tests_being_run_;
13645 int ApiTestFuzzer::current_;
13646
13647
13648 // We are in a callback and want to switch to another thread (if we
13649 // are currently running the thread fuzzing test).
Fuzz()13650 void ApiTestFuzzer::Fuzz() {
13651 if (!fuzzing_) return;
13652 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13653 test->ContextSwitch();
13654 }
13655
13656
13657 // Let the next thread go. Since it is also waiting on the V8 lock it may
13658 // not start immediately.
NextThread()13659 bool ApiTestFuzzer::NextThread() {
13660 int test_position = GetNextTestNumber();
13661 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13662 if (test_position == current_) {
13663 if (kLogThreading)
13664 printf("Stay with %s\n", test_name);
13665 return false;
13666 }
13667 if (kLogThreading) {
13668 printf("Switch from %s to %s\n",
13669 test_name,
13670 RegisterThreadedTest::nth(test_position)->name());
13671 }
13672 current_ = test_position;
13673 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13674 return true;
13675 }
13676
13677
Run()13678 void ApiTestFuzzer::Run() {
13679 // When it is our turn...
13680 gate_.Wait();
13681 {
13682 // ... get the V8 lock and start running the test.
13683 v8::Locker locker(CcTest::isolate());
13684 CallTest();
13685 }
13686 // This test finished.
13687 active_ = false;
13688 active_tests_--;
13689 // If it was the last then signal that fact.
13690 if (active_tests_ == 0) {
13691 all_tests_done_.Signal();
13692 } else {
13693 // Otherwise select a new test and start that.
13694 NextThread();
13695 }
13696 }
13697
13698
13699 static unsigned linear_congruential_generator;
13700
13701
SetUp(PartOfTest part)13702 void ApiTestFuzzer::SetUp(PartOfTest part) {
13703 linear_congruential_generator = i::FLAG_testing_prng_seed;
13704 fuzzing_ = true;
13705 int count = RegisterThreadedTest::count();
13706 int start = count * part / (LAST_PART + 1);
13707 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13708 active_tests_ = tests_being_run_ = end - start + 1;
13709 for (int i = 0; i < tests_being_run_; i++) {
13710 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13711 }
13712 for (int i = 0; i < active_tests_; i++) {
13713 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13714 }
13715 }
13716
13717
CallTestNumber(int test_number)13718 static void CallTestNumber(int test_number) {
13719 (RegisterThreadedTest::nth(test_number)->callback())();
13720 }
13721
13722
RunAllTests()13723 void ApiTestFuzzer::RunAllTests() {
13724 // Set off the first test.
13725 current_ = -1;
13726 NextThread();
13727 // Wait till they are all done.
13728 all_tests_done_.Wait();
13729 }
13730
13731
GetNextTestNumber()13732 int ApiTestFuzzer::GetNextTestNumber() {
13733 int next_test;
13734 do {
13735 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13736 linear_congruential_generator *= 1664525u;
13737 linear_congruential_generator += 1013904223u;
13738 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13739 return next_test;
13740 }
13741
13742
ContextSwitch()13743 void ApiTestFuzzer::ContextSwitch() {
13744 // If the new thread is the same as the current thread there is nothing to do.
13745 if (NextThread()) {
13746 // Now it can start.
13747 v8::Unlocker unlocker(CcTest::isolate());
13748 // Wait till someone starts us again.
13749 gate_.Wait();
13750 // And we're off.
13751 }
13752 }
13753
13754
TearDown()13755 void ApiTestFuzzer::TearDown() {
13756 fuzzing_ = false;
13757 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13758 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13759 if (fuzzer != NULL) fuzzer->Join();
13760 }
13761 }
13762
13763
13764 // Lets not be needlessly self-referential.
TEST(Threading1)13765 TEST(Threading1) {
13766 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13767 ApiTestFuzzer::RunAllTests();
13768 ApiTestFuzzer::TearDown();
13769 }
13770
13771
TEST(Threading2)13772 TEST(Threading2) {
13773 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13774 ApiTestFuzzer::RunAllTests();
13775 ApiTestFuzzer::TearDown();
13776 }
13777
13778
TEST(Threading3)13779 TEST(Threading3) {
13780 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13781 ApiTestFuzzer::RunAllTests();
13782 ApiTestFuzzer::TearDown();
13783 }
13784
13785
TEST(Threading4)13786 TEST(Threading4) {
13787 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13788 ApiTestFuzzer::RunAllTests();
13789 ApiTestFuzzer::TearDown();
13790 }
13791
13792
CallTest()13793 void ApiTestFuzzer::CallTest() {
13794 v8::Isolate::Scope scope(CcTest::isolate());
13795 if (kLogThreading)
13796 printf("Start test %d\n", test_number_);
13797 CallTestNumber(test_number_);
13798 if (kLogThreading)
13799 printf("End test %d\n", test_number_);
13800 }
13801
13802
ThrowInJS(const v8::FunctionCallbackInfo<v8::Value> & args)13803 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13804 v8::Isolate* isolate = args.GetIsolate();
13805 CHECK(v8::Locker::IsLocked(isolate));
13806 ApiTestFuzzer::Fuzz();
13807 v8::Unlocker unlocker(isolate);
13808 const char* code = "throw 7;";
13809 {
13810 v8::Locker nested_locker(isolate);
13811 v8::HandleScope scope(isolate);
13812 v8::Local<Value> exception;
13813 {
13814 v8::TryCatch try_catch(isolate);
13815 v8::Local<Value> value = CompileRun(code);
13816 CHECK(value.IsEmpty());
13817 CHECK(try_catch.HasCaught());
13818 // Make sure to wrap the exception in a new handle because
13819 // the handle returned from the TryCatch is destroyed
13820 // when the TryCatch is destroyed.
13821 exception = Local<Value>::New(isolate, try_catch.Exception());
13822 }
13823 args.GetIsolate()->ThrowException(exception);
13824 }
13825 }
13826
13827
ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value> & args)13828 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13829 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13830 ApiTestFuzzer::Fuzz();
13831 v8::Unlocker unlocker(CcTest::isolate());
13832 const char* code = "throw 7;";
13833 {
13834 v8::Locker nested_locker(CcTest::isolate());
13835 v8::HandleScope scope(args.GetIsolate());
13836 v8::Local<Value> value = CompileRun(code);
13837 CHECK(value.IsEmpty());
13838 args.GetReturnValue().Set(v8_str("foo"));
13839 }
13840 }
13841
13842
13843 // These are locking tests that don't need to be run again
13844 // as part of the locking aggregation tests.
TEST(NestedLockers)13845 TEST(NestedLockers) {
13846 v8::Isolate* isolate = CcTest::isolate();
13847 v8::Locker locker(isolate);
13848 CHECK(v8::Locker::IsLocked(isolate));
13849 LocalContext env;
13850 v8::HandleScope scope(env->GetIsolate());
13851 Local<v8::FunctionTemplate> fun_templ =
13852 v8::FunctionTemplate::New(isolate, ThrowInJS);
13853 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13854 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13855 Local<Script> script = v8_compile("(function () {"
13856 " try {"
13857 " throw_in_js();"
13858 " return 42;"
13859 " } catch (e) {"
13860 " return e * 13;"
13861 " }"
13862 "})();");
13863 CHECK_EQ(91, script->Run(env.local())
13864 .ToLocalChecked()
13865 ->Int32Value(env.local())
13866 .FromJust());
13867 }
13868
13869
13870 // These are locking tests that don't need to be run again
13871 // as part of the locking aggregation tests.
TEST(NestedLockersNoTryCatch)13872 TEST(NestedLockersNoTryCatch) {
13873 v8::Locker locker(CcTest::isolate());
13874 LocalContext env;
13875 v8::HandleScope scope(env->GetIsolate());
13876 Local<v8::FunctionTemplate> fun_templ =
13877 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13878 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13879 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13880 Local<Script> script = v8_compile("(function () {"
13881 " try {"
13882 " throw_in_js();"
13883 " return 42;"
13884 " } catch (e) {"
13885 " return e * 13;"
13886 " }"
13887 "})();");
13888 CHECK_EQ(91, script->Run(env.local())
13889 .ToLocalChecked()
13890 ->Int32Value(env.local())
13891 .FromJust());
13892 }
13893
13894
THREADED_TEST(RecursiveLocking)13895 THREADED_TEST(RecursiveLocking) {
13896 v8::Locker locker(CcTest::isolate());
13897 {
13898 v8::Locker locker2(CcTest::isolate());
13899 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13900 }
13901 }
13902
13903
UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value> & args)13904 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13905 ApiTestFuzzer::Fuzz();
13906 v8::Unlocker unlocker(CcTest::isolate());
13907 }
13908
13909
THREADED_TEST(LockUnlockLock)13910 THREADED_TEST(LockUnlockLock) {
13911 {
13912 v8::Locker locker(CcTest::isolate());
13913 v8::HandleScope scope(CcTest::isolate());
13914 LocalContext env;
13915 Local<v8::FunctionTemplate> fun_templ =
13916 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13917 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13918 CHECK(env->Global()
13919 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13920 .FromJust());
13921 Local<Script> script = v8_compile("(function () {"
13922 " unlock_for_a_moment();"
13923 " return 42;"
13924 "})();");
13925 CHECK_EQ(42, script->Run(env.local())
13926 .ToLocalChecked()
13927 ->Int32Value(env.local())
13928 .FromJust());
13929 }
13930 {
13931 v8::Locker locker(CcTest::isolate());
13932 v8::HandleScope scope(CcTest::isolate());
13933 LocalContext env;
13934 Local<v8::FunctionTemplate> fun_templ =
13935 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13936 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13937 CHECK(env->Global()
13938 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13939 .FromJust());
13940 Local<Script> script = v8_compile("(function () {"
13941 " unlock_for_a_moment();"
13942 " return 42;"
13943 "})();");
13944 CHECK_EQ(42, script->Run(env.local())
13945 .ToLocalChecked()
13946 ->Int32Value(env.local())
13947 .FromJust());
13948 }
13949 }
13950
13951
GetGlobalObjectsCount()13952 static int GetGlobalObjectsCount() {
13953 int count = 0;
13954 i::HeapIterator it(CcTest::heap());
13955 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13956 if (object->IsJSGlobalObject()) {
13957 i::JSGlobalObject* g = i::JSGlobalObject::cast(object);
13958 // Skip dummy global object.
13959 if (i::GlobalDictionary::cast(g->properties())->NumberOfElements() != 0) {
13960 count++;
13961 }
13962 }
13963 return count;
13964 }
13965
13966
CheckSurvivingGlobalObjectsCount(int expected)13967 static void CheckSurvivingGlobalObjectsCount(int expected) {
13968 // We need to collect all garbage twice to be sure that everything
13969 // has been collected. This is because inline caches are cleared in
13970 // the first garbage collection but some of the maps have already
13971 // been marked at that point. Therefore some of the maps are not
13972 // collected until the second garbage collection.
13973 CcTest::heap()->CollectAllGarbage();
13974 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13975 int count = GetGlobalObjectsCount();
13976 #ifdef DEBUG
13977 if (count != expected) CcTest::heap()->TracePathToGlobal();
13978 #endif
13979 CHECK_EQ(expected, count);
13980 }
13981
13982
TEST(DontLeakGlobalObjects)13983 TEST(DontLeakGlobalObjects) {
13984 // Regression test for issues 1139850 and 1174891.
13985
13986 i::FLAG_expose_gc = true;
13987 v8::V8::Initialize();
13988
13989 for (int i = 0; i < 5; i++) {
13990 { v8::HandleScope scope(CcTest::isolate());
13991 LocalContext context;
13992 }
13993 CcTest::isolate()->ContextDisposedNotification();
13994 CheckSurvivingGlobalObjectsCount(0);
13995
13996 { v8::HandleScope scope(CcTest::isolate());
13997 LocalContext context;
13998 v8_compile("Date")->Run(context.local()).ToLocalChecked();
13999 }
14000 CcTest::isolate()->ContextDisposedNotification();
14001 CheckSurvivingGlobalObjectsCount(0);
14002
14003 { v8::HandleScope scope(CcTest::isolate());
14004 LocalContext context;
14005 v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
14006 }
14007 CcTest::isolate()->ContextDisposedNotification();
14008 CheckSurvivingGlobalObjectsCount(0);
14009
14010 { v8::HandleScope scope(CcTest::isolate());
14011 const char* extension_list[] = { "v8/gc" };
14012 v8::ExtensionConfiguration extensions(1, extension_list);
14013 LocalContext context(&extensions);
14014 v8_compile("gc();")->Run(context.local()).ToLocalChecked();
14015 }
14016 CcTest::isolate()->ContextDisposedNotification();
14017 CheckSurvivingGlobalObjectsCount(0);
14018 }
14019 }
14020
14021
TEST(CopyablePersistent)14022 TEST(CopyablePersistent) {
14023 LocalContext context;
14024 v8::Isolate* isolate = context->GetIsolate();
14025 i::GlobalHandles* globals =
14026 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14027 int initial_handles = globals->global_handles_count();
14028 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14029 CopyableObject;
14030 {
14031 CopyableObject handle1;
14032 {
14033 v8::HandleScope scope(isolate);
14034 handle1.Reset(isolate, v8::Object::New(isolate));
14035 }
14036 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14037 CopyableObject handle2;
14038 handle2 = handle1;
14039 CHECK(handle1 == handle2);
14040 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14041 CopyableObject handle3(handle2);
14042 CHECK(handle1 == handle3);
14043 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14044 }
14045 // Verify autodispose
14046 CHECK_EQ(initial_handles, globals->global_handles_count());
14047 }
14048
14049
WeakApiCallback(const v8::WeakCallbackInfo<Persistent<v8::Object>> & data)14050 static void WeakApiCallback(
14051 const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
14052 data.GetParameter()->Reset();
14053 delete data.GetParameter();
14054 }
14055
14056
TEST(WeakCallbackApi)14057 TEST(WeakCallbackApi) {
14058 LocalContext context;
14059 v8::Isolate* isolate = context->GetIsolate();
14060 i::GlobalHandles* globals =
14061 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14062 int initial_handles = globals->global_handles_count();
14063 {
14064 v8::HandleScope scope(isolate);
14065 v8::Local<v8::Object> obj = v8::Object::New(isolate);
14066 CHECK(
14067 obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
14068 .FromJust());
14069 v8::Persistent<v8::Object>* handle =
14070 new v8::Persistent<v8::Object>(isolate, obj);
14071 handle->SetWeak<v8::Persistent<v8::Object>>(
14072 handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
14073 }
14074 reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
14075 i::Heap::kAbortIncrementalMarkingMask);
14076 // Verify disposed.
14077 CHECK_EQ(initial_handles, globals->global_handles_count());
14078 }
14079
14080
14081 v8::Persistent<v8::Object> some_object;
14082 v8::Persistent<v8::Object> bad_handle;
14083
14084
NewPersistentHandleCallback2(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14085 void NewPersistentHandleCallback2(
14086 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14087 v8::HandleScope scope(data.GetIsolate());
14088 bad_handle.Reset(data.GetIsolate(), some_object);
14089 }
14090
14091
NewPersistentHandleCallback1(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14092 void NewPersistentHandleCallback1(
14093 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14094 data.GetParameter()->Reset();
14095 data.SetSecondPassCallback(NewPersistentHandleCallback2);
14096 }
14097
14098
THREADED_TEST(NewPersistentHandleFromWeakCallback)14099 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14100 LocalContext context;
14101 v8::Isolate* isolate = context->GetIsolate();
14102
14103 v8::Persistent<v8::Object> handle1, handle2;
14104 {
14105 v8::HandleScope scope(isolate);
14106 some_object.Reset(isolate, v8::Object::New(isolate));
14107 handle1.Reset(isolate, v8::Object::New(isolate));
14108 handle2.Reset(isolate, v8::Object::New(isolate));
14109 }
14110 // Note: order is implementation dependent alas: currently
14111 // global handle nodes are processed by PostGarbageCollectionProcessing
14112 // in reverse allocation order, so if second allocated handle is deleted,
14113 // weak callback of the first handle would be able to 'reallocate' it.
14114 handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
14115 v8::WeakCallbackType::kParameter);
14116 handle2.Reset();
14117 CcTest::heap()->CollectAllGarbage();
14118 }
14119
14120
14121 v8::Persistent<v8::Object> to_be_disposed;
14122
14123
DisposeAndForceGcCallback2(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14124 void DisposeAndForceGcCallback2(
14125 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14126 to_be_disposed.Reset();
14127 CcTest::heap()->CollectAllGarbage();
14128 }
14129
14130
DisposeAndForceGcCallback1(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14131 void DisposeAndForceGcCallback1(
14132 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14133 data.GetParameter()->Reset();
14134 data.SetSecondPassCallback(DisposeAndForceGcCallback2);
14135 }
14136
14137
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc)14138 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14139 LocalContext context;
14140 v8::Isolate* isolate = context->GetIsolate();
14141
14142 v8::Persistent<v8::Object> handle1, handle2;
14143 {
14144 v8::HandleScope scope(isolate);
14145 handle1.Reset(isolate, v8::Object::New(isolate));
14146 handle2.Reset(isolate, v8::Object::New(isolate));
14147 }
14148 handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
14149 v8::WeakCallbackType::kParameter);
14150 to_be_disposed.Reset(isolate, handle2);
14151 CcTest::heap()->CollectAllGarbage();
14152 }
14153
DisposingCallback(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14154 void DisposingCallback(
14155 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14156 data.GetParameter()->Reset();
14157 }
14158
HandleCreatingCallback2(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14159 void HandleCreatingCallback2(
14160 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14161 v8::HandleScope scope(data.GetIsolate());
14162 v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
14163 }
14164
14165
HandleCreatingCallback1(const v8::WeakCallbackInfo<v8::Persistent<v8::Object>> & data)14166 void HandleCreatingCallback1(
14167 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
14168 data.GetParameter()->Reset();
14169 data.SetSecondPassCallback(HandleCreatingCallback2);
14170 }
14171
14172
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback)14173 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14174 v8::Locker locker(CcTest::isolate());
14175 LocalContext context;
14176 v8::Isolate* isolate = context->GetIsolate();
14177
14178 v8::Persistent<v8::Object> handle1, handle2, handle3;
14179 {
14180 v8::HandleScope scope(isolate);
14181 handle3.Reset(isolate, v8::Object::New(isolate));
14182 handle2.Reset(isolate, v8::Object::New(isolate));
14183 handle1.Reset(isolate, v8::Object::New(isolate));
14184 }
14185 handle2.SetWeak(&handle2, DisposingCallback,
14186 v8::WeakCallbackType::kParameter);
14187 handle3.SetWeak(&handle3, HandleCreatingCallback1,
14188 v8::WeakCallbackType::kParameter);
14189 CcTest::heap()->CollectAllGarbage();
14190 EmptyMessageQueues(isolate);
14191 }
14192
14193
THREADED_TEST(CheckForCrossContextObjectLiterals)14194 THREADED_TEST(CheckForCrossContextObjectLiterals) {
14195 v8::V8::Initialize();
14196
14197 const int nof = 2;
14198 const char* sources[nof] = {
14199 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14200 "Object()"
14201 };
14202
14203 for (int i = 0; i < nof; i++) {
14204 const char* source = sources[i];
14205 { v8::HandleScope scope(CcTest::isolate());
14206 LocalContext context;
14207 CompileRun(source);
14208 }
14209 { v8::HandleScope scope(CcTest::isolate());
14210 LocalContext context;
14211 CompileRun(source);
14212 }
14213 }
14214 }
14215
14216
NestedScope(v8::Local<Context> env)14217 static v8::Local<Value> NestedScope(v8::Local<Context> env) {
14218 v8::EscapableHandleScope inner(env->GetIsolate());
14219 env->Enter();
14220 v8::Local<Value> three = v8_num(3);
14221 v8::Local<Value> value = inner.Escape(three);
14222 env->Exit();
14223 return value;
14224 }
14225
14226
THREADED_TEST(NestedHandleScopeAndContexts)14227 THREADED_TEST(NestedHandleScopeAndContexts) {
14228 v8::Isolate* isolate = CcTest::isolate();
14229 v8::HandleScope outer(isolate);
14230 v8::Local<Context> env = Context::New(isolate);
14231 env->Enter();
14232 v8::Local<Value> value = NestedScope(env);
14233 v8::Local<String> str(value->ToString(env).ToLocalChecked());
14234 CHECK(!str.IsEmpty());
14235 env->Exit();
14236 }
14237
14238
MatchPointers(void * key1,void * key2)14239 static bool MatchPointers(void* key1, void* key2) {
14240 return key1 == key2;
14241 }
14242
14243
14244 struct SymbolInfo {
14245 size_t id;
14246 size_t size;
14247 std::string name;
14248 };
14249
14250
14251 class SetFunctionEntryHookTest {
14252 public:
SetFunctionEntryHookTest()14253 SetFunctionEntryHookTest() {
14254 CHECK(instance_ == NULL);
14255 instance_ = this;
14256 }
~SetFunctionEntryHookTest()14257 ~SetFunctionEntryHookTest() {
14258 CHECK(instance_ == this);
14259 instance_ = NULL;
14260 }
Reset()14261 void Reset() {
14262 symbols_.clear();
14263 symbol_locations_.clear();
14264 invocations_.clear();
14265 }
14266 void RunTest();
14267 void OnJitEvent(const v8::JitCodeEvent* event);
JitEvent(const v8::JitCodeEvent * event)14268 static void JitEvent(const v8::JitCodeEvent* event) {
14269 CHECK(instance_ != NULL);
14270 instance_->OnJitEvent(event);
14271 }
14272
14273 void OnEntryHook(uintptr_t function,
14274 uintptr_t return_addr_location);
EntryHook(uintptr_t function,uintptr_t return_addr_location)14275 static void EntryHook(uintptr_t function,
14276 uintptr_t return_addr_location) {
14277 CHECK(instance_ != NULL);
14278 instance_->OnEntryHook(function, return_addr_location);
14279 }
14280
RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value> & args)14281 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14282 CHECK(instance_ != NULL);
14283 args.GetReturnValue().Set(v8_num(42));
14284 }
14285 void RunLoopInNewEnv(v8::Isolate* isolate);
14286
14287 // Records addr as location of symbol.
14288 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14289
14290 // Finds the symbol containing addr
14291 SymbolInfo* FindSymbolForAddr(i::Address addr);
14292 // Returns the number of invocations where the caller name contains
14293 // \p caller_name and the function name contains \p function_name.
14294 int CountInvocations(const char* caller_name,
14295 const char* function_name);
14296
14297 i::Handle<i::JSFunction> foo_func_;
14298 i::Handle<i::JSFunction> bar_func_;
14299
14300 typedef std::map<size_t, SymbolInfo> SymbolMap;
14301 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14302 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14303 SymbolMap symbols_;
14304 SymbolLocationMap symbol_locations_;
14305 InvocationMap invocations_;
14306
14307 static SetFunctionEntryHookTest* instance_;
14308 };
14309 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14310
14311
14312 // Returns true if addr is in the range [start, start+len).
Overlaps(i::Address start,size_t len,i::Address addr)14313 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14314 if (start <= addr && start + len > addr)
14315 return true;
14316
14317 return false;
14318 }
14319
InsertSymbolAt(i::Address addr,SymbolInfo * symbol)14320 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14321 SymbolInfo* symbol) {
14322 // Insert the symbol at the new location.
14323 SymbolLocationMap::iterator it =
14324 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14325 // Now erase symbols to the left and right that overlap this one.
14326 while (it != symbol_locations_.begin()) {
14327 SymbolLocationMap::iterator left = it;
14328 --left;
14329 if (!Overlaps(left->first, left->second->size, addr))
14330 break;
14331 symbol_locations_.erase(left);
14332 }
14333
14334 // Now erase symbols to the left and right that overlap this one.
14335 while (true) {
14336 SymbolLocationMap::iterator right = it;
14337 ++right;
14338 if (right == symbol_locations_.end())
14339 break;
14340 if (!Overlaps(addr, symbol->size, right->first))
14341 break;
14342 symbol_locations_.erase(right);
14343 }
14344 }
14345
14346
OnJitEvent(const v8::JitCodeEvent * event)14347 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14348 switch (event->type) {
14349 case v8::JitCodeEvent::CODE_ADDED: {
14350 CHECK(event->code_start != NULL);
14351 CHECK_NE(0, static_cast<int>(event->code_len));
14352 CHECK(event->name.str != NULL);
14353 size_t symbol_id = symbols_.size();
14354
14355 // Record the new symbol.
14356 SymbolInfo& info = symbols_[symbol_id];
14357 info.id = symbol_id;
14358 info.size = event->code_len;
14359 info.name.assign(event->name.str, event->name.str + event->name.len);
14360
14361 // And record it's location.
14362 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14363 }
14364 break;
14365
14366 case v8::JitCodeEvent::CODE_MOVED: {
14367 // We would like to never see code move that we haven't seen before,
14368 // but the code creation event does not happen until the line endings
14369 // have been calculated (this is so that we can report the line in the
14370 // script at which the function source is found, see
14371 // Compiler::RecordFunctionCompilation) and the line endings
14372 // calculations can cause a GC, which can move the newly created code
14373 // before its existence can be logged.
14374 SymbolLocationMap::iterator it(
14375 symbol_locations_.find(
14376 reinterpret_cast<i::Address>(event->code_start)));
14377 if (it != symbol_locations_.end()) {
14378 // Found a symbol at this location, move it.
14379 SymbolInfo* info = it->second;
14380 symbol_locations_.erase(it);
14381 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14382 info);
14383 }
14384 }
14385 default:
14386 break;
14387 }
14388 }
14389
OnEntryHook(uintptr_t function,uintptr_t return_addr_location)14390 void SetFunctionEntryHookTest::OnEntryHook(
14391 uintptr_t function, uintptr_t return_addr_location) {
14392 // Get the function's code object.
14393 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14394 reinterpret_cast<i::Address>(function));
14395 CHECK(function_code != NULL);
14396
14397 // Then try and look up the caller's code object.
14398 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14399
14400 // Count the invocation.
14401 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14402 SymbolInfo* function_symbol =
14403 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14404 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14405
14406 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14407 // Check that we have a symbol for the "bar" function at the right location.
14408 SymbolLocationMap::iterator it(
14409 symbol_locations_.find(function_code->instruction_start()));
14410 CHECK(it != symbol_locations_.end());
14411 }
14412
14413 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14414 // Check that we have a symbol for "foo" at the right location.
14415 SymbolLocationMap::iterator it(
14416 symbol_locations_.find(function_code->instruction_start()));
14417 CHECK(it != symbol_locations_.end());
14418 }
14419 }
14420
14421
FindSymbolForAddr(i::Address addr)14422 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14423 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14424 // Do we have a direct hit on a symbol?
14425 if (it != symbol_locations_.end()) {
14426 if (it->first == addr)
14427 return it->second;
14428 }
14429
14430 // If not a direct hit, it'll have to be the previous symbol.
14431 if (it == symbol_locations_.begin())
14432 return NULL;
14433
14434 --it;
14435 size_t offs = addr - it->first;
14436 if (offs < it->second->size)
14437 return it->second;
14438
14439 return NULL;
14440 }
14441
14442
CountInvocations(const char * caller_name,const char * function_name)14443 int SetFunctionEntryHookTest::CountInvocations(
14444 const char* caller_name, const char* function_name) {
14445 InvocationMap::iterator it(invocations_.begin());
14446 int invocations = 0;
14447 for (; it != invocations_.end(); ++it) {
14448 SymbolInfo* caller = it->first.first;
14449 SymbolInfo* function = it->first.second;
14450
14451 // Filter out non-matching functions.
14452 if (function_name != NULL) {
14453 if (function->name.find(function_name) == std::string::npos)
14454 continue;
14455 }
14456
14457 // Filter out non-matching callers.
14458 if (caller_name != NULL) {
14459 if (caller == NULL)
14460 continue;
14461 if (caller->name.find(caller_name) == std::string::npos)
14462 continue;
14463 }
14464
14465 // It matches add the invocation count to the tally.
14466 invocations += it->second;
14467 }
14468
14469 return invocations;
14470 }
14471
RunLoopInNewEnv(v8::Isolate * isolate)14472 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14473 v8::HandleScope outer(isolate);
14474 v8::Local<Context> env = Context::New(isolate);
14475 env->Enter();
14476
14477 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14478 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14479 CHECK(env->Global()
14480 ->Set(env, v8_str("obj"), t->NewInstance(env).ToLocalChecked())
14481 .FromJust());
14482
14483 const char* script =
14484 "function bar() {\n"
14485 " var sum = 0;\n"
14486 " for (i = 0; i < 100; ++i)\n"
14487 " sum = foo(i);\n"
14488 " return sum;\n"
14489 "}\n"
14490 "function foo(i) { return i * i; }\n"
14491 "// Invoke on the runtime function.\n"
14492 "obj.asdf()";
14493 CompileRun(script);
14494 bar_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(
14495 *env->Global()->Get(env, v8_str("bar")).ToLocalChecked()));
14496 CHECK(!bar_func_.is_null());
14497
14498 foo_func_ = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(
14499 *env->Global()->Get(env, v8_str("foo")).ToLocalChecked()));
14500 CHECK(!foo_func_.is_null());
14501
14502 v8::Local<v8::Value> value = CompileRun("bar();");
14503 CHECK(value->IsNumber());
14504 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14505
14506 // Test the optimized codegen path.
14507 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14508 "bar();");
14509 CHECK(value->IsNumber());
14510 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14511
14512 env->Exit();
14513 }
14514
14515
RunTest()14516 void SetFunctionEntryHookTest::RunTest() {
14517 // Work in a new isolate throughout.
14518 v8::Isolate::CreateParams create_params;
14519 create_params.entry_hook = EntryHook;
14520 create_params.code_event_handler = JitEvent;
14521 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14522 v8::Isolate* isolate = v8::Isolate::New(create_params);
14523
14524 {
14525 v8::Isolate::Scope scope(isolate);
14526
14527 RunLoopInNewEnv(isolate);
14528
14529 // Check the expected invocation counts.
14530 if (!i::FLAG_ignition) {
14531 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14532 CHECK_EQ(200, CountInvocations("bar", "foo"));
14533 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14534 } else {
14535 // For ignition we don't see the actual functions being called, instead
14536 // we see the IterpreterEntryTrampoline at least 102 times
14537 // (100 unoptimized calls to foo, and 2 calls to bar).
14538 CHECK_LE(102, CountInvocations(NULL, "InterpreterEntryTrampoline"));
14539 // We should also see the calls to the optimized function foo.
14540 CHECK_EQ(100, CountInvocations(NULL, "foo"));
14541 }
14542
14543 // Verify that we have an entry hook on some specific stubs.
14544 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14545 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14546 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14547 }
14548 isolate->Dispose();
14549
14550 Reset();
14551
14552 // Make sure a second isolate is unaffected by the previous entry hook.
14553 create_params = v8::Isolate::CreateParams();
14554 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14555 isolate = v8::Isolate::New(create_params);
14556 {
14557 v8::Isolate::Scope scope(isolate);
14558
14559 // Reset the entry count to zero and set the entry hook.
14560 RunLoopInNewEnv(isolate);
14561
14562 // We should record no invocations in this isolate.
14563 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14564 }
14565
14566 isolate->Dispose();
14567 }
14568
14569
TEST(SetFunctionEntryHook)14570 TEST(SetFunctionEntryHook) {
14571 // FunctionEntryHook does not work well with experimental natives.
14572 // Experimental natives are compiled during snapshot deserialization.
14573 // This test breaks because InstallGetter (function from snapshot that
14574 // only gets called from experimental natives) is compiled with entry hooks.
14575 i::FLAG_allow_natives_syntax = true;
14576 i::FLAG_turbo_inlining = false;
14577 i::FLAG_use_inlining = false;
14578
14579 SetFunctionEntryHookTest test;
14580 test.RunTest();
14581 }
14582
14583 static v8::base::HashMap* code_map = NULL;
14584 static v8::base::HashMap* jitcode_line_info = NULL;
14585 static int saw_bar = 0;
14586 static int move_events = 0;
14587
14588
FunctionNameIs(const char * expected,const v8::JitCodeEvent * event)14589 static bool FunctionNameIs(const char* expected,
14590 const v8::JitCodeEvent* event) {
14591 // Log lines for functions are of the general form:
14592 // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
14593 // where the type is one of "*", "~" or "".
14594 static const char* kPreamble;
14595 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) {
14596 kPreamble = "Function:";
14597 } else {
14598 kPreamble = "LazyCompile:";
14599 }
14600 static size_t kPreambleLen = strlen(kPreamble);
14601
14602 if (event->name.len < kPreambleLen ||
14603 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14604 return false;
14605 }
14606
14607 const char* tail = event->name.str + kPreambleLen;
14608 size_t tail_len = event->name.len - kPreambleLen;
14609 size_t expected_len = strlen(expected);
14610 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14611 --tail_len;
14612 ++tail;
14613 }
14614
14615 // Check for tails like 'bar :1'.
14616 if (tail_len > expected_len + 2 &&
14617 tail[expected_len] == ' ' &&
14618 tail[expected_len + 1] == ':' &&
14619 tail[expected_len + 2] &&
14620 !strncmp(tail, expected, expected_len)) {
14621 return true;
14622 }
14623
14624 if (tail_len != expected_len)
14625 return false;
14626
14627 return strncmp(tail, expected, expected_len) == 0;
14628 }
14629
14630
event_handler(const v8::JitCodeEvent * event)14631 static void event_handler(const v8::JitCodeEvent* event) {
14632 CHECK(event != NULL);
14633 CHECK(code_map != NULL);
14634 CHECK(jitcode_line_info != NULL);
14635
14636 class DummyJitCodeLineInfo {
14637 };
14638
14639 switch (event->type) {
14640 case v8::JitCodeEvent::CODE_ADDED: {
14641 CHECK(event->code_start != NULL);
14642 CHECK_NE(0, static_cast<int>(event->code_len));
14643 CHECK(event->name.str != NULL);
14644 v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
14645 event->code_start, i::ComputePointerHash(event->code_start));
14646 entry->value = reinterpret_cast<void*>(event->code_len);
14647
14648 if (FunctionNameIs("bar", event)) {
14649 ++saw_bar;
14650 }
14651 }
14652 break;
14653
14654 case v8::JitCodeEvent::CODE_MOVED: {
14655 uint32_t hash = i::ComputePointerHash(event->code_start);
14656 // We would like to never see code move that we haven't seen before,
14657 // but the code creation event does not happen until the line endings
14658 // have been calculated (this is so that we can report the line in the
14659 // script at which the function source is found, see
14660 // Compiler::RecordFunctionCompilation) and the line endings
14661 // calculations can cause a GC, which can move the newly created code
14662 // before its existence can be logged.
14663 v8::base::HashMap::Entry* entry =
14664 code_map->Lookup(event->code_start, hash);
14665 if (entry != NULL) {
14666 ++move_events;
14667
14668 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14669 code_map->Remove(event->code_start, hash);
14670
14671 entry = code_map->LookupOrInsert(
14672 event->new_code_start,
14673 i::ComputePointerHash(event->new_code_start));
14674 entry->value = reinterpret_cast<void*>(event->code_len);
14675 }
14676 }
14677 break;
14678
14679 case v8::JitCodeEvent::CODE_REMOVED:
14680 // Object/code removal events are currently not dispatched from the GC.
14681 CHECK(false);
14682 break;
14683
14684 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14685 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14686 // record it in jitcode_line_info.
14687 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14688 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14689 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14690 temp_event->user_data = line_info;
14691 v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14692 line_info, i::ComputePointerHash(line_info));
14693 entry->value = reinterpret_cast<void*>(line_info);
14694 }
14695 break;
14696 // For these two events, we will check whether the event->user_data
14697 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14698 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14699 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14700 CHECK(event->user_data != NULL);
14701 uint32_t hash = i::ComputePointerHash(event->user_data);
14702 v8::base::HashMap::Entry* entry =
14703 jitcode_line_info->Lookup(event->user_data, hash);
14704 CHECK(entry != NULL);
14705 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14706 }
14707 break;
14708
14709 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14710 CHECK(event->user_data != NULL);
14711 uint32_t hash = i::ComputePointerHash(event->user_data);
14712 v8::base::HashMap::Entry* entry =
14713 jitcode_line_info->Lookup(event->user_data, hash);
14714 CHECK(entry != NULL);
14715 }
14716 break;
14717
14718 default:
14719 // Impossible event.
14720 CHECK(false);
14721 break;
14722 }
14723 }
14724
14725
UNINITIALIZED_TEST(SetJitCodeEventHandler)14726 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14727 i::FLAG_stress_compaction = true;
14728 i::FLAG_incremental_marking = false;
14729 if (i::FLAG_never_compact) return;
14730 const char* script =
14731 "function bar() {"
14732 " var sum = 0;"
14733 " for (i = 0; i < 10; ++i)"
14734 " sum = foo(i);"
14735 " return sum;"
14736 "}"
14737 "function foo(i) { return i; };"
14738 "bar();";
14739
14740 // Run this test in a new isolate to make sure we don't
14741 // have remnants of state from other code.
14742 v8::Isolate::CreateParams create_params;
14743 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14744 v8::Isolate* isolate = v8::Isolate::New(create_params);
14745 isolate->Enter();
14746 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14747 i::Heap* heap = i_isolate->heap();
14748
14749 // Start with a clean slate.
14750 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
14751
14752 {
14753 v8::HandleScope scope(isolate);
14754 v8::base::HashMap code(MatchPointers);
14755 code_map = &code;
14756
14757 v8::base::HashMap lineinfo(MatchPointers);
14758 jitcode_line_info = &lineinfo;
14759
14760 saw_bar = 0;
14761 move_events = 0;
14762
14763 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14764
14765 // Generate new code objects sparsely distributed across several
14766 // different fragmented code-space pages.
14767 const int kIterations = 10;
14768 for (int i = 0; i < kIterations; ++i) {
14769 LocalContext env(isolate);
14770 i::AlwaysAllocateScope always_allocate(i_isolate);
14771 i::heap::SimulateFullSpace(i::FLAG_ignition ? heap->old_space()
14772 : heap->code_space());
14773 CompileRun(script);
14774
14775 // Keep a strong reference to the code object in the handle scope.
14776 i::Handle<i::Code> bar_code(
14777 i::Handle<i::JSFunction>::cast(
14778 v8::Utils::OpenHandle(*env->Global()
14779 ->Get(env.local(), v8_str("bar"))
14780 .ToLocalChecked()))
14781 ->code());
14782 i::Handle<i::Code> foo_code(
14783 i::Handle<i::JSFunction>::cast(
14784 v8::Utils::OpenHandle(*env->Global()
14785 ->Get(env.local(), v8_str("foo"))
14786 .ToLocalChecked()))
14787 ->code());
14788
14789 // Clear the compilation cache to get more wastage.
14790 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14791 }
14792
14793 // Force code movement.
14794 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
14795
14796 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14797
14798 CHECK_LE(kIterations, saw_bar);
14799 CHECK_LT(0, move_events);
14800
14801 code_map = NULL;
14802 jitcode_line_info = NULL;
14803 }
14804
14805 isolate->Exit();
14806 isolate->Dispose();
14807
14808 // Do this in a new isolate.
14809 isolate = v8::Isolate::New(create_params);
14810 isolate->Enter();
14811
14812 // Verify that we get callbacks for existing code objects when we
14813 // request enumeration of existing code.
14814 {
14815 v8::HandleScope scope(isolate);
14816 LocalContext env(isolate);
14817 CompileRun(script);
14818
14819 // Now get code through initial iteration.
14820 v8::base::HashMap code(MatchPointers);
14821 code_map = &code;
14822
14823 v8::base::HashMap lineinfo(MatchPointers);
14824 jitcode_line_info = &lineinfo;
14825
14826 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14827 event_handler);
14828 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14829
14830 jitcode_line_info = NULL;
14831 // We expect that we got some events. Note that if we could get code removal
14832 // notifications, we could compare two collections, one created by listening
14833 // from the time of creation of an isolate, and the other by subscribing
14834 // with EnumExisting.
14835 CHECK_LT(0u, code.occupancy());
14836
14837 code_map = NULL;
14838 }
14839
14840 isolate->Exit();
14841 isolate->Dispose();
14842 }
14843
14844
THREADED_TEST(ExternalAllocatedMemory)14845 THREADED_TEST(ExternalAllocatedMemory) {
14846 v8::Isolate* isolate = CcTest::isolate();
14847 v8::HandleScope outer(isolate);
14848 v8::Local<Context> env(Context::New(isolate));
14849 CHECK(!env.IsEmpty());
14850 const int64_t kSize = 1024*1024;
14851 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14852 CHECK_EQ(baseline + kSize,
14853 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14854 CHECK_EQ(baseline,
14855 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14856 const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1;
14857 CHECK_EQ(baseline + kTriggerGCSize,
14858 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14859 CHECK_EQ(baseline,
14860 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14861 }
14862
14863
TEST(Regress51719)14864 TEST(Regress51719) {
14865 i::FLAG_incremental_marking = false;
14866 CcTest::InitializeVM();
14867
14868 const int64_t kTriggerGCSize = i::kExternalAllocationLimit + 1;
14869 v8::Isolate* isolate = CcTest::isolate();
14870 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14871 }
14872
14873
14874 // Regression test for issue 54, object templates with internal fields
14875 // but no accessors or interceptors did not get their internal field
14876 // count set on instances.
THREADED_TEST(Regress54)14877 THREADED_TEST(Regress54) {
14878 LocalContext context;
14879 v8::Isolate* isolate = context->GetIsolate();
14880 v8::HandleScope outer(isolate);
14881 static v8::Persistent<v8::ObjectTemplate> templ;
14882 if (templ.IsEmpty()) {
14883 v8::EscapableHandleScope inner(isolate);
14884 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14885 local->SetInternalFieldCount(1);
14886 templ.Reset(isolate, inner.Escape(local));
14887 }
14888 v8::Local<v8::Object> result =
14889 v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14890 ->NewInstance(context.local())
14891 .ToLocalChecked();
14892 CHECK_EQ(1, result->InternalFieldCount());
14893 }
14894
14895
14896 // If part of the threaded tests, this test makes ThreadingTest fail
14897 // on mac.
TEST(CatchStackOverflow)14898 TEST(CatchStackOverflow) {
14899 LocalContext context;
14900 v8::HandleScope scope(context->GetIsolate());
14901 v8::TryCatch try_catch(context->GetIsolate());
14902 v8::Local<v8::Value> result = CompileRun(
14903 "function f() {"
14904 " return f();"
14905 "}"
14906 ""
14907 "f();");
14908 CHECK(result.IsEmpty());
14909 }
14910
14911
CheckTryCatchSourceInfo(v8::Local<v8::Script> script,const char * resource_name,int line_offset)14912 static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14913 const char* resource_name,
14914 int line_offset) {
14915 v8::HandleScope scope(CcTest::isolate());
14916 v8::TryCatch try_catch(CcTest::isolate());
14917 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14918 CHECK(script->Run(context).IsEmpty());
14919 CHECK(try_catch.HasCaught());
14920 v8::Local<v8::Message> message = try_catch.Message();
14921 CHECK(!message.IsEmpty());
14922 CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14923 CHECK_EQ(91, message->GetStartPosition());
14924 CHECK_EQ(92, message->GetEndPosition());
14925 CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14926 CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14927 v8::String::Utf8Value line(message->GetSourceLine(context).ToLocalChecked());
14928 CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14929 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14930 CHECK_EQ(0, strcmp(resource_name, *name));
14931 }
14932
14933
THREADED_TEST(TryCatchSourceInfo)14934 THREADED_TEST(TryCatchSourceInfo) {
14935 LocalContext context;
14936 v8::HandleScope scope(context->GetIsolate());
14937 v8::Local<v8::String> source = v8_str(
14938 "function Foo() {\n"
14939 " return Bar();\n"
14940 "}\n"
14941 "\n"
14942 "function Bar() {\n"
14943 " return Baz();\n"
14944 "}\n"
14945 "\n"
14946 "function Baz() {\n"
14947 " throw 'nirk';\n"
14948 "}\n"
14949 "\n"
14950 "Foo();\n");
14951
14952 const char* resource_name;
14953 v8::Local<v8::Script> script;
14954 resource_name = "test.js";
14955 script = CompileWithOrigin(source, resource_name);
14956 CheckTryCatchSourceInfo(script, resource_name, 0);
14957
14958 resource_name = "test1.js";
14959 v8::ScriptOrigin origin1(v8_str(resource_name));
14960 script =
14961 v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
14962 CheckTryCatchSourceInfo(script, resource_name, 0);
14963
14964 resource_name = "test2.js";
14965 v8::ScriptOrigin origin2(v8_str(resource_name),
14966 v8::Integer::New(context->GetIsolate(), 7));
14967 script =
14968 v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
14969 CheckTryCatchSourceInfo(script, resource_name, 7);
14970 }
14971
14972
THREADED_TEST(TryCatchSourceInfoForEOSError)14973 THREADED_TEST(TryCatchSourceInfoForEOSError) {
14974 LocalContext context;
14975 v8::HandleScope scope(context->GetIsolate());
14976 v8::TryCatch try_catch(context->GetIsolate());
14977 CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
14978 CHECK(try_catch.HasCaught());
14979 v8::Local<v8::Message> message = try_catch.Message();
14980 CHECK_EQ(1, message->GetLineNumber(context.local()).FromJust());
14981 CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
14982 }
14983
14984
THREADED_TEST(CompilationCache)14985 THREADED_TEST(CompilationCache) {
14986 LocalContext context;
14987 v8::HandleScope scope(context->GetIsolate());
14988 v8::Local<v8::String> source0 = v8_str("1234");
14989 v8::Local<v8::String> source1 = v8_str("1234");
14990 v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14991 v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14992 v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
14993 .ToLocalChecked(); // different origin
14994 CHECK_EQ(1234, script0->Run(context.local())
14995 .ToLocalChecked()
14996 ->Int32Value(context.local())
14997 .FromJust());
14998 CHECK_EQ(1234, script1->Run(context.local())
14999 .ToLocalChecked()
15000 ->Int32Value(context.local())
15001 .FromJust());
15002 CHECK_EQ(1234, script2->Run(context.local())
15003 .ToLocalChecked()
15004 ->Int32Value(context.local())
15005 .FromJust());
15006 }
15007
15008
FunctionNameCallback(const v8::FunctionCallbackInfo<v8::Value> & args)15009 static void FunctionNameCallback(
15010 const v8::FunctionCallbackInfo<v8::Value>& args) {
15011 ApiTestFuzzer::Fuzz();
15012 args.GetReturnValue().Set(v8_num(42));
15013 }
15014
15015
THREADED_TEST(CallbackFunctionName)15016 THREADED_TEST(CallbackFunctionName) {
15017 LocalContext context;
15018 v8::Isolate* isolate = context->GetIsolate();
15019 v8::HandleScope scope(isolate);
15020 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15021 t->Set(v8_str("asdf"),
15022 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15023 CHECK(context->Global()
15024 ->Set(context.local(), v8_str("obj"),
15025 t->NewInstance(context.local()).ToLocalChecked())
15026 .FromJust());
15027 v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
15028 CHECK(value->IsString());
15029 v8::String::Utf8Value name(value);
15030 CHECK_EQ(0, strcmp("asdf", *name));
15031 }
15032
15033
THREADED_TEST(DateAccess)15034 THREADED_TEST(DateAccess) {
15035 LocalContext context;
15036 v8::HandleScope scope(context->GetIsolate());
15037 v8::Local<v8::Value> date =
15038 v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
15039 CHECK(date->IsDate());
15040 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15041 }
15042
CheckIsSymbolAt(v8::Isolate * isolate,v8::Local<v8::Array> properties,unsigned index,const char * name)15043 void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
15044 unsigned index, const char* name) {
15045 v8::Local<v8::Context> context = isolate->GetCurrentContext();
15046 v8::Local<v8::Value> value =
15047 properties->Get(context, v8::Integer::New(isolate, index))
15048 .ToLocalChecked();
15049 CHECK(value->IsSymbol());
15050 v8::String::Utf8Value symbol_name(Local<Symbol>::Cast(value)->Name());
15051 CHECK_EQ(0, strcmp(name, *symbol_name));
15052 }
15053
CheckStringArray(v8::Isolate * isolate,v8::Local<v8::Array> properties,unsigned length,const char * names[])15054 void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
15055 unsigned length, const char* names[]) {
15056 v8::Local<v8::Context> context = isolate->GetCurrentContext();
15057 CHECK_EQ(length, properties->Length());
15058 for (unsigned i = 0; i < length; i++) {
15059 v8::Local<v8::Value> value =
15060 properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
15061 if (names[i] == nullptr) {
15062 DCHECK(value->IsSymbol());
15063 } else {
15064 v8::String::Utf8Value elm(value);
15065 CHECK_EQ(0, strcmp(names[i], *elm));
15066 }
15067 }
15068 }
15069
CheckProperties(v8::Isolate * isolate,v8::Local<v8::Value> val,unsigned length,const char * names[])15070 void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15071 unsigned length, const char* names[]) {
15072 v8::Local<v8::Context> context = isolate->GetCurrentContext();
15073 v8::Local<v8::Object> obj = val.As<v8::Object>();
15074 v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
15075 CheckStringArray(isolate, props, length, names);
15076 }
15077
15078
CheckOwnProperties(v8::Isolate * isolate,v8::Local<v8::Value> val,unsigned elmc,const char * elmv[])15079 void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
15080 unsigned elmc, const char* elmv[]) {
15081 v8::Local<v8::Context> context = isolate->GetCurrentContext();
15082 v8::Local<v8::Object> obj = val.As<v8::Object>();
15083 v8::Local<v8::Array> props =
15084 obj->GetOwnPropertyNames(context).ToLocalChecked();
15085 CHECK_EQ(elmc, props->Length());
15086 for (unsigned i = 0; i < elmc; i++) {
15087 v8::String::Utf8Value elm(
15088 props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
15089 CHECK_EQ(0, strcmp(elmv[i], *elm));
15090 }
15091 }
15092
15093
THREADED_TEST(PropertyEnumeration)15094 THREADED_TEST(PropertyEnumeration) {
15095 LocalContext context;
15096 v8::Isolate* isolate = context->GetIsolate();
15097 v8::HandleScope scope(isolate);
15098 v8::Local<v8::Value> obj = CompileRun(
15099 "var result = [];"
15100 "result[0] = {};"
15101 "result[1] = {a: 1, b: 2};"
15102 "result[2] = [1, 2, 3];"
15103 "var proto = {x: 1, y: 2, z: 3};"
15104 "var x = { __proto__: proto, w: 0, z: 1 };"
15105 "result[3] = x;"
15106 "result;");
15107 v8::Local<v8::Array> elms = obj.As<v8::Array>();
15108 CHECK_EQ(4u, elms->Length());
15109 int elmc0 = 0;
15110 const char** elmv0 = NULL;
15111 CheckProperties(
15112 isolate,
15113 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15114 elmc0, elmv0);
15115 CheckOwnProperties(
15116 isolate,
15117 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15118 elmc0, elmv0);
15119 int elmc1 = 2;
15120 const char* elmv1[] = {"a", "b"};
15121 CheckProperties(
15122 isolate,
15123 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15124 elmc1, elmv1);
15125 CheckOwnProperties(
15126 isolate,
15127 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
15128 elmc1, elmv1);
15129 int elmc2 = 3;
15130 const char* elmv2[] = {"0", "1", "2"};
15131 CheckProperties(
15132 isolate,
15133 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15134 elmc2, elmv2);
15135 CheckOwnProperties(
15136 isolate,
15137 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
15138 elmc2, elmv2);
15139 int elmc3 = 4;
15140 const char* elmv3[] = {"w", "z", "x", "y"};
15141 CheckProperties(
15142 isolate,
15143 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15144 elmc3, elmv3);
15145 int elmc4 = 2;
15146 const char* elmv4[] = {"w", "z"};
15147 CheckOwnProperties(
15148 isolate,
15149 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
15150 elmc4, elmv4);
15151 }
15152
15153
THREADED_TEST(PropertyEnumeration2)15154 THREADED_TEST(PropertyEnumeration2) {
15155 LocalContext context;
15156 v8::Isolate* isolate = context->GetIsolate();
15157 v8::HandleScope scope(isolate);
15158 v8::Local<v8::Value> obj = CompileRun(
15159 "var result = [];"
15160 "result[0] = {};"
15161 "result[1] = {a: 1, b: 2};"
15162 "result[2] = [1, 2, 3];"
15163 "var proto = {x: 1, y: 2, z: 3};"
15164 "var x = { __proto__: proto, w: 0, z: 1 };"
15165 "result[3] = x;"
15166 "result;");
15167 v8::Local<v8::Array> elms = obj.As<v8::Array>();
15168 CHECK_EQ(4u, elms->Length());
15169 int elmc0 = 0;
15170 const char** elmv0 = NULL;
15171 CheckProperties(
15172 isolate,
15173 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
15174 elmc0, elmv0);
15175
15176 v8::Local<v8::Value> val =
15177 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
15178 v8::Local<v8::Array> props =
15179 val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
15180 CHECK_EQ(0u, props->Length());
15181 for (uint32_t i = 0; i < props->Length(); i++) {
15182 printf("p[%u]\n", i);
15183 }
15184 }
15185
THREADED_TEST(PropertyNames)15186 THREADED_TEST(PropertyNames) {
15187 LocalContext context;
15188 v8::Isolate* isolate = context->GetIsolate();
15189 v8::HandleScope scope(isolate);
15190 v8::Local<v8::Value> result = CompileRun(
15191 "var result = {0: 0, 1: 1, a: 2, b: 3};"
15192 "result[Symbol('symbol')] = true;"
15193 "result.__proto__ = {2: 4, 3: 5, c: 6, d: 7};"
15194 "result;");
15195 v8::Local<v8::Object> object = result.As<v8::Object>();
15196 v8::PropertyFilter default_filter =
15197 static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
15198 v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
15199
15200 v8::Local<v8::Array> properties =
15201 object->GetPropertyNames(context.local()).ToLocalChecked();
15202 const char* expected_properties1[] = {"0", "1", "a", "b", "2", "3", "c", "d"};
15203 CheckStringArray(isolate, properties, 8, expected_properties1);
15204
15205 properties =
15206 object
15207 ->GetPropertyNames(context.local(),
15208 v8::KeyCollectionMode::kIncludePrototypes,
15209 default_filter, v8::IndexFilter::kIncludeIndices)
15210 .ToLocalChecked();
15211 CheckStringArray(isolate, properties, 8, expected_properties1);
15212
15213 properties = object
15214 ->GetPropertyNames(context.local(),
15215 v8::KeyCollectionMode::kIncludePrototypes,
15216 include_symbols_filter,
15217 v8::IndexFilter::kIncludeIndices)
15218 .ToLocalChecked();
15219 const char* expected_properties1_1[] = {"0", "1", "a", "b", nullptr,
15220 "2", "3", "c", "d"};
15221 CheckStringArray(isolate, properties, 9, expected_properties1_1);
15222 CheckIsSymbolAt(isolate, properties, 4, "symbol");
15223
15224 properties =
15225 object
15226 ->GetPropertyNames(context.local(),
15227 v8::KeyCollectionMode::kIncludePrototypes,
15228 default_filter, v8::IndexFilter::kSkipIndices)
15229 .ToLocalChecked();
15230 const char* expected_properties2[] = {"a", "b", "c", "d"};
15231 CheckStringArray(isolate, properties, 4, expected_properties2);
15232
15233 properties = object
15234 ->GetPropertyNames(context.local(),
15235 v8::KeyCollectionMode::kIncludePrototypes,
15236 include_symbols_filter,
15237 v8::IndexFilter::kSkipIndices)
15238 .ToLocalChecked();
15239 const char* expected_properties2_1[] = {"a", "b", nullptr, "c", "d"};
15240 CheckStringArray(isolate, properties, 5, expected_properties2_1);
15241 CheckIsSymbolAt(isolate, properties, 2, "symbol");
15242
15243 properties =
15244 object
15245 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15246 default_filter, v8::IndexFilter::kIncludeIndices)
15247 .ToLocalChecked();
15248 const char* expected_properties3[] = {"0", "1", "a", "b"};
15249 CheckStringArray(isolate, properties, 4, expected_properties3);
15250
15251 properties = object
15252 ->GetPropertyNames(
15253 context.local(), v8::KeyCollectionMode::kOwnOnly,
15254 include_symbols_filter, v8::IndexFilter::kIncludeIndices)
15255 .ToLocalChecked();
15256 const char* expected_properties3_1[] = {"0", "1", "a", "b", nullptr};
15257 CheckStringArray(isolate, properties, 5, expected_properties3_1);
15258 CheckIsSymbolAt(isolate, properties, 4, "symbol");
15259
15260 properties =
15261 object
15262 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
15263 default_filter, v8::IndexFilter::kSkipIndices)
15264 .ToLocalChecked();
15265 const char* expected_properties4[] = {"a", "b"};
15266 CheckStringArray(isolate, properties, 2, expected_properties4);
15267
15268 properties = object
15269 ->GetPropertyNames(
15270 context.local(), v8::KeyCollectionMode::kOwnOnly,
15271 include_symbols_filter, v8::IndexFilter::kSkipIndices)
15272 .ToLocalChecked();
15273 const char* expected_properties4_1[] = {"a", "b", nullptr};
15274 CheckStringArray(isolate, properties, 3, expected_properties4_1);
15275 CheckIsSymbolAt(isolate, properties, 2, "symbol");
15276 }
15277
THREADED_TEST(AccessChecksReenabledCorrectly)15278 THREADED_TEST(AccessChecksReenabledCorrectly) {
15279 LocalContext context;
15280 v8::Isolate* isolate = context->GetIsolate();
15281 v8::HandleScope scope(isolate);
15282 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15283 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15284 templ->Set(v8_str("a"), v8_str("a"));
15285 // Add more than 8 (see kMaxFastProperties) properties
15286 // so that the constructor will force copying map.
15287 // Cannot sprintf, gcc complains unsafety.
15288 char buf[4];
15289 for (char i = '0'; i <= '9' ; i++) {
15290 buf[0] = i;
15291 for (char j = '0'; j <= '9'; j++) {
15292 buf[1] = j;
15293 for (char k = '0'; k <= '9'; k++) {
15294 buf[2] = k;
15295 buf[3] = 0;
15296 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15297 }
15298 }
15299 }
15300
15301 Local<v8::Object> instance_1 =
15302 templ->NewInstance(context.local()).ToLocalChecked();
15303 CHECK(context->Global()
15304 ->Set(context.local(), v8_str("obj_1"), instance_1)
15305 .FromJust());
15306
15307 Local<Value> value_1 = CompileRun("obj_1.a");
15308 CHECK(value_1.IsEmpty());
15309
15310 Local<v8::Object> instance_2 =
15311 templ->NewInstance(context.local()).ToLocalChecked();
15312 CHECK(context->Global()
15313 ->Set(context.local(), v8_str("obj_2"), instance_2)
15314 .FromJust());
15315
15316 Local<Value> value_2 = CompileRun("obj_2.a");
15317 CHECK(value_2.IsEmpty());
15318 }
15319
15320
15321 // Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization)15322 TEST(PreCompileSerialization) {
15323 // Producing cached parser data while parsing eagerly is not supported.
15324 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return;
15325
15326 v8::V8::Initialize();
15327 LocalContext env;
15328 v8::Isolate* isolate = env->GetIsolate();
15329 HandleScope handle_scope(isolate);
15330
15331 i::FLAG_min_preparse_length = 0;
15332 const char* script = "function foo(a) { return a+1; }";
15333 v8::ScriptCompiler::Source source(v8_str(script));
15334 v8::ScriptCompiler::Compile(env.local(), &source,
15335 v8::ScriptCompiler::kProduceParserCache)
15336 .ToLocalChecked();
15337 // Serialize.
15338 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15339 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15340 i::MemCopy(serialized_data, cd->data, cd->length);
15341
15342 // Deserialize.
15343 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15344
15345 // Verify that the original is the same as the deserialized.
15346 CHECK_EQ(cd->length, deserialized->length());
15347 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15348
15349 delete deserialized;
15350 i::DeleteArray(serialized_data);
15351 }
15352
15353
15354 // This tests that we do not allow dictionary load/call inline caches
15355 // to use functions that have not yet been compiled. The potential
15356 // problem of loading a function that has not yet been compiled can
15357 // arise because we share code between contexts via the compilation
15358 // cache.
THREADED_TEST(DictionaryICLoadedFunction)15359 THREADED_TEST(DictionaryICLoadedFunction) {
15360 v8::HandleScope scope(CcTest::isolate());
15361 // Test LoadIC.
15362 for (int i = 0; i < 2; i++) {
15363 LocalContext context;
15364 CHECK(context->Global()
15365 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
15366 .FromJust());
15367 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
15368 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15369 }
15370 // Test CallIC.
15371 for (int i = 0; i < 2; i++) {
15372 LocalContext context;
15373 CHECK(context->Global()
15374 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
15375 .FromJust());
15376 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
15377 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15378 }
15379 }
15380
15381
15382 // Test that cross-context new calls use the context of the callee to
15383 // create the new JavaScript object.
THREADED_TEST(CrossContextNew)15384 THREADED_TEST(CrossContextNew) {
15385 v8::Isolate* isolate = CcTest::isolate();
15386 v8::HandleScope scope(isolate);
15387 v8::Local<Context> context0 = Context::New(isolate);
15388 v8::Local<Context> context1 = Context::New(isolate);
15389
15390 // Allow cross-domain access.
15391 Local<String> token = v8_str("<security token>");
15392 context0->SetSecurityToken(token);
15393 context1->SetSecurityToken(token);
15394
15395 // Set an 'x' property on the Object prototype and define a
15396 // constructor function in context0.
15397 context0->Enter();
15398 CompileRun("Object.prototype.x = 42; function C() {};");
15399 context0->Exit();
15400
15401 // Call the constructor function from context0 and check that the
15402 // result has the 'x' property.
15403 context1->Enter();
15404 CHECK(context1->Global()
15405 ->Set(context1, v8_str("other"), context0->Global())
15406 .FromJust());
15407 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15408 CHECK(value->IsInt32());
15409 CHECK_EQ(42, value->Int32Value(context1).FromJust());
15410 context1->Exit();
15411 }
15412
15413
15414 // Verify that we can clone an object
TEST(ObjectClone)15415 TEST(ObjectClone) {
15416 LocalContext env;
15417 v8::Isolate* isolate = env->GetIsolate();
15418 v8::HandleScope scope(isolate);
15419
15420 const char* sample =
15421 "var rv = {};" \
15422 "rv.alpha = 'hello';" \
15423 "rv.beta = 123;" \
15424 "rv;";
15425
15426 // Create an object, verify basics.
15427 Local<Value> val = CompileRun(sample);
15428 CHECK(val->IsObject());
15429 Local<v8::Object> obj = val.As<v8::Object>();
15430 obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
15431
15432 CHECK(v8_str("hello")
15433 ->Equals(env.local(),
15434 obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15435 .FromJust());
15436 CHECK(v8::Integer::New(isolate, 123)
15437 ->Equals(env.local(),
15438 obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15439 .FromJust());
15440 CHECK(v8_str("cloneme")
15441 ->Equals(env.local(),
15442 obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15443 .FromJust());
15444
15445 // Clone it.
15446 Local<v8::Object> clone = obj->Clone();
15447 CHECK(v8_str("hello")
15448 ->Equals(env.local(),
15449 clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
15450 .FromJust());
15451 CHECK(v8::Integer::New(isolate, 123)
15452 ->Equals(env.local(),
15453 clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15454 .FromJust());
15455 CHECK(v8_str("cloneme")
15456 ->Equals(env.local(),
15457 clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
15458 .FromJust());
15459
15460 // Set a property on the clone, verify each object.
15461 CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
15462 .FromJust());
15463 CHECK(v8::Integer::New(isolate, 123)
15464 ->Equals(env.local(),
15465 obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
15466 .FromJust());
15467 CHECK(v8::Integer::New(isolate, 456)
15468 ->Equals(env.local(),
15469 clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
15470 .FromJust());
15471 }
15472
15473
15474 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15475 public:
OneByteVectorResource(i::Vector<const char> vector)15476 explicit OneByteVectorResource(i::Vector<const char> vector)
15477 : data_(vector) {}
~OneByteVectorResource()15478 virtual ~OneByteVectorResource() {}
length() const15479 virtual size_t length() const { return data_.length(); }
data() const15480 virtual const char* data() const { return data_.start(); }
15481 private:
15482 i::Vector<const char> data_;
15483 };
15484
15485
15486 class UC16VectorResource : public v8::String::ExternalStringResource {
15487 public:
UC16VectorResource(i::Vector<const i::uc16> vector)15488 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15489 : data_(vector) {}
~UC16VectorResource()15490 virtual ~UC16VectorResource() {}
length() const15491 virtual size_t length() const { return data_.length(); }
data() const15492 virtual const i::uc16* data() const { return data_.start(); }
15493 private:
15494 i::Vector<const i::uc16> data_;
15495 };
15496
15497
MorphAString(i::String * string,OneByteVectorResource * one_byte_resource,UC16VectorResource * uc16_resource)15498 static void MorphAString(i::String* string,
15499 OneByteVectorResource* one_byte_resource,
15500 UC16VectorResource* uc16_resource) {
15501 CHECK(i::StringShape(string).IsExternal());
15502 if (string->IsOneByteRepresentation()) {
15503 // Check old map is not internalized or long.
15504 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15505 // Morph external string to be TwoByte string.
15506 string->set_map(CcTest::heap()->external_string_map());
15507 i::ExternalTwoByteString* morphed =
15508 i::ExternalTwoByteString::cast(string);
15509 morphed->set_resource(uc16_resource);
15510 } else {
15511 // Check old map is not internalized or long.
15512 CHECK(string->map() == CcTest::heap()->external_string_map());
15513 // Morph external string to be one-byte string.
15514 string->set_map(CcTest::heap()->external_one_byte_string_map());
15515 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15516 morphed->set_resource(one_byte_resource);
15517 }
15518 }
15519
15520
15521 // Test that we can still flatten a string if the components it is built up
15522 // from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest)15523 THREADED_TEST(MorphCompositeStringTest) {
15524 char utf_buffer[129];
15525 const char* c_string = "Now is the time for all good men"
15526 " to come to the aid of the party";
15527 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15528 {
15529 LocalContext env;
15530 i::Factory* factory = CcTest::i_isolate()->factory();
15531 v8::HandleScope scope(env->GetIsolate());
15532 OneByteVectorResource one_byte_resource(
15533 i::Vector<const char>(c_string, i::StrLength(c_string)));
15534 UC16VectorResource uc16_resource(
15535 i::Vector<const uint16_t>(two_byte_string,
15536 i::StrLength(c_string)));
15537
15538 Local<String> lhs(
15539 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15540 &one_byte_resource).ToHandleChecked()));
15541 Local<String> rhs(
15542 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15543 &one_byte_resource).ToHandleChecked()));
15544
15545 CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
15546 CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
15547
15548 CompileRun(
15549 "var cons = lhs + rhs;"
15550 "var slice = lhs.substring(1, lhs.length - 1);"
15551 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15552
15553 CHECK(lhs->IsOneByte());
15554 CHECK(rhs->IsOneByte());
15555
15556 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15557 &uc16_resource);
15558 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15559 &uc16_resource);
15560
15561 // This should UTF-8 without flattening, since everything is ASCII.
15562 Local<String> cons =
15563 v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15564 CHECK_EQ(128, cons->Utf8Length());
15565 int nchars = -1;
15566 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15567 CHECK_EQ(128, nchars);
15568 CHECK_EQ(0, strcmp(
15569 utf_buffer,
15570 "Now is the time for all good men to come to the aid of the party"
15571 "Now is the time for all good men to come to the aid of the party"));
15572
15573 // Now do some stuff to make sure the strings are flattened, etc.
15574 CompileRun(
15575 "/[^a-z]/.test(cons);"
15576 "/[^a-z]/.test(slice);"
15577 "/[^a-z]/.test(slice_on_cons);");
15578 const char* expected_cons =
15579 "Now is the time for all good men to come to the aid of the party"
15580 "Now is the time for all good men to come to the aid of the party";
15581 const char* expected_slice =
15582 "ow is the time for all good men to come to the aid of the part";
15583 const char* expected_slice_on_cons =
15584 "ow is the time for all good men to come to the aid of the party"
15585 "Now is the time for all good men to come to the aid of the part";
15586 CHECK(v8_str(expected_cons)
15587 ->Equals(env.local(), env->Global()
15588 ->Get(env.local(), v8_str("cons"))
15589 .ToLocalChecked())
15590 .FromJust());
15591 CHECK(v8_str(expected_slice)
15592 ->Equals(env.local(), env->Global()
15593 ->Get(env.local(), v8_str("slice"))
15594 .ToLocalChecked())
15595 .FromJust());
15596 CHECK(v8_str(expected_slice_on_cons)
15597 ->Equals(env.local(),
15598 env->Global()
15599 ->Get(env.local(), v8_str("slice_on_cons"))
15600 .ToLocalChecked())
15601 .FromJust());
15602 }
15603 i::DeleteArray(two_byte_string);
15604 }
15605
15606
TEST(CompileExternalTwoByteSource)15607 TEST(CompileExternalTwoByteSource) {
15608 LocalContext context;
15609 v8::HandleScope scope(context->GetIsolate());
15610
15611 // This is a very short list of sources, which currently is to check for a
15612 // regression caused by r2703.
15613 const char* one_byte_sources[] = {
15614 "0.5",
15615 "-0.5", // This mainly testes PushBack in the Scanner.
15616 "--0.5", // This mainly testes PushBack in the Scanner.
15617 NULL};
15618
15619 // Compile the sources as external two byte strings.
15620 for (int i = 0; one_byte_sources[i] != NULL; i++) {
15621 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15622 TestResource* uc16_resource = new TestResource(two_byte_string);
15623 v8::Local<v8::String> source =
15624 v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15625 .ToLocalChecked();
15626 v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15627 }
15628 }
15629
15630
15631 #ifndef V8_INTERPRETED_REGEXP
15632
15633 struct RegExpInterruptionData {
15634 v8::base::Atomic32 loop_count;
15635 UC16VectorResource* string_resource;
15636 v8::Persistent<v8::String> string;
15637 } regexp_interruption_data;
15638
15639
15640 class RegExpInterruptionThread : public v8::base::Thread {
15641 public:
RegExpInterruptionThread(v8::Isolate * isolate)15642 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15643 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15644
Run()15645 virtual void Run() {
15646 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
15647 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
15648 v8::base::NoBarrier_AtomicIncrement(
15649 ®exp_interruption_data.loop_count, 1)) {
15650 // Wait a bit before requesting GC.
15651 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15652 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15653 }
15654 // Wait a bit before terminating.
15655 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
15656 isolate_->TerminateExecution();
15657 }
15658
15659 private:
15660 v8::Isolate* isolate_;
15661 };
15662
15663
RunBeforeGC(v8::Isolate * isolate,v8::GCType type,v8::GCCallbackFlags flags)15664 void RunBeforeGC(v8::Isolate* isolate, v8::GCType type,
15665 v8::GCCallbackFlags flags) {
15666 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
15667 return;
15668 }
15669 v8::HandleScope scope(isolate);
15670 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15671 CcTest::isolate(), regexp_interruption_data.string);
15672 string->MakeExternal(regexp_interruption_data.string_resource);
15673 }
15674
15675
15676 // Test that RegExp execution can be interrupted. Specifically, we test
15677 // * interrupting with GC
15678 // * turn the subject string from one-byte internal to two-byte external string
15679 // * force termination
TEST(RegExpInterruption)15680 TEST(RegExpInterruption) {
15681 LocalContext env;
15682 v8::HandleScope scope(env->GetIsolate());
15683
15684 RegExpInterruptionThread timeout_thread(env->GetIsolate());
15685
15686 env->GetIsolate()->AddGCPrologueCallback(RunBeforeGC);
15687 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15688 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15689 v8::Local<v8::String> string = v8_str(one_byte_content);
15690
15691 env->Global()->Set(env.local(), v8_str("a"), string).FromJust();
15692 regexp_interruption_data.string.Reset(env->GetIsolate(), string);
15693 regexp_interruption_data.string_resource = new UC16VectorResource(
15694 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15695
15696 v8::TryCatch try_catch(env->GetIsolate());
15697 timeout_thread.Start();
15698
15699 CompileRun("/((a*)*)*b/.exec(a)");
15700 CHECK(try_catch.HasTerminated());
15701
15702 timeout_thread.Join();
15703
15704 regexp_interruption_data.string.Reset();
15705 i::DeleteArray(uc16_content);
15706 }
15707
15708 #endif // V8_INTERPRETED_REGEXP
15709
15710
15711 // Test that we cannot set a property on the global object if there
15712 // is a read-only property in the prototype chain.
TEST(ReadOnlyPropertyInGlobalProto)15713 TEST(ReadOnlyPropertyInGlobalProto) {
15714 v8::Isolate* isolate = CcTest::isolate();
15715 v8::HandleScope scope(isolate);
15716 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15717 LocalContext context(0, templ);
15718 v8::Local<v8::Object> global = context->Global();
15719 v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15720 global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15721 global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15722 v8::Integer::New(isolate, 0), v8::ReadOnly)
15723 .FromJust();
15724 global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15725 v8::Integer::New(isolate, 0), v8::ReadOnly)
15726 .FromJust();
15727 // Check without 'eval' or 'with'.
15728 v8::Local<v8::Value> res =
15729 CompileRun("function f() { x = 42; return x; }; f()");
15730 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15731 // Check with 'eval'.
15732 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15733 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15734 // Check with 'with'.
15735 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15736 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15737 }
15738
15739
TEST(CreateDataProperty)15740 TEST(CreateDataProperty) {
15741 LocalContext env;
15742 v8::Isolate* isolate = env->GetIsolate();
15743 v8::HandleScope handle_scope(isolate);
15744
15745 CompileRun(
15746 "var a = {};"
15747 "var b = [];"
15748 "Object.defineProperty(a, 'foo', {value: 23});"
15749 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15750
15751 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15752 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15753 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15754 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15755 {
15756 // Can't change a non-configurable properties.
15757 v8::TryCatch try_catch(isolate);
15758 CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15759 v8::Integer::New(isolate, 42)).FromJust());
15760 CHECK(!try_catch.HasCaught());
15761 CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15762 v8::Integer::New(isolate, 42)).FromJust());
15763 CHECK(!try_catch.HasCaught());
15764 v8::Local<v8::Value> val =
15765 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15766 CHECK(val->IsNumber());
15767 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15768 }
15769
15770 {
15771 // Set a regular property.
15772 v8::TryCatch try_catch(isolate);
15773 CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15774 v8::Integer::New(isolate, 42)).FromJust());
15775 CHECK(!try_catch.HasCaught());
15776 v8::Local<v8::Value> val =
15777 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15778 CHECK(val->IsNumber());
15779 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15780 }
15781
15782 {
15783 // Set an indexed property.
15784 v8::TryCatch try_catch(isolate);
15785 CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15786 v8::Integer::New(isolate, 42)).FromJust());
15787 CHECK(!try_catch.HasCaught());
15788 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15789 CHECK(val->IsNumber());
15790 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15791 }
15792
15793 {
15794 // Special cases for arrays.
15795 v8::TryCatch try_catch(isolate);
15796 CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15797 v8::Integer::New(isolate, 1)).FromJust());
15798 CHECK(!try_catch.HasCaught());
15799 }
15800 {
15801 // Special cases for arrays: index exceeds the array's length
15802 v8::TryCatch try_catch(isolate);
15803 CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15804 .FromJust());
15805 CHECK(!try_catch.HasCaught());
15806 CHECK_EQ(2U, arr->Length());
15807 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15808 CHECK(val->IsNumber());
15809 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15810
15811 // Set an existing entry.
15812 CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15813 .FromJust());
15814 CHECK(!try_catch.HasCaught());
15815 val = arr->Get(env.local(), 0).ToLocalChecked();
15816 CHECK(val->IsNumber());
15817 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15818 }
15819
15820 CompileRun("Object.freeze(a);");
15821 {
15822 // Can't change non-extensible objects.
15823 v8::TryCatch try_catch(isolate);
15824 CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15825 v8::Integer::New(isolate, 42)).FromJust());
15826 CHECK(!try_catch.HasCaught());
15827 }
15828
15829 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15830 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15831 v8::Local<v8::Object> access_checked =
15832 templ->NewInstance(env.local()).ToLocalChecked();
15833 {
15834 v8::TryCatch try_catch(isolate);
15835 CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15836 v8::Integer::New(isolate, 42))
15837 .IsNothing());
15838 CHECK(try_catch.HasCaught());
15839 }
15840 }
15841
15842
TEST(DefineOwnProperty)15843 TEST(DefineOwnProperty) {
15844 LocalContext env;
15845 v8::Isolate* isolate = env->GetIsolate();
15846 v8::HandleScope handle_scope(isolate);
15847
15848 CompileRun(
15849 "var a = {};"
15850 "var b = [];"
15851 "Object.defineProperty(a, 'foo', {value: 23});"
15852 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15853
15854 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15855 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15856 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15857 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15858 {
15859 // Can't change a non-configurable properties.
15860 v8::TryCatch try_catch(isolate);
15861 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15862 v8::Integer::New(isolate, 42)).FromJust());
15863 CHECK(!try_catch.HasCaught());
15864 CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15865 v8::Integer::New(isolate, 42)).FromJust());
15866 CHECK(!try_catch.HasCaught());
15867 v8::Local<v8::Value> val =
15868 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15869 CHECK(val->IsNumber());
15870 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15871 }
15872
15873 {
15874 // Set a regular property.
15875 v8::TryCatch try_catch(isolate);
15876 CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15877 v8::Integer::New(isolate, 42)).FromJust());
15878 CHECK(!try_catch.HasCaught());
15879 v8::Local<v8::Value> val =
15880 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15881 CHECK(val->IsNumber());
15882 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15883 }
15884
15885 {
15886 // Set an indexed property.
15887 v8::TryCatch try_catch(isolate);
15888 CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15889 v8::Integer::New(isolate, 42)).FromJust());
15890 CHECK(!try_catch.HasCaught());
15891 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15892 CHECK(val->IsNumber());
15893 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15894 }
15895
15896 {
15897 // Special cases for arrays.
15898 v8::TryCatch try_catch(isolate);
15899 CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15900 v8::Integer::New(isolate, 1)).FromJust());
15901 CHECK(!try_catch.HasCaught());
15902 }
15903 {
15904 // Special cases for arrays: index exceeds the array's length
15905 v8::TryCatch try_catch(isolate);
15906 CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15907 v8::Integer::New(isolate, 23)).FromJust());
15908 CHECK(!try_catch.HasCaught());
15909 CHECK_EQ(2U, arr->Length());
15910 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15911 CHECK(val->IsNumber());
15912 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15913
15914 // Set an existing entry.
15915 CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15916 v8::Integer::New(isolate, 42)).FromJust());
15917 CHECK(!try_catch.HasCaught());
15918 val = arr->Get(env.local(), 0).ToLocalChecked();
15919 CHECK(val->IsNumber());
15920 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15921 }
15922
15923 {
15924 // Set a non-writable property.
15925 v8::TryCatch try_catch(isolate);
15926 CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15927 v8::Integer::New(isolate, 42),
15928 v8::ReadOnly).FromJust());
15929 CHECK(!try_catch.HasCaught());
15930 v8::Local<v8::Value> val =
15931 obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15932 CHECK(val->IsNumber());
15933 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15934 CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
15935 env.local(), v8_str("lala")).FromJust());
15936 CHECK(!try_catch.HasCaught());
15937 }
15938
15939 CompileRun("Object.freeze(a);");
15940 {
15941 // Can't change non-extensible objects.
15942 v8::TryCatch try_catch(isolate);
15943 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
15944 v8::Integer::New(isolate, 42)).FromJust());
15945 CHECK(!try_catch.HasCaught());
15946 }
15947
15948 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15949 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15950 v8::Local<v8::Object> access_checked =
15951 templ->NewInstance(env.local()).ToLocalChecked();
15952 {
15953 v8::TryCatch try_catch(isolate);
15954 CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
15955 v8::Integer::New(isolate, 42))
15956 .IsNothing());
15957 CHECK(try_catch.HasCaught());
15958 }
15959 }
15960
15961
THREADED_TEST(GetCurrentContextWhenNotInContext)15962 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15963 i::Isolate* isolate = CcTest::i_isolate();
15964 CHECK(isolate != NULL);
15965 CHECK(isolate->context() == NULL);
15966 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15967 v8::HandleScope scope(v8_isolate);
15968 // The following should not crash, but return an empty handle.
15969 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15970 CHECK(current.IsEmpty());
15971 }
15972
15973
15974 // Check that a variable declaration with no explicit initialization
15975 // value does shadow an existing property in the prototype chain.
THREADED_TEST(InitGlobalVarInProtoChain)15976 THREADED_TEST(InitGlobalVarInProtoChain) {
15977 LocalContext context;
15978 v8::HandleScope scope(context->GetIsolate());
15979 // Introduce a variable in the prototype chain.
15980 CompileRun("__proto__.x = 42");
15981 v8::Local<v8::Value> result = CompileRun("var x = 43; x");
15982 CHECK(!result->IsUndefined());
15983 CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
15984 }
15985
15986
15987 // Regression test for issue 398.
15988 // If a function is added to an object, creating a constant function
15989 // field, and the result is cloned, replacing the constant function on the
15990 // original should not affect the clone.
15991 // See http://code.google.com/p/v8/issues/detail?id=398
THREADED_TEST(ReplaceConstantFunction)15992 THREADED_TEST(ReplaceConstantFunction) {
15993 LocalContext context;
15994 v8::Isolate* isolate = context->GetIsolate();
15995 v8::HandleScope scope(isolate);
15996 v8::Local<v8::Object> obj = v8::Object::New(isolate);
15997 v8::Local<v8::FunctionTemplate> func_templ =
15998 v8::FunctionTemplate::New(isolate);
15999 v8::Local<v8::String> foo_string = v8_str("foo");
16000 obj->Set(context.local(), foo_string,
16001 func_templ->GetFunction(context.local()).ToLocalChecked())
16002 .FromJust();
16003 v8::Local<v8::Object> obj_clone = obj->Clone();
16004 obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
16005 CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
16006 }
16007
16008
CheckElementValue(i::Isolate * isolate,int expected,i::Handle<i::Object> obj,int offset)16009 static void CheckElementValue(i::Isolate* isolate,
16010 int expected,
16011 i::Handle<i::Object> obj,
16012 int offset) {
16013 i::Object* element =
16014 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16015 CHECK_EQ(expected, i::Smi::cast(element)->value());
16016 }
16017
16018
16019 template <class ExternalArrayClass, class ElementType>
ObjectWithExternalArrayTestHelper(Local<Context> context,v8::Local<Object> obj,int element_count,i::ExternalArrayType array_type,int64_t low,int64_t high)16020 static void ObjectWithExternalArrayTestHelper(Local<Context> context,
16021 v8::Local<Object> obj,
16022 int element_count,
16023 i::ExternalArrayType array_type,
16024 int64_t low, int64_t high) {
16025 i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
16026 i::Isolate* isolate = jsobj->GetIsolate();
16027 obj->Set(context, v8_str("field"),
16028 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503))
16029 .FromJust();
16030 CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
16031 v8::Local<v8::Value> result = CompileRun("ext_array.field");
16032 CHECK_EQ(1503, result->Int32Value(context).FromJust());
16033 result = CompileRun("ext_array[1]");
16034 CHECK_EQ(1, result->Int32Value(context).FromJust());
16035
16036 // Check assigned smis
16037 result = CompileRun("for (var i = 0; i < 8; i++) {"
16038 " ext_array[i] = i;"
16039 "}"
16040 "var sum = 0;"
16041 "for (var i = 0; i < 8; i++) {"
16042 " sum += ext_array[i];"
16043 "}"
16044 "sum;");
16045
16046 CHECK_EQ(28, result->Int32Value(context).FromJust());
16047 // Check pass through of assigned smis
16048 result = CompileRun("var sum = 0;"
16049 "for (var i = 0; i < 8; i++) {"
16050 " sum += ext_array[i] = ext_array[i] = -i;"
16051 "}"
16052 "sum;");
16053 CHECK_EQ(-28, result->Int32Value(context).FromJust());
16054
16055
16056 // Check assigned smis in reverse order
16057 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16058 " ext_array[i] = i;"
16059 "}"
16060 "var sum = 0;"
16061 "for (var i = 0; i < 8; i++) {"
16062 " sum += ext_array[i];"
16063 "}"
16064 "sum;");
16065 CHECK_EQ(28, result->Int32Value(context).FromJust());
16066
16067 // Check pass through of assigned HeapNumbers
16068 result = CompileRun("var sum = 0;"
16069 "for (var i = 0; i < 16; i+=2) {"
16070 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16071 "}"
16072 "sum;");
16073 CHECK_EQ(-28, result->Int32Value(context).FromJust());
16074
16075 // Check assigned HeapNumbers
16076 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16077 " ext_array[i] = (i * 0.5);"
16078 "}"
16079 "var sum = 0;"
16080 "for (var i = 0; i < 16; i+=2) {"
16081 " sum += ext_array[i];"
16082 "}"
16083 "sum;");
16084 CHECK_EQ(28, result->Int32Value(context).FromJust());
16085
16086 // Check assigned HeapNumbers in reverse order
16087 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16088 " ext_array[i] = (i * 0.5);"
16089 "}"
16090 "var sum = 0;"
16091 "for (var i = 0; i < 16; i+=2) {"
16092 " sum += ext_array[i];"
16093 "}"
16094 "sum;");
16095 CHECK_EQ(28, result->Int32Value(context).FromJust());
16096
16097 i::ScopedVector<char> test_buf(1024);
16098
16099 // Check legal boundary conditions.
16100 // The repeated loads and stores ensure the ICs are exercised.
16101 const char* boundary_program =
16102 "var res = 0;"
16103 "for (var i = 0; i < 16; i++) {"
16104 " ext_array[i] = %lld;"
16105 " if (i > 8) {"
16106 " res = ext_array[i];"
16107 " }"
16108 "}"
16109 "res;";
16110 i::SNPrintF(test_buf,
16111 boundary_program,
16112 low);
16113 result = CompileRun(test_buf.start());
16114 CHECK_EQ(low, result->IntegerValue(context).FromJust());
16115
16116 i::SNPrintF(test_buf,
16117 boundary_program,
16118 high);
16119 result = CompileRun(test_buf.start());
16120 CHECK_EQ(high, result->IntegerValue(context).FromJust());
16121
16122 // Check misprediction of type in IC.
16123 result = CompileRun("var tmp_array = ext_array;"
16124 "var sum = 0;"
16125 "for (var i = 0; i < 8; i++) {"
16126 " tmp_array[i] = i;"
16127 " sum += tmp_array[i];"
16128 " if (i == 4) {"
16129 " tmp_array = {};"
16130 " }"
16131 "}"
16132 "sum;");
16133 // Force GC to trigger verification.
16134 CcTest::heap()->CollectAllGarbage();
16135 CHECK_EQ(28, result->Int32Value(context).FromJust());
16136
16137 // Make sure out-of-range loads do not throw.
16138 i::SNPrintF(test_buf,
16139 "var caught_exception = false;"
16140 "try {"
16141 " ext_array[%d];"
16142 "} catch (e) {"
16143 " caught_exception = true;"
16144 "}"
16145 "caught_exception;",
16146 element_count);
16147 result = CompileRun(test_buf.start());
16148 CHECK_EQ(false, result->BooleanValue(context).FromJust());
16149
16150 // Make sure out-of-range stores do not throw.
16151 i::SNPrintF(test_buf,
16152 "var caught_exception = false;"
16153 "try {"
16154 " ext_array[%d] = 1;"
16155 "} catch (e) {"
16156 " caught_exception = true;"
16157 "}"
16158 "caught_exception;",
16159 element_count);
16160 result = CompileRun(test_buf.start());
16161 CHECK_EQ(false, result->BooleanValue(context).FromJust());
16162
16163 // Check other boundary conditions, values and operations.
16164 result = CompileRun("for (var i = 0; i < 8; i++) {"
16165 " ext_array[7] = undefined;"
16166 "}"
16167 "ext_array[7];");
16168 CHECK_EQ(0, result->Int32Value(context).FromJust());
16169 if (array_type == i::kExternalFloat64Array ||
16170 array_type == i::kExternalFloat32Array) {
16171 CHECK(std::isnan(
16172 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
16173 } else {
16174 CheckElementValue(isolate, 0, jsobj, 7);
16175 }
16176
16177 result = CompileRun("for (var i = 0; i < 8; i++) {"
16178 " ext_array[6] = '2.3';"
16179 "}"
16180 "ext_array[6];");
16181 CHECK_EQ(2, result->Int32Value(context).FromJust());
16182 CHECK_EQ(2,
16183 static_cast<int>(
16184 i::Object::GetElement(
16185 isolate, jsobj, 6).ToHandleChecked()->Number()));
16186
16187 if (array_type != i::kExternalFloat32Array &&
16188 array_type != i::kExternalFloat64Array) {
16189 // Though the specification doesn't state it, be explicit about
16190 // converting NaNs and +/-Infinity to zero.
16191 result = CompileRun("for (var i = 0; i < 8; i++) {"
16192 " ext_array[i] = 5;"
16193 "}"
16194 "for (var i = 0; i < 8; i++) {"
16195 " ext_array[i] = NaN;"
16196 "}"
16197 "ext_array[5];");
16198 CHECK_EQ(0, result->Int32Value(context).FromJust());
16199 CheckElementValue(isolate, 0, jsobj, 5);
16200
16201 result = CompileRun("for (var i = 0; i < 8; i++) {"
16202 " ext_array[i] = 5;"
16203 "}"
16204 "for (var i = 0; i < 8; i++) {"
16205 " ext_array[i] = Infinity;"
16206 "}"
16207 "ext_array[5];");
16208 int expected_value =
16209 (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
16210 CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
16211 CheckElementValue(isolate, expected_value, jsobj, 5);
16212
16213 result = CompileRun("for (var i = 0; i < 8; i++) {"
16214 " ext_array[i] = 5;"
16215 "}"
16216 "for (var i = 0; i < 8; i++) {"
16217 " ext_array[i] = -Infinity;"
16218 "}"
16219 "ext_array[5];");
16220 CHECK_EQ(0, result->Int32Value(context).FromJust());
16221 CheckElementValue(isolate, 0, jsobj, 5);
16222
16223 // Check truncation behavior of integral arrays.
16224 const char* unsigned_data =
16225 "var source_data = [0.6, 10.6];"
16226 "var expected_results = [0, 10];";
16227 const char* signed_data =
16228 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16229 "var expected_results = [0, 10, 0, -10];";
16230 const char* pixel_data =
16231 "var source_data = [0.6, 10.6];"
16232 "var expected_results = [1, 11];";
16233 bool is_unsigned = (array_type == i::kExternalUint8Array ||
16234 array_type == i::kExternalUint16Array ||
16235 array_type == i::kExternalUint32Array);
16236 bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
16237
16238 i::SNPrintF(test_buf,
16239 "%s"
16240 "var all_passed = true;"
16241 "for (var i = 0; i < source_data.length; i++) {"
16242 " for (var j = 0; j < 8; j++) {"
16243 " ext_array[j] = source_data[i];"
16244 " }"
16245 " all_passed = all_passed &&"
16246 " (ext_array[5] == expected_results[i]);"
16247 "}"
16248 "all_passed;",
16249 (is_unsigned ?
16250 unsigned_data :
16251 (is_pixel_data ? pixel_data : signed_data)));
16252 result = CompileRun(test_buf.start());
16253 CHECK_EQ(true, result->BooleanValue(context).FromJust());
16254 }
16255
16256 i::Handle<ExternalArrayClass> array(ExternalArrayClass::cast(
16257 i::Handle<i::JSObject>::cast(jsobj)->elements()));
16258 for (int i = 0; i < element_count; i++) {
16259 array->set(i, static_cast<ElementType>(i));
16260 }
16261
16262 // Test complex assignments
16263 result = CompileRun("function ee_op_test_complex_func(sum) {"
16264 " for (var i = 0; i < 40; ++i) {"
16265 " sum += (ext_array[i] += 1);"
16266 " sum += (ext_array[i] -= 1);"
16267 " } "
16268 " return sum;"
16269 "}"
16270 "sum=0;"
16271 "for (var i=0;i<10000;++i) {"
16272 " sum=ee_op_test_complex_func(sum);"
16273 "}"
16274 "sum;");
16275 CHECK_EQ(16000000, result->Int32Value(context).FromJust());
16276
16277 // Test count operations
16278 result = CompileRun("function ee_op_test_count_func(sum) {"
16279 " for (var i = 0; i < 40; ++i) {"
16280 " sum += (++ext_array[i]);"
16281 " sum += (--ext_array[i]);"
16282 " } "
16283 " return sum;"
16284 "}"
16285 "sum=0;"
16286 "for (var i=0;i<10000;++i) {"
16287 " sum=ee_op_test_count_func(sum);"
16288 "}"
16289 "sum;");
16290 CHECK_EQ(16000000, result->Int32Value(context).FromJust());
16291
16292 result = CompileRun("ext_array[3] = 33;"
16293 "delete ext_array[3];"
16294 "ext_array[3];");
16295 CHECK_EQ(33, result->Int32Value(context).FromJust());
16296
16297 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16298 "ext_array[2] = 12; ext_array[3] = 13;"
16299 "ext_array.__defineGetter__('2',"
16300 "function() { return 120; });"
16301 "ext_array[2];");
16302 CHECK_EQ(12, result->Int32Value(context).FromJust());
16303
16304 result = CompileRun("var js_array = new Array(40);"
16305 "js_array[0] = 77;"
16306 "js_array;");
16307 CHECK_EQ(77, v8::Object::Cast(*result)
16308 ->Get(context, v8_str("0"))
16309 .ToLocalChecked()
16310 ->Int32Value(context)
16311 .FromJust());
16312
16313 result = CompileRun("ext_array[1] = 23;"
16314 "ext_array.__proto__ = [];"
16315 "js_array.__proto__ = ext_array;"
16316 "js_array.concat(ext_array);");
16317 CHECK_EQ(77, v8::Object::Cast(*result)
16318 ->Get(context, v8_str("0"))
16319 .ToLocalChecked()
16320 ->Int32Value(context)
16321 .FromJust());
16322 CHECK_EQ(23, v8::Object::Cast(*result)
16323 ->Get(context, v8_str("1"))
16324 .ToLocalChecked()
16325 ->Int32Value(context)
16326 .FromJust());
16327
16328 result = CompileRun("ext_array[1] = 23;");
16329 CHECK_EQ(23, result->Int32Value(context).FromJust());
16330 }
16331
16332
16333 template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16334 class ElementType>
FixedTypedArrayTestHelper(i::ExternalArrayType array_type,ElementType low,ElementType high)16335 static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16336 ElementType low, ElementType high) {
16337 i::FLAG_allow_natives_syntax = true;
16338 LocalContext context;
16339 i::Isolate* isolate = CcTest::i_isolate();
16340 i::Factory* factory = isolate->factory();
16341 v8::HandleScope scope(context->GetIsolate());
16342 const int kElementCount = 260;
16343 i::Handle<i::JSTypedArray> jsobj =
16344 factory->NewJSTypedArray(elements_kind, kElementCount);
16345 i::Handle<FixedTypedArrayClass> fixed_array(
16346 FixedTypedArrayClass::cast(jsobj->elements()));
16347 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16348 fixed_array->map()->instance_type());
16349 CHECK_EQ(kElementCount, fixed_array->length());
16350 CcTest::heap()->CollectAllGarbage();
16351 for (int i = 0; i < kElementCount; i++) {
16352 fixed_array->set(i, static_cast<ElementType>(i));
16353 }
16354 // Force GC to trigger verification.
16355 CcTest::heap()->CollectAllGarbage();
16356 for (int i = 0; i < kElementCount; i++) {
16357 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16358 static_cast<int64_t>(fixed_array->get_scalar(i)));
16359 }
16360 v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16361
16362 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16363 context.local(), obj, kElementCount, array_type,
16364 static_cast<int64_t>(low),
16365 static_cast<int64_t>(high));
16366 }
16367
16368
THREADED_TEST(FixedUint8Array)16369 THREADED_TEST(FixedUint8Array) {
16370 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16371 i::kExternalUint8Array, 0x0, 0xFF);
16372 }
16373
16374
THREADED_TEST(FixedUint8ClampedArray)16375 THREADED_TEST(FixedUint8ClampedArray) {
16376 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16377 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16378 i::kExternalUint8ClampedArray, 0x0, 0xFF);
16379 }
16380
16381
THREADED_TEST(FixedInt8Array)16382 THREADED_TEST(FixedInt8Array) {
16383 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16384 i::kExternalInt8Array, -0x80, 0x7F);
16385 }
16386
16387
THREADED_TEST(FixedUint16Array)16388 THREADED_TEST(FixedUint16Array) {
16389 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16390 i::kExternalUint16Array, 0x0, 0xFFFF);
16391 }
16392
16393
THREADED_TEST(FixedInt16Array)16394 THREADED_TEST(FixedInt16Array) {
16395 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16396 i::kExternalInt16Array, -0x8000, 0x7FFF);
16397 }
16398
16399
THREADED_TEST(FixedUint32Array)16400 THREADED_TEST(FixedUint32Array) {
16401 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16402 i::kExternalUint32Array, 0x0, UINT_MAX);
16403 }
16404
16405
THREADED_TEST(FixedInt32Array)16406 THREADED_TEST(FixedInt32Array) {
16407 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16408 i::kExternalInt32Array, INT_MIN, INT_MAX);
16409 }
16410
16411
THREADED_TEST(FixedFloat32Array)16412 THREADED_TEST(FixedFloat32Array) {
16413 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16414 i::kExternalFloat32Array, -500, 500);
16415 }
16416
16417
THREADED_TEST(FixedFloat64Array)16418 THREADED_TEST(FixedFloat64Array) {
16419 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16420 i::kExternalFloat64Array, -500, 500);
16421 }
16422
16423
16424 template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16425 class ArrayBufferType>
TypedArrayTestHelper(i::ExternalArrayType array_type,int64_t low,int64_t high)16426 void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16427 int64_t high) {
16428 const int kElementCount = 50;
16429
16430 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16431
16432 LocalContext env;
16433 v8::Isolate* isolate = env->GetIsolate();
16434 v8::HandleScope handle_scope(isolate);
16435
16436 Local<ArrayBufferType> ab =
16437 ArrayBufferType::New(isolate, backing_store.start(),
16438 (kElementCount + 2) * sizeof(ElementType));
16439 Local<TypedArray> ta =
16440 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16441 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16442 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16443 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16444 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16445 CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16446
16447 ElementType* data = backing_store.start() + 2;
16448 for (int i = 0; i < kElementCount; i++) {
16449 data[i] = static_cast<ElementType>(i);
16450 }
16451
16452 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16453 env.local(), ta, kElementCount, array_type, low, high);
16454 }
16455
16456
THREADED_TEST(Uint8Array)16457 THREADED_TEST(Uint8Array) {
16458 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16459 v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16460 }
16461
16462
THREADED_TEST(Int8Array)16463 THREADED_TEST(Int8Array) {
16464 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16465 v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16466 }
16467
16468
THREADED_TEST(Uint16Array)16469 THREADED_TEST(Uint16Array) {
16470 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16471 v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16472 }
16473
16474
THREADED_TEST(Int16Array)16475 THREADED_TEST(Int16Array) {
16476 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16477 v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16478 0x7FFF);
16479 }
16480
16481
THREADED_TEST(Uint32Array)16482 THREADED_TEST(Uint32Array) {
16483 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16484 v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16485 }
16486
16487
THREADED_TEST(Int32Array)16488 THREADED_TEST(Int32Array) {
16489 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16490 v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16491 INT_MAX);
16492 }
16493
16494
THREADED_TEST(Float32Array)16495 THREADED_TEST(Float32Array) {
16496 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16497 v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16498 }
16499
16500
THREADED_TEST(Float64Array)16501 THREADED_TEST(Float64Array) {
16502 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16503 v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16504 }
16505
16506
THREADED_TEST(Uint8ClampedArray)16507 THREADED_TEST(Uint8ClampedArray) {
16508 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16509 i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16510 i::kExternalUint8ClampedArray, 0, 0xFF);
16511 }
16512
16513
THREADED_TEST(DataView)16514 THREADED_TEST(DataView) {
16515 const int kSize = 50;
16516
16517 i::ScopedVector<uint8_t> backing_store(kSize+2);
16518
16519 LocalContext env;
16520 v8::Isolate* isolate = env->GetIsolate();
16521 v8::HandleScope handle_scope(isolate);
16522
16523 Local<v8::ArrayBuffer> ab =
16524 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16525 Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16526 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16527 CHECK_EQ(2u, dv->ByteOffset());
16528 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16529 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16530 }
16531
16532
THREADED_TEST(SkipArrayBufferBackingStoreDuringGC)16533 THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16534 LocalContext env;
16535 v8::Isolate* isolate = env->GetIsolate();
16536 v8::HandleScope handle_scope(isolate);
16537
16538 // Make sure the pointer looks like a heap object
16539 uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16540
16541 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16542 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16543
16544 // Should not crash
16545 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
16546 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
16547 CcTest::heap()->CollectAllGarbage();
16548 CcTest::heap()->CollectAllGarbage();
16549
16550 // Should not move the pointer
16551 CHECK_EQ(ab->GetContents().Data(), store_ptr);
16552 }
16553
16554
THREADED_TEST(SkipArrayBufferDuringScavenge)16555 THREADED_TEST(SkipArrayBufferDuringScavenge) {
16556 LocalContext env;
16557 v8::Isolate* isolate = env->GetIsolate();
16558 v8::HandleScope handle_scope(isolate);
16559
16560 // Make sure the pointer looks like a heap object
16561 Local<v8::Object> tmp = v8::Object::New(isolate);
16562 uint8_t* store_ptr =
16563 reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16564
16565 // Make `store_ptr` point to from space
16566 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
16567
16568 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16569 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16570
16571 // Should not crash,
16572 // i.e. backing store pointer should not be treated as a heap object pointer
16573 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
16574 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
16575
16576 // Use `ab` to silence compiler warning
16577 CHECK_EQ(ab->GetContents().Data(), store_ptr);
16578 }
16579
16580
THREADED_TEST(SharedUint8Array)16581 THREADED_TEST(SharedUint8Array) {
16582 i::FLAG_harmony_sharedarraybuffer = true;
16583 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16584 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16585 }
16586
16587
THREADED_TEST(SharedInt8Array)16588 THREADED_TEST(SharedInt8Array) {
16589 i::FLAG_harmony_sharedarraybuffer = true;
16590 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16591 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16592 0x7F);
16593 }
16594
16595
THREADED_TEST(SharedUint16Array)16596 THREADED_TEST(SharedUint16Array) {
16597 i::FLAG_harmony_sharedarraybuffer = true;
16598 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16599 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16600 0xFFFF);
16601 }
16602
16603
THREADED_TEST(SharedInt16Array)16604 THREADED_TEST(SharedInt16Array) {
16605 i::FLAG_harmony_sharedarraybuffer = true;
16606 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16607 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16608 0x7FFF);
16609 }
16610
16611
THREADED_TEST(SharedUint32Array)16612 THREADED_TEST(SharedUint32Array) {
16613 i::FLAG_harmony_sharedarraybuffer = true;
16614 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16615 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16616 UINT_MAX);
16617 }
16618
16619
THREADED_TEST(SharedInt32Array)16620 THREADED_TEST(SharedInt32Array) {
16621 i::FLAG_harmony_sharedarraybuffer = true;
16622 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16623 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16624 INT_MAX);
16625 }
16626
16627
THREADED_TEST(SharedFloat32Array)16628 THREADED_TEST(SharedFloat32Array) {
16629 i::FLAG_harmony_sharedarraybuffer = true;
16630 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16631 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16632 500);
16633 }
16634
16635
THREADED_TEST(SharedFloat64Array)16636 THREADED_TEST(SharedFloat64Array) {
16637 i::FLAG_harmony_sharedarraybuffer = true;
16638 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16639 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
16640 500);
16641 }
16642
16643
THREADED_TEST(SharedUint8ClampedArray)16644 THREADED_TEST(SharedUint8ClampedArray) {
16645 i::FLAG_harmony_sharedarraybuffer = true;
16646 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16647 i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
16648 i::kExternalUint8ClampedArray, 0, 0xFF);
16649 }
16650
16651
THREADED_TEST(SharedDataView)16652 THREADED_TEST(SharedDataView) {
16653 i::FLAG_harmony_sharedarraybuffer = true;
16654 const int kSize = 50;
16655
16656 i::ScopedVector<uint8_t> backing_store(kSize + 2);
16657
16658 LocalContext env;
16659 v8::Isolate* isolate = env->GetIsolate();
16660 v8::HandleScope handle_scope(isolate);
16661
16662 Local<v8::SharedArrayBuffer> ab =
16663 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16664 Local<v8::DataView> dv =
16665 v8::DataView::New(ab, 2, kSize);
16666 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16667 CHECK_EQ(2u, dv->ByteOffset());
16668 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16669 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16670 }
16671
16672
16673 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16674 THREADED_TEST(Is##View) { \
16675 LocalContext env; \
16676 v8::Isolate* isolate = env->GetIsolate(); \
16677 v8::HandleScope handle_scope(isolate); \
16678 \
16679 Local<Value> result = CompileRun( \
16680 "var ab = new ArrayBuffer(128);" \
16681 "new " #View "(ab)"); \
16682 CHECK(result->IsArrayBufferView()); \
16683 CHECK(result->Is##View()); \
16684 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16685 }
16686
16687 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)16688 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16689 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16690 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16691 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16692 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16693 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16694 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16695 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16696 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16697
16698 #undef IS_ARRAY_BUFFER_VIEW_TEST
16699
16700
16701
16702 THREADED_TEST(ScriptContextDependence) {
16703 LocalContext c1;
16704 v8::HandleScope scope(c1->GetIsolate());
16705 const char *source = "foo";
16706 v8::Local<v8::Script> dep = v8_compile(source);
16707 v8::ScriptCompiler::Source script_source(
16708 v8::String::NewFromUtf8(c1->GetIsolate(), source,
16709 v8::NewStringType::kNormal)
16710 .ToLocalChecked());
16711 v8::Local<v8::UnboundScript> indep =
16712 v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
16713 .ToLocalChecked();
16714 c1->Global()
16715 ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
16716 v8::NewStringType::kNormal)
16717 .ToLocalChecked(),
16718 v8::Integer::New(c1->GetIsolate(), 100))
16719 .FromJust();
16720 CHECK_EQ(
16721 dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
16722 100);
16723 CHECK_EQ(indep->BindToCurrentContext()
16724 ->Run(c1.local())
16725 .ToLocalChecked()
16726 ->Int32Value(c1.local())
16727 .FromJust(),
16728 100);
16729 LocalContext c2;
16730 c2->Global()
16731 ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
16732 v8::NewStringType::kNormal)
16733 .ToLocalChecked(),
16734 v8::Integer::New(c2->GetIsolate(), 101))
16735 .FromJust();
16736 CHECK_EQ(
16737 dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
16738 100);
16739 CHECK_EQ(indep->BindToCurrentContext()
16740 ->Run(c2.local())
16741 .ToLocalChecked()
16742 ->Int32Value(c2.local())
16743 .FromJust(),
16744 101);
16745 }
16746
16747
THREADED_TEST(StackTrace)16748 THREADED_TEST(StackTrace) {
16749 LocalContext context;
16750 v8::HandleScope scope(context->GetIsolate());
16751 v8::TryCatch try_catch(context->GetIsolate());
16752 const char *source = "function foo() { FAIL.FAIL; }; foo();";
16753 v8::Local<v8::String> src = v8_str(source);
16754 v8::Local<v8::String> origin = v8_str("stack-trace-test");
16755 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
16756 CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
16757 &script_source)
16758 .ToLocalChecked()
16759 ->BindToCurrentContext()
16760 ->Run(context.local())
16761 .IsEmpty());
16762 CHECK(try_catch.HasCaught());
16763 v8::String::Utf8Value stack(
16764 try_catch.StackTrace(context.local()).ToLocalChecked());
16765 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16766 }
16767
16768
16769 // 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::Local<v8::StackFrame> frame)16770 void checkStackFrame(const char* expected_script_name,
16771 const char* expected_func_name, int expected_line_number,
16772 int expected_column, bool is_eval, bool is_constructor,
16773 v8::Local<v8::StackFrame> frame) {
16774 v8::HandleScope scope(CcTest::isolate());
16775 v8::String::Utf8Value func_name(frame->GetFunctionName());
16776 v8::String::Utf8Value script_name(frame->GetScriptName());
16777 if (*script_name == NULL) {
16778 // The situation where there is no associated script, like for evals.
16779 CHECK(expected_script_name == NULL);
16780 } else {
16781 CHECK(strstr(*script_name, expected_script_name) != NULL);
16782 }
16783 CHECK(strstr(*func_name, expected_func_name) != NULL);
16784 CHECK_EQ(expected_line_number, frame->GetLineNumber());
16785 CHECK_EQ(expected_column, frame->GetColumn());
16786 CHECK_EQ(is_eval, frame->IsEval());
16787 CHECK_EQ(is_constructor, frame->IsConstructor());
16788 }
16789
16790
AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value> & args)16791 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16792 v8::HandleScope scope(args.GetIsolate());
16793 const char* origin = "capture-stack-trace-test";
16794 const int kOverviewTest = 1;
16795 const int kDetailedTest = 2;
16796 const int kFunctionName = 3;
16797 const int kDisplayName = 4;
16798 const int kFunctionNameAndDisplayName = 5;
16799 const int kDisplayNameIsNotString = 6;
16800 const int kFunctionNameIsNotString = 7;
16801
16802 CHECK(args.Length() == 1);
16803
16804 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
16805 int testGroup = args[0]->Int32Value(context).FromJust();
16806 if (testGroup == kOverviewTest) {
16807 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16808 args.GetIsolate(), 10, v8::StackTrace::kOverview);
16809 CHECK_EQ(4, stackTrace->GetFrameCount());
16810 checkStackFrame(origin, "bar", 2, 10, false, false,
16811 stackTrace->GetFrame(0));
16812 checkStackFrame(origin, "foo", 6, 3, false, false,
16813 stackTrace->GetFrame(1));
16814 // This is the source string inside the eval which has the call to foo.
16815 checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2));
16816 // The last frame is an anonymous function which has the initial eval call.
16817 checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
16818
16819 CHECK(stackTrace->AsArray()->IsArray());
16820 } else if (testGroup == kDetailedTest) {
16821 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16822 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
16823 CHECK_EQ(4, stackTrace->GetFrameCount());
16824 checkStackFrame(origin, "bat", 4, 22, false, false,
16825 stackTrace->GetFrame(0));
16826 checkStackFrame(origin, "baz", 8, 3, false, true,
16827 stackTrace->GetFrame(1));
16828 bool is_eval = true;
16829 // This is the source string inside the eval which has the call to baz.
16830 checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
16831 // The last frame is an anonymous function which has the initial eval call.
16832 checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
16833
16834 CHECK(stackTrace->AsArray()->IsArray());
16835 } else if (testGroup == kFunctionName) {
16836 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16837 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16838 CHECK_EQ(3, stackTrace->GetFrameCount());
16839 checkStackFrame(origin, "function.name", 2, 24, false, false,
16840 stackTrace->GetFrame(0));
16841 } else if (testGroup == kDisplayName) {
16842 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16843 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16844 CHECK_EQ(3, stackTrace->GetFrameCount());
16845 checkStackFrame(origin, "function.displayName", 2, 24, false, false,
16846 stackTrace->GetFrame(0));
16847 } else if (testGroup == kFunctionNameAndDisplayName) {
16848 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16849 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16850 CHECK_EQ(3, stackTrace->GetFrameCount());
16851 checkStackFrame(origin, "function.displayName", 2, 24, false, false,
16852 stackTrace->GetFrame(0));
16853 } else if (testGroup == kDisplayNameIsNotString) {
16854 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16855 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16856 CHECK_EQ(3, stackTrace->GetFrameCount());
16857 checkStackFrame(origin, "function.name", 2, 24, false, false,
16858 stackTrace->GetFrame(0));
16859 } else if (testGroup == kFunctionNameIsNotString) {
16860 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16861 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16862 CHECK_EQ(3, stackTrace->GetFrameCount());
16863 checkStackFrame(origin, "f", 2, 24, false, false, stackTrace->GetFrame(0));
16864 }
16865 }
16866
16867
16868 // Tests the C++ StackTrace API.
16869 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16870 // THREADED_TEST(CaptureStackTrace) {
TEST(CaptureStackTrace)16871 TEST(CaptureStackTrace) {
16872 v8::Isolate* isolate = CcTest::isolate();
16873 v8::HandleScope scope(isolate);
16874 v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
16875 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16876 templ->Set(v8_str("AnalyzeStackInNativeCode"),
16877 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
16878 LocalContext context(0, templ);
16879
16880 // Test getting OVERVIEW information. Should ignore information that is not
16881 // script name, function name, line number, and column offset.
16882 const char *overview_source =
16883 "function bar() {\n"
16884 " var y; AnalyzeStackInNativeCode(1);\n"
16885 "}\n"
16886 "function foo() {\n"
16887 "\n"
16888 " bar();\n"
16889 "}\n"
16890 "var x;eval('new foo();');";
16891 v8::Local<v8::String> overview_src = v8_str(overview_source);
16892 v8::ScriptCompiler::Source script_source(overview_src,
16893 v8::ScriptOrigin(origin));
16894 v8::Local<Value> overview_result(
16895 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
16896 .ToLocalChecked()
16897 ->BindToCurrentContext()
16898 ->Run(context.local())
16899 .ToLocalChecked());
16900 CHECK(!overview_result.IsEmpty());
16901 CHECK(overview_result->IsObject());
16902
16903 // Test getting DETAILED information.
16904 const char *detailed_source =
16905 "function bat() {AnalyzeStackInNativeCode(2);\n"
16906 "}\n"
16907 "\n"
16908 "function baz() {\n"
16909 " bat();\n"
16910 "}\n"
16911 "eval('new baz();');";
16912 v8::Local<v8::String> detailed_src = v8_str(detailed_source);
16913 // Make the script using a non-zero line and column offset.
16914 v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
16915 v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
16916 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16917 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
16918 v8::Local<v8::UnboundScript> detailed_script(
16919 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
16920 .ToLocalChecked());
16921 v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
16922 ->Run(context.local())
16923 .ToLocalChecked());
16924 CHECK(!detailed_result.IsEmpty());
16925 CHECK(detailed_result->IsObject());
16926
16927 // Test using function.name and function.displayName in stack trace
16928 const char* function_name_source =
16929 "function bar(function_name, display_name, testGroup) {\n"
16930 " var f = function() { AnalyzeStackInNativeCode(testGroup); };\n"
16931 " if (function_name) {\n"
16932 " Object.defineProperty(f, 'name', { value: function_name });\n"
16933 " }\n"
16934 " if (display_name) {\n"
16935 " f.displayName = display_name;"
16936 " }\n"
16937 " f()\n"
16938 "}\n"
16939 "bar('function.name', undefined, 3);\n"
16940 "bar(undefined, 'function.displayName', 4);\n"
16941 "bar('function.name', 'function.displayName', 5);\n"
16942 "bar('function.name', 239, 6);\n"
16943 "bar(239, undefined, 7);\n";
16944 v8::Local<v8::String> function_name_src =
16945 v8::String::NewFromUtf8(isolate, function_name_source,
16946 v8::NewStringType::kNormal)
16947 .ToLocalChecked();
16948 v8::ScriptCompiler::Source script_source3(function_name_src,
16949 v8::ScriptOrigin(origin));
16950 v8::Local<Value> function_name_result(
16951 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
16952 .ToLocalChecked()
16953 ->BindToCurrentContext()
16954 ->Run(context.local())
16955 .ToLocalChecked());
16956 CHECK(!function_name_result.IsEmpty());
16957 }
16958
16959
StackTraceForUncaughtExceptionListener(v8::Local<v8::Message> message,v8::Local<Value>)16960 static void StackTraceForUncaughtExceptionListener(
16961 v8::Local<v8::Message> message, v8::Local<Value>) {
16962 report_count++;
16963 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16964 CHECK_EQ(2, stack_trace->GetFrameCount());
16965 checkStackFrame("origin", "foo", 2, 3, false, false,
16966 stack_trace->GetFrame(0));
16967 checkStackFrame("origin", "bar", 5, 3, false, false,
16968 stack_trace->GetFrame(1));
16969 }
16970
16971
TEST(CaptureStackTraceForUncaughtException)16972 TEST(CaptureStackTraceForUncaughtException) {
16973 report_count = 0;
16974 LocalContext env;
16975 v8::Isolate* isolate = env->GetIsolate();
16976 v8::HandleScope scope(isolate);
16977 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
16978 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16979
16980 CompileRunWithOrigin(
16981 "function foo() {\n"
16982 " throw 1;\n"
16983 "};\n"
16984 "function bar() {\n"
16985 " foo();\n"
16986 "};",
16987 "origin");
16988 v8::Local<v8::Object> global = env->Global();
16989 Local<Value> trouble =
16990 global->Get(env.local(), v8_str("bar")).ToLocalChecked();
16991 CHECK(trouble->IsFunction());
16992 CHECK(Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).IsEmpty());
16993 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16994 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16995 CHECK_EQ(1, report_count);
16996 }
16997
16998
TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace)16999 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
17000 report_count = 0;
17001 LocalContext env;
17002 v8::Isolate* isolate = env->GetIsolate();
17003 v8::HandleScope scope(isolate);
17004
17005 // Create an Error object first.
17006 CompileRunWithOrigin(
17007 "function foo() {\n"
17008 "e=new Error('err');\n"
17009 "};\n"
17010 "function bar() {\n"
17011 " foo();\n"
17012 "};\n"
17013 "var e;",
17014 "origin");
17015 v8::Local<v8::Object> global = env->Global();
17016 Local<Value> trouble =
17017 global->Get(env.local(), v8_str("bar")).ToLocalChecked();
17018 CHECK(trouble->IsFunction());
17019 Function::Cast(*trouble)->Call(env.local(), global, 0, NULL).ToLocalChecked();
17020
17021 // Enable capturing detailed stack trace late, and throw the exception.
17022 // The detailed stack trace should be extracted from the simple stack.
17023 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
17024 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17025 CompileRunWithOrigin("throw e", "origin");
17026 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17027 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17028 CHECK_EQ(1, report_count);
17029 }
17030
17031
TEST(CaptureStackTraceForUncaughtExceptionAndSetters)17032 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17033 LocalContext env;
17034 v8::Isolate* isolate = env->GetIsolate();
17035 v8::HandleScope scope(isolate);
17036 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
17037 v8::StackTrace::kDetailed);
17038
17039 CompileRun(
17040 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17041 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17042 " 'isConstructor'];\n"
17043 "for (var i = 0; i < setters.length; i++) {\n"
17044 " var prop = setters[i];\n"
17045 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17046 "}\n");
17047 CompileRun("throw 'exception';");
17048 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17049 }
17050
17051
StackTraceFunctionNameListener(v8::Local<v8::Message> message,v8::Local<Value>)17052 static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
17053 v8::Local<Value>) {
17054 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17055 CHECK_EQ(5, stack_trace->GetFrameCount());
17056 checkStackFrame("origin", "foo:0", 4, 7, false, false,
17057 stack_trace->GetFrame(0));
17058 checkStackFrame("origin", "foo:1", 5, 27, false, false,
17059 stack_trace->GetFrame(1));
17060 checkStackFrame("origin", "foo", 5, 27, false, false,
17061 stack_trace->GetFrame(2));
17062 checkStackFrame("origin", "foo", 5, 27, false, false,
17063 stack_trace->GetFrame(3));
17064 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
17065 }
17066
17067
TEST(GetStackTraceContainsFunctionsWithFunctionName)17068 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
17069 LocalContext env;
17070 v8::Isolate* isolate = env->GetIsolate();
17071 v8::HandleScope scope(isolate);
17072
17073 CompileRunWithOrigin(
17074 "function gen(name, counter) {\n"
17075 " var f = function foo() {\n"
17076 " if (counter === 0)\n"
17077 " throw 1;\n"
17078 " gen(name, counter - 1)();\n"
17079 " };\n"
17080 " if (counter == 3) {\n"
17081 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
17082 " } else {\n"
17083 " Object.defineProperty(f, 'name', {writable:true});\n"
17084 " if (counter == 2)\n"
17085 " f.name = 42;\n"
17086 " else\n"
17087 " f.name = name + ':' + counter;\n"
17088 " }\n"
17089 " return f;\n"
17090 "};",
17091 "origin");
17092
17093 isolate->AddMessageListener(StackTraceFunctionNameListener);
17094 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17095 CompileRunWithOrigin("gen('foo', 3)();", "origin");
17096 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17097 isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
17098 }
17099
17100
RethrowStackTraceHandler(v8::Local<v8::Message> message,v8::Local<v8::Value> data)17101 static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
17102 v8::Local<v8::Value> data) {
17103 // Use the frame where JavaScript is called from.
17104 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17105 CHECK(!stack_trace.IsEmpty());
17106 int frame_count = stack_trace->GetFrameCount();
17107 CHECK_EQ(3, frame_count);
17108 int line_number[] = {1, 2, 5};
17109 for (int i = 0; i < frame_count; i++) {
17110 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17111 }
17112 }
17113
17114
17115 // Test that we only return the stack trace at the site where the exception
17116 // is first thrown (not where it is rethrown).
TEST(RethrowStackTrace)17117 TEST(RethrowStackTrace) {
17118 LocalContext env;
17119 v8::Isolate* isolate = env->GetIsolate();
17120 v8::HandleScope scope(isolate);
17121 // We make sure that
17122 // - the stack trace of the ReferenceError in g() is reported.
17123 // - the stack trace is not overwritten when e1 is rethrown by t().
17124 // - the stack trace of e2 does not overwrite that of e1.
17125 const char* source =
17126 "function g() { error; } \n"
17127 "function f() { g(); } \n"
17128 "function t(e) { throw e; } \n"
17129 "try { \n"
17130 " f(); \n"
17131 "} catch (e1) { \n"
17132 " try { \n"
17133 " error; \n"
17134 " } catch (e2) { \n"
17135 " t(e1); \n"
17136 " } \n"
17137 "} \n";
17138 isolate->AddMessageListener(RethrowStackTraceHandler);
17139 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17140 CompileRun(source);
17141 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17142 isolate->RemoveMessageListeners(RethrowStackTraceHandler);
17143 }
17144
17145
RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,v8::Local<v8::Value> data)17146 static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
17147 v8::Local<v8::Value> data) {
17148 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17149 CHECK(!stack_trace.IsEmpty());
17150 int frame_count = stack_trace->GetFrameCount();
17151 CHECK_EQ(2, frame_count);
17152 int line_number[] = {3, 7};
17153 for (int i = 0; i < frame_count; i++) {
17154 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17155 }
17156 }
17157
17158
17159 // Test that we do not recognize identity for primitive exceptions.
TEST(RethrowPrimitiveStackTrace)17160 TEST(RethrowPrimitiveStackTrace) {
17161 LocalContext env;
17162 v8::Isolate* isolate = env->GetIsolate();
17163 v8::HandleScope scope(isolate);
17164 // We do not capture stack trace for non Error objects on creation time.
17165 // Instead, we capture the stack trace on last throw.
17166 const char* source =
17167 "function g() { throw 404; } \n"
17168 "function f() { g(); } \n"
17169 "function t(e) { throw e; } \n"
17170 "try { \n"
17171 " f(); \n"
17172 "} catch (e1) { \n"
17173 " t(e1) \n"
17174 "} \n";
17175 isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
17176 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17177 CompileRun(source);
17178 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17179 isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17180 }
17181
17182
RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,v8::Local<v8::Value> data)17183 static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
17184 v8::Local<v8::Value> data) {
17185 // Use the frame where JavaScript is called from.
17186 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17187 CHECK(!stack_trace.IsEmpty());
17188 CHECK_EQ(1, stack_trace->GetFrameCount());
17189 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17190 }
17191
17192
17193 // Test that the stack trace is captured when the error object is created and
17194 // not where it is thrown.
TEST(RethrowExistingStackTrace)17195 TEST(RethrowExistingStackTrace) {
17196 LocalContext env;
17197 v8::Isolate* isolate = env->GetIsolate();
17198 v8::HandleScope scope(isolate);
17199 const char* source =
17200 "var e = new Error(); \n"
17201 "throw e; \n";
17202 isolate->AddMessageListener(RethrowExistingStackTraceHandler);
17203 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17204 CompileRun(source);
17205 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17206 isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
17207 }
17208
17209
RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,v8::Local<v8::Value> data)17210 static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
17211 v8::Local<v8::Value> data) {
17212 // Use the frame where JavaScript is called from.
17213 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17214 CHECK(!stack_trace.IsEmpty());
17215 CHECK_EQ(1, stack_trace->GetFrameCount());
17216 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17217 }
17218
17219
17220 // Test that the stack trace is captured where the bogus Error object is thrown.
TEST(RethrowBogusErrorStackTrace)17221 TEST(RethrowBogusErrorStackTrace) {
17222 LocalContext env;
17223 v8::Isolate* isolate = env->GetIsolate();
17224 v8::HandleScope scope(isolate);
17225 const char* source =
17226 "var e = {__proto__: new Error()} \n"
17227 "throw e; \n";
17228 isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
17229 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
17230 CompileRun(source);
17231 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
17232 isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17233 }
17234
17235
17236 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17237 int promise_reject_counter = 0;
17238 int promise_revoke_counter = 0;
17239 int promise_reject_msg_line_number = -1;
17240 int promise_reject_msg_column_number = -1;
17241 int promise_reject_line_number = -1;
17242 int promise_reject_column_number = -1;
17243 int promise_reject_frame_count = -1;
17244
PromiseRejectCallback(v8::PromiseRejectMessage reject_message)17245 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
17246 v8::Local<v8::Object> global = CcTest::global();
17247 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17248 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
17249 promise_reject_counter++;
17250 global->Set(context, v8_str("rejected"), reject_message.GetPromise())
17251 .FromJust();
17252 global->Set(context, v8_str("value"), reject_message.GetValue()).FromJust();
17253 v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17254 CcTest::isolate(), reject_message.GetValue());
17255 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17256
17257 promise_reject_msg_line_number = message->GetLineNumber(context).FromJust();
17258 promise_reject_msg_column_number =
17259 message->GetStartColumn(context).FromJust() + 1;
17260
17261 if (!stack_trace.IsEmpty()) {
17262 promise_reject_frame_count = stack_trace->GetFrameCount();
17263 if (promise_reject_frame_count > 0) {
17264 CHECK(stack_trace->GetFrame(0)
17265 ->GetScriptName()
17266 ->Equals(context, v8_str("pro"))
17267 .FromJust());
17268 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
17269 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
17270 } else {
17271 promise_reject_line_number = -1;
17272 promise_reject_column_number = -1;
17273 }
17274 }
17275 } else {
17276 promise_revoke_counter++;
17277 global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17278 .FromJust();
17279 CHECK(reject_message.GetValue().IsEmpty());
17280 }
17281 }
17282
17283
GetPromise(const char * name)17284 v8::Local<v8::Promise> GetPromise(const char* name) {
17285 return v8::Local<v8::Promise>::Cast(
17286 CcTest::global()
17287 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17288 .ToLocalChecked());
17289 }
17290
17291
RejectValue()17292 v8::Local<v8::Value> RejectValue() {
17293 return CcTest::global()
17294 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17295 .ToLocalChecked();
17296 }
17297
17298
ResetPromiseStates()17299 void ResetPromiseStates() {
17300 promise_reject_counter = 0;
17301 promise_revoke_counter = 0;
17302 promise_reject_msg_line_number = -1;
17303 promise_reject_msg_column_number = -1;
17304 promise_reject_line_number = -1;
17305 promise_reject_column_number = -1;
17306 promise_reject_frame_count = -1;
17307
17308 v8::Local<v8::Object> global = CcTest::global();
17309 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17310 global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17311 global->Set(context, v8_str("value"), v8_str("")).FromJust();
17312 global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17313 }
17314
17315
TEST(PromiseRejectCallback)17316 TEST(PromiseRejectCallback) {
17317 LocalContext env;
17318 v8::Isolate* isolate = env->GetIsolate();
17319 v8::HandleScope scope(isolate);
17320
17321 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17322
17323 ResetPromiseStates();
17324
17325 // Create promise p0.
17326 CompileRun(
17327 "var reject; \n"
17328 "var p0 = new Promise( \n"
17329 " function(res, rej) { \n"
17330 " reject = rej; \n"
17331 " } \n"
17332 "); \n");
17333 CHECK(!GetPromise("p0")->HasHandler());
17334 CHECK_EQ(0, promise_reject_counter);
17335 CHECK_EQ(0, promise_revoke_counter);
17336
17337 // Add resolve handler (and default reject handler) to p0.
17338 CompileRun("var p1 = p0.then(function(){});");
17339 CHECK(GetPromise("p0")->HasHandler());
17340 CHECK(!GetPromise("p1")->HasHandler());
17341 CHECK_EQ(0, promise_reject_counter);
17342 CHECK_EQ(0, promise_revoke_counter);
17343
17344 // Reject p0.
17345 CompileRun("reject('ppp');");
17346 CHECK(GetPromise("p0")->HasHandler());
17347 CHECK(!GetPromise("p1")->HasHandler());
17348 CHECK_EQ(1, promise_reject_counter);
17349 CHECK_EQ(0, promise_revoke_counter);
17350 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17351 CHECK(
17352 GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17353 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17354
17355 // Reject p0 again. Callback is not triggered again.
17356 CompileRun("reject();");
17357 CHECK(GetPromise("p0")->HasHandler());
17358 CHECK(!GetPromise("p1")->HasHandler());
17359 CHECK_EQ(1, promise_reject_counter);
17360 CHECK_EQ(0, promise_revoke_counter);
17361
17362 // Add resolve handler to p1.
17363 CompileRun("var p2 = p1.then(function(){});");
17364 CHECK(GetPromise("p0")->HasHandler());
17365 CHECK(GetPromise("p1")->HasHandler());
17366 CHECK(!GetPromise("p2")->HasHandler());
17367 CHECK_EQ(2, promise_reject_counter);
17368 CHECK_EQ(1, promise_revoke_counter);
17369 CHECK(
17370 GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17371 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17372 CHECK(
17373 GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17374
17375 ResetPromiseStates();
17376
17377 // Create promise q0.
17378 CompileRun(
17379 "var q0 = new Promise( \n"
17380 " function(res, rej) { \n"
17381 " reject = rej; \n"
17382 " } \n"
17383 "); \n");
17384 CHECK(!GetPromise("q0")->HasHandler());
17385 CHECK_EQ(0, promise_reject_counter);
17386 CHECK_EQ(0, promise_revoke_counter);
17387
17388 // Add reject handler to q0.
17389 CompileRun("var q1 = q0.catch(function() {});");
17390 CHECK(GetPromise("q0")->HasHandler());
17391 CHECK(!GetPromise("q1")->HasHandler());
17392 CHECK_EQ(0, promise_reject_counter);
17393 CHECK_EQ(0, promise_revoke_counter);
17394
17395 // Reject q0.
17396 CompileRun("reject('qq')");
17397 CHECK(GetPromise("q0")->HasHandler());
17398 CHECK(!GetPromise("q1")->HasHandler());
17399 CHECK_EQ(0, promise_reject_counter);
17400 CHECK_EQ(0, promise_revoke_counter);
17401
17402 // Add a new reject handler, which rejects by returning Promise.reject().
17403 // The returned promise q_ triggers a reject callback at first, only to
17404 // revoke it when returning it causes q2 to be rejected.
17405 CompileRun(
17406 "var q_;"
17407 "var q2 = q0.catch( \n"
17408 " function() { \n"
17409 " q_ = Promise.reject('qqq'); \n"
17410 " return q_; \n"
17411 " } \n"
17412 "); \n");
17413 CHECK(GetPromise("q0")->HasHandler());
17414 CHECK(!GetPromise("q1")->HasHandler());
17415 CHECK(!GetPromise("q2")->HasHandler());
17416 CHECK(GetPromise("q_")->HasHandler());
17417 CHECK_EQ(2, promise_reject_counter);
17418 CHECK_EQ(1, promise_revoke_counter);
17419 CHECK(
17420 GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17421 CHECK(
17422 GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17423 CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17424
17425 // Add a reject handler to the resolved q1, which rejects by throwing.
17426 CompileRun(
17427 "var q3 = q1.then( \n"
17428 " function() { \n"
17429 " throw 'qqqq'; \n"
17430 " } \n"
17431 "); \n");
17432 CHECK(GetPromise("q0")->HasHandler());
17433 CHECK(GetPromise("q1")->HasHandler());
17434 CHECK(!GetPromise("q2")->HasHandler());
17435 CHECK(!GetPromise("q3")->HasHandler());
17436 CHECK_EQ(3, promise_reject_counter);
17437 CHECK_EQ(1, promise_revoke_counter);
17438 CHECK(
17439 GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17440 CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17441
17442 ResetPromiseStates();
17443
17444 // Create promise r0, which has three handlers, two of which handle rejects.
17445 CompileRun(
17446 "var r0 = new Promise( \n"
17447 " function(res, rej) { \n"
17448 " reject = rej; \n"
17449 " } \n"
17450 "); \n"
17451 "var r1 = r0.catch(function() {}); \n"
17452 "var r2 = r0.then(function() {}); \n"
17453 "var r3 = r0.then(function() {}, \n"
17454 " function() {}); \n");
17455 CHECK(GetPromise("r0")->HasHandler());
17456 CHECK(!GetPromise("r1")->HasHandler());
17457 CHECK(!GetPromise("r2")->HasHandler());
17458 CHECK(!GetPromise("r3")->HasHandler());
17459 CHECK_EQ(0, promise_reject_counter);
17460 CHECK_EQ(0, promise_revoke_counter);
17461
17462 // Reject r0.
17463 CompileRun("reject('rrr')");
17464 CHECK(GetPromise("r0")->HasHandler());
17465 CHECK(!GetPromise("r1")->HasHandler());
17466 CHECK(!GetPromise("r2")->HasHandler());
17467 CHECK(!GetPromise("r3")->HasHandler());
17468 CHECK_EQ(1, promise_reject_counter);
17469 CHECK_EQ(0, promise_revoke_counter);
17470 CHECK(
17471 GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17472 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17473
17474 // Add reject handler to r2.
17475 CompileRun("var r4 = r2.catch(function() {});");
17476 CHECK(GetPromise("r0")->HasHandler());
17477 CHECK(!GetPromise("r1")->HasHandler());
17478 CHECK(GetPromise("r2")->HasHandler());
17479 CHECK(!GetPromise("r3")->HasHandler());
17480 CHECK(!GetPromise("r4")->HasHandler());
17481 CHECK_EQ(1, promise_reject_counter);
17482 CHECK_EQ(1, promise_revoke_counter);
17483 CHECK(
17484 GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17485 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17486
17487 // Add reject handlers to r4.
17488 CompileRun("var r5 = r4.then(function() {}, function() {});");
17489 CHECK(GetPromise("r0")->HasHandler());
17490 CHECK(!GetPromise("r1")->HasHandler());
17491 CHECK(GetPromise("r2")->HasHandler());
17492 CHECK(!GetPromise("r3")->HasHandler());
17493 CHECK(GetPromise("r4")->HasHandler());
17494 CHECK(!GetPromise("r5")->HasHandler());
17495 CHECK_EQ(1, promise_reject_counter);
17496 CHECK_EQ(1, promise_revoke_counter);
17497
17498 ResetPromiseStates();
17499
17500 // Create promise s0, which has three handlers, none of which handle rejects.
17501 CompileRun(
17502 "var s0 = new Promise( \n"
17503 " function(res, rej) { \n"
17504 " reject = rej; \n"
17505 " } \n"
17506 "); \n"
17507 "var s1 = s0.then(function() {}); \n"
17508 "var s2 = s0.then(function() {}); \n"
17509 "var s3 = s0.then(function() {}); \n");
17510 CHECK(GetPromise("s0")->HasHandler());
17511 CHECK(!GetPromise("s1")->HasHandler());
17512 CHECK(!GetPromise("s2")->HasHandler());
17513 CHECK(!GetPromise("s3")->HasHandler());
17514 CHECK_EQ(0, promise_reject_counter);
17515 CHECK_EQ(0, promise_revoke_counter);
17516
17517 // Reject s0.
17518 CompileRun("reject('sss')");
17519 CHECK(GetPromise("s0")->HasHandler());
17520 CHECK(!GetPromise("s1")->HasHandler());
17521 CHECK(!GetPromise("s2")->HasHandler());
17522 CHECK(!GetPromise("s3")->HasHandler());
17523 CHECK_EQ(3, promise_reject_counter);
17524 CHECK_EQ(0, promise_revoke_counter);
17525 CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17526
17527 // Test stack frames.
17528 env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
17529
17530 ResetPromiseStates();
17531
17532 // Create promise t0, which is rejected in the constructor with an error.
17533 CompileRunWithOrigin(
17534 "var t0 = new Promise( \n"
17535 " function(res, rej) { \n"
17536 " reference_error; \n"
17537 " } \n"
17538 "); \n",
17539 "pro", 0, 0);
17540 CHECK(!GetPromise("t0")->HasHandler());
17541 CHECK_EQ(1, promise_reject_counter);
17542 CHECK_EQ(0, promise_revoke_counter);
17543 CHECK_EQ(2, promise_reject_frame_count);
17544 CHECK_EQ(3, promise_reject_line_number);
17545 CHECK_EQ(5, promise_reject_column_number);
17546 CHECK_EQ(3, promise_reject_msg_line_number);
17547 CHECK_EQ(5, promise_reject_msg_column_number);
17548
17549 ResetPromiseStates();
17550
17551 // Create promise u0 and chain u1 to it, which is rejected via throw.
17552 CompileRunWithOrigin(
17553 "var u0 = Promise.resolve(); \n"
17554 "var u1 = u0.then( \n"
17555 " function() { \n"
17556 " (function() { \n"
17557 " throw new Error(); \n"
17558 " })(); \n"
17559 " } \n"
17560 " ); \n",
17561 "pro", 0, 0);
17562 CHECK(GetPromise("u0")->HasHandler());
17563 CHECK(!GetPromise("u1")->HasHandler());
17564 CHECK_EQ(1, promise_reject_counter);
17565 CHECK_EQ(0, promise_revoke_counter);
17566 CHECK_EQ(2, promise_reject_frame_count);
17567 CHECK_EQ(5, promise_reject_line_number);
17568 CHECK_EQ(23, promise_reject_column_number);
17569 CHECK_EQ(5, promise_reject_msg_line_number);
17570 CHECK_EQ(23, promise_reject_msg_column_number);
17571
17572 // Throw in u3, which handles u1's rejection.
17573 CompileRunWithOrigin(
17574 "function f() { \n"
17575 " return (function() { \n"
17576 " return new Error(); \n"
17577 " })(); \n"
17578 "} \n"
17579 "var u2 = Promise.reject(f()); \n"
17580 "var u3 = u1.catch( \n"
17581 " function() { \n"
17582 " return u2; \n"
17583 " } \n"
17584 " ); \n",
17585 "pro", 0, 0);
17586 CHECK(GetPromise("u0")->HasHandler());
17587 CHECK(GetPromise("u1")->HasHandler());
17588 CHECK(GetPromise("u2")->HasHandler());
17589 CHECK(!GetPromise("u3")->HasHandler());
17590 CHECK_EQ(3, promise_reject_counter);
17591 CHECK_EQ(2, promise_revoke_counter);
17592 CHECK_EQ(3, promise_reject_frame_count);
17593 CHECK_EQ(3, promise_reject_line_number);
17594 CHECK_EQ(12, promise_reject_column_number);
17595 CHECK_EQ(3, promise_reject_msg_line_number);
17596 CHECK_EQ(12, promise_reject_msg_column_number);
17597
17598 ResetPromiseStates();
17599
17600 // Create promise rejected promise v0, which is incorrectly handled by v1
17601 // via chaining cycle.
17602 CompileRunWithOrigin(
17603 "var v0 = Promise.reject(); \n"
17604 "var v1 = v0.catch( \n"
17605 " function() { \n"
17606 " return v1; \n"
17607 " } \n"
17608 " ); \n",
17609 "pro", 0, 0);
17610 CHECK(GetPromise("v0")->HasHandler());
17611 CHECK(!GetPromise("v1")->HasHandler());
17612 CHECK_EQ(2, promise_reject_counter);
17613 CHECK_EQ(1, promise_revoke_counter);
17614 CHECK_EQ(0, promise_reject_frame_count);
17615 CHECK_EQ(-1, promise_reject_line_number);
17616 CHECK_EQ(-1, promise_reject_column_number);
17617
17618 ResetPromiseStates();
17619
17620 // Create promise t1, which rejects by throwing syntax error from eval.
17621 CompileRunWithOrigin(
17622 "var t1 = new Promise( \n"
17623 " function(res, rej) { \n"
17624 " var content = '\\n\\\n"
17625 " }'; \n"
17626 " eval(content); \n"
17627 " } \n"
17628 "); \n",
17629 "pro", 0, 0);
17630 CHECK(!GetPromise("t1")->HasHandler());
17631 CHECK_EQ(1, promise_reject_counter);
17632 CHECK_EQ(0, promise_revoke_counter);
17633 CHECK_EQ(2, promise_reject_frame_count);
17634 CHECK_EQ(5, promise_reject_line_number);
17635 CHECK_EQ(10, promise_reject_column_number);
17636 CHECK_EQ(2, promise_reject_msg_line_number);
17637 CHECK_EQ(7, promise_reject_msg_column_number);
17638 }
17639
17640
AnalyzeStackOfEvalWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17641 void AnalyzeStackOfEvalWithSourceURL(
17642 const v8::FunctionCallbackInfo<v8::Value>& args) {
17643 v8::HandleScope scope(args.GetIsolate());
17644 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17645 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17646 CHECK_EQ(5, stackTrace->GetFrameCount());
17647 v8::Local<v8::String> url = v8_str("eval_url");
17648 for (int i = 0; i < 3; i++) {
17649 v8::Local<v8::String> name =
17650 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17651 CHECK(!name.IsEmpty());
17652 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17653 }
17654 }
17655
17656
TEST(SourceURLInStackTrace)17657 TEST(SourceURLInStackTrace) {
17658 v8::Isolate* isolate = CcTest::isolate();
17659 v8::HandleScope scope(isolate);
17660 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17661 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17662 v8::FunctionTemplate::New(isolate,
17663 AnalyzeStackOfEvalWithSourceURL));
17664 LocalContext context(0, templ);
17665
17666 const char *source =
17667 "function outer() {\n"
17668 "function bar() {\n"
17669 " AnalyzeStackOfEvalWithSourceURL();\n"
17670 "}\n"
17671 "function foo() {\n"
17672 "\n"
17673 " bar();\n"
17674 "}\n"
17675 "foo();\n"
17676 "}\n"
17677 "eval('(' + outer +')()%s');";
17678
17679 i::ScopedVector<char> code(1024);
17680 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17681 CHECK(CompileRun(code.start())->IsUndefined());
17682 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17683 CHECK(CompileRun(code.start())->IsUndefined());
17684 }
17685
17686
17687 static int scriptIdInStack[2];
17688
AnalyzeScriptIdInStack(const v8::FunctionCallbackInfo<v8::Value> & args)17689 void AnalyzeScriptIdInStack(
17690 const v8::FunctionCallbackInfo<v8::Value>& args) {
17691 v8::HandleScope scope(args.GetIsolate());
17692 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17693 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17694 CHECK_EQ(2, stackTrace->GetFrameCount());
17695 for (int i = 0; i < 2; i++) {
17696 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17697 }
17698 }
17699
17700
TEST(ScriptIdInStackTrace)17701 TEST(ScriptIdInStackTrace) {
17702 v8::Isolate* isolate = CcTest::isolate();
17703 v8::HandleScope scope(isolate);
17704 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17705 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17706 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17707 LocalContext context(0, templ);
17708
17709 v8::Local<v8::String> scriptSource = v8_str(
17710 "function foo() {\n"
17711 " AnalyzeScriptIdInStack();"
17712 "}\n"
17713 "foo();\n");
17714 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17715 script->Run(context.local()).ToLocalChecked();
17716 for (int i = 0; i < 2; i++) {
17717 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17718 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17719 }
17720 }
17721
17722
AnalyzeStackOfInlineScriptWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17723 void AnalyzeStackOfInlineScriptWithSourceURL(
17724 const v8::FunctionCallbackInfo<v8::Value>& args) {
17725 v8::HandleScope scope(args.GetIsolate());
17726 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17727 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17728 CHECK_EQ(4, stackTrace->GetFrameCount());
17729 v8::Local<v8::String> url = v8_str("source_url");
17730 for (int i = 0; i < 3; i++) {
17731 v8::Local<v8::String> name =
17732 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17733 CHECK(!name.IsEmpty());
17734 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17735 }
17736 }
17737
17738
TEST(InlineScriptWithSourceURLInStackTrace)17739 TEST(InlineScriptWithSourceURLInStackTrace) {
17740 v8::Isolate* isolate = CcTest::isolate();
17741 v8::HandleScope scope(isolate);
17742 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17743 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17744 v8::FunctionTemplate::New(
17745 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17746 LocalContext context(0, templ);
17747
17748 const char *source =
17749 "function outer() {\n"
17750 "function bar() {\n"
17751 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17752 "}\n"
17753 "function foo() {\n"
17754 "\n"
17755 " bar();\n"
17756 "}\n"
17757 "foo();\n"
17758 "}\n"
17759 "outer()\n%s";
17760
17761 i::ScopedVector<char> code(1024);
17762 i::SNPrintF(code, source, "//# sourceURL=source_url");
17763 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17764 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17765 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17766 }
17767
17768
AnalyzeStackOfDynamicScriptWithSourceURL(const v8::FunctionCallbackInfo<v8::Value> & args)17769 void AnalyzeStackOfDynamicScriptWithSourceURL(
17770 const v8::FunctionCallbackInfo<v8::Value>& args) {
17771 v8::HandleScope scope(args.GetIsolate());
17772 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17773 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17774 CHECK_EQ(4, stackTrace->GetFrameCount());
17775 v8::Local<v8::String> url = v8_str("source_url");
17776 for (int i = 0; i < 3; i++) {
17777 v8::Local<v8::String> name =
17778 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17779 CHECK(!name.IsEmpty());
17780 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17781 }
17782 }
17783
17784
TEST(DynamicWithSourceURLInStackTrace)17785 TEST(DynamicWithSourceURLInStackTrace) {
17786 v8::Isolate* isolate = CcTest::isolate();
17787 v8::HandleScope scope(isolate);
17788 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17789 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17790 v8::FunctionTemplate::New(
17791 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17792 LocalContext context(0, templ);
17793
17794 const char *source =
17795 "function outer() {\n"
17796 "function bar() {\n"
17797 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17798 "}\n"
17799 "function foo() {\n"
17800 "\n"
17801 " bar();\n"
17802 "}\n"
17803 "foo();\n"
17804 "}\n"
17805 "outer()\n%s";
17806
17807 i::ScopedVector<char> code(1024);
17808 i::SNPrintF(code, source, "//# sourceURL=source_url");
17809 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17810 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17811 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17812 }
17813
17814
TEST(DynamicWithSourceURLInStackTraceString)17815 TEST(DynamicWithSourceURLInStackTraceString) {
17816 LocalContext context;
17817 v8::HandleScope scope(context->GetIsolate());
17818
17819 const char *source =
17820 "function outer() {\n"
17821 " function foo() {\n"
17822 " FAIL.FAIL;\n"
17823 " }\n"
17824 " foo();\n"
17825 "}\n"
17826 "outer()\n%s";
17827
17828 i::ScopedVector<char> code(1024);
17829 i::SNPrintF(code, source, "//# sourceURL=source_url");
17830 v8::TryCatch try_catch(context->GetIsolate());
17831 CompileRunWithOrigin(code.start(), "", 0, 0);
17832 CHECK(try_catch.HasCaught());
17833 v8::String::Utf8Value stack(
17834 try_catch.StackTrace(context.local()).ToLocalChecked());
17835 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17836 }
17837
17838
TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL)17839 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17840 LocalContext context;
17841 v8::HandleScope scope(context->GetIsolate());
17842
17843 const char *source =
17844 "function outer() {\n"
17845 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17846 " //# sourceURL=source_url\";\n"
17847 " eval(scriptContents);\n"
17848 " foo(); }\n"
17849 "outer();\n"
17850 "//# sourceURL=outer_url";
17851
17852 v8::TryCatch try_catch(context->GetIsolate());
17853 CompileRun(source);
17854 CHECK(try_catch.HasCaught());
17855
17856 Local<v8::Message> message = try_catch.Message();
17857 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
17858 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
17859 }
17860
17861
TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL)17862 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17863 LocalContext context;
17864 v8::HandleScope scope(context->GetIsolate());
17865
17866 const char *source =
17867 "function outer() {\n"
17868 " var scriptContents = \"function boo(){ boo(); }\\\n"
17869 " //# sourceURL=source_url\";\n"
17870 " eval(scriptContents);\n"
17871 " boo(); }\n"
17872 "outer();\n"
17873 "//# sourceURL=outer_url";
17874
17875 v8::TryCatch try_catch(context->GetIsolate());
17876 CompileRun(source);
17877 CHECK(try_catch.HasCaught());
17878
17879 Local<v8::Message> message = try_catch.Message();
17880 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
17881 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
17882 }
17883
17884
CreateGarbageInOldSpace()17885 static void CreateGarbageInOldSpace() {
17886 i::Factory* factory = CcTest::i_isolate()->factory();
17887 v8::HandleScope scope(CcTest::isolate());
17888 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17889 for (int i = 0; i < 1000; i++) {
17890 factory->NewFixedArray(1000, i::TENURED);
17891 }
17892 }
17893
17894
17895 // Test that idle notification can be handled and eventually collects garbage.
TEST(TestIdleNotification)17896 TEST(TestIdleNotification) {
17897 if (!i::FLAG_incremental_marking) return;
17898 const intptr_t MB = 1024 * 1024;
17899 const double IdlePauseInSeconds = 1.0;
17900 LocalContext env;
17901 v8::HandleScope scope(env->GetIsolate());
17902 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17903 CreateGarbageInOldSpace();
17904 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17905 CHECK_GT(size_with_garbage, initial_size + MB);
17906 bool finished = false;
17907 for (int i = 0; i < 200 && !finished; i++) {
17908 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
17909 CcTest::heap()->StartIdleIncrementalMarking();
17910 }
17911 finished = env->GetIsolate()->IdleNotificationDeadline(
17912 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
17913 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
17914 IdlePauseInSeconds);
17915 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
17916 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
17917 }
17918 }
17919 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17920 CHECK(finished);
17921 CHECK_LT(final_size, initial_size + 1);
17922 }
17923
17924
TEST(Regress2333)17925 TEST(Regress2333) {
17926 LocalContext env;
17927 for (int i = 0; i < 3; i++) {
17928 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17929 }
17930 }
17931
17932 static uint32_t* stack_limit;
17933
GetStackLimitCallback(const v8::FunctionCallbackInfo<v8::Value> & args)17934 static void GetStackLimitCallback(
17935 const v8::FunctionCallbackInfo<v8::Value>& args) {
17936 stack_limit = reinterpret_cast<uint32_t*>(
17937 CcTest::i_isolate()->stack_guard()->real_climit());
17938 }
17939
17940
17941 // Uses the address of a local variable to determine the stack top now.
17942 // Given a size, returns an address that is that far from the current
17943 // top of stack.
ComputeStackLimit(uint32_t size)17944 static uint32_t* ComputeStackLimit(uint32_t size) {
17945 uint32_t* answer = &size - (size / sizeof(size));
17946 // If the size is very large and the stack is very near the bottom of
17947 // memory then the calculation above may wrap around and give an address
17948 // that is above the (downwards-growing) stack. In that case we return
17949 // a very low address.
17950 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17951 return answer;
17952 }
17953
17954
17955 // We need at least 165kB for an x64 debug build with clang and ASAN.
17956 static const int stack_breathing_room = 256 * i::KB;
17957
17958
TEST(SetStackLimit)17959 TEST(SetStackLimit) {
17960 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17961
17962 // Set stack limit.
17963 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17964
17965 // Execute a script.
17966 LocalContext env;
17967 v8::HandleScope scope(env->GetIsolate());
17968 Local<v8::FunctionTemplate> fun_templ =
17969 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17970 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
17971 CHECK(env->Global()
17972 ->Set(env.local(), v8_str("get_stack_limit"), fun)
17973 .FromJust());
17974 CompileRun("get_stack_limit();");
17975
17976 CHECK(stack_limit == set_limit);
17977 }
17978
17979
TEST(SetStackLimitInThread)17980 TEST(SetStackLimitInThread) {
17981 uint32_t* set_limit;
17982 {
17983 v8::Locker locker(CcTest::isolate());
17984 set_limit = ComputeStackLimit(stack_breathing_room);
17985
17986 // Set stack limit.
17987 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
17988
17989 // Execute a script.
17990 v8::HandleScope scope(CcTest::isolate());
17991 LocalContext env;
17992 Local<v8::FunctionTemplate> fun_templ =
17993 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17994 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
17995 CHECK(env->Global()
17996 ->Set(env.local(), v8_str("get_stack_limit"), fun)
17997 .FromJust());
17998 CompileRun("get_stack_limit();");
17999
18000 CHECK(stack_limit == set_limit);
18001 }
18002 {
18003 v8::Locker locker(CcTest::isolate());
18004 CHECK(stack_limit == set_limit);
18005 }
18006 }
18007
18008
THREADED_TEST(GetHeapStatistics)18009 THREADED_TEST(GetHeapStatistics) {
18010 LocalContext c1;
18011 v8::HandleScope scope(c1->GetIsolate());
18012 v8::HeapStatistics heap_statistics;
18013 CHECK_EQ(0u, heap_statistics.total_heap_size());
18014 CHECK_EQ(0u, heap_statistics.used_heap_size());
18015 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18016 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18017 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18018 }
18019
18020
18021 class VisitorImpl : public v8::ExternalResourceVisitor {
18022 public:
VisitorImpl(TestResource ** resource)18023 explicit VisitorImpl(TestResource** resource) {
18024 for (int i = 0; i < 4; i++) {
18025 resource_[i] = resource[i];
18026 found_resource_[i] = false;
18027 }
18028 }
~VisitorImpl()18029 virtual ~VisitorImpl() {}
VisitExternalString(v8::Local<v8::String> string)18030 virtual void VisitExternalString(v8::Local<v8::String> string) {
18031 if (!string->IsExternal()) {
18032 CHECK(string->IsExternalOneByte());
18033 return;
18034 }
18035 v8::String::ExternalStringResource* resource =
18036 string->GetExternalStringResource();
18037 CHECK(resource);
18038 for (int i = 0; i < 4; i++) {
18039 if (resource_[i] == resource) {
18040 CHECK(!found_resource_[i]);
18041 found_resource_[i] = true;
18042 }
18043 }
18044 }
CheckVisitedResources()18045 void CheckVisitedResources() {
18046 for (int i = 0; i < 4; i++) {
18047 CHECK(found_resource_[i]);
18048 }
18049 }
18050
18051 private:
18052 v8::String::ExternalStringResource* resource_[4];
18053 bool found_resource_[4];
18054 };
18055
18056
TEST(ExternalizeOldSpaceTwoByteCons)18057 TEST(ExternalizeOldSpaceTwoByteCons) {
18058 v8::Isolate* isolate = CcTest::isolate();
18059 LocalContext env;
18060 v8::HandleScope scope(isolate);
18061 v8::Local<v8::String> cons =
18062 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18063 ->ToString(env.local())
18064 .ToLocalChecked();
18065 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18066 CcTest::heap()->CollectAllAvailableGarbage();
18067 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18068
18069 TestResource* resource = new TestResource(
18070 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18071 cons->MakeExternal(resource);
18072
18073 CHECK(cons->IsExternal());
18074 CHECK_EQ(resource, cons->GetExternalStringResource());
18075 String::Encoding encoding;
18076 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18077 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18078 }
18079
18080
TEST(ExternalizeOldSpaceOneByteCons)18081 TEST(ExternalizeOldSpaceOneByteCons) {
18082 v8::Isolate* isolate = CcTest::isolate();
18083 LocalContext env;
18084 v8::HandleScope scope(isolate);
18085 v8::Local<v8::String> cons =
18086 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18087 ->ToString(env.local())
18088 .ToLocalChecked();
18089 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18090 CcTest::heap()->CollectAllAvailableGarbage();
18091 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18092
18093 TestOneByteResource* resource =
18094 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18095 cons->MakeExternal(resource);
18096
18097 CHECK(cons->IsExternalOneByte());
18098 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18099 String::Encoding encoding;
18100 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18101 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18102 }
18103
18104
TEST(VisitExternalStrings)18105 TEST(VisitExternalStrings) {
18106 v8::Isolate* isolate = CcTest::isolate();
18107 LocalContext env;
18108 v8::HandleScope scope(isolate);
18109 const char* string = "Some string";
18110 uint16_t* two_byte_string = AsciiToTwoByteString(string);
18111 TestResource* resource[4];
18112 resource[0] = new TestResource(two_byte_string);
18113 v8::Local<v8::String> string0 =
18114 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
18115 .ToLocalChecked();
18116 resource[1] = new TestResource(two_byte_string, NULL, false);
18117 v8::Local<v8::String> string1 =
18118 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
18119 .ToLocalChecked();
18120
18121 // Externalized symbol.
18122 resource[2] = new TestResource(two_byte_string, NULL, false);
18123 v8::Local<v8::String> string2 =
18124 v8::String::NewFromUtf8(env->GetIsolate(), string,
18125 v8::NewStringType::kInternalized)
18126 .ToLocalChecked();
18127 CHECK(string2->MakeExternal(resource[2]));
18128
18129 // Symbolized External.
18130 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18131 v8::Local<v8::String> string3 =
18132 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
18133 .ToLocalChecked();
18134 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
18135 // Turn into a symbol.
18136 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18137 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18138 string3_i).is_null());
18139 CHECK(string3_i->IsInternalizedString());
18140
18141 // We need to add usages for string* to avoid warnings in GCC 4.7
18142 CHECK(string0->IsExternal());
18143 CHECK(string1->IsExternal());
18144 CHECK(string2->IsExternal());
18145 CHECK(string3->IsExternal());
18146
18147 VisitorImpl visitor(resource);
18148 isolate->VisitExternalResources(&visitor);
18149 visitor.CheckVisitedResources();
18150 }
18151
18152
TEST(ExternalStringCollectedAtTearDown)18153 TEST(ExternalStringCollectedAtTearDown) {
18154 int destroyed = 0;
18155 v8::Isolate::CreateParams create_params;
18156 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18157 v8::Isolate* isolate = v8::Isolate::New(create_params);
18158 { v8::Isolate::Scope isolate_scope(isolate);
18159 v8::HandleScope handle_scope(isolate);
18160 const char* s = "One string to test them all, one string to find them.";
18161 TestOneByteResource* inscription =
18162 new TestOneByteResource(i::StrDup(s), &destroyed);
18163 v8::Local<v8::String> ring =
18164 v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
18165 // Ring is still alive. Orcs are roaming freely across our lands.
18166 CHECK_EQ(0, destroyed);
18167 USE(ring);
18168 }
18169
18170 isolate->Dispose();
18171 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18172 CHECK_EQ(1, destroyed);
18173 }
18174
18175
TEST(ExternalInternalizedStringCollectedAtTearDown)18176 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18177 int destroyed = 0;
18178 v8::Isolate::CreateParams create_params;
18179 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18180 v8::Isolate* isolate = v8::Isolate::New(create_params);
18181 { v8::Isolate::Scope isolate_scope(isolate);
18182 LocalContext env(isolate);
18183 v8::HandleScope handle_scope(isolate);
18184 CompileRun("var ring = 'One string to test them all';");
18185 const char* s = "One string to test them all";
18186 TestOneByteResource* inscription =
18187 new TestOneByteResource(i::StrDup(s), &destroyed);
18188 v8::Local<v8::String> ring =
18189 CompileRun("ring")->ToString(env.local()).ToLocalChecked();
18190 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18191 ring->MakeExternal(inscription);
18192 // Ring is still alive. Orcs are roaming freely across our lands.
18193 CHECK_EQ(0, destroyed);
18194 USE(ring);
18195 }
18196
18197 isolate->Dispose();
18198 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18199 CHECK_EQ(1, destroyed);
18200 }
18201
18202
TEST(ExternalInternalizedStringCollectedAtGC)18203 TEST(ExternalInternalizedStringCollectedAtGC) {
18204 int destroyed = 0;
18205 { LocalContext env;
18206 v8::HandleScope handle_scope(env->GetIsolate());
18207 CompileRun("var ring = 'One string to test them all';");
18208 const char* s = "One string to test them all";
18209 TestOneByteResource* inscription =
18210 new TestOneByteResource(i::StrDup(s), &destroyed);
18211 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
18212 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18213 ring->MakeExternal(inscription);
18214 // Ring is still alive. Orcs are roaming freely across our lands.
18215 CHECK_EQ(0, destroyed);
18216 USE(ring);
18217 }
18218
18219 // Garbage collector deals swift blows to evil.
18220 CcTest::i_isolate()->compilation_cache()->Clear();
18221 CcTest::heap()->CollectAllAvailableGarbage();
18222
18223 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18224 CHECK_EQ(1, destroyed);
18225 }
18226
18227
DoubleFromBits(uint64_t value)18228 static double DoubleFromBits(uint64_t value) {
18229 double target;
18230 i::MemCopy(&target, &value, sizeof(target));
18231 return target;
18232 }
18233
18234
DoubleToBits(double value)18235 static uint64_t DoubleToBits(double value) {
18236 uint64_t target;
18237 i::MemCopy(&target, &value, sizeof(target));
18238 return target;
18239 }
18240
18241
DoubleToDateTime(double input)18242 static double DoubleToDateTime(double input) {
18243 double date_limit = 864e13;
18244 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18245 return std::numeric_limits<double>::quiet_NaN();
18246 }
18247 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18248 }
18249
18250
18251 // We don't have a consistent way to write 64-bit constants syntactically, so we
18252 // split them into two 32-bit constants and combine them programmatically.
DoubleFromBits(uint32_t high_bits,uint32_t low_bits)18253 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18254 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18255 }
18256
18257
THREADED_TEST(QuietSignalingNaNs)18258 THREADED_TEST(QuietSignalingNaNs) {
18259 LocalContext context;
18260 v8::Isolate* isolate = context->GetIsolate();
18261 v8::HandleScope scope(isolate);
18262 v8::TryCatch try_catch(isolate);
18263
18264 // Special double values.
18265 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18266 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18267 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18268 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18269 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18270 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18271 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18272
18273 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18274 // on either side of the epoch.
18275 double date_limit = 864e13;
18276
18277 double test_values[] = {
18278 snan,
18279 qnan,
18280 infinity,
18281 max_normal,
18282 date_limit + 1,
18283 date_limit,
18284 min_normal,
18285 max_denormal,
18286 min_denormal,
18287 0,
18288 -0,
18289 -min_denormal,
18290 -max_denormal,
18291 -min_normal,
18292 -date_limit,
18293 -date_limit - 1,
18294 -max_normal,
18295 -infinity,
18296 -qnan,
18297 -snan
18298 };
18299 int num_test_values = 20;
18300
18301 for (int i = 0; i < num_test_values; i++) {
18302 double test_value = test_values[i];
18303
18304 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18305 v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
18306 double stored_number = number->NumberValue(context.local()).FromJust();
18307 if (!std::isnan(test_value)) {
18308 CHECK_EQ(test_value, stored_number);
18309 } else {
18310 uint64_t stored_bits = DoubleToBits(stored_number);
18311 // Check if quiet nan (bits 51..62 all set).
18312 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18313 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18314 !defined(USE_SIMULATOR)
18315 // Most significant fraction bit for quiet nan is set to 0
18316 // on MIPS architecture. Allowed by IEEE-754.
18317 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18318 #else
18319 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18320 #endif
18321 }
18322
18323 // Check that Date::New preserves non-NaNs in the date range and
18324 // quiets SNaNs.
18325 v8::Local<v8::Value> date =
18326 v8::Date::New(context.local(), test_value).ToLocalChecked();
18327 double expected_stored_date = DoubleToDateTime(test_value);
18328 double stored_date = date->NumberValue(context.local()).FromJust();
18329 if (!std::isnan(expected_stored_date)) {
18330 CHECK_EQ(expected_stored_date, stored_date);
18331 } else {
18332 uint64_t stored_bits = DoubleToBits(stored_date);
18333 // Check if quiet nan (bits 51..62 all set).
18334 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18335 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18336 !defined(USE_SIMULATOR)
18337 // Most significant fraction bit for quiet nan is set to 0
18338 // on MIPS architecture. Allowed by IEEE-754.
18339 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18340 #else
18341 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18342 #endif
18343 }
18344 }
18345 }
18346
18347
SpaghettiIncident(const v8::FunctionCallbackInfo<v8::Value> & args)18348 static void SpaghettiIncident(
18349 const v8::FunctionCallbackInfo<v8::Value>& args) {
18350 v8::HandleScope scope(args.GetIsolate());
18351 v8::TryCatch tc(args.GetIsolate());
18352 v8::MaybeLocal<v8::String> str(
18353 args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
18354 USE(str);
18355 if (tc.HasCaught())
18356 tc.ReThrow();
18357 }
18358
18359
18360 // Test that an exception can be propagated down through a spaghetti
18361 // stack using ReThrow.
THREADED_TEST(SpaghettiStackReThrow)18362 THREADED_TEST(SpaghettiStackReThrow) {
18363 v8::Isolate* isolate = CcTest::isolate();
18364 v8::HandleScope scope(isolate);
18365 LocalContext context;
18366 context->Global()
18367 ->Set(context.local(), v8_str("s"),
18368 v8::FunctionTemplate::New(isolate, SpaghettiIncident)
18369 ->GetFunction(context.local())
18370 .ToLocalChecked())
18371 .FromJust();
18372 v8::TryCatch try_catch(isolate);
18373 CompileRun(
18374 "var i = 0;"
18375 "var o = {"
18376 " toString: function () {"
18377 " if (i == 10) {"
18378 " throw 'Hey!';"
18379 " } else {"
18380 " i++;"
18381 " return s(o);"
18382 " }"
18383 " }"
18384 "};"
18385 "s(o);");
18386 CHECK(try_catch.HasCaught());
18387 v8::String::Utf8Value value(try_catch.Exception());
18388 CHECK_EQ(0, strcmp(*value, "Hey!"));
18389 }
18390
18391
TEST(Regress528)18392 TEST(Regress528) {
18393 v8::V8::Initialize();
18394 v8::Isolate* isolate = CcTest::isolate();
18395 i::FLAG_retain_maps_for_n_gc = 0;
18396 v8::HandleScope scope(isolate);
18397 v8::Local<Context> other_context;
18398 int gc_count;
18399
18400 // Create a context used to keep the code from aging in the compilation
18401 // cache.
18402 other_context = Context::New(isolate);
18403
18404 // Context-dependent context data creates reference from the compilation
18405 // cache to the global object.
18406 const char* source_simple = "1";
18407 {
18408 v8::HandleScope scope(isolate);
18409 v8::Local<Context> context = Context::New(isolate);
18410
18411 context->Enter();
18412 Local<v8::String> obj = v8_str("");
18413 context->SetEmbedderData(0, obj);
18414 CompileRun(source_simple);
18415 context->Exit();
18416 }
18417 isolate->ContextDisposedNotification();
18418 for (gc_count = 1; gc_count < 10; gc_count++) {
18419 other_context->Enter();
18420 CompileRun(source_simple);
18421 other_context->Exit();
18422 CcTest::heap()->CollectAllGarbage();
18423 if (GetGlobalObjectsCount() == 1) break;
18424 }
18425 CHECK_GE(2, gc_count);
18426 CHECK_EQ(1, GetGlobalObjectsCount());
18427
18428 // Eval in a function creates reference from the compilation cache to the
18429 // global object.
18430 const char* source_eval = "function f(){eval('1')}; f()";
18431 {
18432 v8::HandleScope scope(isolate);
18433 v8::Local<Context> context = Context::New(isolate);
18434
18435 context->Enter();
18436 CompileRun(source_eval);
18437 context->Exit();
18438 }
18439 isolate->ContextDisposedNotification();
18440 for (gc_count = 1; gc_count < 10; gc_count++) {
18441 other_context->Enter();
18442 CompileRun(source_eval);
18443 other_context->Exit();
18444 CcTest::heap()->CollectAllGarbage();
18445 if (GetGlobalObjectsCount() == 1) break;
18446 }
18447 CHECK_GE(2, gc_count);
18448 CHECK_EQ(1, GetGlobalObjectsCount());
18449
18450 // Looking up the line number for an exception creates reference from the
18451 // compilation cache to the global object.
18452 const char* source_exception = "function f(){throw 1;} f()";
18453 {
18454 v8::HandleScope scope(isolate);
18455 v8::Local<Context> context = Context::New(isolate);
18456
18457 context->Enter();
18458 v8::TryCatch try_catch(isolate);
18459 CompileRun(source_exception);
18460 CHECK(try_catch.HasCaught());
18461 v8::Local<v8::Message> message = try_catch.Message();
18462 CHECK(!message.IsEmpty());
18463 CHECK_EQ(1, message->GetLineNumber(context).FromJust());
18464 context->Exit();
18465 }
18466 isolate->ContextDisposedNotification();
18467 for (gc_count = 1; gc_count < 10; gc_count++) {
18468 other_context->Enter();
18469 CompileRun(source_exception);
18470 other_context->Exit();
18471 CcTest::heap()->CollectAllGarbage();
18472 if (GetGlobalObjectsCount() == 1) break;
18473 }
18474 CHECK_GE(2, gc_count);
18475 CHECK_EQ(1, GetGlobalObjectsCount());
18476
18477 isolate->ContextDisposedNotification();
18478 }
18479
18480
THREADED_TEST(ScriptOrigin)18481 THREADED_TEST(ScriptOrigin) {
18482 LocalContext env;
18483 v8::HandleScope scope(env->GetIsolate());
18484 v8::ScriptOrigin origin = v8::ScriptOrigin(
18485 v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
18486 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
18487 v8::Local<v8::Integer>(), v8::True(env->GetIsolate()),
18488 v8_str("http://sourceMapUrl"), v8::True(env->GetIsolate()));
18489 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
18490 v8::Script::Compile(env.local(), script, &origin)
18491 .ToLocalChecked()
18492 ->Run(env.local())
18493 .ToLocalChecked();
18494 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18495 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18496 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18497 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18498
18499 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18500 CHECK_EQ(0, strcmp("test",
18501 *v8::String::Utf8Value(script_origin_f.ResourceName())));
18502 CHECK_EQ(
18503 1,
18504 script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18505 CHECK(script_origin_f.Options().IsSharedCrossOrigin());
18506 CHECK(script_origin_f.Options().IsEmbedderDebugScript());
18507 CHECK(script_origin_f.Options().IsOpaque());
18508 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
18509
18510 CHECK_EQ(0, strcmp("http://sourceMapUrl",
18511 *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
18512
18513 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18514 CHECK_EQ(0, strcmp("test",
18515 *v8::String::Utf8Value(script_origin_g.ResourceName())));
18516 CHECK_EQ(
18517 1,
18518 script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18519 CHECK(script_origin_g.Options().IsSharedCrossOrigin());
18520 CHECK(script_origin_g.Options().IsEmbedderDebugScript());
18521 CHECK(script_origin_g.Options().IsOpaque());
18522 CHECK_EQ(0, strcmp("http://sourceMapUrl",
18523 *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
18524 }
18525
18526
THREADED_TEST(FunctionGetInferredName)18527 THREADED_TEST(FunctionGetInferredName) {
18528 LocalContext env;
18529 v8::HandleScope scope(env->GetIsolate());
18530 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18531 v8::Local<v8::String> script =
18532 v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18533 v8::Script::Compile(env.local(), script, &origin)
18534 .ToLocalChecked()
18535 ->Run(env.local())
18536 .ToLocalChecked();
18537 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18538 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18539 CHECK_EQ(0,
18540 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
18541 }
18542
18543
THREADED_TEST(FunctionGetDebugName)18544 THREADED_TEST(FunctionGetDebugName) {
18545 LocalContext env;
18546 v8::HandleScope scope(env->GetIsolate());
18547 const char* code =
18548 "var error = false;"
18549 "function a() { this.x = 1; };"
18550 "a.displayName = 'display_a';"
18551 "var b = (function() {"
18552 " var f = function() { this.x = 2; };"
18553 " f.displayName = 'display_b';"
18554 " return f;"
18555 "})();"
18556 "var c = function() {};"
18557 "c.__defineGetter__('displayName', function() {"
18558 " error = true;"
18559 " throw new Error();"
18560 "});"
18561 "function d() {};"
18562 "d.__defineGetter__('displayName', function() {"
18563 " error = true;"
18564 " return 'wrong_display_name';"
18565 "});"
18566 "function e() {};"
18567 "e.displayName = 'wrong_display_name';"
18568 "e.__defineSetter__('displayName', function() {"
18569 " error = true;"
18570 " throw new Error();"
18571 "});"
18572 "function f() {};"
18573 "f.displayName = { 'foo': 6, toString: function() {"
18574 " error = true;"
18575 " return 'wrong_display_name';"
18576 "}};"
18577 "var g = function() {"
18578 " arguments.callee.displayName = 'set_in_runtime';"
18579 "}; g();"
18580 "var h = function() {};"
18581 "h.displayName = 'displayName';"
18582 "Object.defineProperty(h, 'name', { value: 'function.name' });"
18583 "var i = function() {};"
18584 "i.displayName = 239;"
18585 "Object.defineProperty(i, 'name', { value: 'function.name' });"
18586 "var j = function() {};"
18587 "Object.defineProperty(j, 'name', { value: 'function.name' });"
18588 "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
18589 "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
18590 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18591 v8::Script::Compile(env.local(), v8_str(code), &origin)
18592 .ToLocalChecked()
18593 ->Run(env.local())
18594 .ToLocalChecked();
18595 v8::Local<v8::Value> error =
18596 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
18597 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust());
18598 const char* functions[] = {"a", "display_a",
18599 "b", "display_b",
18600 "c", "c",
18601 "d", "d",
18602 "e", "e",
18603 "f", "f",
18604 "g", "set_in_runtime",
18605 "h", "displayName",
18606 "i", "function.name",
18607 "j", "function.name",
18608 "k", "foo.bar.baz",
18609 "l", "baz"};
18610 for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
18611 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18612 env->Global()
18613 ->Get(env.local(),
18614 v8::String::NewFromUtf8(env->GetIsolate(), functions[i * 2],
18615 v8::NewStringType::kNormal)
18616 .ToLocalChecked())
18617 .ToLocalChecked());
18618 CHECK_EQ(0, strcmp(functions[i * 2 + 1],
18619 *v8::String::Utf8Value(f->GetDebugName())));
18620 }
18621 }
18622
18623
THREADED_TEST(FunctionGetDisplayName)18624 THREADED_TEST(FunctionGetDisplayName) {
18625 LocalContext env;
18626 v8::HandleScope scope(env->GetIsolate());
18627 const char* code = "var error = false;"
18628 "function a() { this.x = 1; };"
18629 "a.displayName = 'display_a';"
18630 "var b = (function() {"
18631 " var f = function() { this.x = 2; };"
18632 " f.displayName = 'display_b';"
18633 " return f;"
18634 "})();"
18635 "var c = function() {};"
18636 "c.__defineGetter__('displayName', function() {"
18637 " error = true;"
18638 " throw new Error();"
18639 "});"
18640 "function d() {};"
18641 "d.__defineGetter__('displayName', function() {"
18642 " error = true;"
18643 " return 'wrong_display_name';"
18644 "});"
18645 "function e() {};"
18646 "e.displayName = 'wrong_display_name';"
18647 "e.__defineSetter__('displayName', function() {"
18648 " error = true;"
18649 " throw new Error();"
18650 "});"
18651 "function f() {};"
18652 "f.displayName = { 'foo': 6, toString: function() {"
18653 " error = true;"
18654 " return 'wrong_display_name';"
18655 "}};"
18656 "var g = function() {"
18657 " arguments.callee.displayName = 'set_in_runtime';"
18658 "}; g();";
18659 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18660 v8::Script::Compile(env.local(), v8_str(code), &origin)
18661 .ToLocalChecked()
18662 ->Run(env.local())
18663 .ToLocalChecked();
18664 v8::Local<v8::Value> error =
18665 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
18666 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18667 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
18668 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18669 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
18670 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18671 env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
18672 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18673 env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
18674 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18675 env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
18676 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18677 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18678 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18679 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18680 CHECK_EQ(false, error->BooleanValue(env.local()).FromJust());
18681 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
18682 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
18683 CHECK(c->GetDisplayName()->IsUndefined());
18684 CHECK(d->GetDisplayName()->IsUndefined());
18685 CHECK(e->GetDisplayName()->IsUndefined());
18686 CHECK(f->GetDisplayName()->IsUndefined());
18687 CHECK_EQ(
18688 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
18689 }
18690
18691
THREADED_TEST(ScriptLineNumber)18692 THREADED_TEST(ScriptLineNumber) {
18693 LocalContext env;
18694 v8::HandleScope scope(env->GetIsolate());
18695 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18696 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
18697 v8::Script::Compile(env.local(), script, &origin)
18698 .ToLocalChecked()
18699 ->Run(env.local())
18700 .ToLocalChecked();
18701 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18702 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18703 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18704 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18705 CHECK_EQ(0, f->GetScriptLineNumber());
18706 CHECK_EQ(2, g->GetScriptLineNumber());
18707 }
18708
18709
THREADED_TEST(ScriptColumnNumber)18710 THREADED_TEST(ScriptColumnNumber) {
18711 LocalContext env;
18712 v8::Isolate* isolate = env->GetIsolate();
18713 v8::HandleScope scope(isolate);
18714 v8::ScriptOrigin origin =
18715 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
18716 v8::Integer::New(isolate, 2));
18717 v8::Local<v8::String> script =
18718 v8_str("function foo() {}\n\n function bar() {}");
18719 v8::Script::Compile(env.local(), script, &origin)
18720 .ToLocalChecked()
18721 ->Run(env.local())
18722 .ToLocalChecked();
18723 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18724 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
18725 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18726 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
18727 CHECK_EQ(14, foo->GetScriptColumnNumber());
18728 CHECK_EQ(17, bar->GetScriptColumnNumber());
18729 }
18730
18731
THREADED_TEST(FunctionIsBuiltin)18732 THREADED_TEST(FunctionIsBuiltin) {
18733 LocalContext env;
18734 v8::Isolate* isolate = env->GetIsolate();
18735 v8::HandleScope scope(isolate);
18736 v8::Local<v8::Function> f;
18737 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18738 CHECK(f->IsBuiltin());
18739 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18740 CHECK(f->IsBuiltin());
18741 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18742 CHECK(f->IsBuiltin());
18743 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18744 CHECK(f->IsBuiltin());
18745 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18746 CHECK(!f->IsBuiltin());
18747 }
18748
18749
THREADED_TEST(FunctionGetScriptId)18750 THREADED_TEST(FunctionGetScriptId) {
18751 LocalContext env;
18752 v8::Isolate* isolate = env->GetIsolate();
18753 v8::HandleScope scope(isolate);
18754 v8::ScriptOrigin origin =
18755 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
18756 v8::Integer::New(isolate, 2));
18757 v8::Local<v8::String> scriptSource =
18758 v8_str("function foo() {}\n\n function bar() {}");
18759 v8::Local<v8::Script> script(
18760 v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
18761 script->Run(env.local()).ToLocalChecked();
18762 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18763 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
18764 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18765 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
18766 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18767 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18768 }
18769
18770
THREADED_TEST(FunctionGetBoundFunction)18771 THREADED_TEST(FunctionGetBoundFunction) {
18772 LocalContext env;
18773 v8::HandleScope scope(env->GetIsolate());
18774 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18775 v8::Local<v8::String> script = v8_str(
18776 "var a = new Object();\n"
18777 "a.x = 1;\n"
18778 "function f () { return this.x };\n"
18779 "var g = f.bind(a);\n"
18780 "var b = g();");
18781 v8::Script::Compile(env.local(), script, &origin)
18782 .ToLocalChecked()
18783 ->Run(env.local())
18784 .ToLocalChecked();
18785 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18786 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18787 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18788 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18789 CHECK(g->GetBoundFunction()->IsFunction());
18790 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18791 g->GetBoundFunction());
18792 CHECK(f->GetName()
18793 ->Equals(env.local(), original_function->GetName())
18794 .FromJust());
18795 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18796 CHECK_EQ(f->GetScriptColumnNumber(),
18797 original_function->GetScriptColumnNumber());
18798 }
18799
18800
GetterWhichReturns42(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)18801 static void GetterWhichReturns42(
18802 Local<String> name,
18803 const v8::PropertyCallbackInfo<v8::Value>& info) {
18804 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18805 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18806 info.GetReturnValue().Set(v8_num(42));
18807 }
18808
18809
SetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)18810 static void SetterWhichSetsYOnThisTo23(
18811 Local<String> name,
18812 Local<Value> value,
18813 const v8::PropertyCallbackInfo<void>& info) {
18814 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18815 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18816 Local<Object>::Cast(info.This())
18817 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
18818 .FromJust();
18819 }
18820
18821
FooGetInterceptor(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)18822 void FooGetInterceptor(Local<Name> name,
18823 const v8::PropertyCallbackInfo<v8::Value>& info) {
18824 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18825 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18826 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
18827 .FromJust()) {
18828 return;
18829 }
18830 info.GetReturnValue().Set(v8_num(42));
18831 }
18832
18833
FooSetInterceptor(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)18834 void FooSetInterceptor(Local<Name> name, Local<Value> value,
18835 const v8::PropertyCallbackInfo<v8::Value>& info) {
18836 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18837 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18838 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
18839 .FromJust()) {
18840 return;
18841 }
18842 Local<Object>::Cast(info.This())
18843 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
18844 .FromJust();
18845 info.GetReturnValue().Set(v8_num(23));
18846 }
18847
18848
TEST(SetterOnConstructorPrototype)18849 TEST(SetterOnConstructorPrototype) {
18850 v8::Isolate* isolate = CcTest::isolate();
18851 v8::HandleScope scope(isolate);
18852 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18853 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18854 SetterWhichSetsYOnThisTo23);
18855 LocalContext context;
18856 CHECK(context->Global()
18857 ->Set(context.local(), v8_str("P"),
18858 templ->NewInstance(context.local()).ToLocalChecked())
18859 .FromJust());
18860 CompileRun("function C1() {"
18861 " this.x = 23;"
18862 "};"
18863 "C1.prototype = P;"
18864 "function C2() {"
18865 " this.x = 23"
18866 "};"
18867 "C2.prototype = { };"
18868 "C2.prototype.__proto__ = P;");
18869
18870 v8::Local<v8::Script> script;
18871 script = v8_compile("new C1();");
18872 for (int i = 0; i < 10; i++) {
18873 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
18874 script->Run(context.local()).ToLocalChecked());
18875 CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
18876 .ToLocalChecked()
18877 ->Int32Value(context.local())
18878 .FromJust());
18879 CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
18880 .ToLocalChecked()
18881 ->Int32Value(context.local())
18882 .FromJust());
18883 }
18884
18885 script = v8_compile("new C2();");
18886 for (int i = 0; i < 10; i++) {
18887 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
18888 script->Run(context.local()).ToLocalChecked());
18889 CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
18890 .ToLocalChecked()
18891 ->Int32Value(context.local())
18892 .FromJust());
18893 CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
18894 .ToLocalChecked()
18895 ->Int32Value(context.local())
18896 .FromJust());
18897 }
18898 }
18899
18900
NamedPropertySetterWhichSetsYOnThisTo23(Local<Name> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)18901 static void NamedPropertySetterWhichSetsYOnThisTo23(
18902 Local<Name> name, Local<Value> value,
18903 const v8::PropertyCallbackInfo<v8::Value>& info) {
18904 if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
18905 .FromJust()) {
18906 Local<Object>::Cast(info.This())
18907 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
18908 .FromJust();
18909 }
18910 }
18911
18912
THREADED_TEST(InterceptorOnConstructorPrototype)18913 THREADED_TEST(InterceptorOnConstructorPrototype) {
18914 v8::Isolate* isolate = CcTest::isolate();
18915 v8::HandleScope scope(isolate);
18916 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18917 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18918 NamedPropertyGetterWhichReturns42,
18919 NamedPropertySetterWhichSetsYOnThisTo23));
18920 LocalContext context;
18921 CHECK(context->Global()
18922 ->Set(context.local(), v8_str("P"),
18923 templ->NewInstance(context.local()).ToLocalChecked())
18924 .FromJust());
18925 CompileRun("function C1() {"
18926 " this.x = 23;"
18927 "};"
18928 "C1.prototype = P;"
18929 "function C2() {"
18930 " this.x = 23"
18931 "};"
18932 "C2.prototype = { };"
18933 "C2.prototype.__proto__ = P;");
18934
18935 v8::Local<v8::Script> script;
18936 script = v8_compile("new C1();");
18937 for (int i = 0; i < 10; i++) {
18938 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
18939 script->Run(context.local()).ToLocalChecked());
18940 CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
18941 .ToLocalChecked()
18942 ->Int32Value(context.local())
18943 .FromJust());
18944 CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
18945 .ToLocalChecked()
18946 ->Int32Value(context.local())
18947 .FromJust());
18948 }
18949
18950 script = v8_compile("new C2();");
18951 for (int i = 0; i < 10; i++) {
18952 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
18953 script->Run(context.local()).ToLocalChecked());
18954 CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
18955 .ToLocalChecked()
18956 ->Int32Value(context.local())
18957 .FromJust());
18958 CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
18959 .ToLocalChecked()
18960 ->Int32Value(context.local())
18961 .FromJust());
18962 }
18963 }
18964
18965
TEST(Regress618)18966 TEST(Regress618) {
18967 const char* source = "function C1() {"
18968 " this.x = 23;"
18969 "};"
18970 "C1.prototype = P;";
18971
18972 LocalContext context;
18973 v8::Isolate* isolate = context->GetIsolate();
18974 v8::HandleScope scope(isolate);
18975 v8::Local<v8::Script> script;
18976
18977 // Use a simple object as prototype.
18978 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18979 prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
18980 CHECK(context->Global()
18981 ->Set(context.local(), v8_str("P"), prototype)
18982 .FromJust());
18983
18984 // This compile will add the code to the compilation cache.
18985 CompileRun(source);
18986
18987 script = v8_compile("new C1();");
18988 // Allow enough iterations for the inobject slack tracking logic
18989 // to finalize instance size and install the fast construct stub.
18990 for (int i = 0; i < 256; i++) {
18991 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
18992 script->Run(context.local()).ToLocalChecked());
18993 CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
18994 .ToLocalChecked()
18995 ->Int32Value(context.local())
18996 .FromJust());
18997 CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
18998 .ToLocalChecked()
18999 ->Int32Value(context.local())
19000 .FromJust());
19001 }
19002
19003 // Use an API object with accessors as prototype.
19004 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19005 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19006 SetterWhichSetsYOnThisTo23);
19007 CHECK(context->Global()
19008 ->Set(context.local(), v8_str("P"),
19009 templ->NewInstance(context.local()).ToLocalChecked())
19010 .FromJust());
19011
19012 // This compile will get the code from the compilation cache.
19013 CompileRun(source);
19014
19015 script = v8_compile("new C1();");
19016 for (int i = 0; i < 10; i++) {
19017 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19018 script->Run(context.local()).ToLocalChecked());
19019 CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19020 .ToLocalChecked()
19021 ->Int32Value(context.local())
19022 .FromJust());
19023 CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19024 .ToLocalChecked()
19025 ->Int32Value(context.local())
19026 .FromJust());
19027 }
19028 }
19029
19030 v8::Isolate* gc_callbacks_isolate = NULL;
19031 int prologue_call_count = 0;
19032 int epilogue_call_count = 0;
19033 int prologue_call_count_second = 0;
19034 int epilogue_call_count_second = 0;
19035 int prologue_call_count_alloc = 0;
19036 int epilogue_call_count_alloc = 0;
19037
PrologueCallback(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19038 void PrologueCallback(v8::Isolate* isolate,
19039 v8::GCType,
19040 v8::GCCallbackFlags flags) {
19041 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19042 CHECK_EQ(gc_callbacks_isolate, isolate);
19043 ++prologue_call_count;
19044 }
19045
EpilogueCallback(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19046 void EpilogueCallback(v8::Isolate* isolate,
19047 v8::GCType,
19048 v8::GCCallbackFlags flags) {
19049 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19050 CHECK_EQ(gc_callbacks_isolate, isolate);
19051 ++epilogue_call_count;
19052 }
19053
19054
PrologueCallbackSecond(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19055 void PrologueCallbackSecond(v8::Isolate* isolate,
19056 v8::GCType,
19057 v8::GCCallbackFlags flags) {
19058 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19059 CHECK_EQ(gc_callbacks_isolate, isolate);
19060 ++prologue_call_count_second;
19061 }
19062
19063
EpilogueCallbackSecond(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19064 void EpilogueCallbackSecond(v8::Isolate* isolate,
19065 v8::GCType,
19066 v8::GCCallbackFlags flags) {
19067 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19068 CHECK_EQ(gc_callbacks_isolate, isolate);
19069 ++epilogue_call_count_second;
19070 }
19071
19072
PrologueCallbackAlloc(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19073 void PrologueCallbackAlloc(v8::Isolate* isolate,
19074 v8::GCType,
19075 v8::GCCallbackFlags flags) {
19076 v8::HandleScope scope(isolate);
19077
19078 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19079 CHECK_EQ(gc_callbacks_isolate, isolate);
19080 ++prologue_call_count_alloc;
19081
19082 // Simulate full heap to see if we will reenter this callback
19083 i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19084
19085 Local<Object> obj = Object::New(isolate);
19086 CHECK(!obj.IsEmpty());
19087
19088 CcTest::heap()->CollectAllGarbage(
19089 i::Heap::kAbortIncrementalMarkingMask);
19090 }
19091
19092
EpilogueCallbackAlloc(v8::Isolate * isolate,v8::GCType,v8::GCCallbackFlags flags)19093 void EpilogueCallbackAlloc(v8::Isolate* isolate,
19094 v8::GCType,
19095 v8::GCCallbackFlags flags) {
19096 v8::HandleScope scope(isolate);
19097
19098 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19099 CHECK_EQ(gc_callbacks_isolate, isolate);
19100 ++epilogue_call_count_alloc;
19101
19102 // Simulate full heap to see if we will reenter this callback
19103 i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19104
19105 Local<Object> obj = Object::New(isolate);
19106 CHECK(!obj.IsEmpty());
19107
19108 CcTest::heap()->CollectAllGarbage(
19109 i::Heap::kAbortIncrementalMarkingMask);
19110 }
19111
19112
TEST(GCCallbacksOld)19113 TEST(GCCallbacksOld) {
19114 LocalContext context;
19115
19116 gc_callbacks_isolate = context->GetIsolate();
19117
19118 context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
19119 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
19120 CHECK_EQ(0, prologue_call_count);
19121 CHECK_EQ(0, epilogue_call_count);
19122 CcTest::heap()->CollectAllGarbage();
19123 CHECK_EQ(1, prologue_call_count);
19124 CHECK_EQ(1, epilogue_call_count);
19125 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
19126 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
19127 CcTest::heap()->CollectAllGarbage();
19128 CHECK_EQ(2, prologue_call_count);
19129 CHECK_EQ(2, epilogue_call_count);
19130 CHECK_EQ(1, prologue_call_count_second);
19131 CHECK_EQ(1, epilogue_call_count_second);
19132 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
19133 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
19134 CcTest::heap()->CollectAllGarbage();
19135 CHECK_EQ(2, prologue_call_count);
19136 CHECK_EQ(2, epilogue_call_count);
19137 CHECK_EQ(2, prologue_call_count_second);
19138 CHECK_EQ(2, epilogue_call_count_second);
19139 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
19140 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19141 CcTest::heap()->CollectAllGarbage();
19142 CHECK_EQ(2, prologue_call_count);
19143 CHECK_EQ(2, epilogue_call_count);
19144 CHECK_EQ(2, prologue_call_count_second);
19145 CHECK_EQ(2, epilogue_call_count_second);
19146 }
19147
19148
TEST(GCCallbacks)19149 TEST(GCCallbacks) {
19150 LocalContext context;
19151 v8::Isolate* isolate = context->GetIsolate();
19152 gc_callbacks_isolate = isolate;
19153 isolate->AddGCPrologueCallback(PrologueCallback);
19154 isolate->AddGCEpilogueCallback(EpilogueCallback);
19155 CHECK_EQ(0, prologue_call_count);
19156 CHECK_EQ(0, epilogue_call_count);
19157 CcTest::heap()->CollectAllGarbage();
19158 CHECK_EQ(1, prologue_call_count);
19159 CHECK_EQ(1, epilogue_call_count);
19160 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19161 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19162 CcTest::heap()->CollectAllGarbage();
19163 CHECK_EQ(2, prologue_call_count);
19164 CHECK_EQ(2, epilogue_call_count);
19165 CHECK_EQ(1, prologue_call_count_second);
19166 CHECK_EQ(1, epilogue_call_count_second);
19167 isolate->RemoveGCPrologueCallback(PrologueCallback);
19168 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19169 CcTest::heap()->CollectAllGarbage();
19170 CHECK_EQ(2, prologue_call_count);
19171 CHECK_EQ(2, epilogue_call_count);
19172 CHECK_EQ(2, prologue_call_count_second);
19173 CHECK_EQ(2, epilogue_call_count_second);
19174 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19175 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19176 CcTest::heap()->CollectAllGarbage();
19177 CHECK_EQ(2, prologue_call_count);
19178 CHECK_EQ(2, epilogue_call_count);
19179 CHECK_EQ(2, prologue_call_count_second);
19180 CHECK_EQ(2, epilogue_call_count_second);
19181
19182 CHECK_EQ(0, prologue_call_count_alloc);
19183 CHECK_EQ(0, epilogue_call_count_alloc);
19184 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19185 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19186 CcTest::heap()->CollectAllGarbage(
19187 i::Heap::kAbortIncrementalMarkingMask);
19188 CHECK_EQ(1, prologue_call_count_alloc);
19189 CHECK_EQ(1, epilogue_call_count_alloc);
19190 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19191 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19192 }
19193
19194
THREADED_TEST(TwoByteStringInOneByteCons)19195 THREADED_TEST(TwoByteStringInOneByteCons) {
19196 // See Chromium issue 47824.
19197 LocalContext context;
19198 v8::HandleScope scope(context->GetIsolate());
19199
19200 const char* init_code =
19201 "var str1 = 'abelspendabel';"
19202 "var str2 = str1 + str1 + str1;"
19203 "str2;";
19204 Local<Value> result = CompileRun(init_code);
19205
19206 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19207 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19208
19209 CHECK(result->IsString());
19210 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19211 int length = string->length();
19212 CHECK(string->IsOneByteRepresentation());
19213
19214 i::Handle<i::String> flat_string = i::String::Flatten(string);
19215
19216 CHECK(string->IsOneByteRepresentation());
19217 CHECK(flat_string->IsOneByteRepresentation());
19218
19219 // Create external resource.
19220 uint16_t* uc16_buffer = new uint16_t[length + 1];
19221
19222 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19223 uc16_buffer[length] = 0;
19224
19225 TestResource resource(uc16_buffer);
19226
19227 flat_string->MakeExternal(&resource);
19228
19229 CHECK(flat_string->IsTwoByteRepresentation());
19230
19231 // If the cons string has been short-circuited, skip the following checks.
19232 if (!string.is_identical_to(flat_string)) {
19233 // At this point, we should have a Cons string which is flat and one-byte,
19234 // with a first half that is a two-byte string (although it only contains
19235 // one-byte characters). This is a valid sequence of steps, and it can
19236 // happen in real pages.
19237 CHECK(string->IsOneByteRepresentation());
19238 i::ConsString* cons = i::ConsString::cast(*string);
19239 CHECK_EQ(0, cons->second()->length());
19240 CHECK(cons->first()->IsTwoByteRepresentation());
19241 }
19242
19243 // Check that some string operations work.
19244
19245 // Atom RegExp.
19246 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19247 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19248
19249 // Nonatom RegExp.
19250 reresult = CompileRun("str2.match(/abe./g).length;");
19251 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19252
19253 reresult = CompileRun("str2.search(/bel/g);");
19254 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19255
19256 reresult = CompileRun("str2.search(/be./g);");
19257 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19258
19259 ExpectTrue("/bel/g.test(str2);");
19260
19261 ExpectTrue("/be./g.test(str2);");
19262
19263 reresult = CompileRun("/bel/g.exec(str2);");
19264 CHECK(!reresult->IsNull());
19265
19266 reresult = CompileRun("/be./g.exec(str2);");
19267 CHECK(!reresult->IsNull());
19268
19269 ExpectString("str2.substring(2, 10);", "elspenda");
19270
19271 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19272
19273 ExpectString("str2.charAt(2);", "e");
19274
19275 ExpectObject("str2.indexOf('els');", indexof);
19276
19277 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19278
19279 reresult = CompileRun("str2.charCodeAt(2);");
19280 CHECK_EQ(static_cast<int32_t>('e'),
19281 reresult->Int32Value(context.local()).FromJust());
19282 }
19283
19284
TEST(ContainsOnlyOneByte)19285 TEST(ContainsOnlyOneByte) {
19286 v8::V8::Initialize();
19287 v8::Isolate* isolate = CcTest::isolate();
19288 v8::HandleScope scope(isolate);
19289 // Make a buffer long enough that it won't automatically be converted.
19290 const int length = 512;
19291 // Ensure word aligned assignment.
19292 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19293 v8::base::SmartArrayPointer<uintptr_t> aligned_contents(
19294 new uintptr_t[aligned_length]);
19295 uint16_t* string_contents =
19296 reinterpret_cast<uint16_t*>(aligned_contents.get());
19297 // Set to contain only one byte.
19298 for (int i = 0; i < length-1; i++) {
19299 string_contents[i] = 0x41;
19300 }
19301 string_contents[length-1] = 0;
19302 // Simple case.
19303 Local<String> string =
19304 String::NewExternalTwoByte(isolate,
19305 new TestResource(string_contents, NULL, false))
19306 .ToLocalChecked();
19307 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19308 // Counter example.
19309 string = String::NewFromTwoByte(isolate, string_contents,
19310 v8::NewStringType::kNormal)
19311 .ToLocalChecked();
19312 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19313 // Test left right and balanced cons strings.
19314 Local<String> base = v8_str("a");
19315 Local<String> left = base;
19316 Local<String> right = base;
19317 for (int i = 0; i < 1000; i++) {
19318 left = String::Concat(base, left);
19319 right = String::Concat(right, base);
19320 }
19321 Local<String> balanced = String::Concat(left, base);
19322 balanced = String::Concat(balanced, right);
19323 Local<String> cons_strings[] = {left, balanced, right};
19324 Local<String> two_byte =
19325 String::NewExternalTwoByte(isolate,
19326 new TestResource(string_contents, NULL, false))
19327 .ToLocalChecked();
19328 USE(two_byte); USE(cons_strings);
19329 for (size_t i = 0; i < arraysize(cons_strings); i++) {
19330 // Base assumptions.
19331 string = cons_strings[i];
19332 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19333 // Test left and right concatentation.
19334 string = String::Concat(two_byte, cons_strings[i]);
19335 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19336 string = String::Concat(cons_strings[i], two_byte);
19337 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19338 }
19339 // Set bits in different positions
19340 // for strings of different lengths and alignments.
19341 for (int alignment = 0; alignment < 7; alignment++) {
19342 for (int size = 2; alignment + size < length; size *= 2) {
19343 int zero_offset = size + alignment;
19344 string_contents[zero_offset] = 0;
19345 for (int i = 0; i < size; i++) {
19346 int shift = 8 + (i % 7);
19347 string_contents[alignment + i] = 1 << shift;
19348 string = String::NewExternalTwoByte(
19349 isolate,
19350 new TestResource(string_contents + alignment, NULL, false))
19351 .ToLocalChecked();
19352 CHECK_EQ(size, string->Length());
19353 CHECK(!string->ContainsOnlyOneByte());
19354 string_contents[alignment + i] = 0x41;
19355 }
19356 string_contents[zero_offset] = 0x41;
19357 }
19358 }
19359 }
19360
19361
19362 // Failed access check callback that performs a GC on each invocation.
FailedAccessCheckCallbackGC(Local<v8::Object> target,v8::AccessType type,Local<v8::Value> data)19363 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19364 v8::AccessType type,
19365 Local<v8::Value> data) {
19366 CcTest::heap()->CollectAllGarbage();
19367 CcTest::isolate()->ThrowException(
19368 v8::Exception::Error(v8_str("cross context")));
19369 }
19370
19371
TEST(GCInFailedAccessCheckCallback)19372 TEST(GCInFailedAccessCheckCallback) {
19373 // Install a failed access check callback that performs a GC on each
19374 // invocation. Then force the callback to be called from va
19375
19376 v8::V8::Initialize();
19377 v8::Isolate* isolate = CcTest::isolate();
19378
19379 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19380
19381 v8::HandleScope scope(isolate);
19382
19383 // Create an ObjectTemplate for global objects and install access
19384 // check callbacks that will block access.
19385 v8::Local<v8::ObjectTemplate> global_template =
19386 v8::ObjectTemplate::New(isolate);
19387 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
19388
19389 // Create a context and set an x property on it's global object.
19390 LocalContext context0(NULL, global_template);
19391 CHECK(context0->Global()
19392 ->Set(context0.local(), v8_str("x"), v8_num(42))
19393 .FromJust());
19394 v8::Local<v8::Object> global0 = context0->Global();
19395
19396 // Create a context with a different security token so that the
19397 // failed access check callback will be called on each access.
19398 LocalContext context1(NULL, global_template);
19399 CHECK(context1->Global()
19400 ->Set(context1.local(), v8_str("other"), global0)
19401 .FromJust());
19402
19403 v8::TryCatch try_catch(isolate);
19404
19405 // Get property with failed access check.
19406 CHECK(CompileRun("other.x").IsEmpty());
19407 CHECK(try_catch.HasCaught());
19408 try_catch.Reset();
19409
19410 // Get element with failed access check.
19411 CHECK(CompileRun("other[0]").IsEmpty());
19412 CHECK(try_catch.HasCaught());
19413 try_catch.Reset();
19414
19415 // Set property with failed access check.
19416 CHECK(CompileRun("other.x = new Object()").IsEmpty());
19417 CHECK(try_catch.HasCaught());
19418 try_catch.Reset();
19419
19420 // Set element with failed access check.
19421 CHECK(CompileRun("other[0] = new Object()").IsEmpty());
19422 CHECK(try_catch.HasCaught());
19423 try_catch.Reset();
19424
19425 // Get property attribute with failed access check.
19426 CHECK(CompileRun("\'x\' in other").IsEmpty());
19427 CHECK(try_catch.HasCaught());
19428 try_catch.Reset();
19429
19430 // Get property attribute for element with failed access check.
19431 CHECK(CompileRun("0 in other").IsEmpty());
19432 CHECK(try_catch.HasCaught());
19433 try_catch.Reset();
19434
19435 // Delete property.
19436 CHECK(CompileRun("delete other.x").IsEmpty());
19437 CHECK(try_catch.HasCaught());
19438 try_catch.Reset();
19439
19440 // Delete element.
19441 CHECK(global0->Delete(context1.local(), 0).IsNothing());
19442 CHECK(try_catch.HasCaught());
19443 try_catch.Reset();
19444
19445 // DefineAccessor.
19446 CHECK(global0->SetAccessor(context1.local(), v8_str("x"), GetXValue, NULL,
19447 v8_str("x"))
19448 .IsNothing());
19449 CHECK(try_catch.HasCaught());
19450 try_catch.Reset();
19451
19452 // Define JavaScript accessor.
19453 CHECK(CompileRun(
19454 "Object.prototype.__defineGetter__.call("
19455 " other, \'x\', function() { return 42; })").IsEmpty());
19456 CHECK(try_catch.HasCaught());
19457 try_catch.Reset();
19458
19459 // LookupAccessor.
19460 CHECK(CompileRun(
19461 "Object.prototype.__lookupGetter__.call("
19462 " other, \'x\')").IsEmpty());
19463 CHECK(try_catch.HasCaught());
19464 try_catch.Reset();
19465
19466 // HasOwnElement.
19467 CHECK(CompileRun(
19468 "Object.prototype.hasOwnProperty.call("
19469 "other, \'0\')").IsEmpty());
19470 CHECK(try_catch.HasCaught());
19471 try_catch.Reset();
19472
19473 CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
19474 CHECK(try_catch.HasCaught());
19475 try_catch.Reset();
19476
19477 CHECK(
19478 global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
19479 CHECK(try_catch.HasCaught());
19480 try_catch.Reset();
19481
19482 CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
19483 .IsNothing());
19484 CHECK(try_catch.HasCaught());
19485 try_catch.Reset();
19486
19487 // Reset the failed access check callback so it does not influence
19488 // the other tests.
19489 isolate->SetFailedAccessCheckCallbackFunction(NULL);
19490 }
19491
19492
TEST(IsolateNewDispose)19493 TEST(IsolateNewDispose) {
19494 v8::Isolate* current_isolate = CcTest::isolate();
19495 v8::Isolate::CreateParams create_params;
19496 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19497 v8::Isolate* isolate = v8::Isolate::New(create_params);
19498 CHECK(isolate != NULL);
19499 CHECK(current_isolate != isolate);
19500 CHECK(current_isolate == CcTest::isolate());
19501
19502 isolate->SetFatalErrorHandler(StoringErrorCallback);
19503 last_location = last_message = NULL;
19504 isolate->Dispose();
19505 CHECK(!last_location);
19506 CHECK(!last_message);
19507 }
19508
19509
UNINITIALIZED_TEST(DisposeIsolateWhenInUse)19510 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19511 v8::Isolate::CreateParams create_params;
19512 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19513 v8::Isolate* isolate = v8::Isolate::New(create_params);
19514 {
19515 v8::Isolate::Scope i_scope(isolate);
19516 v8::HandleScope scope(isolate);
19517 LocalContext context(isolate);
19518 // Run something in this isolate.
19519 ExpectTrue("true");
19520 isolate->SetFatalErrorHandler(StoringErrorCallback);
19521 last_location = last_message = NULL;
19522 // Still entered, should fail.
19523 isolate->Dispose();
19524 CHECK(last_location);
19525 CHECK(last_message);
19526 }
19527 isolate->Dispose();
19528 }
19529
19530
BreakArrayGuarantees(const char * script)19531 static void BreakArrayGuarantees(const char* script) {
19532 v8::Isolate::CreateParams create_params;
19533 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19534 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
19535 isolate1->Enter();
19536 v8::Persistent<v8::Context> context1;
19537 {
19538 v8::HandleScope scope(isolate1);
19539 context1.Reset(isolate1, Context::New(isolate1));
19540 }
19541
19542 {
19543 v8::HandleScope scope(isolate1);
19544 v8::Local<v8::Context> context =
19545 v8::Local<v8::Context>::New(isolate1, context1);
19546 v8::Context::Scope context_scope(context);
19547 v8::internal::Isolate* i_isolate =
19548 reinterpret_cast<v8::internal::Isolate*>(isolate1);
19549 CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
19550 // Run something in new isolate.
19551 CompileRun(script);
19552 CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
19553 }
19554 isolate1->Exit();
19555 isolate1->Dispose();
19556 }
19557
19558
TEST(VerifyArrayPrototypeGuarantees)19559 TEST(VerifyArrayPrototypeGuarantees) {
19560 // Break fast array hole handling by element changes.
19561 BreakArrayGuarantees("[].__proto__[1] = 3;");
19562 BreakArrayGuarantees("Object.prototype[3] = 'three';");
19563 BreakArrayGuarantees("Array.prototype.push(1);");
19564 BreakArrayGuarantees("Array.prototype.unshift(1);");
19565 // Break fast array hole handling by changing length.
19566 BreakArrayGuarantees("Array.prototype.length = 30;");
19567 // Break fast array hole handling by prototype structure changes.
19568 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
19569 // By sending elements to dictionary mode.
19570 BreakArrayGuarantees(
19571 "Object.defineProperty(Array.prototype, 0, {"
19572 " get: function() { return 3; }});");
19573 BreakArrayGuarantees(
19574 "Object.defineProperty(Object.prototype, 0, {"
19575 " get: function() { return 3; }});");
19576 }
19577
19578
TEST(RunTwoIsolatesOnSingleThread)19579 TEST(RunTwoIsolatesOnSingleThread) {
19580 // Run isolate 1.
19581 v8::Isolate::CreateParams create_params;
19582 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19583 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
19584 isolate1->Enter();
19585 v8::Persistent<v8::Context> context1;
19586 {
19587 v8::HandleScope scope(isolate1);
19588 context1.Reset(isolate1, Context::New(isolate1));
19589 }
19590
19591 {
19592 v8::HandleScope scope(isolate1);
19593 v8::Local<v8::Context> context =
19594 v8::Local<v8::Context>::New(isolate1, context1);
19595 v8::Context::Scope context_scope(context);
19596 // Run something in new isolate.
19597 CompileRun("var foo = 'isolate 1';");
19598 ExpectString("function f() { return foo; }; f()", "isolate 1");
19599 }
19600
19601 // Run isolate 2.
19602 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
19603 v8::Persistent<v8::Context> context2;
19604
19605 {
19606 v8::Isolate::Scope iscope(isolate2);
19607 v8::HandleScope scope(isolate2);
19608 context2.Reset(isolate2, Context::New(isolate2));
19609 v8::Local<v8::Context> context =
19610 v8::Local<v8::Context>::New(isolate2, context2);
19611 v8::Context::Scope context_scope(context);
19612
19613 // Run something in new isolate.
19614 CompileRun("var foo = 'isolate 2';");
19615 ExpectString("function f() { return foo; }; f()", "isolate 2");
19616 }
19617
19618 {
19619 v8::HandleScope scope(isolate1);
19620 v8::Local<v8::Context> context =
19621 v8::Local<v8::Context>::New(isolate1, context1);
19622 v8::Context::Scope context_scope(context);
19623 // Now again in isolate 1
19624 ExpectString("function f() { return foo; }; f()", "isolate 1");
19625 }
19626
19627 isolate1->Exit();
19628
19629 // Run some stuff in default isolate.
19630 v8::Persistent<v8::Context> context_default;
19631 {
19632 v8::Isolate* isolate = CcTest::isolate();
19633 v8::Isolate::Scope iscope(isolate);
19634 v8::HandleScope scope(isolate);
19635 context_default.Reset(isolate, Context::New(isolate));
19636 }
19637
19638 {
19639 v8::HandleScope scope(CcTest::isolate());
19640 v8::Local<v8::Context> context =
19641 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19642 v8::Context::Scope context_scope(context);
19643 // Variables in other isolates should be not available, verify there
19644 // is an exception.
19645 ExpectTrue("function f() {"
19646 " try {"
19647 " foo;"
19648 " return false;"
19649 " } catch(e) {"
19650 " return true;"
19651 " }"
19652 "};"
19653 "var isDefaultIsolate = true;"
19654 "f()");
19655 }
19656
19657 isolate1->Enter();
19658
19659 {
19660 v8::Isolate::Scope iscope(isolate2);
19661 v8::HandleScope scope(isolate2);
19662 v8::Local<v8::Context> context =
19663 v8::Local<v8::Context>::New(isolate2, context2);
19664 v8::Context::Scope context_scope(context);
19665 ExpectString("function f() { return foo; }; f()", "isolate 2");
19666 }
19667
19668 {
19669 v8::HandleScope scope(v8::Isolate::GetCurrent());
19670 v8::Local<v8::Context> context =
19671 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19672 v8::Context::Scope context_scope(context);
19673 ExpectString("function f() { return foo; }; f()", "isolate 1");
19674 }
19675
19676 {
19677 v8::Isolate::Scope iscope(isolate2);
19678 context2.Reset();
19679 }
19680
19681 context1.Reset();
19682 isolate1->Exit();
19683
19684 isolate2->SetFatalErrorHandler(StoringErrorCallback);
19685 last_location = last_message = NULL;
19686
19687 isolate1->Dispose();
19688 CHECK(!last_location);
19689 CHECK(!last_message);
19690
19691 isolate2->Dispose();
19692 CHECK(!last_location);
19693 CHECK(!last_message);
19694
19695 // Check that default isolate still runs.
19696 {
19697 v8::HandleScope scope(CcTest::isolate());
19698 v8::Local<v8::Context> context =
19699 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19700 v8::Context::Scope context_scope(context);
19701 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19702 }
19703 }
19704
19705
CalcFibonacci(v8::Isolate * isolate,int limit)19706 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19707 v8::Isolate::Scope isolate_scope(isolate);
19708 v8::HandleScope scope(isolate);
19709 LocalContext context(isolate);
19710 i::ScopedVector<char> code(1024);
19711 i::SNPrintF(code, "function fib(n) {"
19712 " if (n <= 2) return 1;"
19713 " return fib(n-1) + fib(n-2);"
19714 "}"
19715 "fib(%d)", limit);
19716 Local<Value> value = CompileRun(code.start());
19717 CHECK(value->IsNumber());
19718 return static_cast<int>(value->NumberValue(context.local()).FromJust());
19719 }
19720
19721 class IsolateThread : public v8::base::Thread {
19722 public:
IsolateThread(int fib_limit)19723 explicit IsolateThread(int fib_limit)
19724 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
19725
Run()19726 void Run() {
19727 v8::Isolate::CreateParams create_params;
19728 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19729 v8::Isolate* isolate = v8::Isolate::New(create_params);
19730 result_ = CalcFibonacci(isolate, fib_limit_);
19731 isolate->Dispose();
19732 }
19733
result()19734 int result() { return result_; }
19735
19736 private:
19737 int fib_limit_;
19738 int result_;
19739 };
19740
19741
TEST(MultipleIsolatesOnIndividualThreads)19742 TEST(MultipleIsolatesOnIndividualThreads) {
19743 IsolateThread thread1(21);
19744 IsolateThread thread2(12);
19745
19746 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19747 thread1.Start();
19748 thread2.Start();
19749
19750 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19751 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19752
19753 thread1.Join();
19754 thread2.Join();
19755
19756 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19757 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19758 CHECK_EQ(result1, 10946);
19759 CHECK_EQ(result2, 144);
19760 CHECK_EQ(result1, thread1.result());
19761 CHECK_EQ(result2, thread2.result());
19762 }
19763
19764
TEST(IsolateDifferentContexts)19765 TEST(IsolateDifferentContexts) {
19766 v8::Isolate::CreateParams create_params;
19767 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19768 v8::Isolate* isolate = v8::Isolate::New(create_params);
19769 Local<v8::Context> context;
19770 {
19771 v8::Isolate::Scope isolate_scope(isolate);
19772 v8::HandleScope handle_scope(isolate);
19773 context = v8::Context::New(isolate);
19774 v8::Context::Scope context_scope(context);
19775 Local<Value> v = CompileRun("2");
19776 CHECK(v->IsNumber());
19777 CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
19778 }
19779 {
19780 v8::Isolate::Scope isolate_scope(isolate);
19781 v8::HandleScope handle_scope(isolate);
19782 context = v8::Context::New(isolate);
19783 v8::Context::Scope context_scope(context);
19784 Local<Value> v = CompileRun("22");
19785 CHECK(v->IsNumber());
19786 CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
19787 }
19788 isolate->Dispose();
19789 }
19790
19791 class InitDefaultIsolateThread : public v8::base::Thread {
19792 public:
19793 enum TestCase {
19794 SetResourceConstraints,
19795 SetFatalHandler,
19796 SetCounterFunction,
19797 SetCreateHistogramFunction,
19798 SetAddHistogramSampleFunction
19799 };
19800
InitDefaultIsolateThread(TestCase testCase)19801 explicit InitDefaultIsolateThread(TestCase testCase)
19802 : Thread(Options("InitDefaultIsolateThread")),
19803 testCase_(testCase),
19804 result_(false) {}
19805
Run()19806 void Run() {
19807 v8::Isolate::CreateParams create_params;
19808 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19809 const intptr_t pageSizeMult =
19810 v8::internal::Page::kPageSize / v8::internal::MB;
19811 switch (testCase_) {
19812 case SetResourceConstraints: {
19813 create_params.constraints.set_max_semi_space_size(1 * pageSizeMult);
19814 create_params.constraints.set_max_old_space_size(4 * pageSizeMult);
19815 break;
19816 }
19817 default:
19818 break;
19819 }
19820 v8::Isolate* isolate = v8::Isolate::New(create_params);
19821 isolate->Enter();
19822 switch (testCase_) {
19823 case SetResourceConstraints:
19824 // Already handled in pre-Isolate-creation block.
19825 break;
19826
19827 case SetFatalHandler:
19828 isolate->SetFatalErrorHandler(NULL);
19829 break;
19830
19831 case SetCounterFunction:
19832 CcTest::isolate()->SetCounterFunction(NULL);
19833 break;
19834
19835 case SetCreateHistogramFunction:
19836 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19837 break;
19838
19839 case SetAddHistogramSampleFunction:
19840 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19841 break;
19842 }
19843 isolate->Exit();
19844 isolate->Dispose();
19845 result_ = true;
19846 }
19847
result()19848 bool result() { return result_; }
19849
19850 private:
19851 TestCase testCase_;
19852 bool result_;
19853 };
19854
19855
InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase)19856 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19857 InitDefaultIsolateThread thread(testCase);
19858 thread.Start();
19859 thread.Join();
19860 CHECK_EQ(thread.result(), true);
19861 }
19862
19863
TEST(InitializeDefaultIsolateOnSecondaryThread1)19864 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19865 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19866 }
19867
19868
TEST(InitializeDefaultIsolateOnSecondaryThread2)19869 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19870 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19871 }
19872
19873
TEST(InitializeDefaultIsolateOnSecondaryThread3)19874 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19875 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19876 }
19877
19878
TEST(InitializeDefaultIsolateOnSecondaryThread4)19879 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19880 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19881 }
19882
19883
TEST(InitializeDefaultIsolateOnSecondaryThread5)19884 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19885 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19886 }
19887
19888
TEST(StringCheckMultipleContexts)19889 TEST(StringCheckMultipleContexts) {
19890 const char* code =
19891 "(function() { return \"a\".charAt(0); })()";
19892
19893 {
19894 // Run the code twice in the first context to initialize the call IC.
19895 LocalContext context1;
19896 v8::HandleScope scope(context1->GetIsolate());
19897 ExpectString(code, "a");
19898 ExpectString(code, "a");
19899 }
19900
19901 {
19902 // Change the String.prototype in the second context and check
19903 // that the right function gets called.
19904 LocalContext context2;
19905 v8::HandleScope scope(context2->GetIsolate());
19906 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19907 ExpectString(code, "not a");
19908 }
19909 }
19910
19911
TEST(NumberCheckMultipleContexts)19912 TEST(NumberCheckMultipleContexts) {
19913 const char* code =
19914 "(function() { return (42).toString(); })()";
19915
19916 {
19917 // Run the code twice in the first context to initialize the call IC.
19918 LocalContext context1;
19919 v8::HandleScope scope(context1->GetIsolate());
19920 ExpectString(code, "42");
19921 ExpectString(code, "42");
19922 }
19923
19924 {
19925 // Change the Number.prototype in the second context and check
19926 // that the right function gets called.
19927 LocalContext context2;
19928 v8::HandleScope scope(context2->GetIsolate());
19929 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19930 ExpectString(code, "not 42");
19931 }
19932 }
19933
19934
TEST(BooleanCheckMultipleContexts)19935 TEST(BooleanCheckMultipleContexts) {
19936 const char* code =
19937 "(function() { return true.toString(); })()";
19938
19939 {
19940 // Run the code twice in the first context to initialize the call IC.
19941 LocalContext context1;
19942 v8::HandleScope scope(context1->GetIsolate());
19943 ExpectString(code, "true");
19944 ExpectString(code, "true");
19945 }
19946
19947 {
19948 // Change the Boolean.prototype in the second context and check
19949 // that the right function gets called.
19950 LocalContext context2;
19951 v8::HandleScope scope(context2->GetIsolate());
19952 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19953 ExpectString(code, "");
19954 }
19955 }
19956
19957
TEST(DontDeleteCellLoadIC)19958 TEST(DontDeleteCellLoadIC) {
19959 const char* function_code =
19960 "function readCell() { while (true) { return cell; } }";
19961
19962 {
19963 // Run the code twice in the first context to initialize the load
19964 // IC for a don't delete cell.
19965 LocalContext context1;
19966 v8::HandleScope scope(context1->GetIsolate());
19967 CompileRun("var cell = \"first\";");
19968 ExpectBoolean("delete cell", false);
19969 CompileRun(function_code);
19970 ExpectString("readCell()", "first");
19971 ExpectString("readCell()", "first");
19972 }
19973
19974 {
19975 // Use a deletable cell in the second context.
19976 LocalContext context2;
19977 v8::HandleScope scope(context2->GetIsolate());
19978 CompileRun("cell = \"second\";");
19979 CompileRun(function_code);
19980 ExpectString("readCell()", "second");
19981 ExpectBoolean("delete cell", true);
19982 ExpectString("(function() {"
19983 " try {"
19984 " return readCell();"
19985 " } catch(e) {"
19986 " return e.toString();"
19987 " }"
19988 "})()",
19989 "ReferenceError: cell is not defined");
19990 CompileRun("cell = \"new_second\";");
19991 CcTest::heap()->CollectAllGarbage();
19992 ExpectString("readCell()", "new_second");
19993 ExpectString("readCell()", "new_second");
19994 }
19995 }
19996
19997
19998 class Visitor42 : public v8::PersistentHandleVisitor {
19999 public:
Visitor42(v8::Persistent<v8::Object> * object)20000 explicit Visitor42(v8::Persistent<v8::Object>* object)
20001 : counter_(0), object_(object) { }
20002
VisitPersistentHandle(Persistent<Value> * value,uint16_t class_id)20003 virtual void VisitPersistentHandle(Persistent<Value>* value,
20004 uint16_t class_id) {
20005 if (class_id != 42) return;
20006 CHECK_EQ(42, value->WrapperClassId());
20007 v8::Isolate* isolate = CcTest::isolate();
20008 v8::HandleScope handle_scope(isolate);
20009 v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20010 v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
20011 CHECK(handle->IsObject());
20012 CHECK(Local<Object>::Cast(handle)
20013 ->Equals(isolate->GetCurrentContext(), object)
20014 .FromJust());
20015 ++counter_;
20016 }
20017
20018 int counter_;
20019 v8::Persistent<v8::Object>* object_;
20020 };
20021
20022
TEST(PersistentHandleVisitor)20023 TEST(PersistentHandleVisitor) {
20024 LocalContext context;
20025 v8::Isolate* isolate = context->GetIsolate();
20026 v8::HandleScope scope(isolate);
20027 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20028 CHECK_EQ(0, object.WrapperClassId());
20029 object.SetWrapperClassId(42);
20030 CHECK_EQ(42, object.WrapperClassId());
20031
20032 Visitor42 visitor(&object);
20033 isolate->VisitHandlesWithClassIds(&visitor);
20034 CHECK_EQ(1, visitor.counter_);
20035
20036 object.Reset();
20037 }
20038
20039
TEST(WrapperClassId)20040 TEST(WrapperClassId) {
20041 LocalContext context;
20042 v8::Isolate* isolate = context->GetIsolate();
20043 v8::HandleScope scope(isolate);
20044 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20045 CHECK_EQ(0, object.WrapperClassId());
20046 object.SetWrapperClassId(65535);
20047 CHECK_EQ(65535, object.WrapperClassId());
20048 object.Reset();
20049 }
20050
20051
TEST(PersistentHandleInNewSpaceVisitor)20052 TEST(PersistentHandleInNewSpaceVisitor) {
20053 LocalContext context;
20054 v8::Isolate* isolate = context->GetIsolate();
20055 v8::HandleScope scope(isolate);
20056 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
20057 CHECK_EQ(0, object1.WrapperClassId());
20058 object1.SetWrapperClassId(42);
20059 CHECK_EQ(42, object1.WrapperClassId());
20060
20061 CcTest::heap()->CollectAllGarbage();
20062 CcTest::heap()->CollectAllGarbage();
20063
20064 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
20065 CHECK_EQ(0, object2.WrapperClassId());
20066 object2.SetWrapperClassId(42);
20067 CHECK_EQ(42, object2.WrapperClassId());
20068
20069 Visitor42 visitor(&object2);
20070 isolate->VisitHandlesForPartialDependence(&visitor);
20071 CHECK_EQ(1, visitor.counter_);
20072
20073 object1.Reset();
20074 object2.Reset();
20075 }
20076
20077
TEST(RegExp)20078 TEST(RegExp) {
20079 LocalContext context;
20080 v8::HandleScope scope(context->GetIsolate());
20081
20082 v8::Local<v8::RegExp> re =
20083 v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
20084 .ToLocalChecked();
20085 CHECK(re->IsRegExp());
20086 CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
20087 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20088
20089 re = v8::RegExp::New(context.local(), v8_str("bar"),
20090 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20091 v8::RegExp::kGlobal))
20092 .ToLocalChecked();
20093 CHECK(re->IsRegExp());
20094 CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
20095 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20096 static_cast<int>(re->GetFlags()));
20097
20098 re = v8::RegExp::New(context.local(), v8_str("baz"),
20099 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20100 v8::RegExp::kMultiline))
20101 .ToLocalChecked();
20102 CHECK(re->IsRegExp());
20103 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20104 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20105 static_cast<int>(re->GetFlags()));
20106
20107 re = v8::RegExp::New(context.local(), v8_str("baz"),
20108 static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
20109 v8::RegExp::kSticky))
20110 .ToLocalChecked();
20111 CHECK(re->IsRegExp());
20112 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20113 CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
20114 static_cast<int>(re->GetFlags()));
20115
20116 re = CompileRun("/quux/").As<v8::RegExp>();
20117 CHECK(re->IsRegExp());
20118 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20119 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20120
20121 re = CompileRun("/quux/gm").As<v8::RegExp>();
20122 CHECK(re->IsRegExp());
20123 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20124 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20125 static_cast<int>(re->GetFlags()));
20126
20127 // Override the RegExp constructor and check the API constructor
20128 // still works.
20129 CompileRun("RegExp = function() {}");
20130
20131 re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
20132 .ToLocalChecked();
20133 CHECK(re->IsRegExp());
20134 CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
20135 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20136
20137 re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
20138 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20139 v8::RegExp::kMultiline))
20140 .ToLocalChecked();
20141 CHECK(re->IsRegExp());
20142 CHECK(
20143 re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
20144 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20145 static_cast<int>(re->GetFlags()));
20146
20147 CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
20148 ExpectTrue("re.test('FoobarbaZ')");
20149
20150 // RegExps are objects on which you can set properties.
20151 re->Set(context.local(), v8_str("property"),
20152 v8::Integer::New(context->GetIsolate(), 32))
20153 .FromJust();
20154 v8::Local<v8::Value> value(CompileRun("re.property"));
20155 CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
20156
20157 v8::TryCatch try_catch(context->GetIsolate());
20158 CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
20159 .IsEmpty());
20160 CHECK(try_catch.HasCaught());
20161 CHECK(context->Global()
20162 ->Set(context.local(), v8_str("ex"), try_catch.Exception())
20163 .FromJust());
20164 ExpectTrue("ex instanceof SyntaxError");
20165 }
20166
20167
THREADED_TEST(Equals)20168 THREADED_TEST(Equals) {
20169 LocalContext localContext;
20170 v8::HandleScope handleScope(localContext->GetIsolate());
20171
20172 v8::Local<v8::Object> globalProxy = localContext->Global();
20173 v8::Local<Value> global = globalProxy->GetPrototype();
20174
20175 CHECK(global->StrictEquals(global));
20176 CHECK(!global->StrictEquals(globalProxy));
20177 CHECK(!globalProxy->StrictEquals(global));
20178 CHECK(globalProxy->StrictEquals(globalProxy));
20179
20180 CHECK(global->Equals(localContext.local(), global).FromJust());
20181 CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
20182 CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
20183 CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
20184 }
20185
20186
Getter(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)20187 static void Getter(v8::Local<v8::Name> property,
20188 const v8::PropertyCallbackInfo<v8::Value>& info) {
20189 info.GetReturnValue().Set(v8_str("42!"));
20190 }
20191
20192
Enumerator(const v8::PropertyCallbackInfo<v8::Array> & info)20193 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20194 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
20195 result->Set(info.GetIsolate()->GetCurrentContext(), 0,
20196 v8_str("universalAnswer"))
20197 .FromJust();
20198 info.GetReturnValue().Set(result);
20199 }
20200
20201
TEST(NamedEnumeratorAndForIn)20202 TEST(NamedEnumeratorAndForIn) {
20203 LocalContext context;
20204 v8::Isolate* isolate = context->GetIsolate();
20205 v8::HandleScope handle_scope(isolate);
20206 v8::Context::Scope context_scope(context.local());
20207
20208 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20209 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
20210 NULL, Enumerator));
20211 CHECK(context->Global()
20212 ->Set(context.local(), v8_str("o"),
20213 tmpl->NewInstance(context.local()).ToLocalChecked())
20214 .FromJust());
20215 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
20216 CompileRun("var result = []; for (var k in o) result.push(k); result"));
20217 CHECK_EQ(1u, result->Length());
20218 CHECK(v8_str("universalAnswer")
20219 ->Equals(context.local(),
20220 result->Get(context.local(), 0).ToLocalChecked())
20221 .FromJust());
20222 }
20223
20224
TEST(DefinePropertyPostDetach)20225 TEST(DefinePropertyPostDetach) {
20226 LocalContext context;
20227 v8::HandleScope scope(context->GetIsolate());
20228 v8::Local<v8::Object> proxy = context->Global();
20229 v8::Local<v8::Function> define_property =
20230 CompileRun(
20231 "(function() {"
20232 " Object.defineProperty("
20233 " this,"
20234 " 1,"
20235 " { configurable: true, enumerable: true, value: 3 });"
20236 "})")
20237 .As<Function>();
20238 context->DetachGlobal();
20239 CHECK(define_property->Call(context.local(), proxy, 0, NULL).IsEmpty());
20240 }
20241
20242
InstallContextId(v8::Local<Context> context,int id)20243 static void InstallContextId(v8::Local<Context> context, int id) {
20244 Context::Scope scope(context);
20245 CHECK(CompileRun("Object.prototype")
20246 .As<Object>()
20247 ->Set(context, v8_str("context_id"),
20248 v8::Integer::New(context->GetIsolate(), id))
20249 .FromJust());
20250 }
20251
20252
CheckContextId(v8::Local<Object> object,int expected)20253 static void CheckContextId(v8::Local<Object> object, int expected) {
20254 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20255 CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
20256 .ToLocalChecked()
20257 ->Int32Value(context)
20258 .FromJust());
20259 }
20260
20261
THREADED_TEST(CreationContext)20262 THREADED_TEST(CreationContext) {
20263 v8::Isolate* isolate = CcTest::isolate();
20264 HandleScope handle_scope(isolate);
20265 Local<Context> context1 = Context::New(isolate);
20266 InstallContextId(context1, 1);
20267 Local<Context> context2 = Context::New(isolate);
20268 InstallContextId(context2, 2);
20269 Local<Context> context3 = Context::New(isolate);
20270 InstallContextId(context3, 3);
20271
20272 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20273
20274 Local<Object> object1;
20275 Local<Function> func1;
20276 {
20277 Context::Scope scope(context1);
20278 object1 = Object::New(isolate);
20279 func1 = tmpl->GetFunction(context1).ToLocalChecked();
20280 }
20281
20282 Local<Object> object2;
20283 Local<Function> func2;
20284 {
20285 Context::Scope scope(context2);
20286 object2 = Object::New(isolate);
20287 func2 = tmpl->GetFunction(context2).ToLocalChecked();
20288 }
20289
20290 Local<Object> instance1;
20291 Local<Object> instance2;
20292
20293 {
20294 Context::Scope scope(context3);
20295 instance1 = func1->NewInstance(context3).ToLocalChecked();
20296 instance2 = func2->NewInstance(context3).ToLocalChecked();
20297 }
20298
20299 {
20300 Local<Context> other_context = Context::New(isolate);
20301 Context::Scope scope(other_context);
20302 CHECK(object1->CreationContext() == context1);
20303 CheckContextId(object1, 1);
20304 CHECK(func1->CreationContext() == context1);
20305 CheckContextId(func1, 1);
20306 CHECK(instance1->CreationContext() == context1);
20307 CheckContextId(instance1, 1);
20308 CHECK(object2->CreationContext() == context2);
20309 CheckContextId(object2, 2);
20310 CHECK(func2->CreationContext() == context2);
20311 CheckContextId(func2, 2);
20312 CHECK(instance2->CreationContext() == context2);
20313 CheckContextId(instance2, 2);
20314 }
20315
20316 {
20317 Context::Scope scope(context1);
20318 CHECK(object1->CreationContext() == context1);
20319 CheckContextId(object1, 1);
20320 CHECK(func1->CreationContext() == context1);
20321 CheckContextId(func1, 1);
20322 CHECK(instance1->CreationContext() == context1);
20323 CheckContextId(instance1, 1);
20324 CHECK(object2->CreationContext() == context2);
20325 CheckContextId(object2, 2);
20326 CHECK(func2->CreationContext() == context2);
20327 CheckContextId(func2, 2);
20328 CHECK(instance2->CreationContext() == context2);
20329 CheckContextId(instance2, 2);
20330 }
20331
20332 {
20333 Context::Scope scope(context2);
20334 CHECK(object1->CreationContext() == context1);
20335 CheckContextId(object1, 1);
20336 CHECK(func1->CreationContext() == context1);
20337 CheckContextId(func1, 1);
20338 CHECK(instance1->CreationContext() == context1);
20339 CheckContextId(instance1, 1);
20340 CHECK(object2->CreationContext() == context2);
20341 CheckContextId(object2, 2);
20342 CHECK(func2->CreationContext() == context2);
20343 CheckContextId(func2, 2);
20344 CHECK(instance2->CreationContext() == context2);
20345 CheckContextId(instance2, 2);
20346 }
20347 }
20348
20349
THREADED_TEST(CreationContextOfJsFunction)20350 THREADED_TEST(CreationContextOfJsFunction) {
20351 HandleScope handle_scope(CcTest::isolate());
20352 Local<Context> context = Context::New(CcTest::isolate());
20353 InstallContextId(context, 1);
20354
20355 Local<Object> function;
20356 {
20357 Context::Scope scope(context);
20358 function = CompileRun("function foo() {}; foo").As<Object>();
20359 }
20360
20361 Local<Context> other_context = Context::New(CcTest::isolate());
20362 Context::Scope scope(other_context);
20363 CHECK(function->CreationContext() == context);
20364 CheckContextId(function, 1);
20365 }
20366
20367
THREADED_TEST(CreationContextOfJsBoundFunction)20368 THREADED_TEST(CreationContextOfJsBoundFunction) {
20369 HandleScope handle_scope(CcTest::isolate());
20370 Local<Context> context1 = Context::New(CcTest::isolate());
20371 InstallContextId(context1, 1);
20372 Local<Context> context2 = Context::New(CcTest::isolate());
20373 InstallContextId(context2, 2);
20374
20375 Local<Function> target_function;
20376 {
20377 Context::Scope scope(context1);
20378 target_function = CompileRun("function foo() {}; foo").As<Function>();
20379 }
20380
20381 Local<Function> bound_function1, bound_function2;
20382 {
20383 Context::Scope scope(context2);
20384 CHECK(context2->Global()
20385 ->Set(context2, v8_str("foo"), target_function)
20386 .FromJust());
20387 bound_function1 = CompileRun("foo.bind(1)").As<Function>();
20388 bound_function2 =
20389 CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
20390 }
20391
20392 Local<Context> other_context = Context::New(CcTest::isolate());
20393 Context::Scope scope(other_context);
20394 CHECK(bound_function1->CreationContext() == context1);
20395 CheckContextId(bound_function1, 1);
20396 CHECK(bound_function2->CreationContext() == context1);
20397 CheckContextId(bound_function2, 1);
20398 }
20399
20400
HasOwnPropertyIndexedPropertyGetter(uint32_t index,const v8::PropertyCallbackInfo<v8::Value> & info)20401 void HasOwnPropertyIndexedPropertyGetter(
20402 uint32_t index,
20403 const v8::PropertyCallbackInfo<v8::Value>& info) {
20404 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20405 }
20406
20407
HasOwnPropertyNamedPropertyGetter(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)20408 void HasOwnPropertyNamedPropertyGetter(
20409 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20410 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20411 .FromJust()) {
20412 info.GetReturnValue().Set(v8_str("yes"));
20413 }
20414 }
20415
20416
HasOwnPropertyIndexedPropertyQuery(uint32_t index,const v8::PropertyCallbackInfo<v8::Integer> & info)20417 void HasOwnPropertyIndexedPropertyQuery(
20418 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20419 if (index == 42) info.GetReturnValue().Set(1);
20420 }
20421
20422
HasOwnPropertyNamedPropertyQuery(Local<Name> property,const v8::PropertyCallbackInfo<v8::Integer> & info)20423 void HasOwnPropertyNamedPropertyQuery(
20424 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20425 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20426 .FromJust()) {
20427 info.GetReturnValue().Set(1);
20428 }
20429 }
20430
20431
HasOwnPropertyNamedPropertyQuery2(Local<Name> property,const v8::PropertyCallbackInfo<v8::Integer> & info)20432 void HasOwnPropertyNamedPropertyQuery2(
20433 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20434 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
20435 .FromJust()) {
20436 info.GetReturnValue().Set(1);
20437 }
20438 }
20439
20440
HasOwnPropertyAccessorGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)20441 void HasOwnPropertyAccessorGetter(
20442 Local<String> property,
20443 const v8::PropertyCallbackInfo<v8::Value>& info) {
20444 info.GetReturnValue().Set(v8_str("yes"));
20445 }
20446
20447
TEST(HasOwnProperty)20448 TEST(HasOwnProperty) {
20449 LocalContext env;
20450 v8::Isolate* isolate = env->GetIsolate();
20451 v8::HandleScope scope(isolate);
20452 { // Check normal properties and defined getters.
20453 Local<Value> value = CompileRun(
20454 "function Foo() {"
20455 " this.foo = 11;"
20456 " this.__defineGetter__('baz', function() { return 1; });"
20457 "};"
20458 "function Bar() { "
20459 " this.bar = 13;"
20460 " this.__defineGetter__('bla', function() { return 2; });"
20461 "};"
20462 "Bar.prototype = new Foo();"
20463 "new Bar();");
20464 CHECK(value->IsObject());
20465 Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
20466 CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
20467 CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20468 CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20469 CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
20470 CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
20471 CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
20472 }
20473 { // Check named getter interceptors.
20474 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20475 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20476 HasOwnPropertyNamedPropertyGetter));
20477 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20478 CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20479 CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
20480 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20481 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20482 }
20483 { // Check indexed getter interceptors.
20484 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20485 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20486 HasOwnPropertyIndexedPropertyGetter));
20487 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20488 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20489 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20490 CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
20491 CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
20492 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20493 }
20494 { // Check named query interceptors.
20495 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20496 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20497 0, 0, HasOwnPropertyNamedPropertyQuery));
20498 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20499 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20500 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20501 }
20502 { // Check indexed query interceptors.
20503 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20504 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20505 0, 0, HasOwnPropertyIndexedPropertyQuery));
20506 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20507 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20508 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20509 CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
20510 CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
20511 }
20512 { // Check callbacks.
20513 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20514 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20515 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20516 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20517 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20518 }
20519 { // Check that query wins on disagreement.
20520 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20521 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20522 HasOwnPropertyNamedPropertyGetter, 0,
20523 HasOwnPropertyNamedPropertyQuery2));
20524 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20525 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20526 CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20527 }
20528 }
20529
20530
TEST(IndexedInterceptorWithStringProto)20531 TEST(IndexedInterceptorWithStringProto) {
20532 v8::Isolate* isolate = CcTest::isolate();
20533 v8::HandleScope scope(isolate);
20534 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20535 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20536 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
20537 LocalContext context;
20538 CHECK(context->Global()
20539 ->Set(context.local(), v8_str("obj"),
20540 templ->NewInstance(context.local()).ToLocalChecked())
20541 .FromJust());
20542 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20543 // These should be intercepted.
20544 CHECK(CompileRun("42 in obj")->BooleanValue(context.local()).FromJust());
20545 CHECK(CompileRun("'42' in obj")->BooleanValue(context.local()).FromJust());
20546 // These should fall through to the String prototype.
20547 CHECK(CompileRun("0 in obj")->BooleanValue(context.local()).FromJust());
20548 CHECK(CompileRun("'0' in obj")->BooleanValue(context.local()).FromJust());
20549 // And these should both fail.
20550 CHECK(!CompileRun("32 in obj")->BooleanValue(context.local()).FromJust());
20551 CHECK(!CompileRun("'32' in obj")->BooleanValue(context.local()).FromJust());
20552 }
20553
20554
CheckCodeGenerationAllowed()20555 void CheckCodeGenerationAllowed() {
20556 Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20557 Local<Value> result = CompileRun("eval('42')");
20558 CHECK_EQ(42, result->Int32Value(context).FromJust());
20559 result = CompileRun("(function(e) { return e('42'); })(eval)");
20560 CHECK_EQ(42, result->Int32Value(context).FromJust());
20561 result = CompileRun("var f = new Function('return 42'); f()");
20562 CHECK_EQ(42, result->Int32Value(context).FromJust());
20563 }
20564
20565
CheckCodeGenerationDisallowed()20566 void CheckCodeGenerationDisallowed() {
20567 TryCatch try_catch(CcTest::isolate());
20568
20569 Local<Value> result = CompileRun("eval('42')");
20570 CHECK(result.IsEmpty());
20571 CHECK(try_catch.HasCaught());
20572 try_catch.Reset();
20573
20574 result = CompileRun("(function(e) { return e('42'); })(eval)");
20575 CHECK(result.IsEmpty());
20576 CHECK(try_catch.HasCaught());
20577 try_catch.Reset();
20578
20579 result = CompileRun("var f = new Function('return 42'); f()");
20580 CHECK(result.IsEmpty());
20581 CHECK(try_catch.HasCaught());
20582 }
20583
20584
CodeGenerationAllowed(Local<Context> context)20585 bool CodeGenerationAllowed(Local<Context> context) {
20586 ApiTestFuzzer::Fuzz();
20587 return true;
20588 }
20589
20590
CodeGenerationDisallowed(Local<Context> context)20591 bool CodeGenerationDisallowed(Local<Context> context) {
20592 ApiTestFuzzer::Fuzz();
20593 return false;
20594 }
20595
20596
THREADED_TEST(AllowCodeGenFromStrings)20597 THREADED_TEST(AllowCodeGenFromStrings) {
20598 LocalContext context;
20599 v8::HandleScope scope(context->GetIsolate());
20600
20601 // eval and the Function constructor allowed by default.
20602 CHECK(context->IsCodeGenerationFromStringsAllowed());
20603 CheckCodeGenerationAllowed();
20604
20605 // Disallow eval and the Function constructor.
20606 context->AllowCodeGenerationFromStrings(false);
20607 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20608 CheckCodeGenerationDisallowed();
20609
20610 // Allow again.
20611 context->AllowCodeGenerationFromStrings(true);
20612 CheckCodeGenerationAllowed();
20613
20614 // Disallow but setting a global callback that will allow the calls.
20615 context->AllowCodeGenerationFromStrings(false);
20616 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
20617 &CodeGenerationAllowed);
20618 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20619 CheckCodeGenerationAllowed();
20620
20621 // Set a callback that disallows the code generation.
20622 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
20623 &CodeGenerationDisallowed);
20624 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20625 CheckCodeGenerationDisallowed();
20626 }
20627
20628
TEST(SetErrorMessageForCodeGenFromStrings)20629 TEST(SetErrorMessageForCodeGenFromStrings) {
20630 LocalContext context;
20631 v8::HandleScope scope(context->GetIsolate());
20632 TryCatch try_catch(context->GetIsolate());
20633
20634 Local<String> message = v8_str("Message");
20635 Local<String> expected_message = v8_str("Uncaught EvalError: Message");
20636 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
20637 &CodeGenerationDisallowed);
20638 context->AllowCodeGenerationFromStrings(false);
20639 context->SetErrorMessageForCodeGenerationFromStrings(message);
20640 Local<Value> result = CompileRun("eval('42')");
20641 CHECK(result.IsEmpty());
20642 CHECK(try_catch.HasCaught());
20643 Local<String> actual_message = try_catch.Message()->Get();
20644 CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
20645 }
20646
20647
NonObjectThis(const v8::FunctionCallbackInfo<v8::Value> & args)20648 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20649 }
20650
20651
THREADED_TEST(CallAPIFunctionOnNonObject)20652 THREADED_TEST(CallAPIFunctionOnNonObject) {
20653 LocalContext context;
20654 v8::Isolate* isolate = context->GetIsolate();
20655 v8::HandleScope scope(isolate);
20656 Local<FunctionTemplate> templ =
20657 v8::FunctionTemplate::New(isolate, NonObjectThis);
20658 Local<Function> function =
20659 templ->GetFunction(context.local()).ToLocalChecked();
20660 CHECK(context->Global()
20661 ->Set(context.local(), v8_str("f"), function)
20662 .FromJust());
20663 TryCatch try_catch(isolate);
20664 CompileRun("f.call(2)");
20665 }
20666
20667
20668 // Regression test for issue 1470.
THREADED_TEST(ReadOnlyIndexedProperties)20669 THREADED_TEST(ReadOnlyIndexedProperties) {
20670 v8::Isolate* isolate = CcTest::isolate();
20671 v8::HandleScope scope(isolate);
20672 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20673
20674 LocalContext context;
20675 Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
20676 CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
20677 obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
20678 v8::ReadOnly)
20679 .FromJust();
20680 obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
20681 CHECK(v8_str("DONT_CHANGE")
20682 ->Equals(context.local(),
20683 obj->Get(context.local(), v8_str("1")).ToLocalChecked())
20684 .FromJust());
20685 obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
20686 v8::ReadOnly)
20687 .FromJust();
20688 obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
20689 CHECK(v8_str("DONT_CHANGE")
20690 ->Equals(context.local(),
20691 obj->Get(context.local(), v8_num(2)).ToLocalChecked())
20692 .FromJust());
20693
20694 // Test non-smi case.
20695 obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
20696 v8_str("DONT_CHANGE"), v8::ReadOnly)
20697 .FromJust();
20698 obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
20699 CHECK(v8_str("DONT_CHANGE")
20700 ->Equals(context.local(),
20701 obj->Get(context.local(), v8_str("2000000000"))
20702 .ToLocalChecked())
20703 .FromJust());
20704 }
20705
20706
CountLiveMapsInMapCache(i::Context * context)20707 static int CountLiveMapsInMapCache(i::Context* context) {
20708 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
20709 int length = map_cache->length();
20710 int count = 0;
20711 for (int i = 0; i < length; i++) {
20712 i::Object* value = map_cache->get(i);
20713 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
20714 }
20715 return count;
20716 }
20717
20718
THREADED_TEST(Regress1516)20719 THREADED_TEST(Regress1516) {
20720 LocalContext context;
20721 v8::HandleScope scope(context->GetIsolate());
20722
20723 // Object with 20 properties is not a common case, so it should be removed
20724 // from the cache after GC.
20725 { v8::HandleScope temp_scope(context->GetIsolate());
20726 CompileRun(
20727 "({"
20728 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
20729 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
20730 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
20731 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
20732 "})");
20733 }
20734
20735 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
20736 CHECK_LE(1, elements);
20737
20738 // We have to abort incremental marking here to abandon black pages.
20739 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
20740
20741 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
20742 }
20743
20744
THREADED_TEST(Regress93759)20745 THREADED_TEST(Regress93759) {
20746 v8::Isolate* isolate = CcTest::isolate();
20747 HandleScope scope(isolate);
20748
20749 // Template for object with security check.
20750 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20751 no_proto_template->SetAccessCheckCallback(AccessAlwaysBlocked);
20752
20753 // Templates for objects with hidden prototypes and possibly security check.
20754 Local<FunctionTemplate> hidden_proto_template =
20755 v8::FunctionTemplate::New(isolate);
20756 hidden_proto_template->SetHiddenPrototype(true);
20757
20758 Local<FunctionTemplate> protected_hidden_proto_template =
20759 v8::FunctionTemplate::New(isolate);
20760 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallback(
20761 AccessAlwaysBlocked);
20762 protected_hidden_proto_template->SetHiddenPrototype(true);
20763
20764 // Context for "foreign" objects used in test.
20765 Local<Context> context = v8::Context::New(isolate);
20766 context->Enter();
20767
20768 // Plain object, no security check.
20769 Local<Object> simple_object = Object::New(isolate);
20770
20771 // Object with explicit security check.
20772 Local<Object> protected_object =
20773 no_proto_template->NewInstance(context).ToLocalChecked();
20774
20775 // JSGlobalProxy object, always have security check.
20776 Local<Object> proxy_object = context->Global();
20777
20778 // Global object, the prototype of proxy_object. No security checks.
20779 Local<Object> global_object =
20780 proxy_object->GetPrototype()->ToObject(context).ToLocalChecked();
20781
20782 // Hidden prototype without security check.
20783 Local<Object> hidden_prototype = hidden_proto_template->GetFunction(context)
20784 .ToLocalChecked()
20785 ->NewInstance(context)
20786 .ToLocalChecked();
20787 Local<Object> object_with_hidden =
20788 Object::New(isolate);
20789 object_with_hidden->SetPrototype(context, hidden_prototype).FromJust();
20790
20791 context->Exit();
20792
20793 LocalContext context2;
20794 v8::Local<v8::Object> global = context2->Global();
20795
20796 // Setup global variables.
20797 CHECK(global->Set(context2.local(), v8_str("simple"), simple_object)
20798 .FromJust());
20799 CHECK(global->Set(context2.local(), v8_str("protected"), protected_object)
20800 .FromJust());
20801 CHECK(global->Set(context2.local(), v8_str("global"), global_object)
20802 .FromJust());
20803 CHECK(
20804 global->Set(context2.local(), v8_str("proxy"), proxy_object).FromJust());
20805 CHECK(global->Set(context2.local(), v8_str("hidden"), object_with_hidden)
20806 .FromJust());
20807
20808 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20809 CHECK(result1->Equals(context2.local(), simple_object->GetPrototype())
20810 .FromJust());
20811
20812 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20813 CHECK(result2->IsNull());
20814
20815 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20816 CHECK(result3->Equals(context2.local(), global_object->GetPrototype())
20817 .FromJust());
20818
20819 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20820 CHECK(result4->IsNull());
20821
20822 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20823 CHECK(result5->Equals(context2.local(), object_with_hidden->GetPrototype()
20824 ->ToObject(context2.local())
20825 .ToLocalChecked()
20826 ->GetPrototype())
20827 .FromJust());
20828 }
20829
20830
TestReceiver(Local<Value> expected_result,Local<Value> expected_receiver,const char * code)20831 static void TestReceiver(Local<Value> expected_result,
20832 Local<Value> expected_receiver,
20833 const char* code) {
20834 Local<Value> result = CompileRun(code);
20835 Local<Context> context = CcTest::isolate()->GetCurrentContext();
20836 CHECK(result->IsObject());
20837 CHECK(expected_receiver
20838 ->Equals(context,
20839 result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
20840 .FromJust());
20841 CHECK(expected_result
20842 ->Equals(context,
20843 result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
20844 .FromJust());
20845 }
20846
20847
THREADED_TEST(ForeignFunctionReceiver)20848 THREADED_TEST(ForeignFunctionReceiver) {
20849 v8::Isolate* isolate = CcTest::isolate();
20850 HandleScope scope(isolate);
20851
20852 // Create two contexts with different "id" properties ('i' and 'o').
20853 // Call a function both from its own context and from a the foreign
20854 // context, and see what "this" is bound to (returning both "this"
20855 // and "this.id" for comparison).
20856
20857 Local<Context> foreign_context = v8::Context::New(isolate);
20858 foreign_context->Enter();
20859 Local<Value> foreign_function =
20860 CompileRun("function func() { return { 0: this.id, "
20861 " 1: this, "
20862 " toString: function() { "
20863 " return this[0];"
20864 " }"
20865 " };"
20866 "}"
20867 "var id = 'i';"
20868 "func;");
20869 CHECK(foreign_function->IsFunction());
20870 foreign_context->Exit();
20871
20872 LocalContext context;
20873
20874 Local<String> password = v8_str("Password");
20875 // Don't get hit by security checks when accessing foreign_context's
20876 // global receiver (aka. global proxy).
20877 context->SetSecurityToken(password);
20878 foreign_context->SetSecurityToken(password);
20879
20880 Local<String> i = v8_str("i");
20881 Local<String> o = v8_str("o");
20882 Local<String> id = v8_str("id");
20883
20884 CompileRun("function ownfunc() { return { 0: this.id, "
20885 " 1: this, "
20886 " toString: function() { "
20887 " return this[0];"
20888 " }"
20889 " };"
20890 "}"
20891 "var id = 'o';"
20892 "ownfunc");
20893 CHECK(context->Global()
20894 ->Set(context.local(), v8_str("func"), foreign_function)
20895 .FromJust());
20896
20897 // Sanity check the contexts.
20898 CHECK(
20899 i->Equals(
20900 context.local(),
20901 foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
20902 .FromJust());
20903 CHECK(o->Equals(context.local(),
20904 context->Global()->Get(context.local(), id).ToLocalChecked())
20905 .FromJust());
20906
20907 // Checking local function's receiver.
20908 // Calling function using its call/apply methods.
20909 TestReceiver(o, context->Global(), "ownfunc.call()");
20910 TestReceiver(o, context->Global(), "ownfunc.apply()");
20911 // Making calls through built-in functions.
20912 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20913 CHECK(
20914 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
20915 .FromJust());
20916 CHECK(
20917 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
20918 .FromJust());
20919 CHECK(
20920 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
20921 .FromJust());
20922 // Calling with environment record as base.
20923 TestReceiver(o, context->Global(), "ownfunc()");
20924 // Calling with no base.
20925 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20926
20927 // Checking foreign function return value.
20928 // Calling function using its call/apply methods.
20929 TestReceiver(i, foreign_context->Global(), "func.call()");
20930 TestReceiver(i, foreign_context->Global(), "func.apply()");
20931 // Calling function using another context's call/apply methods.
20932 TestReceiver(i, foreign_context->Global(),
20933 "Function.prototype.call.call(func)");
20934 TestReceiver(i, foreign_context->Global(),
20935 "Function.prototype.call.apply(func)");
20936 TestReceiver(i, foreign_context->Global(),
20937 "Function.prototype.apply.call(func)");
20938 TestReceiver(i, foreign_context->Global(),
20939 "Function.prototype.apply.apply(func)");
20940 // Making calls through built-in functions.
20941 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20942 // ToString(func()) is func()[0], i.e., the returned this.id.
20943 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
20944 .FromJust());
20945 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
20946 .FromJust());
20947 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
20948 .FromJust());
20949
20950 // Calling with environment record as base.
20951 TestReceiver(i, foreign_context->Global(), "func()");
20952 // Calling with no base.
20953 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20954 }
20955
20956
20957 uint8_t callback_fired = 0;
20958 uint8_t before_call_entered_callback_count1 = 0;
20959 uint8_t before_call_entered_callback_count2 = 0;
20960
20961
CallCompletedCallback1(v8::Isolate *)20962 void CallCompletedCallback1(v8::Isolate*) {
20963 v8::base::OS::Print("Firing callback 1.\n");
20964 callback_fired ^= 1; // Toggle first bit.
20965 }
20966
20967
CallCompletedCallback2(v8::Isolate *)20968 void CallCompletedCallback2(v8::Isolate*) {
20969 v8::base::OS::Print("Firing callback 2.\n");
20970 callback_fired ^= 2; // Toggle second bit.
20971 }
20972
20973
BeforeCallEnteredCallback1(v8::Isolate *)20974 void BeforeCallEnteredCallback1(v8::Isolate*) {
20975 v8::base::OS::Print("Firing before call entered callback 1.\n");
20976 before_call_entered_callback_count1++;
20977 }
20978
20979
BeforeCallEnteredCallback2(v8::Isolate *)20980 void BeforeCallEnteredCallback2(v8::Isolate*) {
20981 v8::base::OS::Print("Firing before call entered callback 2.\n");
20982 before_call_entered_callback_count2++;
20983 }
20984
20985
RecursiveCall(const v8::FunctionCallbackInfo<v8::Value> & args)20986 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20987 int32_t level =
20988 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
20989 if (level < 3) {
20990 level++;
20991 v8::base::OS::Print("Entering recursion level %d.\n", level);
20992 char script[64];
20993 i::Vector<char> script_vector(script, sizeof(script));
20994 i::SNPrintF(script_vector, "recursion(%d)", level);
20995 CompileRun(script_vector.start());
20996 v8::base::OS::Print("Leaving recursion level %d.\n", level);
20997 CHECK_EQ(0, callback_fired);
20998 } else {
20999 v8::base::OS::Print("Recursion ends.\n");
21000 CHECK_EQ(0, callback_fired);
21001 }
21002 }
21003
21004
TEST(CallCompletedCallback)21005 TEST(CallCompletedCallback) {
21006 LocalContext env;
21007 v8::HandleScope scope(env->GetIsolate());
21008 v8::Local<v8::FunctionTemplate> recursive_runtime =
21009 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21010 env->Global()
21011 ->Set(env.local(), v8_str("recursion"),
21012 recursive_runtime->GetFunction(env.local()).ToLocalChecked())
21013 .FromJust();
21014 // Adding the same callback a second time has no effect.
21015 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21016 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21017 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21018 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21019 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
21020 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21021 v8::base::OS::Print("--- Script (1) ---\n");
21022 callback_fired = 0;
21023 before_call_entered_callback_count1 = 0;
21024 before_call_entered_callback_count2 = 0;
21025 Local<Script> script =
21026 v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
21027 script->Run(env.local()).ToLocalChecked();
21028 CHECK_EQ(3, callback_fired);
21029 CHECK_EQ(4, before_call_entered_callback_count1);
21030 CHECK_EQ(4, before_call_entered_callback_count2);
21031
21032 v8::base::OS::Print("\n--- Script (2) ---\n");
21033 callback_fired = 0;
21034 before_call_entered_callback_count1 = 0;
21035 before_call_entered_callback_count2 = 0;
21036 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21037 env->GetIsolate()->RemoveBeforeCallEnteredCallback(
21038 BeforeCallEnteredCallback1);
21039 script->Run(env.local()).ToLocalChecked();
21040 CHECK_EQ(2, callback_fired);
21041 CHECK_EQ(0, before_call_entered_callback_count1);
21042 CHECK_EQ(4, before_call_entered_callback_count2);
21043
21044 v8::base::OS::Print("\n--- Function ---\n");
21045 callback_fired = 0;
21046 before_call_entered_callback_count1 = 0;
21047 before_call_entered_callback_count2 = 0;
21048 Local<Function> recursive_function = Local<Function>::Cast(
21049 env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
21050 v8::Local<Value> args[] = {v8_num(0)};
21051 recursive_function->Call(env.local(), env->Global(), 1, args)
21052 .ToLocalChecked();
21053 CHECK_EQ(2, callback_fired);
21054 CHECK_EQ(0, before_call_entered_callback_count1);
21055 CHECK_EQ(4, before_call_entered_callback_count2);
21056 }
21057
21058
CallCompletedCallbackNoException(v8::Isolate *)21059 void CallCompletedCallbackNoException(v8::Isolate*) {
21060 v8::HandleScope scope(CcTest::isolate());
21061 CompileRun("1+1;");
21062 }
21063
21064
CallCompletedCallbackException(v8::Isolate *)21065 void CallCompletedCallbackException(v8::Isolate*) {
21066 v8::HandleScope scope(CcTest::isolate());
21067 CompileRun("throw 'second exception';");
21068 }
21069
21070
TEST(CallCompletedCallbackOneException)21071 TEST(CallCompletedCallbackOneException) {
21072 LocalContext env;
21073 v8::HandleScope scope(env->GetIsolate());
21074 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21075 CompileRun("throw 'exception';");
21076 }
21077
21078
TEST(CallCompletedCallbackTwoExceptions)21079 TEST(CallCompletedCallbackTwoExceptions) {
21080 LocalContext env;
21081 v8::HandleScope scope(env->GetIsolate());
21082 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21083 CompileRun("throw 'first exception';");
21084 }
21085
21086
MicrotaskOne(const v8::FunctionCallbackInfo<Value> & info)21087 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21088 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21089 v8::HandleScope scope(info.GetIsolate());
21090 v8::MicrotasksScope microtasks(info.GetIsolate(),
21091 v8::MicrotasksScope::kDoNotRunMicrotasks);
21092 CompileRun("ext1Calls++;");
21093 }
21094
21095
MicrotaskTwo(const v8::FunctionCallbackInfo<Value> & info)21096 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21097 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21098 v8::HandleScope scope(info.GetIsolate());
21099 v8::MicrotasksScope microtasks(info.GetIsolate(),
21100 v8::MicrotasksScope::kDoNotRunMicrotasks);
21101 CompileRun("ext2Calls++;");
21102 }
21103
21104
21105 void* g_passed_to_three = NULL;
21106
21107
MicrotaskThree(void * data)21108 static void MicrotaskThree(void* data) {
21109 g_passed_to_three = data;
21110 }
21111
21112
TEST(EnqueueMicrotask)21113 TEST(EnqueueMicrotask) {
21114 LocalContext env;
21115 v8::HandleScope scope(env->GetIsolate());
21116 CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
21117 CompileRun(
21118 "var ext1Calls = 0;"
21119 "var ext2Calls = 0;");
21120 CompileRun("1+1;");
21121 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21122 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21123
21124 env->GetIsolate()->EnqueueMicrotask(
21125 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21126 CompileRun("1+1;");
21127 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21128 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21129
21130 env->GetIsolate()->EnqueueMicrotask(
21131 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21132 env->GetIsolate()->EnqueueMicrotask(
21133 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21134 CompileRun("1+1;");
21135 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21136 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21137
21138 env->GetIsolate()->EnqueueMicrotask(
21139 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21140 CompileRun("1+1;");
21141 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21142 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21143
21144 CompileRun("1+1;");
21145 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21146 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21147
21148 g_passed_to_three = NULL;
21149 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21150 CompileRun("1+1;");
21151 CHECK(!g_passed_to_three);
21152 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21153 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21154
21155 int dummy;
21156 env->GetIsolate()->EnqueueMicrotask(
21157 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21158 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21159 env->GetIsolate()->EnqueueMicrotask(
21160 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21161 CompileRun("1+1;");
21162 CHECK_EQ(&dummy, g_passed_to_three);
21163 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21164 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21165 g_passed_to_three = NULL;
21166 }
21167
21168
MicrotaskExceptionOne(const v8::FunctionCallbackInfo<Value> & info)21169 static void MicrotaskExceptionOne(
21170 const v8::FunctionCallbackInfo<Value>& info) {
21171 v8::HandleScope scope(info.GetIsolate());
21172 CompileRun("exception1Calls++;");
21173 info.GetIsolate()->ThrowException(
21174 v8::Exception::Error(v8_str("first")));
21175 }
21176
21177
MicrotaskExceptionTwo(const v8::FunctionCallbackInfo<Value> & info)21178 static void MicrotaskExceptionTwo(
21179 const v8::FunctionCallbackInfo<Value>& info) {
21180 v8::HandleScope scope(info.GetIsolate());
21181 CompileRun("exception2Calls++;");
21182 info.GetIsolate()->ThrowException(
21183 v8::Exception::Error(v8_str("second")));
21184 }
21185
21186
TEST(RunMicrotasksIgnoresThrownExceptions)21187 TEST(RunMicrotasksIgnoresThrownExceptions) {
21188 LocalContext env;
21189 v8::Isolate* isolate = env->GetIsolate();
21190 v8::HandleScope scope(isolate);
21191 CompileRun(
21192 "var exception1Calls = 0;"
21193 "var exception2Calls = 0;");
21194 isolate->EnqueueMicrotask(
21195 Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
21196 isolate->EnqueueMicrotask(
21197 Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
21198 TryCatch try_catch(isolate);
21199 CompileRun("1+1;");
21200 CHECK(!try_catch.HasCaught());
21201 CHECK_EQ(1,
21202 CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
21203 CHECK_EQ(1,
21204 CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
21205 }
21206
21207
21208 uint8_t microtasks_completed_callback_count = 0;
21209
21210
MicrotasksCompletedCallback(v8::Isolate * isolate)21211 static void MicrotasksCompletedCallback(v8::Isolate* isolate) {
21212 ++microtasks_completed_callback_count;
21213 }
21214
21215
TEST(SetAutorunMicrotasks)21216 TEST(SetAutorunMicrotasks) {
21217 LocalContext env;
21218 v8::HandleScope scope(env->GetIsolate());
21219 env->GetIsolate()->AddMicrotasksCompletedCallback(
21220 &MicrotasksCompletedCallback);
21221 CompileRun(
21222 "var ext1Calls = 0;"
21223 "var ext2Calls = 0;");
21224 CompileRun("1+1;");
21225 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21226 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21227 CHECK_EQ(0u, microtasks_completed_callback_count);
21228
21229 env->GetIsolate()->EnqueueMicrotask(
21230 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21231 CompileRun("1+1;");
21232 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21233 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21234 CHECK_EQ(1u, microtasks_completed_callback_count);
21235
21236 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21237 env->GetIsolate()->EnqueueMicrotask(
21238 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21239 env->GetIsolate()->EnqueueMicrotask(
21240 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21241 CompileRun("1+1;");
21242 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21243 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21244 CHECK_EQ(1u, microtasks_completed_callback_count);
21245
21246 env->GetIsolate()->RunMicrotasks();
21247 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21248 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21249 CHECK_EQ(2u, microtasks_completed_callback_count);
21250
21251 env->GetIsolate()->EnqueueMicrotask(
21252 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21253 CompileRun("1+1;");
21254 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21255 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21256 CHECK_EQ(2u, microtasks_completed_callback_count);
21257
21258 env->GetIsolate()->RunMicrotasks();
21259 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21260 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21261 CHECK_EQ(3u, microtasks_completed_callback_count);
21262
21263 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21264 env->GetIsolate()->EnqueueMicrotask(
21265 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21266 CompileRun("1+1;");
21267 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21268 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21269 CHECK_EQ(4u, microtasks_completed_callback_count);
21270
21271 env->GetIsolate()->EnqueueMicrotask(
21272 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21273 {
21274 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21275 CompileRun("1+1;");
21276 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21277 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21278 CHECK_EQ(4u, microtasks_completed_callback_count);
21279 }
21280
21281 CompileRun("1+1;");
21282 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21283 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21284 CHECK_EQ(5u, microtasks_completed_callback_count);
21285
21286 env->GetIsolate()->RemoveMicrotasksCompletedCallback(
21287 &MicrotasksCompletedCallback);
21288 env->GetIsolate()->EnqueueMicrotask(
21289 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21290 CompileRun("1+1;");
21291 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21292 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21293 CHECK_EQ(5u, microtasks_completed_callback_count);
21294 }
21295
21296
TEST(RunMicrotasksWithoutEnteringContext)21297 TEST(RunMicrotasksWithoutEnteringContext) {
21298 v8::Isolate* isolate = CcTest::isolate();
21299 HandleScope handle_scope(isolate);
21300 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21301 Local<Context> context = Context::New(isolate);
21302 {
21303 Context::Scope context_scope(context);
21304 CompileRun("var ext1Calls = 0;");
21305 isolate->EnqueueMicrotask(
21306 Function::New(context, MicrotaskOne).ToLocalChecked());
21307 }
21308 isolate->RunMicrotasks();
21309 {
21310 Context::Scope context_scope(context);
21311 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
21312 }
21313 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21314 }
21315
21316
TEST(ScopedMicrotasks)21317 TEST(ScopedMicrotasks) {
21318 LocalContext env;
21319 v8::HandleScope handles(env->GetIsolate());
21320 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
21321 {
21322 v8::MicrotasksScope scope1(env->GetIsolate(),
21323 v8::MicrotasksScope::kDoNotRunMicrotasks);
21324 env->GetIsolate()->EnqueueMicrotask(
21325 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21326 CompileRun(
21327 "var ext1Calls = 0;"
21328 "var ext2Calls = 0;");
21329 CompileRun("1+1;");
21330 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21331 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21332 {
21333 v8::MicrotasksScope scope2(env->GetIsolate(),
21334 v8::MicrotasksScope::kRunMicrotasks);
21335 CompileRun("1+1;");
21336 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21337 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21338 {
21339 v8::MicrotasksScope scope3(env->GetIsolate(),
21340 v8::MicrotasksScope::kRunMicrotasks);
21341 CompileRun("1+1;");
21342 CHECK_EQ(0,
21343 CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21344 CHECK_EQ(0,
21345 CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21346 }
21347 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21348 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21349 }
21350 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21351 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21352 env->GetIsolate()->EnqueueMicrotask(
21353 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21354 }
21355
21356 {
21357 v8::MicrotasksScope scope(env->GetIsolate(),
21358 v8::MicrotasksScope::kDoNotRunMicrotasks);
21359 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21360 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21361 }
21362
21363 {
21364 v8::MicrotasksScope scope1(env->GetIsolate(),
21365 v8::MicrotasksScope::kRunMicrotasks);
21366 CompileRun("1+1;");
21367 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21368 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21369 {
21370 v8::MicrotasksScope scope2(env->GetIsolate(),
21371 v8::MicrotasksScope::kDoNotRunMicrotasks);
21372 }
21373 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21374 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21375 }
21376
21377 {
21378 v8::MicrotasksScope scope(env->GetIsolate(),
21379 v8::MicrotasksScope::kDoNotRunMicrotasks);
21380 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21381 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21382 env->GetIsolate()->EnqueueMicrotask(
21383 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21384 }
21385
21386 {
21387 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21388 {
21389 v8::MicrotasksScope scope2(env->GetIsolate(),
21390 v8::MicrotasksScope::kRunMicrotasks);
21391 }
21392 v8::MicrotasksScope scope3(env->GetIsolate(),
21393 v8::MicrotasksScope::kDoNotRunMicrotasks);
21394 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21395 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21396 }
21397
21398 {
21399 v8::MicrotasksScope scope1(env->GetIsolate(),
21400 v8::MicrotasksScope::kRunMicrotasks);
21401 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21402 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21403 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21404 }
21405
21406 {
21407 v8::MicrotasksScope scope(env->GetIsolate(),
21408 v8::MicrotasksScope::kDoNotRunMicrotasks);
21409 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21410 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21411 }
21412
21413 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21414
21415 {
21416 v8::MicrotasksScope scope(env->GetIsolate(),
21417 v8::MicrotasksScope::kDoNotRunMicrotasks);
21418 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21419 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21420 env->GetIsolate()->EnqueueMicrotask(
21421 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21422 }
21423
21424 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21425
21426 {
21427 v8::MicrotasksScope scope(env->GetIsolate(),
21428 v8::MicrotasksScope::kDoNotRunMicrotasks);
21429 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21430 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21431 }
21432
21433 env->GetIsolate()->EnqueueMicrotask(
21434 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21435 {
21436 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21437 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21438 v8::MicrotasksScope scope2(env->GetIsolate(),
21439 v8::MicrotasksScope::kDoNotRunMicrotasks);
21440 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21441 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21442 }
21443
21444 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21445
21446 {
21447 v8::MicrotasksScope scope(env->GetIsolate(),
21448 v8::MicrotasksScope::kDoNotRunMicrotasks);
21449 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21450 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21451 }
21452
21453 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21454 }
21455
21456 #ifdef ENABLE_DISASSEMBLER
21457 // FLAG_test_primary_stub_cache and FLAG_test_secondary_stub_cache are read
21458 // only when ENABLE_DISASSEMBLER is not defined.
21459
21460 namespace {
21461
21462 int probes_counter = 0;
21463 int misses_counter = 0;
21464 int updates_counter = 0;
21465
LookupCounter(const char * name)21466 int* LookupCounter(const char* name) {
21467 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21468 return &probes_counter;
21469 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21470 return &misses_counter;
21471 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21472 return &updates_counter;
21473 }
21474 return NULL;
21475 }
21476
21477 const char* kMegamorphicTestProgram =
21478 "function CreateClass(name) {\n"
21479 " var src = \n"
21480 " ` function ${name}() {};` +\n"
21481 " ` ${name}.prototype.foo = function() {};` +\n"
21482 " ` ${name};\\n`;\n"
21483 " return (0, eval)(src);\n"
21484 "}\n"
21485 "function fooify(obj) { obj.foo(); };\n"
21486 "var objs = [];\n"
21487 "for (var i = 0; i < 6; i++) {\n"
21488 " var Class = CreateClass('Class' + i);\n"
21489 " var obj = new Class();\n"
21490 " objs.push(obj);\n"
21491 "}\n"
21492 "for (var i = 0; i < 10000; i++) {\n"
21493 " for (var obj of objs) {\n"
21494 " fooify(obj);\n"
21495 " }\n"
21496 "}\n";
21497
StubCacheHelper(bool primary)21498 void StubCacheHelper(bool primary) {
21499 i::FLAG_native_code_counters = true;
21500 if (primary) {
21501 i::FLAG_test_primary_stub_cache = true;
21502 } else {
21503 i::FLAG_test_secondary_stub_cache = true;
21504 }
21505 i::FLAG_crankshaft = false;
21506 i::FLAG_turbo = false;
21507 v8::Isolate::CreateParams create_params;
21508 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21509 create_params.counter_lookup_callback = LookupCounter;
21510 v8::Isolate* isolate = v8::Isolate::New(create_params);
21511 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21512
21513 if (!i_isolate->snapshot_available()) {
21514 // The test is valid only for no-snapshot mode.
21515 v8::Isolate::Scope isolate_scope(isolate);
21516 LocalContext env(isolate);
21517 v8::HandleScope scope(isolate);
21518
21519 int initial_probes = probes_counter;
21520 int initial_misses = misses_counter;
21521 int initial_updates = updates_counter;
21522 CompileRun(kMegamorphicTestProgram);
21523 int probes = probes_counter - initial_probes;
21524 int misses = misses_counter - initial_misses;
21525 int updates = updates_counter - initial_updates;
21526 const int kClassesCount = 6;
21527 // Check that updates and misses counts are bounded.
21528 CHECK_LE(kClassesCount, updates);
21529 CHECK_LT(updates, kClassesCount * 3);
21530 CHECK_LE(1, misses);
21531 CHECK_LT(misses, kClassesCount * 2);
21532 // 2 is for PREMONOMORPHIC and MONOMORPHIC states,
21533 // 4 is for POLYMORPHIC states,
21534 // and all the others probes are for MEGAMORPHIC state.
21535 CHECK_EQ(10000 * kClassesCount - 2 - 4, probes);
21536 }
21537 isolate->Dispose();
21538 }
21539
21540 } // namespace
21541
UNINITIALIZED_TEST(PrimaryStubCache)21542 UNINITIALIZED_TEST(PrimaryStubCache) { StubCacheHelper(true); }
21543
UNINITIALIZED_TEST(SecondaryStubCache)21544 UNINITIALIZED_TEST(SecondaryStubCache) { StubCacheHelper(false); }
21545
21546 #endif // ENABLE_DISASSEMBLER
21547
21548 #ifdef DEBUG
21549 static int cow_arrays_created_runtime = 0;
21550
21551
LookupCounterCOWArrays(const char * name)21552 static int* LookupCounterCOWArrays(const char* name) {
21553 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21554 return &cow_arrays_created_runtime;
21555 }
21556 return NULL;
21557 }
21558 #endif
21559
21560
TEST(CheckCOWArraysCreatedRuntimeCounter)21561 TEST(CheckCOWArraysCreatedRuntimeCounter) {
21562 #ifdef DEBUG
21563 i::FLAG_native_code_counters = true;
21564 LocalContext env;
21565 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21566 v8::HandleScope scope(env->GetIsolate());
21567 int initial_cow_arrays = cow_arrays_created_runtime;
21568 CompileRun("var o = [1, 2, 3];");
21569 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21570 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21571 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21572 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21573 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21574 #endif
21575 }
21576
21577
TEST(StaticGetters)21578 TEST(StaticGetters) {
21579 LocalContext context;
21580 i::Factory* factory = CcTest::i_isolate()->factory();
21581 v8::Isolate* isolate = CcTest::isolate();
21582 v8::HandleScope scope(isolate);
21583 i::Handle<i::Object> undefined_value = factory->undefined_value();
21584 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21585 i::Handle<i::Object> null_value = factory->null_value();
21586 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21587 i::Handle<i::Object> true_value = factory->true_value();
21588 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21589 i::Handle<i::Object> false_value = factory->false_value();
21590 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21591 }
21592
21593
UNINITIALIZED_TEST(IsolateEmbedderData)21594 UNINITIALIZED_TEST(IsolateEmbedderData) {
21595 CcTest::DisableAutomaticDispose();
21596 v8::Isolate::CreateParams create_params;
21597 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21598 v8::Isolate* isolate = v8::Isolate::New(create_params);
21599 isolate->Enter();
21600 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21601 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21602 CHECK(!isolate->GetData(slot));
21603 CHECK(!i_isolate->GetData(slot));
21604 }
21605 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21606 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21607 isolate->SetData(slot, data);
21608 }
21609 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21610 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21611 CHECK_EQ(data, isolate->GetData(slot));
21612 CHECK_EQ(data, i_isolate->GetData(slot));
21613 }
21614 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21615 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21616 isolate->SetData(slot, data);
21617 }
21618 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21619 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21620 CHECK_EQ(data, isolate->GetData(slot));
21621 CHECK_EQ(data, i_isolate->GetData(slot));
21622 }
21623 isolate->Exit();
21624 isolate->Dispose();
21625 }
21626
21627
TEST(StringEmpty)21628 TEST(StringEmpty) {
21629 LocalContext context;
21630 i::Factory* factory = CcTest::i_isolate()->factory();
21631 v8::Isolate* isolate = CcTest::isolate();
21632 v8::HandleScope scope(isolate);
21633 i::Handle<i::Object> empty_string = factory->empty_string();
21634 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21635 }
21636
21637
21638 static int instance_checked_getter_count = 0;
InstanceCheckedGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)21639 static void InstanceCheckedGetter(
21640 Local<String> name,
21641 const v8::PropertyCallbackInfo<v8::Value>& info) {
21642 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21643 .FromJust());
21644 instance_checked_getter_count++;
21645 info.GetReturnValue().Set(v8_num(11));
21646 }
21647
21648
21649 static int instance_checked_setter_count = 0;
InstanceCheckedSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)21650 static void InstanceCheckedSetter(Local<String> name,
21651 Local<Value> value,
21652 const v8::PropertyCallbackInfo<void>& info) {
21653 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21654 .FromJust());
21655 CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
21656 .FromJust());
21657 instance_checked_setter_count++;
21658 }
21659
21660
CheckInstanceCheckedResult(int getters,int setters,bool expects_callbacks,TryCatch * try_catch)21661 static void CheckInstanceCheckedResult(int getters, int setters,
21662 bool expects_callbacks,
21663 TryCatch* try_catch) {
21664 if (expects_callbacks) {
21665 CHECK(!try_catch->HasCaught());
21666 CHECK_EQ(getters, instance_checked_getter_count);
21667 CHECK_EQ(setters, instance_checked_setter_count);
21668 } else {
21669 CHECK(try_catch->HasCaught());
21670 CHECK_EQ(0, instance_checked_getter_count);
21671 CHECK_EQ(0, instance_checked_setter_count);
21672 }
21673 try_catch->Reset();
21674 }
21675
21676
CheckInstanceCheckedAccessors(bool expects_callbacks)21677 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21678 instance_checked_getter_count = 0;
21679 instance_checked_setter_count = 0;
21680 TryCatch try_catch(CcTest::isolate());
21681
21682 // Test path through generic runtime code.
21683 CompileRun("obj.foo");
21684 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21685 CompileRun("obj.foo = 23");
21686 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21687
21688 // Test path through generated LoadIC and StoredIC.
21689 CompileRun("function test_get(o) { o.foo; }"
21690 "test_get(obj);");
21691 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21692 CompileRun("test_get(obj);");
21693 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21694 CompileRun("test_get(obj);");
21695 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21696 CompileRun("function test_set(o) { o.foo = 23; }"
21697 "test_set(obj);");
21698 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21699 CompileRun("test_set(obj);");
21700 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21701 CompileRun("test_set(obj);");
21702 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21703
21704 // Test path through optimized code.
21705 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21706 "test_get(obj);");
21707 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21708 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21709 "test_set(obj);");
21710 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21711
21712 // Cleanup so that closures start out fresh in next check.
21713 CompileRun("%DeoptimizeFunction(test_get);"
21714 "%ClearFunctionTypeFeedback(test_get);"
21715 "%DeoptimizeFunction(test_set);"
21716 "%ClearFunctionTypeFeedback(test_set);");
21717 }
21718
21719
THREADED_TEST(InstanceCheckOnInstanceAccessor)21720 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21721 v8::internal::FLAG_allow_natives_syntax = true;
21722 LocalContext context;
21723 v8::HandleScope scope(context->GetIsolate());
21724
21725 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21726 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21727 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
21728 Local<Value>(), v8::DEFAULT, v8::None,
21729 v8::AccessorSignature::New(context->GetIsolate(), templ));
21730 CHECK(context->Global()
21731 ->Set(context.local(), v8_str("f"),
21732 templ->GetFunction(context.local()).ToLocalChecked())
21733 .FromJust());
21734
21735 printf("Testing positive ...\n");
21736 CompileRun("var obj = new f();");
21737 CHECK(templ->HasInstance(
21738 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21739 CheckInstanceCheckedAccessors(true);
21740
21741 printf("Testing negative ...\n");
21742 CompileRun("var obj = {};"
21743 "obj.__proto__ = new f();");
21744 CHECK(!templ->HasInstance(
21745 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21746 CheckInstanceCheckedAccessors(false);
21747 }
21748
21749
EmptyInterceptorGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)21750 static void EmptyInterceptorGetter(
21751 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
21752
21753
EmptyInterceptorSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)21754 static void EmptyInterceptorSetter(
21755 Local<String> name, Local<Value> value,
21756 const v8::PropertyCallbackInfo<v8::Value>& info) {}
21757
21758
THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor)21759 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21760 v8::internal::FLAG_allow_natives_syntax = true;
21761 LocalContext context;
21762 v8::HandleScope scope(context->GetIsolate());
21763
21764 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21765 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21766 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
21767 EmptyInterceptorSetter);
21768 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
21769 Local<Value>(), v8::DEFAULT, v8::None,
21770 v8::AccessorSignature::New(context->GetIsolate(), templ));
21771 CHECK(context->Global()
21772 ->Set(context.local(), v8_str("f"),
21773 templ->GetFunction(context.local()).ToLocalChecked())
21774 .FromJust());
21775
21776 printf("Testing positive ...\n");
21777 CompileRun("var obj = new f();");
21778 CHECK(templ->HasInstance(
21779 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21780 CheckInstanceCheckedAccessors(true);
21781
21782 printf("Testing negative ...\n");
21783 CompileRun("var obj = {};"
21784 "obj.__proto__ = new f();");
21785 CHECK(!templ->HasInstance(
21786 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21787 CheckInstanceCheckedAccessors(false);
21788 }
21789
21790
THREADED_TEST(InstanceCheckOnPrototypeAccessor)21791 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21792 v8::internal::FLAG_allow_natives_syntax = true;
21793 LocalContext context;
21794 v8::HandleScope scope(context->GetIsolate());
21795
21796 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21797 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21798 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21799 InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
21800 v8::None,
21801 v8::AccessorSignature::New(context->GetIsolate(), templ));
21802 CHECK(context->Global()
21803 ->Set(context.local(), v8_str("f"),
21804 templ->GetFunction(context.local()).ToLocalChecked())
21805 .FromJust());
21806
21807 printf("Testing positive ...\n");
21808 CompileRun("var obj = new f();");
21809 CHECK(templ->HasInstance(
21810 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21811 CheckInstanceCheckedAccessors(true);
21812
21813 printf("Testing negative ...\n");
21814 CompileRun("var obj = {};"
21815 "obj.__proto__ = new f();");
21816 CHECK(!templ->HasInstance(
21817 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21818 CheckInstanceCheckedAccessors(false);
21819
21820 printf("Testing positive with modified prototype chain ...\n");
21821 CompileRun("var obj = new f();"
21822 "var pro = {};"
21823 "pro.__proto__ = obj.__proto__;"
21824 "obj.__proto__ = pro;");
21825 CHECK(templ->HasInstance(
21826 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
21827 CheckInstanceCheckedAccessors(true);
21828 }
21829
21830
TEST(TryFinallyMessage)21831 TEST(TryFinallyMessage) {
21832 LocalContext context;
21833 v8::HandleScope scope(context->GetIsolate());
21834 {
21835 // Test that the original error message is not lost if there is a
21836 // recursive call into Javascript is done in the finally block, e.g. to
21837 // initialize an IC. (crbug.com/129171)
21838 TryCatch try_catch(context->GetIsolate());
21839 const char* trigger_ic =
21840 "try { \n"
21841 " throw new Error('test'); \n"
21842 "} finally { \n"
21843 " var x = 0; \n"
21844 " x++; \n" // Trigger an IC initialization here.
21845 "} \n";
21846 CompileRun(trigger_ic);
21847 CHECK(try_catch.HasCaught());
21848 Local<Message> message = try_catch.Message();
21849 CHECK(!message.IsEmpty());
21850 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
21851 }
21852
21853 {
21854 // Test that the original exception message is indeed overwritten if
21855 // a new error is thrown in the finally block.
21856 TryCatch try_catch(context->GetIsolate());
21857 const char* throw_again =
21858 "try { \n"
21859 " throw new Error('test'); \n"
21860 "} finally { \n"
21861 " var x = 0; \n"
21862 " x++; \n"
21863 " throw new Error('again'); \n" // This is the new uncaught error.
21864 "} \n";
21865 CompileRun(throw_again);
21866 CHECK(try_catch.HasCaught());
21867 Local<Message> message = try_catch.Message();
21868 CHECK(!message.IsEmpty());
21869 CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
21870 }
21871 }
21872
21873
Helper137002(bool do_store,bool polymorphic,bool remove_accessor,bool interceptor)21874 static void Helper137002(bool do_store,
21875 bool polymorphic,
21876 bool remove_accessor,
21877 bool interceptor) {
21878 LocalContext context;
21879 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21880 if (interceptor) {
21881 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
21882 FooSetInterceptor));
21883 } else {
21884 templ->SetAccessor(v8_str("foo"),
21885 GetterWhichReturns42,
21886 SetterWhichSetsYOnThisTo23);
21887 }
21888 CHECK(context->Global()
21889 ->Set(context.local(), v8_str("obj"),
21890 templ->NewInstance(context.local()).ToLocalChecked())
21891 .FromJust());
21892
21893 // Turn monomorphic on slow object with native accessor, then turn
21894 // polymorphic, finally optimize to create negative lookup and fail.
21895 CompileRun(do_store ?
21896 "function f(x) { x.foo = void 0; }" :
21897 "function f(x) { return x.foo; }");
21898 CompileRun("obj.y = void 0;");
21899 if (!interceptor) {
21900 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21901 }
21902 CompileRun("obj.__proto__ = null;"
21903 "f(obj); f(obj); f(obj);");
21904 if (polymorphic) {
21905 CompileRun("f({});");
21906 }
21907 CompileRun("obj.y = void 0;"
21908 "%OptimizeFunctionOnNextCall(f);");
21909 if (remove_accessor) {
21910 CompileRun("delete obj.foo;");
21911 }
21912 CompileRun("var result = f(obj);");
21913 if (do_store) {
21914 CompileRun("result = obj.y;");
21915 }
21916 if (remove_accessor && !interceptor) {
21917 CHECK(context->Global()
21918 ->Get(context.local(), v8_str("result"))
21919 .ToLocalChecked()
21920 ->IsUndefined());
21921 } else {
21922 CHECK_EQ(do_store ? 23 : 42, context->Global()
21923 ->Get(context.local(), v8_str("result"))
21924 .ToLocalChecked()
21925 ->Int32Value(context.local())
21926 .FromJust());
21927 }
21928 }
21929
21930
THREADED_TEST(Regress137002a)21931 THREADED_TEST(Regress137002a) {
21932 i::FLAG_allow_natives_syntax = true;
21933 i::FLAG_compilation_cache = false;
21934 v8::HandleScope scope(CcTest::isolate());
21935 for (int i = 0; i < 16; i++) {
21936 Helper137002(i & 8, i & 4, i & 2, i & 1);
21937 }
21938 }
21939
21940
THREADED_TEST(Regress137002b)21941 THREADED_TEST(Regress137002b) {
21942 i::FLAG_allow_natives_syntax = true;
21943 LocalContext context;
21944 v8::Isolate* isolate = context->GetIsolate();
21945 v8::HandleScope scope(isolate);
21946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21947 templ->SetAccessor(v8_str("foo"),
21948 GetterWhichReturns42,
21949 SetterWhichSetsYOnThisTo23);
21950 CHECK(context->Global()
21951 ->Set(context.local(), v8_str("obj"),
21952 templ->NewInstance(context.local()).ToLocalChecked())
21953 .FromJust());
21954
21955 // Turn monomorphic on slow object with native accessor, then just
21956 // delete the property and fail.
21957 CompileRun("function load(x) { return x.foo; }"
21958 "function store(x) { x.foo = void 0; }"
21959 "function keyed_load(x, key) { return x[key]; }"
21960 // Second version of function has a different source (add void 0)
21961 // so that it does not share code with the first version. This
21962 // ensures that the ICs are monomorphic.
21963 "function load2(x) { void 0; return x.foo; }"
21964 "function store2(x) { void 0; x.foo = void 0; }"
21965 "function keyed_load2(x, key) { void 0; return x[key]; }"
21966
21967 "obj.y = void 0;"
21968 "obj.__proto__ = null;"
21969 "var subobj = {};"
21970 "subobj.y = void 0;"
21971 "subobj.__proto__ = obj;"
21972 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21973
21974 // Make the ICs monomorphic.
21975 "load(obj); load(obj);"
21976 "load2(subobj); load2(subobj);"
21977 "store(obj); store(obj);"
21978 "store2(subobj); store2(subobj);"
21979 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21980 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21981
21982 // Actually test the shiny new ICs and better not crash. This
21983 // serves as a regression test for issue 142088 as well.
21984 "load(obj);"
21985 "load2(subobj);"
21986 "store(obj);"
21987 "store2(subobj);"
21988 "keyed_load(obj, 'foo');"
21989 "keyed_load2(subobj, 'foo');"
21990
21991 // Delete the accessor. It better not be called any more now.
21992 "delete obj.foo;"
21993 "obj.y = void 0;"
21994 "subobj.y = void 0;"
21995
21996 "var load_result = load(obj);"
21997 "var load_result2 = load2(subobj);"
21998 "var keyed_load_result = keyed_load(obj, 'foo');"
21999 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22000 "store(obj);"
22001 "store2(subobj);"
22002 "var y_from_obj = obj.y;"
22003 "var y_from_subobj = subobj.y;");
22004 CHECK(context->Global()
22005 ->Get(context.local(), v8_str("load_result"))
22006 .ToLocalChecked()
22007 ->IsUndefined());
22008 CHECK(context->Global()
22009 ->Get(context.local(), v8_str("load_result2"))
22010 .ToLocalChecked()
22011 ->IsUndefined());
22012 CHECK(context->Global()
22013 ->Get(context.local(), v8_str("keyed_load_result"))
22014 .ToLocalChecked()
22015 ->IsUndefined());
22016 CHECK(context->Global()
22017 ->Get(context.local(), v8_str("keyed_load_result2"))
22018 .ToLocalChecked()
22019 ->IsUndefined());
22020 CHECK(context->Global()
22021 ->Get(context.local(), v8_str("y_from_obj"))
22022 .ToLocalChecked()
22023 ->IsUndefined());
22024 CHECK(context->Global()
22025 ->Get(context.local(), v8_str("y_from_subobj"))
22026 .ToLocalChecked()
22027 ->IsUndefined());
22028 }
22029
22030
THREADED_TEST(Regress142088)22031 THREADED_TEST(Regress142088) {
22032 i::FLAG_allow_natives_syntax = true;
22033 LocalContext context;
22034 v8::Isolate* isolate = context->GetIsolate();
22035 v8::HandleScope scope(isolate);
22036 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22037 templ->SetAccessor(v8_str("foo"),
22038 GetterWhichReturns42,
22039 SetterWhichSetsYOnThisTo23);
22040 CHECK(context->Global()
22041 ->Set(context.local(), v8_str("obj"),
22042 templ->NewInstance(context.local()).ToLocalChecked())
22043 .FromJust());
22044
22045 CompileRun("function load(x) { return x.foo; }"
22046 "var o = Object.create(obj);"
22047 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22048 "load(o); load(o); load(o); load(o);");
22049 }
22050
22051
THREADED_TEST(Regress137496)22052 THREADED_TEST(Regress137496) {
22053 i::FLAG_expose_gc = true;
22054 LocalContext context;
22055 v8::HandleScope scope(context->GetIsolate());
22056
22057 // Compile a try-finally clause where the finally block causes a GC
22058 // while there still is a message pending for external reporting.
22059 TryCatch try_catch(context->GetIsolate());
22060 try_catch.SetVerbose(true);
22061 CompileRun("try { throw new Error(); } finally { gc(); }");
22062 CHECK(try_catch.HasCaught());
22063 }
22064
22065
THREADED_TEST(Regress157124)22066 THREADED_TEST(Regress157124) {
22067 LocalContext context;
22068 v8::Isolate* isolate = context->GetIsolate();
22069 v8::HandleScope scope(isolate);
22070 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22071 Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
22072 obj->GetIdentityHash();
22073 obj->DeletePrivate(context.local(),
22074 v8::Private::ForApi(isolate, v8_str("Bug")))
22075 .FromJust();
22076 }
22077
22078
THREADED_TEST(Regress2535)22079 THREADED_TEST(Regress2535) {
22080 LocalContext context;
22081 v8::HandleScope scope(context->GetIsolate());
22082 Local<Value> set_value = CompileRun("new Set();");
22083 Local<Object> set_object(Local<Object>::Cast(set_value));
22084 CHECK_EQ(0, set_object->InternalFieldCount());
22085 Local<Value> map_value = CompileRun("new Map();");
22086 Local<Object> map_object(Local<Object>::Cast(map_value));
22087 CHECK_EQ(0, map_object->InternalFieldCount());
22088 }
22089
22090
THREADED_TEST(Regress2746)22091 THREADED_TEST(Regress2746) {
22092 LocalContext context;
22093 v8::Isolate* isolate = context->GetIsolate();
22094 v8::HandleScope scope(isolate);
22095 Local<Object> obj = Object::New(isolate);
22096 Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
22097 CHECK(
22098 obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
22099 Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
22100 CHECK(!value.IsEmpty());
22101 CHECK(value->IsUndefined());
22102 }
22103
22104
THREADED_TEST(Regress260106)22105 THREADED_TEST(Regress260106) {
22106 LocalContext context;
22107 v8::Isolate* isolate = context->GetIsolate();
22108 v8::HandleScope scope(isolate);
22109 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22110 DummyCallHandler);
22111 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22112 Local<Function> function =
22113 templ->GetFunction(context.local()).ToLocalChecked();
22114 CHECK(!function.IsEmpty());
22115 CHECK(function->IsFunction());
22116 }
22117
THREADED_TEST(JSONParseObject)22118 THREADED_TEST(JSONParseObject) {
22119 LocalContext context;
22120 HandleScope scope(context->GetIsolate());
22121 Local<Value> obj =
22122 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22123 Local<Object> global = context->Global();
22124 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22125 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22126 }
22127
THREADED_TEST(JSONParseNumber)22128 THREADED_TEST(JSONParseNumber) {
22129 LocalContext context;
22130 HandleScope scope(context->GetIsolate());
22131 Local<Value> obj =
22132 v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
22133 Local<Object> global = context->Global();
22134 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22135 ExpectString("JSON.stringify(obj)", "42");
22136 }
22137
THREADED_TEST(JSONStringifyObject)22138 THREADED_TEST(JSONStringifyObject) {
22139 LocalContext context;
22140 HandleScope scope(context->GetIsolate());
22141 Local<Value> value =
22142 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22143 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22144 Local<Object> global = context->Global();
22145 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22146 Local<String> json =
22147 v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
22148 v8::String::Utf8Value utf8(json);
22149 ExpectString("JSON.stringify(obj)", *utf8);
22150 }
22151
THREADED_TEST(JSONStringifyObjectWithGap)22152 THREADED_TEST(JSONStringifyObjectWithGap) {
22153 LocalContext context;
22154 HandleScope scope(context->GetIsolate());
22155 Local<Value> value =
22156 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22157 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22158 Local<Object> global = context->Global();
22159 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22160 Local<String> json =
22161 v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
22162 v8::String::Utf8Value utf8(json);
22163 ExpectString("JSON.stringify(obj, null, '*')", *utf8);
22164 }
22165
22166 #if V8_OS_POSIX && !V8_OS_NACL
22167 class ThreadInterruptTest {
22168 public:
ThreadInterruptTest()22169 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
~ThreadInterruptTest()22170 ~ThreadInterruptTest() {}
22171
RunTest()22172 void RunTest() {
22173 InterruptThread i_thread(this);
22174 i_thread.Start();
22175
22176 sem_.Wait();
22177 CHECK_EQ(kExpectedValue, sem_value_);
22178 }
22179
22180 private:
22181 static const int kExpectedValue = 1;
22182
22183 class InterruptThread : public v8::base::Thread {
22184 public:
InterruptThread(ThreadInterruptTest * test)22185 explicit InterruptThread(ThreadInterruptTest* test)
22186 : Thread(Options("InterruptThread")), test_(test) {}
22187
Run()22188 virtual void Run() {
22189 struct sigaction action;
22190
22191 // Ensure that we'll enter waiting condition
22192 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22193
22194 // Setup signal handler
22195 memset(&action, 0, sizeof(action));
22196 action.sa_handler = SignalHandler;
22197 sigaction(SIGCHLD, &action, NULL);
22198
22199 // Send signal
22200 kill(getpid(), SIGCHLD);
22201
22202 // Ensure that if wait has returned because of error
22203 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22204
22205 // Set value and signal semaphore
22206 test_->sem_value_ = 1;
22207 test_->sem_.Signal();
22208 }
22209
SignalHandler(int signal)22210 static void SignalHandler(int signal) {
22211 }
22212
22213 private:
22214 ThreadInterruptTest* test_;
22215 };
22216
22217 v8::base::Semaphore sem_;
22218 volatile int sem_value_;
22219 };
22220
22221
THREADED_TEST(SemaphoreInterruption)22222 THREADED_TEST(SemaphoreInterruption) {
22223 ThreadInterruptTest().RunTest();
22224 }
22225
22226
22227 #endif // V8_OS_POSIX
22228
22229
UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value> & args)22230 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22231 CHECK(false);
22232 }
22233
22234
TEST(JSONStringifyAccessCheck)22235 TEST(JSONStringifyAccessCheck) {
22236 v8::V8::Initialize();
22237 v8::Isolate* isolate = CcTest::isolate();
22238 v8::HandleScope scope(isolate);
22239
22240 // Create an ObjectTemplate for global objects and install access
22241 // check callbacks that will block access.
22242 v8::Local<v8::ObjectTemplate> global_template =
22243 v8::ObjectTemplate::New(isolate);
22244 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22245
22246 // Create a context and set an x property on it's global object.
22247 LocalContext context0(NULL, global_template);
22248 v8::Local<v8::Object> global0 = context0->Global();
22249 global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
22250 ExpectString("JSON.stringify(this)", "{\"x\":42}");
22251
22252 for (int i = 0; i < 2; i++) {
22253 if (i == 1) {
22254 // Install a toJSON function on the second run.
22255 v8::Local<v8::FunctionTemplate> toJSON =
22256 v8::FunctionTemplate::New(isolate, UnreachableCallback);
22257
22258 global0->Set(context0.local(), v8_str("toJSON"),
22259 toJSON->GetFunction(context0.local()).ToLocalChecked())
22260 .FromJust();
22261 }
22262 // Create a context with a different security token so that the
22263 // failed access check callback will be called on each access.
22264 LocalContext context1(NULL, global_template);
22265 CHECK(context1->Global()
22266 ->Set(context1.local(), v8_str("other"), global0)
22267 .FromJust());
22268
22269 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22270 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22271 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22272 }
22273 }
22274
22275
22276 bool access_check_fail_thrown = false;
22277 bool catch_callback_called = false;
22278
22279
22280 // Failed access check callback that performs a GC on each invocation.
FailedAccessCheckThrows(Local<v8::Object> target,v8::AccessType type,Local<v8::Value> data)22281 void FailedAccessCheckThrows(Local<v8::Object> target,
22282 v8::AccessType type,
22283 Local<v8::Value> data) {
22284 access_check_fail_thrown = true;
22285 i::PrintF("Access check failed. Error thrown.\n");
22286 CcTest::isolate()->ThrowException(
22287 v8::Exception::Error(v8_str("cross context")));
22288 }
22289
22290
CatcherCallback(const v8::FunctionCallbackInfo<v8::Value> & args)22291 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22292 for (int i = 0; i < args.Length(); i++) {
22293 i::PrintF("%s\n", *String::Utf8Value(args[i]));
22294 }
22295 catch_callback_called = true;
22296 }
22297
22298
HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value> & args)22299 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22300 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
22301 CHECK(
22302 args[0]
22303 ->ToObject(context)
22304 .ToLocalChecked()
22305 ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
22306 .IsNothing());
22307 }
22308
22309
CheckCorrectThrow(const char * script)22310 void CheckCorrectThrow(const char* script) {
22311 // Test that the script, when wrapped into a try-catch, triggers the catch
22312 // clause due to failed access check throwing an exception.
22313 // The subsequent try-catch should run without any exception.
22314 access_check_fail_thrown = false;
22315 catch_callback_called = false;
22316 i::ScopedVector<char> source(1024);
22317 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22318 CompileRun(source.start());
22319 CHECK(access_check_fail_thrown);
22320 CHECK(catch_callback_called);
22321
22322 access_check_fail_thrown = false;
22323 catch_callback_called = false;
22324 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22325 CHECK(!access_check_fail_thrown);
22326 CHECK(!catch_callback_called);
22327 }
22328
22329
TEST(AccessCheckThrows)22330 TEST(AccessCheckThrows) {
22331 i::FLAG_allow_natives_syntax = true;
22332 v8::V8::Initialize();
22333 v8::Isolate* isolate = CcTest::isolate();
22334 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22335 v8::HandleScope scope(isolate);
22336
22337 // Create an ObjectTemplate for global objects and install access
22338 // check callbacks that will block access.
22339 v8::Local<v8::ObjectTemplate> global_template =
22340 v8::ObjectTemplate::New(isolate);
22341 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22342
22343 // Create a context and set an x property on it's global object.
22344 LocalContext context0(NULL, global_template);
22345 v8::Local<v8::Object> global0 = context0->Global();
22346
22347 // Create a context with a different security token so that the
22348 // failed access check callback will be called on each access.
22349 LocalContext context1(NULL, global_template);
22350 CHECK(context1->Global()
22351 ->Set(context1.local(), v8_str("other"), global0)
22352 .FromJust());
22353
22354 v8::Local<v8::FunctionTemplate> catcher_fun =
22355 v8::FunctionTemplate::New(isolate, CatcherCallback);
22356 CHECK(context1->Global()
22357 ->Set(context1.local(), v8_str("catcher"),
22358 catcher_fun->GetFunction(context1.local()).ToLocalChecked())
22359 .FromJust());
22360
22361 v8::Local<v8::FunctionTemplate> has_own_property_fun =
22362 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22363 CHECK(context1->Global()
22364 ->Set(context1.local(), v8_str("has_own_property"),
22365 has_own_property_fun->GetFunction(context1.local())
22366 .ToLocalChecked())
22367 .FromJust());
22368
22369 {
22370 v8::TryCatch try_catch(isolate);
22371 access_check_fail_thrown = false;
22372 CompileRun("other.x;");
22373 CHECK(access_check_fail_thrown);
22374 CHECK(try_catch.HasCaught());
22375 }
22376
22377 CheckCorrectThrow("other.x");
22378 CheckCorrectThrow("other[1]");
22379 CheckCorrectThrow("JSON.stringify(other)");
22380 CheckCorrectThrow("has_own_property(other, 'x')");
22381 CheckCorrectThrow("%GetProperty(other, 'x')");
22382 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22383 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22384 CheckCorrectThrow("%DeleteProperty_Sloppy(other, 'x')");
22385 CheckCorrectThrow("%DeleteProperty_Strict(other, 'x')");
22386 CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')");
22387 CheckCorrectThrow("%DeleteProperty_Strict(other, '1')");
22388 CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
22389 CheckCorrectThrow("%HasProperty('x', other)");
22390 CheckCorrectThrow("%PropertyIsEnumerable(other, 'x')");
22391 // PROPERTY_ATTRIBUTES_NONE = 0
22392 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22393 "other, 'x', null, null, 1)");
22394
22395 // Reset the failed access check callback so it does not influence
22396 // the other tests.
22397 isolate->SetFailedAccessCheckCallbackFunction(NULL);
22398 }
22399
22400
22401 class RequestInterruptTestBase {
22402 public:
RequestInterruptTestBase()22403 RequestInterruptTestBase()
22404 : env_(),
22405 isolate_(env_->GetIsolate()),
22406 sem_(0),
22407 warmup_(20000),
22408 should_continue_(true) {
22409 }
22410
~RequestInterruptTestBase()22411 virtual ~RequestInterruptTestBase() { }
22412
22413 virtual void StartInterruptThread() = 0;
22414
22415 virtual void TestBody() = 0;
22416
RunTest()22417 void RunTest() {
22418 StartInterruptThread();
22419
22420 v8::HandleScope handle_scope(isolate_);
22421
22422 TestBody();
22423
22424 // Verify we arrived here because interruptor was called
22425 // not due to a bug causing us to exit the loop too early.
22426 CHECK(!should_continue());
22427 }
22428
WakeUpInterruptor()22429 void WakeUpInterruptor() {
22430 sem_.Signal();
22431 }
22432
should_continue() const22433 bool should_continue() const { return should_continue_; }
22434
ShouldContinue()22435 bool ShouldContinue() {
22436 if (warmup_ > 0) {
22437 if (--warmup_ == 0) {
22438 WakeUpInterruptor();
22439 }
22440 }
22441
22442 return should_continue_;
22443 }
22444
ShouldContinueCallback(const v8::FunctionCallbackInfo<Value> & info)22445 static void ShouldContinueCallback(
22446 const v8::FunctionCallbackInfo<Value>& info) {
22447 RequestInterruptTestBase* test =
22448 reinterpret_cast<RequestInterruptTestBase*>(
22449 info.Data().As<v8::External>()->Value());
22450 info.GetReturnValue().Set(test->ShouldContinue());
22451 }
22452
22453 LocalContext env_;
22454 v8::Isolate* isolate_;
22455 v8::base::Semaphore sem_;
22456 int warmup_;
22457 bool should_continue_;
22458 };
22459
22460
22461 class RequestInterruptTestBaseWithSimpleInterrupt
22462 : public RequestInterruptTestBase {
22463 public:
RequestInterruptTestBaseWithSimpleInterrupt()22464 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22465
StartInterruptThread()22466 virtual void StartInterruptThread() {
22467 i_thread.Start();
22468 }
22469
22470 private:
22471 class InterruptThread : public v8::base::Thread {
22472 public:
InterruptThread(RequestInterruptTestBase * test)22473 explicit InterruptThread(RequestInterruptTestBase* test)
22474 : Thread(Options("RequestInterruptTest")), test_(test) {}
22475
Run()22476 virtual void Run() {
22477 test_->sem_.Wait();
22478 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22479 }
22480
OnInterrupt(v8::Isolate * isolate,void * data)22481 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22482 reinterpret_cast<RequestInterruptTestBase*>(data)->
22483 should_continue_ = false;
22484 }
22485
22486 private:
22487 RequestInterruptTestBase* test_;
22488 };
22489
22490 InterruptThread i_thread;
22491 };
22492
22493
22494 class RequestInterruptTestWithFunctionCall
22495 : public RequestInterruptTestBaseWithSimpleInterrupt {
22496 public:
TestBody()22497 virtual void TestBody() {
22498 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
22499 v8::External::New(isolate_, this))
22500 .ToLocalChecked();
22501 CHECK(env_->Global()
22502 ->Set(env_.local(), v8_str("ShouldContinue"), func)
22503 .FromJust());
22504
22505 CompileRun("while (ShouldContinue()) { }");
22506 }
22507 };
22508
22509
22510 class RequestInterruptTestWithMethodCall
22511 : public RequestInterruptTestBaseWithSimpleInterrupt {
22512 public:
TestBody()22513 virtual void TestBody() {
22514 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22515 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22516 proto->Set(v8_str("shouldContinue"),
22517 FunctionTemplate::New(isolate_, ShouldContinueCallback,
22518 v8::External::New(isolate_, this)));
22519 CHECK(env_->Global()
22520 ->Set(env_.local(), v8_str("Klass"),
22521 t->GetFunction(env_.local()).ToLocalChecked())
22522 .FromJust());
22523
22524 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22525 }
22526 };
22527
22528
22529 class RequestInterruptTestWithAccessor
22530 : public RequestInterruptTestBaseWithSimpleInterrupt {
22531 public:
TestBody()22532 virtual void TestBody() {
22533 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22534 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22535 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22536 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22537 CHECK(env_->Global()
22538 ->Set(env_.local(), v8_str("Klass"),
22539 t->GetFunction(env_.local()).ToLocalChecked())
22540 .FromJust());
22541
22542 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22543 }
22544 };
22545
22546
22547 class RequestInterruptTestWithNativeAccessor
22548 : public RequestInterruptTestBaseWithSimpleInterrupt {
22549 public:
TestBody()22550 virtual void TestBody() {
22551 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22552 t->InstanceTemplate()->SetNativeDataProperty(
22553 v8_str("shouldContinue"),
22554 &ShouldContinueNativeGetter,
22555 NULL,
22556 v8::External::New(isolate_, this));
22557 CHECK(env_->Global()
22558 ->Set(env_.local(), v8_str("Klass"),
22559 t->GetFunction(env_.local()).ToLocalChecked())
22560 .FromJust());
22561
22562 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22563 }
22564
22565 private:
ShouldContinueNativeGetter(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)22566 static void ShouldContinueNativeGetter(
22567 Local<String> property,
22568 const v8::PropertyCallbackInfo<v8::Value>& info) {
22569 RequestInterruptTestBase* test =
22570 reinterpret_cast<RequestInterruptTestBase*>(
22571 info.Data().As<v8::External>()->Value());
22572 info.GetReturnValue().Set(test->ShouldContinue());
22573 }
22574 };
22575
22576
22577 class RequestInterruptTestWithMethodCallAndInterceptor
22578 : public RequestInterruptTestBaseWithSimpleInterrupt {
22579 public:
TestBody()22580 virtual void TestBody() {
22581 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22582 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22583 proto->Set(v8_str("shouldContinue"),
22584 FunctionTemplate::New(isolate_, ShouldContinueCallback,
22585 v8::External::New(isolate_, this)));
22586 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22587 instance_template->SetHandler(
22588 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
22589
22590 CHECK(env_->Global()
22591 ->Set(env_.local(), v8_str("Klass"),
22592 t->GetFunction(env_.local()).ToLocalChecked())
22593 .FromJust());
22594
22595 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22596 }
22597
22598 private:
EmptyInterceptor(Local<Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)22599 static void EmptyInterceptor(
22600 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22601 };
22602
22603
22604 class RequestInterruptTestWithMathAbs
22605 : public RequestInterruptTestBaseWithSimpleInterrupt {
22606 public:
TestBody()22607 virtual void TestBody() {
22608 env_->Global()
22609 ->Set(env_.local(), v8_str("WakeUpInterruptor"),
22610 Function::New(env_.local(), WakeUpInterruptorCallback,
22611 v8::External::New(isolate_, this))
22612 .ToLocalChecked())
22613 .FromJust();
22614
22615 env_->Global()
22616 ->Set(env_.local(), v8_str("ShouldContinue"),
22617 Function::New(env_.local(), ShouldContinueCallback,
22618 v8::External::New(isolate_, this))
22619 .ToLocalChecked())
22620 .FromJust();
22621
22622 i::FLAG_allow_natives_syntax = true;
22623 CompileRun("function loopish(o) {"
22624 " var pre = 10;"
22625 " while (o.abs(1) > 0) {"
22626 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22627 " if (pre > 0) {"
22628 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22629 " }"
22630 " }"
22631 "}"
22632 "var i = 50;"
22633 "var obj = {abs: function () { return i-- }, x: null};"
22634 "delete obj.x;"
22635 "loopish(obj);"
22636 "%OptimizeFunctionOnNextCall(loopish);"
22637 "loopish(Math);");
22638
22639 i::FLAG_allow_natives_syntax = false;
22640 }
22641
22642 private:
WakeUpInterruptorCallback(const v8::FunctionCallbackInfo<Value> & info)22643 static void WakeUpInterruptorCallback(
22644 const v8::FunctionCallbackInfo<Value>& info) {
22645 if (!info[0]
22646 ->BooleanValue(info.GetIsolate()->GetCurrentContext())
22647 .FromJust()) {
22648 return;
22649 }
22650
22651 RequestInterruptTestBase* test =
22652 reinterpret_cast<RequestInterruptTestBase*>(
22653 info.Data().As<v8::External>()->Value());
22654 test->WakeUpInterruptor();
22655 }
22656
ShouldContinueCallback(const v8::FunctionCallbackInfo<Value> & info)22657 static void ShouldContinueCallback(
22658 const v8::FunctionCallbackInfo<Value>& info) {
22659 RequestInterruptTestBase* test =
22660 reinterpret_cast<RequestInterruptTestBase*>(
22661 info.Data().As<v8::External>()->Value());
22662 info.GetReturnValue().Set(test->should_continue());
22663 }
22664 };
22665
22666
TEST(RequestInterruptTestWithFunctionCall)22667 TEST(RequestInterruptTestWithFunctionCall) {
22668 RequestInterruptTestWithFunctionCall().RunTest();
22669 }
22670
22671
TEST(RequestInterruptTestWithMethodCall)22672 TEST(RequestInterruptTestWithMethodCall) {
22673 RequestInterruptTestWithMethodCall().RunTest();
22674 }
22675
22676
TEST(RequestInterruptTestWithAccessor)22677 TEST(RequestInterruptTestWithAccessor) {
22678 RequestInterruptTestWithAccessor().RunTest();
22679 }
22680
22681
TEST(RequestInterruptTestWithNativeAccessor)22682 TEST(RequestInterruptTestWithNativeAccessor) {
22683 RequestInterruptTestWithNativeAccessor().RunTest();
22684 }
22685
22686
TEST(RequestInterruptTestWithMethodCallAndInterceptor)22687 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22688 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22689 }
22690
22691
TEST(RequestInterruptTestWithMathAbs)22692 TEST(RequestInterruptTestWithMathAbs) {
22693 RequestInterruptTestWithMathAbs().RunTest();
22694 }
22695
22696
22697 class RequestMultipleInterrupts : public RequestInterruptTestBase {
22698 public:
RequestMultipleInterrupts()22699 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
22700
StartInterruptThread()22701 virtual void StartInterruptThread() {
22702 i_thread.Start();
22703 }
22704
TestBody()22705 virtual void TestBody() {
22706 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
22707 v8::External::New(isolate_, this))
22708 .ToLocalChecked();
22709 CHECK(env_->Global()
22710 ->Set(env_.local(), v8_str("ShouldContinue"), func)
22711 .FromJust());
22712
22713 CompileRun("while (ShouldContinue()) { }");
22714 }
22715
22716 private:
22717 class InterruptThread : public v8::base::Thread {
22718 public:
22719 enum { NUM_INTERRUPTS = 10 };
InterruptThread(RequestMultipleInterrupts * test)22720 explicit InterruptThread(RequestMultipleInterrupts* test)
22721 : Thread(Options("RequestInterruptTest")), test_(test) {}
22722
Run()22723 virtual void Run() {
22724 test_->sem_.Wait();
22725 for (int i = 0; i < NUM_INTERRUPTS; i++) {
22726 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22727 }
22728 }
22729
OnInterrupt(v8::Isolate * isolate,void * data)22730 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22731 RequestMultipleInterrupts* test =
22732 reinterpret_cast<RequestMultipleInterrupts*>(data);
22733 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
22734 }
22735
22736 private:
22737 RequestMultipleInterrupts* test_;
22738 };
22739
22740 InterruptThread i_thread;
22741 int counter_;
22742 };
22743
22744
TEST(RequestMultipleInterrupts)22745 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
22746
22747
22748 static bool interrupt_was_called = false;
22749
22750
SmallScriptsInterruptCallback(v8::Isolate * isolate,void * data)22751 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
22752 interrupt_was_called = true;
22753 }
22754
22755
TEST(RequestInterruptSmallScripts)22756 TEST(RequestInterruptSmallScripts) {
22757 LocalContext env;
22758 v8::Isolate* isolate = CcTest::isolate();
22759 v8::HandleScope scope(isolate);
22760
22761 interrupt_was_called = false;
22762 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL);
22763 CompileRun("(function(x){return x;})(1);");
22764 CHECK(interrupt_was_called);
22765 }
22766
22767
22768 static Local<Value> function_new_expected_env;
FunctionNewCallback(const v8::FunctionCallbackInfo<Value> & info)22769 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22770 CHECK(
22771 function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
22772 info.Data())
22773 .FromJust());
22774 info.GetReturnValue().Set(17);
22775 }
22776
22777
THREADED_TEST(FunctionNew)22778 THREADED_TEST(FunctionNew) {
22779 LocalContext env;
22780 v8::Isolate* isolate = env->GetIsolate();
22781 v8::HandleScope scope(isolate);
22782 Local<Object> data = v8::Object::New(isolate);
22783 function_new_expected_env = data;
22784 Local<Function> func =
22785 Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
22786 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
22787 Local<Value> result = CompileRun("func();");
22788 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
22789 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22790 // Verify function not cached
22791 auto serial_number = handle(
22792 i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
22793 ->shared()
22794 ->get_api_func_data()
22795 ->serial_number()),
22796 i_isolate);
22797 auto cache = i_isolate->template_instantiations_cache();
22798 CHECK(cache->FindEntry(static_cast<uint32_t>(serial_number->value())) ==
22799 i::UnseededNumberDictionary::kNotFound);
22800 // Verify that each Function::New creates a new function instance
22801 Local<Object> data2 = v8::Object::New(isolate);
22802 function_new_expected_env = data2;
22803 Local<Function> func2 =
22804 Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
22805 CHECK(!func2->IsNull());
22806 CHECK(!func->Equals(env.local(), func2).FromJust());
22807 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
22808 Local<Value> result2 = CompileRun("func2();");
22809 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
22810 }
22811
22812
TEST(EscapeableHandleScope)22813 TEST(EscapeableHandleScope) {
22814 HandleScope outer_scope(CcTest::isolate());
22815 LocalContext context;
22816 const int runs = 10;
22817 Local<String> values[runs];
22818 for (int i = 0; i < runs; i++) {
22819 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22820 Local<String> value;
22821 if (i != 0) value = v8_str("escape value");
22822 values[i] = inner_scope.Escape(value);
22823 }
22824 for (int i = 0; i < runs; i++) {
22825 Local<String> expected;
22826 if (i != 0) {
22827 CHECK(v8_str("escape value")
22828 ->Equals(context.local(), values[i])
22829 .FromJust());
22830 } else {
22831 CHECK(values[i].IsEmpty());
22832 }
22833 }
22834 }
22835
22836
SetterWhichExpectsThisAndHolderToDiffer(Local<String>,Local<Value>,const v8::PropertyCallbackInfo<void> & info)22837 static void SetterWhichExpectsThisAndHolderToDiffer(
22838 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22839 CHECK(info.Holder() != info.This());
22840 }
22841
22842
TEST(Regress239669)22843 TEST(Regress239669) {
22844 LocalContext context;
22845 v8::Isolate* isolate = context->GetIsolate();
22846 v8::HandleScope scope(isolate);
22847 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22848 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22849 CHECK(context->Global()
22850 ->Set(context.local(), v8_str("P"),
22851 templ->NewInstance(context.local()).ToLocalChecked())
22852 .FromJust());
22853 CompileRun(
22854 "function C1() {"
22855 " this.x = 23;"
22856 "};"
22857 "C1.prototype = P;"
22858 "for (var i = 0; i < 4; i++ ) {"
22859 " new C1();"
22860 "}");
22861 }
22862
22863
22864 class ApiCallOptimizationChecker {
22865 private:
22866 static Local<Object> data;
22867 static Local<Object> receiver;
22868 static Local<Object> holder;
22869 static Local<Object> callee;
22870 static int count;
22871
OptimizationCallback(const v8::FunctionCallbackInfo<v8::Value> & info)22872 static void OptimizationCallback(
22873 const v8::FunctionCallbackInfo<v8::Value>& info) {
22874 CHECK(data == info.Data());
22875 CHECK(receiver == info.This());
22876 if (info.Length() == 1) {
22877 CHECK(v8_num(1)
22878 ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
22879 .FromJust());
22880 }
22881 CHECK(holder == info.Holder());
22882 count++;
22883 info.GetReturnValue().Set(v8_str("returned"));
22884 }
22885
22886 public:
22887 enum SignatureType {
22888 kNoSignature,
22889 kSignatureOnReceiver,
22890 kSignatureOnPrototype
22891 };
22892
RunAll()22893 void RunAll() {
22894 SignatureType signature_types[] =
22895 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22896 for (unsigned i = 0; i < arraysize(signature_types); i++) {
22897 SignatureType signature_type = signature_types[i];
22898 for (int j = 0; j < 2; j++) {
22899 bool global = j == 0;
22900 int key = signature_type +
22901 arraysize(signature_types) * (global ? 1 : 0);
22902 Run(signature_type, global, key);
22903 }
22904 }
22905 }
22906
Run(SignatureType signature_type,bool global,int key)22907 void Run(SignatureType signature_type, bool global, int key) {
22908 v8::Isolate* isolate = CcTest::isolate();
22909 v8::HandleScope scope(isolate);
22910 // Build a template for signature checks.
22911 Local<v8::ObjectTemplate> signature_template;
22912 Local<v8::Signature> signature;
22913 {
22914 Local<v8::FunctionTemplate> parent_template =
22915 FunctionTemplate::New(isolate);
22916 parent_template->SetHiddenPrototype(true);
22917 Local<v8::FunctionTemplate> function_template
22918 = FunctionTemplate::New(isolate);
22919 function_template->Inherit(parent_template);
22920 switch (signature_type) {
22921 case kNoSignature:
22922 break;
22923 case kSignatureOnReceiver:
22924 signature = v8::Signature::New(isolate, function_template);
22925 break;
22926 case kSignatureOnPrototype:
22927 signature = v8::Signature::New(isolate, parent_template);
22928 break;
22929 }
22930 signature_template = function_template->InstanceTemplate();
22931 }
22932 // Global object must pass checks.
22933 Local<v8::Context> context =
22934 v8::Context::New(isolate, NULL, signature_template);
22935 v8::Context::Scope context_scope(context);
22936 // Install regular object that can pass signature checks.
22937 Local<Object> function_receiver =
22938 signature_template->NewInstance(context).ToLocalChecked();
22939 CHECK(context->Global()
22940 ->Set(context, v8_str("function_receiver"), function_receiver)
22941 .FromJust());
22942 // Get the holder objects.
22943 Local<Object> inner_global =
22944 Local<Object>::Cast(context->Global()->GetPrototype());
22945 // Install functions on hidden prototype object if there is one.
22946 data = Object::New(isolate);
22947 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22948 isolate, OptimizationCallback, data, signature);
22949 Local<Function> function =
22950 function_template->GetFunction(context).ToLocalChecked();
22951 Local<Object> global_holder = inner_global;
22952 Local<Object> function_holder = function_receiver;
22953 if (signature_type == kSignatureOnPrototype) {
22954 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22955 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22956 }
22957 global_holder->Set(context, v8_str("g_f"), function).FromJust();
22958 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22959 function_holder->Set(context, v8_str("f"), function).FromJust();
22960 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22961 // Initialize expected values.
22962 callee = function;
22963 count = 0;
22964 if (global) {
22965 receiver = context->Global();
22966 holder = inner_global;
22967 } else {
22968 holder = function_receiver;
22969 // If not using a signature, add something else to the prototype chain
22970 // to test the case that holder != receiver
22971 if (signature_type == kNoSignature) {
22972 receiver = Local<Object>::Cast(CompileRun(
22973 "var receiver_subclass = {};\n"
22974 "receiver_subclass.__proto__ = function_receiver;\n"
22975 "receiver_subclass"));
22976 } else {
22977 receiver = Local<Object>::Cast(CompileRun(
22978 "var receiver_subclass = function_receiver;\n"
22979 "receiver_subclass"));
22980 }
22981 }
22982 // With no signature, the holder is not set.
22983 if (signature_type == kNoSignature) holder = receiver;
22984 // build wrap_function
22985 i::ScopedVector<char> wrap_function(200);
22986 if (global) {
22987 i::SNPrintF(
22988 wrap_function,
22989 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22990 "function wrap_get_%d() { return this.g_acc; }\n"
22991 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22992 key, key, key);
22993 } else {
22994 i::SNPrintF(
22995 wrap_function,
22996 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22997 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22998 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22999 key, key, key);
23000 }
23001 // build source string
23002 i::ScopedVector<char> source(1000);
23003 i::SNPrintF(
23004 source,
23005 "%s\n" // wrap functions
23006 "function wrap_f() { return wrap_f_%d(); }\n"
23007 "function wrap_get() { return wrap_get_%d(); }\n"
23008 "function wrap_set() { return wrap_set_%d(); }\n"
23009 "check = function(returned) {\n"
23010 " if (returned !== 'returned') { throw returned; }\n"
23011 "}\n"
23012 "\n"
23013 "check(wrap_f());\n"
23014 "check(wrap_f());\n"
23015 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23016 "check(wrap_f());\n"
23017 "\n"
23018 "check(wrap_get());\n"
23019 "check(wrap_get());\n"
23020 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23021 "check(wrap_get());\n"
23022 "\n"
23023 "check = function(returned) {\n"
23024 " if (returned !== 1) { throw returned; }\n"
23025 "}\n"
23026 "check(wrap_set());\n"
23027 "check(wrap_set());\n"
23028 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23029 "check(wrap_set());\n",
23030 wrap_function.start(), key, key, key, key, key, key);
23031 v8::TryCatch try_catch(isolate);
23032 CompileRun(source.start());
23033 CHECK(!try_catch.HasCaught());
23034 CHECK_EQ(9, count);
23035 }
23036 };
23037
23038
23039 Local<Object> ApiCallOptimizationChecker::data;
23040 Local<Object> ApiCallOptimizationChecker::receiver;
23041 Local<Object> ApiCallOptimizationChecker::holder;
23042 Local<Object> ApiCallOptimizationChecker::callee;
23043 int ApiCallOptimizationChecker::count = 0;
23044
23045
TEST(FunctionCallOptimization)23046 TEST(FunctionCallOptimization) {
23047 i::FLAG_allow_natives_syntax = true;
23048 ApiCallOptimizationChecker checker;
23049 checker.RunAll();
23050 }
23051
23052
TEST(FunctionCallOptimizationMultipleArgs)23053 TEST(FunctionCallOptimizationMultipleArgs) {
23054 i::FLAG_allow_natives_syntax = true;
23055 LocalContext context;
23056 v8::Isolate* isolate = context->GetIsolate();
23057 v8::HandleScope scope(isolate);
23058 Local<Object> global = context->Global();
23059 Local<v8::Function> function =
23060 Function::New(context.local(), Returns42).ToLocalChecked();
23061 global->Set(context.local(), v8_str("x"), function).FromJust();
23062 CompileRun(
23063 "function x_wrap() {\n"
23064 " for (var i = 0; i < 5; i++) {\n"
23065 " x(1,2,3);\n"
23066 " }\n"
23067 "}\n"
23068 "x_wrap();\n"
23069 "%OptimizeFunctionOnNextCall(x_wrap);"
23070 "x_wrap();\n");
23071 }
23072
23073
ReturnsSymbolCallback(const v8::FunctionCallbackInfo<v8::Value> & info)23074 static void ReturnsSymbolCallback(
23075 const v8::FunctionCallbackInfo<v8::Value>& info) {
23076 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
23077 }
23078
23079
TEST(ApiCallbackCanReturnSymbols)23080 TEST(ApiCallbackCanReturnSymbols) {
23081 i::FLAG_allow_natives_syntax = true;
23082 LocalContext context;
23083 v8::Isolate* isolate = context->GetIsolate();
23084 v8::HandleScope scope(isolate);
23085 Local<Object> global = context->Global();
23086 Local<v8::Function> function =
23087 Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
23088 global->Set(context.local(), v8_str("x"), function).FromJust();
23089 CompileRun(
23090 "function x_wrap() {\n"
23091 " for (var i = 0; i < 5; i++) {\n"
23092 " x();\n"
23093 " }\n"
23094 "}\n"
23095 "x_wrap();\n"
23096 "%OptimizeFunctionOnNextCall(x_wrap);"
23097 "x_wrap();\n");
23098 }
23099
23100
TEST(EmptyApiCallback)23101 TEST(EmptyApiCallback) {
23102 LocalContext context;
23103 auto isolate = context->GetIsolate();
23104 v8::HandleScope scope(isolate);
23105 auto global = context->Global();
23106 auto function = FunctionTemplate::New(isolate)
23107 ->GetFunction(context.local())
23108 .ToLocalChecked();
23109 global->Set(context.local(), v8_str("x"), function).FromJust();
23110
23111 auto result = CompileRun("x()");
23112 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23113
23114 result = CompileRun("x(1,2,3)");
23115 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23116
23117 result = CompileRun("x.call(undefined)");
23118 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23119
23120 result = CompileRun("x.call(null)");
23121 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23122
23123 result = CompileRun("7 + x.call(3) + 11");
23124 CHECK(result->IsInt32());
23125 CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23126
23127 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
23128 CHECK(result->IsInt32());
23129 CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23130
23131 result = CompileRun("var y = []; x.call(y)");
23132 CHECK(result->IsArray());
23133
23134 result = CompileRun("x.call(y, 1, 2, 3, 4)");
23135 CHECK(result->IsArray());
23136 }
23137
23138
TEST(SimpleSignatureCheck)23139 TEST(SimpleSignatureCheck) {
23140 LocalContext context;
23141 auto isolate = context->GetIsolate();
23142 v8::HandleScope scope(isolate);
23143 auto global = context->Global();
23144 auto sig_obj = FunctionTemplate::New(isolate);
23145 auto sig = v8::Signature::New(isolate, sig_obj);
23146 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23147 global->Set(context.local(), v8_str("sig_obj"),
23148 sig_obj->GetFunction(context.local()).ToLocalChecked())
23149 .FromJust();
23150 global->Set(context.local(), v8_str("x"),
23151 x->GetFunction(context.local()).ToLocalChecked())
23152 .FromJust();
23153 CompileRun("var s = new sig_obj();");
23154 {
23155 TryCatch try_catch(isolate);
23156 CompileRun("x()");
23157 CHECK(try_catch.HasCaught());
23158 }
23159 {
23160 TryCatch try_catch(isolate);
23161 CompileRun("x.call(1)");
23162 CHECK(try_catch.HasCaught());
23163 }
23164 {
23165 TryCatch try_catch(isolate);
23166 auto result = CompileRun("s.x = x; s.x()");
23167 CHECK(!try_catch.HasCaught());
23168 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23169 }
23170 {
23171 TryCatch try_catch(isolate);
23172 auto result = CompileRun("x.call(s)");
23173 CHECK(!try_catch.HasCaught());
23174 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23175 }
23176 }
23177
23178
TEST(ChainSignatureCheck)23179 TEST(ChainSignatureCheck) {
23180 LocalContext context;
23181 auto isolate = context->GetIsolate();
23182 v8::HandleScope scope(isolate);
23183 auto global = context->Global();
23184 auto sig_obj = FunctionTemplate::New(isolate);
23185 auto sig = v8::Signature::New(isolate, sig_obj);
23186 for (int i = 0; i < 4; ++i) {
23187 auto temp = FunctionTemplate::New(isolate);
23188 temp->Inherit(sig_obj);
23189 sig_obj = temp;
23190 }
23191 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23192 global->Set(context.local(), v8_str("sig_obj"),
23193 sig_obj->GetFunction(context.local()).ToLocalChecked())
23194 .FromJust();
23195 global->Set(context.local(), v8_str("x"),
23196 x->GetFunction(context.local()).ToLocalChecked())
23197 .FromJust();
23198 CompileRun("var s = new sig_obj();");
23199 {
23200 TryCatch try_catch(isolate);
23201 CompileRun("x()");
23202 CHECK(try_catch.HasCaught());
23203 }
23204 {
23205 TryCatch try_catch(isolate);
23206 CompileRun("x.call(1)");
23207 CHECK(try_catch.HasCaught());
23208 }
23209 {
23210 TryCatch try_catch(isolate);
23211 auto result = CompileRun("s.x = x; s.x()");
23212 CHECK(!try_catch.HasCaught());
23213 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23214 }
23215 {
23216 TryCatch try_catch(isolate);
23217 auto result = CompileRun("x.call(s)");
23218 CHECK(!try_catch.HasCaught());
23219 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23220 }
23221 }
23222
23223
TEST(PrototypeSignatureCheck)23224 TEST(PrototypeSignatureCheck) {
23225 LocalContext context;
23226 auto isolate = context->GetIsolate();
23227 v8::HandleScope scope(isolate);
23228 auto global = context->Global();
23229 auto sig_obj = FunctionTemplate::New(isolate);
23230 sig_obj->SetHiddenPrototype(true);
23231 auto sig = v8::Signature::New(isolate, sig_obj);
23232 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23233 global->Set(context.local(), v8_str("sig_obj"),
23234 sig_obj->GetFunction(context.local()).ToLocalChecked())
23235 .FromJust();
23236 global->Set(context.local(), v8_str("x"),
23237 x->GetFunction(context.local()).ToLocalChecked())
23238 .FromJust();
23239 CompileRun("s = {}; s.__proto__ = new sig_obj();");
23240 {
23241 TryCatch try_catch(isolate);
23242 CompileRun("x()");
23243 CHECK(try_catch.HasCaught());
23244 }
23245 {
23246 TryCatch try_catch(isolate);
23247 CompileRun("x.call(1)");
23248 CHECK(try_catch.HasCaught());
23249 }
23250 {
23251 TryCatch try_catch(isolate);
23252 auto result = CompileRun("s.x = x; s.x()");
23253 CHECK(!try_catch.HasCaught());
23254 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23255 }
23256 {
23257 TryCatch try_catch(isolate);
23258 auto result = CompileRun("x.call(s)");
23259 CHECK(!try_catch.HasCaught());
23260 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23261 }
23262 }
23263
23264
23265 static const char* last_event_message;
23266 static int last_event_status;
StoringEventLoggerCallback(const char * message,int status)23267 void StoringEventLoggerCallback(const char* message, int status) {
23268 last_event_message = message;
23269 last_event_status = status;
23270 }
23271
23272
TEST(EventLogging)23273 TEST(EventLogging) {
23274 v8::Isolate* isolate = CcTest::isolate();
23275 isolate->SetEventLogger(StoringEventLoggerCallback);
23276 v8::internal::HistogramTimer histogramTimer(
23277 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
23278 reinterpret_cast<v8::internal::Isolate*>(isolate));
23279 histogramTimer.Start();
23280 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23281 CHECK_EQ(0, last_event_status);
23282 histogramTimer.Stop();
23283 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23284 CHECK_EQ(1, last_event_status);
23285 }
23286
23287
TEST(Promises)23288 TEST(Promises) {
23289 LocalContext context;
23290 v8::Isolate* isolate = context->GetIsolate();
23291 v8::HandleScope scope(isolate);
23292
23293 // Creation.
23294 Local<v8::Promise::Resolver> pr =
23295 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23296 Local<v8::Promise::Resolver> rr =
23297 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23298 Local<v8::Promise> p = pr->GetPromise();
23299 Local<v8::Promise> r = rr->GetPromise();
23300
23301 // IsPromise predicate.
23302 CHECK(p->IsPromise());
23303 CHECK(r->IsPromise());
23304 Local<Value> o = v8::Object::New(isolate);
23305 CHECK(!o->IsPromise());
23306
23307 // Resolution and rejection.
23308 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
23309 CHECK(p->IsPromise());
23310 rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
23311 CHECK(r->IsPromise());
23312 }
23313
23314
TEST(PromiseThen)23315 TEST(PromiseThen) {
23316 LocalContext context;
23317 v8::Isolate* isolate = context->GetIsolate();
23318 v8::HandleScope scope(isolate);
23319 Local<Object> global = context->Global();
23320
23321 // Creation.
23322 Local<v8::Promise::Resolver> pr =
23323 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23324 Local<v8::Promise::Resolver> qr =
23325 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23326 Local<v8::Promise> p = pr->GetPromise();
23327 Local<v8::Promise> q = qr->GetPromise();
23328
23329 CHECK(p->IsPromise());
23330 CHECK(q->IsPromise());
23331
23332 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
23333 qr->Resolve(context.local(), p).FromJust();
23334
23335 // Chaining non-pending promises.
23336 CompileRun(
23337 "var x1 = 0;\n"
23338 "var x2 = 0;\n"
23339 "function f1(x) { x1 = x; return x+1 };\n"
23340 "function f2(x) { x2 = x; return x+1 };\n");
23341 Local<Function> f1 = Local<Function>::Cast(
23342 global->Get(context.local(), v8_str("f1")).ToLocalChecked());
23343 Local<Function> f2 = Local<Function>::Cast(
23344 global->Get(context.local(), v8_str("f2")).ToLocalChecked());
23345
23346 // Then
23347 CompileRun("x1 = x2 = 0;");
23348 q->Then(context.local(), f1).ToLocalChecked();
23349 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
23350 .ToLocalChecked()
23351 ->Int32Value(context.local())
23352 .FromJust());
23353 isolate->RunMicrotasks();
23354 CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
23355 .ToLocalChecked()
23356 ->Int32Value(context.local())
23357 .FromJust());
23358
23359 // Then
23360 CompileRun("x1 = x2 = 0;");
23361 pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23362 qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
23363
23364 qr->Resolve(context.local(), pr).FromJust();
23365 qr->GetPromise()
23366 ->Then(context.local(), f1)
23367 .ToLocalChecked()
23368 ->Then(context.local(), f2)
23369 .ToLocalChecked();
23370
23371 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
23372 .ToLocalChecked()
23373 ->Int32Value(context.local())
23374 .FromJust());
23375 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
23376 .ToLocalChecked()
23377 ->Int32Value(context.local())
23378 .FromJust());
23379 isolate->RunMicrotasks();
23380 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
23381 .ToLocalChecked()
23382 ->Int32Value(context.local())
23383 .FromJust());
23384 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
23385 .ToLocalChecked()
23386 ->Int32Value(context.local())
23387 .FromJust());
23388
23389 pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
23390
23391 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
23392 .ToLocalChecked()
23393 ->Int32Value(context.local())
23394 .FromJust());
23395 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
23396 .ToLocalChecked()
23397 ->Int32Value(context.local())
23398 .FromJust());
23399 isolate->RunMicrotasks();
23400 CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
23401 .ToLocalChecked()
23402 ->Int32Value(context.local())
23403 .FromJust());
23404 CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
23405 .ToLocalChecked()
23406 ->Int32Value(context.local())
23407 .FromJust());
23408 }
23409
23410
TEST(DisallowJavascriptExecutionScope)23411 TEST(DisallowJavascriptExecutionScope) {
23412 LocalContext context;
23413 v8::Isolate* isolate = context->GetIsolate();
23414 v8::HandleScope scope(isolate);
23415 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23416 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23417 CompileRun("2+2");
23418 }
23419
23420
TEST(AllowJavascriptExecutionScope)23421 TEST(AllowJavascriptExecutionScope) {
23422 LocalContext context;
23423 v8::Isolate* isolate = context->GetIsolate();
23424 v8::HandleScope scope(isolate);
23425 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23426 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23427 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23428 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23429 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23430 CompileRun("1+1");
23431 }
23432 }
23433
23434
TEST(ThrowOnJavascriptExecution)23435 TEST(ThrowOnJavascriptExecution) {
23436 LocalContext context;
23437 v8::Isolate* isolate = context->GetIsolate();
23438 v8::HandleScope scope(isolate);
23439 v8::TryCatch try_catch(isolate);
23440 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23441 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23442 CompileRun("1+1");
23443 CHECK(try_catch.HasCaught());
23444 }
23445
23446
TEST(Regress354123)23447 TEST(Regress354123) {
23448 LocalContext current;
23449 v8::Isolate* isolate = current->GetIsolate();
23450 v8::HandleScope scope(isolate);
23451
23452 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23453 templ->SetAccessCheckCallback(AccessCounter);
23454 CHECK(current->Global()
23455 ->Set(current.local(), v8_str("friend"),
23456 templ->NewInstance(current.local()).ToLocalChecked())
23457 .FromJust());
23458
23459 // Test access using __proto__ from the prototype chain.
23460 access_count = 0;
23461 CompileRun("friend.__proto__ = {};");
23462 CHECK_EQ(2, access_count);
23463 CompileRun("friend.__proto__;");
23464 CHECK_EQ(4, access_count);
23465
23466 // Test access using __proto__ as a hijacked function (A).
23467 access_count = 0;
23468 CompileRun("var p = Object.prototype;"
23469 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23470 "f.call(friend, {});");
23471 CHECK_EQ(1, access_count);
23472 CompileRun("var p = Object.prototype;"
23473 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23474 "f.call(friend);");
23475 CHECK_EQ(2, access_count);
23476
23477 // Test access using __proto__ as a hijacked function (B).
23478 access_count = 0;
23479 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23480 "f.call(friend, {});");
23481 CHECK_EQ(1, access_count);
23482 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23483 "f.call(friend);");
23484 CHECK_EQ(2, access_count);
23485
23486 // Test access using Object.setPrototypeOf reflective method.
23487 access_count = 0;
23488 CompileRun("Object.setPrototypeOf(friend, {});");
23489 CHECK_EQ(1, access_count);
23490 CompileRun("Object.getPrototypeOf(friend);");
23491 CHECK_EQ(2, access_count);
23492 }
23493
23494
TEST(CaptureStackTraceForStackOverflow)23495 TEST(CaptureStackTraceForStackOverflow) {
23496 v8::internal::FLAG_stack_size = 150;
23497 LocalContext current;
23498 v8::Isolate* isolate = current->GetIsolate();
23499 v8::HandleScope scope(isolate);
23500 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
23501 v8::StackTrace::kDetailed);
23502 v8::TryCatch try_catch(isolate);
23503 CompileRun("(function f(x) { f(x+1); })(0)");
23504 CHECK(try_catch.HasCaught());
23505 }
23506
23507
TEST(ScriptNameAndLineNumber)23508 TEST(ScriptNameAndLineNumber) {
23509 LocalContext env;
23510 v8::Isolate* isolate = env->GetIsolate();
23511 v8::HandleScope scope(isolate);
23512 const char* url = "http://www.foo.com/foo.js";
23513 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23514 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23515 Local<Script> script =
23516 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
23517 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23518 CHECK(!script_name.IsEmpty());
23519 CHECK(script_name->IsString());
23520 String::Utf8Value utf8_name(script_name);
23521 CHECK_EQ(0, strcmp(url, *utf8_name));
23522 int line_number = script->GetUnboundScript()->GetLineNumber(0);
23523 CHECK_EQ(13, line_number);
23524 }
23525
TEST(ScriptPositionInfo)23526 TEST(ScriptPositionInfo) {
23527 LocalContext env;
23528 v8::Isolate* isolate = env->GetIsolate();
23529 v8::HandleScope scope(isolate);
23530 const char* url = "http://www.foo.com/foo.js";
23531 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23532 v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
23533 "var bar;\n"
23534 "var fisk = foo + bar;\n"),
23535 origin);
23536 Local<Script> script =
23537 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
23538
23539 i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
23540 v8::Utils::OpenHandle(*script->GetUnboundScript()));
23541 CHECK(obj->script()->IsScript());
23542
23543 i::Handle<i::Script> script1(i::Script::cast(obj->script()));
23544
23545 v8::internal::Script::PositionInfo info;
23546
23547 // With offset.
23548
23549 // Behave as if 0 was passed if position is negative.
23550 CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
23551 CHECK_EQ(13, info.line);
23552 CHECK_EQ(0, info.column);
23553 CHECK_EQ(0, info.line_start);
23554 CHECK_EQ(8, info.line_end);
23555
23556 CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
23557 CHECK_EQ(13, info.line);
23558 CHECK_EQ(0, info.column);
23559 CHECK_EQ(0, info.line_start);
23560 CHECK_EQ(8, info.line_end);
23561
23562 CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
23563 CHECK_EQ(13, info.line);
23564 CHECK_EQ(8, info.column);
23565 CHECK_EQ(0, info.line_start);
23566 CHECK_EQ(8, info.line_end);
23567
23568 CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
23569 CHECK_EQ(14, info.line);
23570 CHECK_EQ(0, info.column);
23571 CHECK_EQ(9, info.line_start);
23572 CHECK_EQ(17, info.line_end);
23573
23574 // Fail when position is larger than script size.
23575 CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
23576
23577 // Without offset.
23578
23579 // Behave as if 0 was passed if position is negative.
23580 CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
23581 CHECK_EQ(0, info.line);
23582 CHECK_EQ(0, info.column);
23583 CHECK_EQ(0, info.line_start);
23584 CHECK_EQ(8, info.line_end);
23585
23586 CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
23587 CHECK_EQ(0, info.line);
23588 CHECK_EQ(0, info.column);
23589 CHECK_EQ(0, info.line_start);
23590 CHECK_EQ(8, info.line_end);
23591
23592 CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
23593 CHECK_EQ(0, info.line);
23594 CHECK_EQ(8, info.column);
23595 CHECK_EQ(0, info.line_start);
23596 CHECK_EQ(8, info.line_end);
23597
23598 CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
23599 CHECK_EQ(1, info.line);
23600 CHECK_EQ(0, info.column);
23601 CHECK_EQ(9, info.line_start);
23602 CHECK_EQ(17, info.line_end);
23603
23604 // Fail when position is larger than script size.
23605 CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
23606 }
23607
CheckMagicComments(Local<Script> script,const char * expected_source_url,const char * expected_source_mapping_url)23608 void CheckMagicComments(Local<Script> script, const char* expected_source_url,
23609 const char* expected_source_mapping_url) {
23610 if (expected_source_url != NULL) {
23611 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
23612 CHECK_EQ(0, strcmp(expected_source_url, *url));
23613 } else {
23614 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
23615 }
23616 if (expected_source_mapping_url != NULL) {
23617 v8::String::Utf8Value url(
23618 script->GetUnboundScript()->GetSourceMappingURL());
23619 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
23620 } else {
23621 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
23622 }
23623 }
23624
SourceURLHelper(const char * source,const char * expected_source_url,const char * expected_source_mapping_url)23625 void SourceURLHelper(const char* source, const char* expected_source_url,
23626 const char* expected_source_mapping_url) {
23627 Local<Script> script = v8_compile(source);
23628 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
23629 }
23630
23631
TEST(ScriptSourceURLAndSourceMappingURL)23632 TEST(ScriptSourceURLAndSourceMappingURL) {
23633 LocalContext env;
23634 v8::Isolate* isolate = env->GetIsolate();
23635 v8::HandleScope scope(isolate);
23636 SourceURLHelper("function foo() {}\n"
23637 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
23638 SourceURLHelper("function foo() {}\n"
23639 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
23640
23641 // Both sourceURL and sourceMappingURL.
23642 SourceURLHelper("function foo() {}\n"
23643 "//# sourceURL=bar3.js\n"
23644 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
23645
23646 // Two source URLs; the first one is ignored.
23647 SourceURLHelper("function foo() {}\n"
23648 "//# sourceURL=ignoreme.js\n"
23649 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
23650 SourceURLHelper("function foo() {}\n"
23651 "//# sourceMappingURL=ignoreme.js\n"
23652 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
23653
23654 // SourceURL or sourceMappingURL in the middle of the script.
23655 SourceURLHelper("function foo() {}\n"
23656 "//# sourceURL=bar7.js\n"
23657 "function baz() {}\n", "bar7.js", NULL);
23658 SourceURLHelper("function foo() {}\n"
23659 "//# sourceMappingURL=bar8.js\n"
23660 "function baz() {}\n", NULL, "bar8.js");
23661
23662 // Too much whitespace.
23663 SourceURLHelper("function foo() {}\n"
23664 "//# sourceURL=bar9.js\n"
23665 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
23666 SourceURLHelper("function foo() {}\n"
23667 "//# sourceURL =bar11.js\n"
23668 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
23669
23670 // Disallowed characters in value.
23671 SourceURLHelper("function foo() {}\n"
23672 "//# sourceURL=bar13 .js \n"
23673 "//# sourceMappingURL=bar14 .js \n",
23674 NULL, NULL);
23675 SourceURLHelper("function foo() {}\n"
23676 "//# sourceURL=bar15\t.js \n"
23677 "//# sourceMappingURL=bar16\t.js \n",
23678 NULL, NULL);
23679 SourceURLHelper("function foo() {}\n"
23680 "//# sourceURL=bar17'.js \n"
23681 "//# sourceMappingURL=bar18'.js \n",
23682 NULL, NULL);
23683 SourceURLHelper("function foo() {}\n"
23684 "//# sourceURL=bar19\".js \n"
23685 "//# sourceMappingURL=bar20\".js \n",
23686 NULL, NULL);
23687
23688 // Not too much whitespace.
23689 SourceURLHelper("function foo() {}\n"
23690 "//# sourceURL= bar21.js \n"
23691 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
23692 }
23693
23694
TEST(GetOwnPropertyDescriptor)23695 TEST(GetOwnPropertyDescriptor) {
23696 LocalContext env;
23697 v8::Isolate* isolate = env->GetIsolate();
23698 v8::HandleScope scope(isolate);
23699 CompileRun(
23700 "var x = { value : 13};"
23701 "Object.defineProperty(x, 'p0', {value : 12});"
23702 "Object.defineProperty(x, 'p1', {"
23703 " set : function(value) { this.value = value; },"
23704 " get : function() { return this.value; },"
23705 "});");
23706 Local<Object> x = Local<Object>::Cast(
23707 env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
23708 Local<Value> desc =
23709 x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
23710 .ToLocalChecked();
23711 CHECK(desc->IsUndefined());
23712 desc =
23713 x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
23714 CHECK(v8_num(12)
23715 ->Equals(env.local(), Local<Object>::Cast(desc)
23716 ->Get(env.local(), v8_str("value"))
23717 .ToLocalChecked())
23718 .FromJust());
23719 desc =
23720 x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
23721 Local<Function> set =
23722 Local<Function>::Cast(Local<Object>::Cast(desc)
23723 ->Get(env.local(), v8_str("set"))
23724 .ToLocalChecked());
23725 Local<Function> get =
23726 Local<Function>::Cast(Local<Object>::Cast(desc)
23727 ->Get(env.local(), v8_str("get"))
23728 .ToLocalChecked());
23729 CHECK(v8_num(13)
23730 ->Equals(env.local(),
23731 get->Call(env.local(), x, 0, NULL).ToLocalChecked())
23732 .FromJust());
23733 Local<Value> args[] = {v8_num(14)};
23734 set->Call(env.local(), x, 1, args).ToLocalChecked();
23735 CHECK(v8_num(14)
23736 ->Equals(env.local(),
23737 get->Call(env.local(), x, 0, NULL).ToLocalChecked())
23738 .FromJust());
23739 }
23740
23741
TEST(Regress411877)23742 TEST(Regress411877) {
23743 v8::Isolate* isolate = CcTest::isolate();
23744 v8::HandleScope handle_scope(isolate);
23745 v8::Local<v8::ObjectTemplate> object_template =
23746 v8::ObjectTemplate::New(isolate);
23747 object_template->SetAccessCheckCallback(AccessCounter);
23748
23749 v8::Local<Context> context = Context::New(isolate);
23750 v8::Context::Scope context_scope(context);
23751
23752 CHECK(context->Global()
23753 ->Set(context, v8_str("o"),
23754 object_template->NewInstance(context).ToLocalChecked())
23755 .FromJust());
23756 CompileRun("Object.getOwnPropertyNames(o)");
23757 }
23758
23759
TEST(GetHiddenPropertyTableAfterAccessCheck)23760 TEST(GetHiddenPropertyTableAfterAccessCheck) {
23761 v8::Isolate* isolate = CcTest::isolate();
23762 v8::HandleScope handle_scope(isolate);
23763 v8::Local<v8::ObjectTemplate> object_template =
23764 v8::ObjectTemplate::New(isolate);
23765 object_template->SetAccessCheckCallback(AccessCounter);
23766
23767 v8::Local<Context> context = Context::New(isolate);
23768 v8::Context::Scope context_scope(context);
23769
23770 v8::Local<v8::Object> obj =
23771 object_template->NewInstance(context).ToLocalChecked();
23772 obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
23773 obj->Delete(context, v8_str("key")).FromJust();
23774
23775 obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
23776 v8_str("hidden value 2"))
23777 .FromJust();
23778 }
23779
23780
TEST(Regress411793)23781 TEST(Regress411793) {
23782 v8::Isolate* isolate = CcTest::isolate();
23783 v8::HandleScope handle_scope(isolate);
23784 v8::Local<v8::ObjectTemplate> object_template =
23785 v8::ObjectTemplate::New(isolate);
23786 object_template->SetAccessCheckCallback(AccessCounter);
23787
23788 v8::Local<Context> context = Context::New(isolate);
23789 v8::Context::Scope context_scope(context);
23790
23791 CHECK(context->Global()
23792 ->Set(context, v8_str("o"),
23793 object_template->NewInstance(context).ToLocalChecked())
23794 .FromJust());
23795 CompileRun(
23796 "Object.defineProperty(o, 'key', "
23797 " { get: function() {}, set: function() {} });");
23798 }
23799
23800 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23801 public:
TestSourceStream(const char ** chunks)23802 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23803
GetMoreData(const uint8_t ** src)23804 virtual size_t GetMoreData(const uint8_t** src) {
23805 // Unlike in real use cases, this function will never block.
23806 if (chunks_[index_] == NULL) {
23807 return 0;
23808 }
23809 // Copy the data, since the caller takes ownership of it.
23810 size_t len = strlen(chunks_[index_]);
23811 // We don't need to zero-terminate since we return the length.
23812 uint8_t* copy = new uint8_t[len];
23813 memcpy(copy, chunks_[index_], len);
23814 *src = copy;
23815 ++index_;
23816 return len;
23817 }
23818
23819 // Helper for constructing a string from chunks (the compilation needs it
23820 // too).
FullSourceString(const char ** chunks)23821 static char* FullSourceString(const char** chunks) {
23822 size_t total_len = 0;
23823 for (size_t i = 0; chunks[i] != NULL; ++i) {
23824 total_len += strlen(chunks[i]);
23825 }
23826 char* full_string = new char[total_len + 1];
23827 size_t offset = 0;
23828 for (size_t i = 0; chunks[i] != NULL; ++i) {
23829 size_t len = strlen(chunks[i]);
23830 memcpy(full_string + offset, chunks[i], len);
23831 offset += len;
23832 }
23833 full_string[total_len] = 0;
23834 return full_string;
23835 }
23836
23837 private:
23838 const char** chunks_;
23839 unsigned index_;
23840 };
23841
23842
23843 // Helper function for running streaming tests.
RunStreamingTest(const char ** chunks,v8::ScriptCompiler::StreamedSource::Encoding encoding=v8::ScriptCompiler::StreamedSource::ONE_BYTE,bool expected_success=true,const char * expected_source_url=NULL,const char * expected_source_mapping_url=NULL)23844 void RunStreamingTest(const char** chunks,
23845 v8::ScriptCompiler::StreamedSource::Encoding encoding =
23846 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23847 bool expected_success = true,
23848 const char* expected_source_url = NULL,
23849 const char* expected_source_mapping_url = NULL) {
23850 LocalContext env;
23851 v8::Isolate* isolate = env->GetIsolate();
23852 v8::HandleScope scope(isolate);
23853 v8::TryCatch try_catch(isolate);
23854
23855 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23856 encoding);
23857 v8::ScriptCompiler::ScriptStreamingTask* task =
23858 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23859
23860 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23861 // task here in the main thread.
23862 task->Run();
23863 delete task;
23864
23865 // Possible errors are only produced while compiling.
23866 CHECK_EQ(false, try_catch.HasCaught());
23867
23868 v8::ScriptOrigin origin(v8_str("http://foo.com"));
23869 char* full_source = TestSourceStream::FullSourceString(chunks);
23870 v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
23871 env.local(), &source, v8_str(full_source), origin);
23872 if (expected_success) {
23873 CHECK(!script.IsEmpty());
23874 v8::Local<Value> result(
23875 script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
23876 // All scripts are supposed to return the fixed value 13 when ran.
23877 CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
23878 CheckMagicComments(script.ToLocalChecked(), expected_source_url,
23879 expected_source_mapping_url);
23880 } else {
23881 CHECK(script.IsEmpty());
23882 CHECK(try_catch.HasCaught());
23883 }
23884 delete[] full_source;
23885 }
23886
23887
TEST(StreamingSimpleScript)23888 TEST(StreamingSimpleScript) {
23889 // This script is unrealistically small, since no one chunk is enough to fill
23890 // the backing buffer of Scanner, let alone overflow it.
23891 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23892 NULL};
23893 RunStreamingTest(chunks);
23894 }
23895
23896
TEST(StreamingBiggerScript)23897 TEST(StreamingBiggerScript) {
23898 const char* chunk1 =
23899 "function foo() {\n"
23900 " // Make this chunk sufficiently long so that it will overflow the\n"
23901 " // backing buffer of the Scanner.\n"
23902 " var i = 0;\n"
23903 " var result = 0;\n"
23904 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23905 " result = 0;\n"
23906 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23907 " result = 0;\n"
23908 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23909 " result = 0;\n"
23910 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23911 " return result;\n"
23912 "}\n";
23913 const char* chunks[] = {chunk1, "foo(); ", NULL};
23914 RunStreamingTest(chunks);
23915 }
23916
23917
TEST(StreamingScriptWithParseError)23918 TEST(StreamingScriptWithParseError) {
23919 // Test that parse errors from streamed scripts are propagated correctly.
23920 {
23921 char chunk1[] =
23922 " // This will result in a parse error.\n"
23923 " var if else then foo";
23924 char chunk2[] = " 13\n";
23925 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23926
23927 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23928 false);
23929 }
23930 // Test that the next script succeeds normally.
23931 {
23932 char chunk1[] =
23933 " // This will be parsed successfully.\n"
23934 " function foo() { return ";
23935 char chunk2[] = " 13; }\n";
23936 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23937
23938 RunStreamingTest(chunks);
23939 }
23940 }
23941
23942
TEST(StreamingUtf8Script)23943 TEST(StreamingUtf8Script) {
23944 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
23945 // don't like it.
23946 const char* chunk1 =
23947 "function foo() {\n"
23948 " // This function will contain an UTF-8 character which is not in\n"
23949 " // ASCII.\n"
23950 " var foob\xec\x92\x81r = 13;\n"
23951 " return foob\xec\x92\x81r;\n"
23952 "}\n";
23953 const char* chunks[] = {chunk1, "foo(); ", NULL};
23954 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23955 }
23956
23957
TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck)23958 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23959 // A sanity check to prove that the approach of splitting UTF-8
23960 // characters is correct. Here is an UTF-8 character which will take three
23961 // bytes.
23962 const char* reference = "\xec\x92\x81";
23963 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
23964
23965 char chunk1[] =
23966 "function foo() {\n"
23967 " // This function will contain an UTF-8 character which is not in\n"
23968 " // ASCII.\n"
23969 " var foob";
23970 char chunk2[] =
23971 "XXXr = 13;\n"
23972 " return foob\xec\x92\x81r;\n"
23973 "}\n";
23974 for (int i = 0; i < 3; ++i) {
23975 chunk2[i] = reference[i];
23976 }
23977 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23978 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23979 }
23980
23981
TEST(StreamingUtf8ScriptWithSplitCharacters)23982 TEST(StreamingUtf8ScriptWithSplitCharacters) {
23983 // Stream data where a multi-byte UTF-8 character is split between two data
23984 // chunks.
23985 const char* reference = "\xec\x92\x81";
23986 char chunk1[] =
23987 "function foo() {\n"
23988 " // This function will contain an UTF-8 character which is not in\n"
23989 " // ASCII.\n"
23990 " var foobX";
23991 char chunk2[] =
23992 "XXr = 13;\n"
23993 " return foob\xec\x92\x81r;\n"
23994 "}\n";
23995 chunk1[strlen(chunk1) - 1] = reference[0];
23996 chunk2[0] = reference[1];
23997 chunk2[1] = reference[2];
23998 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23999 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24000 }
24001
24002
TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases)24003 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24004 // Tests edge cases which should still be decoded correctly.
24005
24006 // Case 1: a chunk contains only bytes for a split character (and no other
24007 // data). This kind of a chunk would be exceptionally small, but we should
24008 // still decode it correctly.
24009 const char* reference = "\xec\x92\x81";
24010 // The small chunk is at the beginning of the split character
24011 {
24012 char chunk1[] =
24013 "function foo() {\n"
24014 " // This function will contain an UTF-8 character which is not in\n"
24015 " // ASCII.\n"
24016 " var foob";
24017 char chunk2[] = "XX";
24018 char chunk3[] =
24019 "Xr = 13;\n"
24020 " return foob\xec\x92\x81r;\n"
24021 "}\n";
24022 chunk2[0] = reference[0];
24023 chunk2[1] = reference[1];
24024 chunk3[0] = reference[2];
24025 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24026 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24027 }
24028 // The small chunk is at the end of a character
24029 {
24030 char chunk1[] =
24031 "function foo() {\n"
24032 " // This function will contain an UTF-8 character which is not in\n"
24033 " // ASCII.\n"
24034 " var foobX";
24035 char chunk2[] = "XX";
24036 char chunk3[] =
24037 "r = 13;\n"
24038 " return foob\xec\x92\x81r;\n"
24039 "}\n";
24040 chunk1[strlen(chunk1) - 1] = reference[0];
24041 chunk2[0] = reference[1];
24042 chunk2[1] = reference[2];
24043 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24044 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24045 }
24046 // Case 2: the script ends with a multi-byte character. Make sure that it's
24047 // decoded correctly and not just ignored.
24048 {
24049 char chunk1[] =
24050 "var foob\xec\x92\x81 = 13;\n"
24051 "foob\xec\x92\x81";
24052 const char* chunks[] = {chunk1, NULL};
24053 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24054 }
24055 }
24056
24057
TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases)24058 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24059 // Test cases where a UTF-8 character is split over several chunks. Those
24060 // cases are not supported (the embedder should give the data in big enough
24061 // chunks), but we shouldn't crash, just produce a parse error.
24062 const char* reference = "\xec\x92\x81";
24063 char chunk1[] =
24064 "function foo() {\n"
24065 " // This function will contain an UTF-8 character which is not in\n"
24066 " // ASCII.\n"
24067 " var foobX";
24068 char chunk2[] = "X";
24069 char chunk3[] =
24070 "Xr = 13;\n"
24071 " return foob\xec\x92\x81r;\n"
24072 "}\n";
24073 chunk1[strlen(chunk1) - 1] = reference[0];
24074 chunk2[0] = reference[1];
24075 chunk3[0] = reference[2];
24076 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24077
24078 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24079 }
24080
24081
TEST(StreamingProducesParserCache)24082 TEST(StreamingProducesParserCache) {
24083 i::FLAG_min_preparse_length = 0;
24084 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24085 NULL};
24086
24087 LocalContext env;
24088 v8::Isolate* isolate = env->GetIsolate();
24089 v8::HandleScope scope(isolate);
24090
24091 v8::ScriptCompiler::StreamedSource source(
24092 new TestSourceStream(chunks),
24093 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24094 v8::ScriptCompiler::ScriptStreamingTask* task =
24095 v8::ScriptCompiler::StartStreamingScript(
24096 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24097
24098 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24099 // task here in the main thread.
24100 task->Run();
24101 delete task;
24102
24103 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24104 CHECK(cached_data != NULL);
24105 CHECK(cached_data->data != NULL);
24106 CHECK(!cached_data->rejected);
24107 CHECK_GT(cached_data->length, 0);
24108 }
24109
24110
TEST(StreamingWithDebuggingEnabledLate)24111 TEST(StreamingWithDebuggingEnabledLate) {
24112 // The streaming parser can only parse lazily, i.e. inner functions are not
24113 // fully parsed. However, we may compile inner functions eagerly when
24114 // debugging. Make sure that we can deal with this when turning on debugging
24115 // after streaming parser has already finished parsing.
24116 i::FLAG_min_preparse_length = 0;
24117 const char* chunks[] = {"with({x:1}) {",
24118 " var foo = function foo(y) {",
24119 " return x + y;",
24120 " };",
24121 " foo(2);",
24122 "}",
24123 NULL};
24124
24125 LocalContext env;
24126 v8::Isolate* isolate = env->GetIsolate();
24127 v8::HandleScope scope(isolate);
24128 v8::TryCatch try_catch(isolate);
24129
24130 v8::ScriptCompiler::StreamedSource source(
24131 new TestSourceStream(chunks),
24132 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24133 v8::ScriptCompiler::ScriptStreamingTask* task =
24134 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24135
24136 task->Run();
24137 delete task;
24138
24139 CHECK(!try_catch.HasCaught());
24140
24141 v8::ScriptOrigin origin(v8_str("http://foo.com"));
24142 char* full_source = TestSourceStream::FullSourceString(chunks);
24143
24144 EnableDebugger(isolate);
24145
24146 v8::Local<Script> script =
24147 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
24148 origin)
24149 .ToLocalChecked();
24150
24151 Maybe<uint32_t> result =
24152 script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
24153 CHECK_EQ(3U, result.FromMaybe(0));
24154
24155 delete[] full_source;
24156
24157 DisableDebugger(isolate);
24158 }
24159
24160
TEST(StreamingScriptWithInvalidUtf8)24161 TEST(StreamingScriptWithInvalidUtf8) {
24162 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24163 // chunk don't produce a crash.
24164 const char* reference = "\xec\x92\x81\x80\x80";
24165 char chunk1[] =
24166 "function foo() {\n"
24167 " // This function will contain an UTF-8 character which is not in\n"
24168 " // ASCII.\n"
24169 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
24170 char chunk2[] =
24171 "r = 13;\n"
24172 " return foob\xec\x92\x81\x80\x80r;\n"
24173 "}\n";
24174 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24175
24176 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24177 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24178 }
24179
24180
TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit)24181 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24182 // Regression test: Stream data where there are several multi-byte UTF-8
24183 // characters in a sequence and one of them is split between two data chunks.
24184 const char* reference = "\xec\x92\x81";
24185 char chunk1[] =
24186 "function foo() {\n"
24187 " // This function will contain an UTF-8 character which is not in\n"
24188 " // ASCII.\n"
24189 " var foob\xec\x92\x81X";
24190 char chunk2[] =
24191 "XXr = 13;\n"
24192 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24193 "}\n";
24194 chunk1[strlen(chunk1) - 1] = reference[0];
24195 chunk2[0] = reference[1];
24196 chunk2[1] = reference[2];
24197 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24198 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24199 }
24200
24201
TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2)24202 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24203 // Another regression test, similar to the previous one. The difference is
24204 // that the split character is not the last one in the sequence.
24205 const char* reference = "\xec\x92\x81";
24206 char chunk1[] =
24207 "function foo() {\n"
24208 " // This function will contain an UTF-8 character which is not in\n"
24209 " // ASCII.\n"
24210 " var foobX";
24211 char chunk2[] =
24212 "XX\xec\x92\x81r = 13;\n"
24213 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24214 "}\n";
24215 chunk1[strlen(chunk1) - 1] = reference[0];
24216 chunk2[0] = reference[1];
24217 chunk2[1] = reference[2];
24218 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24219 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24220 }
24221
24222
TEST(StreamingWithHarmonyScopes)24223 TEST(StreamingWithHarmonyScopes) {
24224 // Don't use RunStreamingTest here so that both scripts get to use the same
24225 // LocalContext and HandleScope.
24226 LocalContext env;
24227 v8::Isolate* isolate = env->GetIsolate();
24228 v8::HandleScope scope(isolate);
24229
24230 // First, run a script with a let variable.
24231 CompileRun("\"use strict\"; let x = 1;");
24232
24233 // Then stream a script which (erroneously) tries to introduce the same
24234 // variable again.
24235 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
24236
24237 v8::TryCatch try_catch(isolate);
24238 v8::ScriptCompiler::StreamedSource source(
24239 new TestSourceStream(chunks),
24240 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24241 v8::ScriptCompiler::ScriptStreamingTask* task =
24242 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24243 task->Run();
24244 delete task;
24245
24246 // Parsing should succeed (the script will be parsed and compiled in a context
24247 // independent way, so the error is not detected).
24248 CHECK_EQ(false, try_catch.HasCaught());
24249
24250 v8::ScriptOrigin origin(v8_str("http://foo.com"));
24251 char* full_source = TestSourceStream::FullSourceString(chunks);
24252 v8::Local<Script> script =
24253 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
24254 origin)
24255 .ToLocalChecked();
24256 CHECK(!script.IsEmpty());
24257 CHECK_EQ(false, try_catch.HasCaught());
24258
24259 // Running the script exposes the error.
24260 CHECK(script->Run(env.local()).IsEmpty());
24261 CHECK(try_catch.HasCaught());
24262 delete[] full_source;
24263 }
24264
24265
TEST(CodeCache)24266 TEST(CodeCache) {
24267 v8::Isolate::CreateParams create_params;
24268 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
24269
24270 const char* source = "Math.sqrt(4)";
24271 const char* origin = "code cache test";
24272 v8::ScriptCompiler::CachedData* cache;
24273
24274 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
24275 {
24276 v8::Isolate::Scope iscope(isolate1);
24277 v8::HandleScope scope(isolate1);
24278 v8::Local<v8::Context> context = v8::Context::New(isolate1);
24279 v8::Context::Scope cscope(context);
24280 v8::Local<v8::String> source_string = v8_str(source);
24281 v8::ScriptOrigin script_origin(v8_str(origin));
24282 v8::ScriptCompiler::Source source(source_string, script_origin);
24283 v8::ScriptCompiler::CompileOptions option =
24284 v8::ScriptCompiler::kProduceCodeCache;
24285 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
24286 int length = source.GetCachedData()->length;
24287 uint8_t* cache_data = new uint8_t[length];
24288 memcpy(cache_data, source.GetCachedData()->data, length);
24289 cache = new v8::ScriptCompiler::CachedData(
24290 cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
24291 }
24292 isolate1->Dispose();
24293
24294 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
24295 {
24296 v8::Isolate::Scope iscope(isolate2);
24297 v8::HandleScope scope(isolate2);
24298 v8::Local<v8::Context> context = v8::Context::New(isolate2);
24299 v8::Context::Scope cscope(context);
24300 v8::Local<v8::String> source_string = v8_str(source);
24301 v8::ScriptOrigin script_origin(v8_str(origin));
24302 v8::ScriptCompiler::Source source(source_string, script_origin, cache);
24303 v8::ScriptCompiler::CompileOptions option =
24304 v8::ScriptCompiler::kConsumeCodeCache;
24305 v8::Local<v8::Script> script;
24306 {
24307 i::DisallowCompilation no_compile(
24308 reinterpret_cast<i::Isolate*>(isolate2));
24309 script = v8::ScriptCompiler::Compile(context, &source, option)
24310 .ToLocalChecked();
24311 }
24312 CHECK_EQ(2, script->Run(context)
24313 .ToLocalChecked()
24314 ->ToInt32(context)
24315 .ToLocalChecked()
24316 ->Int32Value(context)
24317 .FromJust());
24318 }
24319 isolate2->Dispose();
24320 }
24321
24322
TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option)24323 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
24324 const char* garbage = "garbage garbage garbage garbage garbage garbage";
24325 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
24326 int length = 16;
24327 v8::ScriptCompiler::CachedData* cached_data =
24328 new v8::ScriptCompiler::CachedData(data, length);
24329 CHECK(!cached_data->rejected);
24330 v8::ScriptOrigin origin(v8_str("origin"));
24331 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
24332 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
24333 v8::Local<v8::Script> script =
24334 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
24335 CHECK(cached_data->rejected);
24336 CHECK_EQ(
24337 42,
24338 script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
24339 }
24340
TEST(InvalidParserCacheData)24341 TEST(InvalidParserCacheData) {
24342 v8::V8::Initialize();
24343 v8::HandleScope scope(CcTest::isolate());
24344 LocalContext context;
24345 if (i::FLAG_lazy && !(i::FLAG_ignition && i::FLAG_ignition_eager)) {
24346 // Cached parser data is not consumed while parsing eagerly.
24347 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
24348 }
24349 }
24350
TEST(InvalidCodeCacheData)24351 TEST(InvalidCodeCacheData) {
24352 v8::V8::Initialize();
24353 v8::HandleScope scope(CcTest::isolate());
24354 LocalContext context;
24355 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
24356 }
24357
24358
TEST(ParserCacheRejectedGracefully)24359 TEST(ParserCacheRejectedGracefully) {
24360 // Producing cached parser data while parsing eagerly is not supported.
24361 if (!i::FLAG_lazy || (i::FLAG_ignition && i::FLAG_ignition_eager)) return;
24362
24363 i::FLAG_min_preparse_length = 0;
24364 v8::V8::Initialize();
24365 v8::HandleScope scope(CcTest::isolate());
24366 LocalContext context;
24367 // Produce valid cached data.
24368 v8::ScriptOrigin origin(v8_str("origin"));
24369 v8::Local<v8::String> source_str = v8_str("function foo() {}");
24370 v8::ScriptCompiler::Source source(source_str, origin);
24371 v8::Local<v8::Script> script =
24372 v8::ScriptCompiler::Compile(context.local(), &source,
24373 v8::ScriptCompiler::kProduceParserCache)
24374 .ToLocalChecked();
24375 USE(script);
24376 const v8::ScriptCompiler::CachedData* original_cached_data =
24377 source.GetCachedData();
24378 CHECK(original_cached_data != NULL);
24379 CHECK(original_cached_data->data != NULL);
24380 CHECK(!original_cached_data->rejected);
24381 CHECK_GT(original_cached_data->length, 0);
24382 // Recompiling the same script with it won't reject the data.
24383 {
24384 v8::ScriptCompiler::Source source_with_cached_data(
24385 source_str, origin,
24386 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24387 original_cached_data->length));
24388 v8::Local<v8::Script> script =
24389 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
24390 v8::ScriptCompiler::kConsumeParserCache)
24391 .ToLocalChecked();
24392 USE(script);
24393 const v8::ScriptCompiler::CachedData* new_cached_data =
24394 source_with_cached_data.GetCachedData();
24395 CHECK(new_cached_data != NULL);
24396 CHECK(!new_cached_data->rejected);
24397 }
24398 // Compile an incompatible script with the cached data. The new script doesn't
24399 // have the same starting position for the function as the old one, so the old
24400 // cached data will be incompatible with it and will be rejected.
24401 {
24402 v8::Local<v8::String> incompatible_source_str =
24403 v8_str(" function foo() {}");
24404 v8::ScriptCompiler::Source source_with_cached_data(
24405 incompatible_source_str, origin,
24406 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24407 original_cached_data->length));
24408 v8::Local<v8::Script> script =
24409 v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
24410 v8::ScriptCompiler::kConsumeParserCache)
24411 .ToLocalChecked();
24412 USE(script);
24413 const v8::ScriptCompiler::CachedData* new_cached_data =
24414 source_with_cached_data.GetCachedData();
24415 CHECK(new_cached_data != NULL);
24416 CHECK(new_cached_data->rejected);
24417 }
24418 }
24419
24420
TEST(StringConcatOverflow)24421 TEST(StringConcatOverflow) {
24422 v8::V8::Initialize();
24423 v8::HandleScope scope(CcTest::isolate());
24424 RandomLengthOneByteResource* r =
24425 new RandomLengthOneByteResource(i::String::kMaxLength);
24426 v8::Local<v8::String> str =
24427 v8::String::NewExternalOneByte(CcTest::isolate(), r).ToLocalChecked();
24428 CHECK(!str.IsEmpty());
24429 v8::TryCatch try_catch(CcTest::isolate());
24430 v8::Local<v8::String> result = v8::String::Concat(str, str);
24431 CHECK(result.IsEmpty());
24432 CHECK(!try_catch.HasCaught());
24433 }
24434
24435
TEST(TurboAsmDisablesNeuter)24436 TEST(TurboAsmDisablesNeuter) {
24437 i::FLAG_allow_natives_syntax = true;
24438 v8::V8::Initialize();
24439 v8::HandleScope scope(CcTest::isolate());
24440 LocalContext context;
24441 bool should_be_neuterable = !i::FLAG_turbo_asm;
24442 const char* load =
24443 "function Module(stdlib, foreign, heap) {"
24444 " 'use asm';"
24445 " var MEM32 = new stdlib.Int32Array(heap);"
24446 " function load() { return MEM32[0]; }"
24447 " return { load: load };"
24448 "}"
24449 "var buffer = new ArrayBuffer(4);"
24450 "var module = Module(this, {}, buffer);"
24451 "%OptimizeFunctionOnNextCall(module.load);"
24452 "module.load();"
24453 "buffer";
24454
24455 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
24456 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24457
24458 const char* store =
24459 "function Module(stdlib, foreign, heap) {"
24460 " 'use asm';"
24461 " var MEM32 = new stdlib.Int32Array(heap);"
24462 " function store() { MEM32[0] = 0; }"
24463 " return { store: store };"
24464 "}"
24465 "var buffer = new ArrayBuffer(4);"
24466 "var module = Module(this, {}, buffer);"
24467 "%OptimizeFunctionOnNextCall(module.store);"
24468 "module.store();"
24469 "buffer";
24470
24471 result = CompileRun(store).As<v8::ArrayBuffer>();
24472 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24473 }
24474
24475
TEST(GetPrototypeAccessControl)24476 TEST(GetPrototypeAccessControl) {
24477 i::FLAG_allow_natives_syntax = true;
24478 v8::Isolate* isolate = CcTest::isolate();
24479 v8::HandleScope handle_scope(isolate);
24480 LocalContext env;
24481
24482 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
24483 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
24484
24485 CHECK(env->Global()
24486 ->Set(env.local(), v8_str("prohibited"),
24487 obj_template->NewInstance(env.local()).ToLocalChecked())
24488 .FromJust());
24489
24490 CHECK(CompileRun(
24491 "function f() { return %_GetPrototype(prohibited); }"
24492 "%OptimizeFunctionOnNextCall(f);"
24493 "f();")->IsNull());
24494 }
24495
24496
TEST(GetPrototypeHidden)24497 TEST(GetPrototypeHidden) {
24498 i::FLAG_allow_natives_syntax = true;
24499 v8::Isolate* isolate = CcTest::isolate();
24500 v8::HandleScope handle_scope(isolate);
24501 LocalContext env;
24502
24503 Local<FunctionTemplate> t = FunctionTemplate::New(isolate);
24504 t->SetHiddenPrototype(true);
24505 Local<Object> proto = t->GetFunction(env.local())
24506 .ToLocalChecked()
24507 ->NewInstance(env.local())
24508 .ToLocalChecked();
24509 Local<Object> object = Object::New(isolate);
24510 Local<Object> proto2 = Object::New(isolate);
24511 object->SetPrototype(env.local(), proto).FromJust();
24512 proto->SetPrototype(env.local(), proto2).FromJust();
24513
24514 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
24515 CHECK(env->Global()->Set(env.local(), v8_str("proto"), proto).FromJust());
24516 CHECK(env->Global()->Set(env.local(), v8_str("proto2"), proto2).FromJust());
24517
24518 v8::Local<v8::Value> result = CompileRun("%_GetPrototype(object)");
24519 CHECK(result->Equals(env.local(), proto2).FromJust());
24520
24521 result = CompileRun(
24522 "function f() { return %_GetPrototype(object); }"
24523 "%OptimizeFunctionOnNextCall(f);"
24524 "f()");
24525 CHECK(result->Equals(env.local(), proto2).FromJust());
24526 }
24527
24528
TEST(ClassPrototypeCreationContext)24529 TEST(ClassPrototypeCreationContext) {
24530 v8::Isolate* isolate = CcTest::isolate();
24531 v8::HandleScope handle_scope(isolate);
24532 LocalContext env;
24533
24534 Local<Object> result = Local<Object>::Cast(
24535 CompileRun("'use strict'; class Example { }; Example.prototype"));
24536 CHECK(env.local() == result->CreationContext());
24537 }
24538
24539
TEST(SimpleStreamingScriptWithSourceURL)24540 TEST(SimpleStreamingScriptWithSourceURL) {
24541 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
24542 "//# sourceURL=bar2.js\n", NULL};
24543 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
24544 "bar2.js");
24545 }
24546
24547
TEST(StreamingScriptWithSplitSourceURL)24548 TEST(StreamingScriptWithSplitSourceURL) {
24549 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
24550 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
24551 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
24552 "bar2.js");
24553 }
24554
24555
TEST(StreamingScriptWithSourceMappingURLInTheMiddle)24556 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
24557 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
24558 " sourceMappingURL=bar2.js\n", "foo();", NULL};
24559 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
24560 "bar2.js");
24561 }
24562
24563
TEST(NewStringRangeError)24564 TEST(NewStringRangeError) {
24565 v8::Isolate* isolate = CcTest::isolate();
24566 v8::HandleScope handle_scope(isolate);
24567 const int length = i::String::kMaxLength + 1;
24568 const int buffer_size = length * sizeof(uint16_t);
24569 void* buffer = malloc(buffer_size);
24570 if (buffer == NULL) return;
24571 memset(buffer, 'A', buffer_size);
24572 {
24573 v8::TryCatch try_catch(isolate);
24574 char* data = reinterpret_cast<char*>(buffer);
24575 CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
24576 length)
24577 .IsEmpty());
24578 CHECK(!try_catch.HasCaught());
24579 }
24580 {
24581 v8::TryCatch try_catch(isolate);
24582 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
24583 CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
24584 length)
24585 .IsEmpty());
24586 CHECK(!try_catch.HasCaught());
24587 }
24588 {
24589 v8::TryCatch try_catch(isolate);
24590 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
24591 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
24592 length)
24593 .IsEmpty());
24594 CHECK(!try_catch.HasCaught());
24595 }
24596 free(buffer);
24597 }
24598
24599
TEST(SealHandleScope)24600 TEST(SealHandleScope) {
24601 v8::Isolate* isolate = CcTest::isolate();
24602 v8::HandleScope handle_scope(isolate);
24603 LocalContext env;
24604
24605 v8::SealHandleScope seal(isolate);
24606
24607 // Should fail
24608 v8::Local<v8::Object> obj = v8::Object::New(isolate);
24609
24610 USE(obj);
24611 }
24612
24613
TEST(SealHandleScopeNested)24614 TEST(SealHandleScopeNested) {
24615 v8::Isolate* isolate = CcTest::isolate();
24616 v8::HandleScope handle_scope(isolate);
24617 LocalContext env;
24618
24619 v8::SealHandleScope seal(isolate);
24620
24621 {
24622 v8::HandleScope handle_scope(isolate);
24623
24624 // Should work
24625 v8::Local<v8::Object> obj = v8::Object::New(isolate);
24626
24627 USE(obj);
24628 }
24629 }
24630
24631
ExtrasBindingTestRuntimeFunction(const v8::FunctionCallbackInfo<v8::Value> & args)24632 static void ExtrasBindingTestRuntimeFunction(
24633 const v8::FunctionCallbackInfo<v8::Value>& args) {
24634 CHECK_EQ(
24635 3,
24636 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
24637 args.GetReturnValue().Set(v8_num(7));
24638 }
24639
TEST(ExtrasFunctionSource)24640 TEST(ExtrasFunctionSource) {
24641 v8::Isolate* isolate = CcTest::isolate();
24642 v8::HandleScope handle_scope(isolate);
24643 LocalContext env;
24644
24645 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
24646
24647 // Functions defined in extras do not expose source code.
24648 auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
24649 .ToLocalChecked()
24650 .As<v8::Function>();
24651 auto undefined = v8::Undefined(isolate);
24652 auto result = func->Call(env.local(), undefined, 0, {})
24653 .ToLocalChecked()
24654 .As<v8::String>();
24655 CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
24656
24657 // Functions defined in extras do not show up in the stack trace.
24658 auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
24659 .ToLocalChecked()
24660 .As<v8::Function>();
24661 CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
24662 ExpectString(
24663 "function f(x) { return wrapper(x) }"
24664 "function g() { return new Error().stack; }"
24665 "f(g)",
24666 "Error\n"
24667 " at g (<anonymous>:1:58)\n"
24668 " at f (<anonymous>:1:24)\n"
24669 " at <anonymous>:1:78");
24670 }
24671
TEST(ExtrasBindingObject)24672 TEST(ExtrasBindingObject) {
24673 v8::Isolate* isolate = CcTest::isolate();
24674 v8::HandleScope handle_scope(isolate);
24675 LocalContext env;
24676
24677 // standalone.gypi ensures we include the test-extra.js file, which should
24678 // export the tested functions.
24679 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
24680
24681 auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
24682 .ToLocalChecked()
24683 .As<v8::Function>();
24684 auto undefined = v8::Undefined(isolate);
24685 auto result = func->Call(env.local(), undefined, 0, {})
24686 .ToLocalChecked()
24687 .As<v8::Number>();
24688 CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
24689
24690 v8::Local<v8::FunctionTemplate> runtimeFunction =
24691 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
24692 binding->Set(env.local(), v8_str("runtime"),
24693 runtimeFunction->GetFunction(env.local()).ToLocalChecked())
24694 .FromJust();
24695 func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
24696 .ToLocalChecked()
24697 .As<v8::Function>();
24698 result = func->Call(env.local(), undefined, 0, {})
24699 .ToLocalChecked()
24700 .As<v8::Number>();
24701 CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
24702 }
24703
24704
TEST(ExperimentalExtras)24705 TEST(ExperimentalExtras) {
24706 i::FLAG_experimental_extras = true;
24707
24708 v8::Isolate* isolate = CcTest::isolate();
24709 v8::HandleScope handle_scope(isolate);
24710 LocalContext env;
24711
24712 // standalone.gypi ensures we include the test-experimental-extra.js file,
24713 // which should export the tested functions.
24714 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
24715
24716 auto func =
24717 binding->Get(env.local(), v8_str("testExperimentalExtraShouldReturnTen"))
24718 .ToLocalChecked()
24719 .As<v8::Function>();
24720 auto undefined = v8::Undefined(isolate);
24721 auto result = func->Call(env.local(), undefined, 0, {})
24722 .ToLocalChecked()
24723 .As<v8::Number>();
24724 CHECK_EQ(10, result->Int32Value(env.local()).FromJust());
24725
24726 v8::Local<v8::FunctionTemplate> runtimeFunction =
24727 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
24728 binding->Set(env.local(), v8_str("runtime"),
24729 runtimeFunction->GetFunction(env.local()).ToLocalChecked())
24730 .FromJust();
24731 func = binding->Get(env.local(),
24732 v8_str("testExperimentalExtraShouldCallToRuntime"))
24733 .ToLocalChecked()
24734 .As<v8::Function>();
24735 result = func->Call(env.local(), undefined, 0, {})
24736 .ToLocalChecked()
24737 .As<v8::Number>();
24738 CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
24739 }
24740
24741
TEST(ExtrasUtilsObject)24742 TEST(ExtrasUtilsObject) {
24743 LocalContext context;
24744 v8::Isolate* isolate = context->GetIsolate();
24745 v8::HandleScope handle_scope(isolate);
24746
24747 LocalContext env;
24748 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
24749
24750 auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
24751 .ToLocalChecked()
24752 .As<v8::Function>();
24753 auto undefined = v8::Undefined(isolate);
24754 auto result = func->Call(env.local(), undefined, 0, {})
24755 .ToLocalChecked()
24756 .As<v8::Object>();
24757
24758 auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
24759 .ToLocalChecked()
24760 .As<v8::Symbol>();
24761 i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
24762 CHECK_EQ(true, ips->IsPrivate());
24763
24764 CompileRun("var result = 0; function store(x) { result = x; }");
24765 auto store = CompileRun("store").As<v8::Function>();
24766
24767 auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
24768 .ToLocalChecked()
24769 .As<v8::Promise>();
24770 fulfilled_promise->Then(env.local(), store).ToLocalChecked();
24771 isolate->RunMicrotasks();
24772 CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
24773
24774 auto fulfilled_promise_2 =
24775 result->Get(env.local(), v8_str("fulfilledPromise2"))
24776 .ToLocalChecked()
24777 .As<v8::Promise>();
24778 fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
24779 isolate->RunMicrotasks();
24780 CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
24781
24782 auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
24783 .ToLocalChecked()
24784 .As<v8::Promise>();
24785 rejected_promise->Catch(env.local(), store).ToLocalChecked();
24786 isolate->RunMicrotasks();
24787 CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
24788 }
24789
24790
TEST(Map)24791 TEST(Map) {
24792 v8::Isolate* isolate = CcTest::isolate();
24793 v8::HandleScope handle_scope(isolate);
24794 LocalContext env;
24795
24796 v8::Local<v8::Map> map = v8::Map::New(isolate);
24797 CHECK(map->IsObject());
24798 CHECK(map->IsMap());
24799 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
24800 CHECK_EQ(0U, map->Size());
24801
24802 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
24803 CHECK(val->IsMap());
24804 map = v8::Local<v8::Map>::Cast(val);
24805 CHECK_EQ(2U, map->Size());
24806
24807 v8::Local<v8::Array> contents = map->AsArray();
24808 CHECK_EQ(4U, contents->Length());
24809 CHECK_EQ(
24810 1,
24811 contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
24812 CHECK_EQ(
24813 2,
24814 contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
24815 CHECK_EQ(
24816 3,
24817 contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
24818 CHECK_EQ(
24819 4,
24820 contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
24821
24822 CHECK_EQ(2U, map->Size());
24823
24824 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
24825 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
24826
24827 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
24828 CHECK(!map->Has(env.local(), map).FromJust());
24829
24830 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
24831 .ToLocalChecked()
24832 ->Int32Value(env.local())
24833 .FromJust());
24834 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
24835 .ToLocalChecked()
24836 ->Int32Value(env.local())
24837 .FromJust());
24838
24839 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
24840 .ToLocalChecked()
24841 ->IsUndefined());
24842
24843 CHECK(!map->Set(env.local(), map, map).IsEmpty());
24844 CHECK_EQ(3U, map->Size());
24845 CHECK(map->Has(env.local(), map).FromJust());
24846
24847 CHECK(map->Delete(env.local(), map).FromJust());
24848 CHECK_EQ(2U, map->Size());
24849 CHECK(!map->Has(env.local(), map).FromJust());
24850 CHECK(!map->Delete(env.local(), map).FromJust());
24851
24852 map->Clear();
24853 CHECK_EQ(0U, map->Size());
24854 }
24855
24856
TEST(Set)24857 TEST(Set) {
24858 v8::Isolate* isolate = CcTest::isolate();
24859 v8::HandleScope handle_scope(isolate);
24860 LocalContext env;
24861
24862 v8::Local<v8::Set> set = v8::Set::New(isolate);
24863 CHECK(set->IsObject());
24864 CHECK(set->IsSet());
24865 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
24866 CHECK_EQ(0U, set->Size());
24867
24868 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
24869 CHECK(val->IsSet());
24870 set = v8::Local<v8::Set>::Cast(val);
24871 CHECK_EQ(2U, set->Size());
24872
24873 v8::Local<v8::Array> keys = set->AsArray();
24874 CHECK_EQ(2U, keys->Length());
24875 CHECK_EQ(1,
24876 keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
24877 CHECK_EQ(2,
24878 keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
24879
24880 CHECK_EQ(2U, set->Size());
24881
24882 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
24883 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
24884
24885 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
24886 CHECK(!set->Has(env.local(), set).FromJust());
24887
24888 CHECK(!set->Add(env.local(), set).IsEmpty());
24889 CHECK_EQ(3U, set->Size());
24890 CHECK(set->Has(env.local(), set).FromJust());
24891
24892 CHECK(set->Delete(env.local(), set).FromJust());
24893 CHECK_EQ(2U, set->Size());
24894 CHECK(!set->Has(env.local(), set).FromJust());
24895 CHECK(!set->Delete(env.local(), set).FromJust());
24896
24897 set->Clear();
24898 CHECK_EQ(0U, set->Size());
24899 }
24900
TEST(SetDeleteThenAsArray)24901 TEST(SetDeleteThenAsArray) {
24902 // https://bugs.chromium.org/p/v8/issues/detail?id=4946
24903 v8::Isolate* isolate = CcTest::isolate();
24904 v8::HandleScope handle_scope(isolate);
24905 LocalContext env;
24906
24907 // make a Set
24908 v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
24909 v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
24910 CHECK_EQ(3U, set->Size());
24911
24912 // delete the "middle" element (using AsArray to
24913 // determine which element is the "middle" element)
24914 v8::Local<v8::Array> array1 = set->AsArray();
24915 CHECK_EQ(3U, array1->Length());
24916 CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
24917 .FromJust());
24918
24919 // make sure there are no undefined values when we convert to an array again.
24920 v8::Local<v8::Array> array2 = set->AsArray();
24921 uint32_t length = array2->Length();
24922 CHECK_EQ(2U, length);
24923 for (uint32_t i = 0; i < length; i++) {
24924 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
24925 }
24926 }
24927
TEST(MapDeleteThenAsArray)24928 TEST(MapDeleteThenAsArray) {
24929 // https://bugs.chromium.org/p/v8/issues/detail?id=4946
24930 v8::Isolate* isolate = CcTest::isolate();
24931 v8::HandleScope handle_scope(isolate);
24932 LocalContext env;
24933
24934 // make a Map
24935 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
24936 v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
24937 CHECK_EQ(3U, map->Size());
24938
24939 // delete the "middle" element (using AsArray to
24940 // determine which element is the "middle" element)
24941 v8::Local<v8::Array> array1 = map->AsArray();
24942 CHECK_EQ(6U, array1->Length());
24943 // Map::AsArray returns a flat array, so the second key is at index 2.
24944 v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
24945 CHECK(map->Delete(env.local(), key).FromJust());
24946
24947 // make sure there are no undefined values when we convert to an array again.
24948 v8::Local<v8::Array> array2 = map->AsArray();
24949 uint32_t length = array2->Length();
24950 CHECK_EQ(4U, length);
24951 for (uint32_t i = 0; i < length; i++) {
24952 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
24953 }
24954 }
24955
TEST(CompatibleReceiverCheckOnCachedICHandler)24956 TEST(CompatibleReceiverCheckOnCachedICHandler) {
24957 v8::Isolate* isolate = CcTest::isolate();
24958 v8::HandleScope scope(isolate);
24959 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
24960 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
24961 auto returns_42 =
24962 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
24963 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
24964 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
24965 child->Inherit(parent);
24966 LocalContext env;
24967 CHECK(env->Global()
24968 ->Set(env.local(), v8_str("Child"),
24969 child->GetFunction(env.local()).ToLocalChecked())
24970 .FromJust());
24971
24972 // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
24973 CompileRun(
24974 "var real = new Child();\n"
24975 "for (var i = 0; i < 3; ++i) {\n"
24976 " real.age;\n"
24977 "}\n");
24978
24979 // Check that the cached stub is never used.
24980 ExpectInt32(
24981 "var fake = Object.create(Child.prototype);\n"
24982 "var result = 0;\n"
24983 "function test(d) {\n"
24984 " if (d == 3) return;\n"
24985 " try {\n"
24986 " fake.age;\n"
24987 " result = 1;\n"
24988 " } catch (e) {\n"
24989 " }\n"
24990 " test(d+1);\n"
24991 "}\n"
24992 "test(0);\n"
24993 "result;\n",
24994 0);
24995 }
24996
THREADED_TEST(ReceiverConversionForAccessors)24997 THREADED_TEST(ReceiverConversionForAccessors) {
24998 LocalContext env;
24999 v8::Isolate* isolate = CcTest::isolate();
25000 v8::HandleScope scope(isolate);
25001 Local<v8::FunctionTemplate> acc =
25002 v8::FunctionTemplate::New(isolate, Returns42);
25003 CHECK(env->Global()
25004 ->Set(env.local(), v8_str("acc"),
25005 acc->GetFunction(env.local()).ToLocalChecked())
25006 .FromJust());
25007
25008 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
25009 templ->SetAccessorProperty(v8_str("acc"), acc, acc);
25010 Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
25011
25012 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
25013 CHECK(CompileRun("(p.acc == 42)")->BooleanValue(env.local()).FromJust());
25014 CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
25015
25016 CHECK(!CompileRun("Number.prototype.__proto__ = p;"
25017 "var a = 1;")
25018 .IsEmpty());
25019 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
25020 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
25021
25022 CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
25023 "var a = true;")
25024 .IsEmpty());
25025 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
25026 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
25027
25028 CHECK(!CompileRun("String.prototype.__proto__ = p;"
25029 "var a = 'foo';")
25030 .IsEmpty());
25031 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(env.local()).FromJust());
25032 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(env.local()).FromJust());
25033
25034 CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(env.local()).FromJust());
25035 CHECK(CompileRun("acc.call(true)==42")->BooleanValue(env.local()).FromJust());
25036 CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(env.local()).FromJust());
25037 CHECK(
25038 CompileRun("acc.call(null) == 42")->BooleanValue(env.local()).FromJust());
25039 CHECK(CompileRun("acc.call(undefined) == 42")
25040 ->BooleanValue(env.local())
25041 .FromJust());
25042 }
25043
25044 class FutexInterruptionThread : public v8::base::Thread {
25045 public:
FutexInterruptionThread(v8::Isolate * isolate)25046 explicit FutexInterruptionThread(v8::Isolate* isolate)
25047 : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
25048
Run()25049 virtual void Run() {
25050 // Wait a bit before terminating.
25051 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
25052 isolate_->TerminateExecution();
25053 }
25054
25055 private:
25056 v8::Isolate* isolate_;
25057 };
25058
25059
TEST(FutexInterruption)25060 TEST(FutexInterruption) {
25061 i::FLAG_harmony_sharedarraybuffer = true;
25062 v8::Isolate* isolate = CcTest::isolate();
25063 v8::HandleScope scope(isolate);
25064 LocalContext env;
25065
25066 FutexInterruptionThread timeout_thread(isolate);
25067
25068 v8::TryCatch try_catch(CcTest::isolate());
25069 timeout_thread.Start();
25070
25071 CompileRun(
25072 "var ab = new SharedArrayBuffer(4);"
25073 "var i32a = new Int32Array(ab);"
25074 "Atomics.futexWait(i32a, 0, 0);");
25075 CHECK(try_catch.HasTerminated());
25076 timeout_thread.Join();
25077 }
25078
25079
TEST(EstimatedContextSize)25080 TEST(EstimatedContextSize) {
25081 v8::Isolate* isolate = CcTest::isolate();
25082 v8::HandleScope scope(isolate);
25083 LocalContext env;
25084 CHECK(50000 < env->EstimatedSize());
25085 }
25086
25087
25088 static int nb_uncaught_exception_callback_calls = 0;
25089
25090
NoAbortOnUncaughtException(v8::Isolate * isolate)25091 bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
25092 ++nb_uncaught_exception_callback_calls;
25093 return false;
25094 }
25095
25096
TEST(AbortOnUncaughtExceptionNoAbort)25097 TEST(AbortOnUncaughtExceptionNoAbort) {
25098 v8::Isolate* isolate = CcTest::isolate();
25099 v8::HandleScope handle_scope(isolate);
25100 v8::Local<v8::ObjectTemplate> global_template =
25101 v8::ObjectTemplate::New(isolate);
25102 LocalContext env(NULL, global_template);
25103
25104 i::FLAG_abort_on_uncaught_exception = true;
25105 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
25106
25107 CompileRun("function boom() { throw new Error(\"boom\") }");
25108
25109 v8::Local<v8::Object> global_object = env->Global();
25110 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
25111 global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
25112
25113 CHECK(foo->Call(env.local(), global_object, 0, NULL).IsEmpty());
25114
25115 CHECK_EQ(1, nb_uncaught_exception_callback_calls);
25116 }
25117
25118
TEST(AccessCheckedIsConcatSpreadable)25119 TEST(AccessCheckedIsConcatSpreadable) {
25120 v8::Isolate* isolate = CcTest::isolate();
25121 HandleScope scope(isolate);
25122 LocalContext env;
25123
25124 // Object with access check
25125 Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
25126 spreadable_template->SetAccessCheckCallback(AccessBlocker);
25127 spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
25128 v8::Boolean::New(isolate, true));
25129 Local<Object> object =
25130 spreadable_template->NewInstance(env.local()).ToLocalChecked();
25131
25132 allowed_access = true;
25133 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
25134 object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
25135 object->Set(env.local(), 0U, v8_str("a")).FromJust();
25136 object->Set(env.local(), 1U, v8_str("b")).FromJust();
25137
25138 // Access check is allowed, and the object is spread
25139 CompileRun("var result = [].concat(object)");
25140 ExpectTrue("Array.isArray(result)");
25141 ExpectString("result[0]", "a");
25142 ExpectString("result[1]", "b");
25143 ExpectTrue("result.length === 2");
25144 ExpectTrue("object[Symbol.isConcatSpreadable]");
25145
25146 // If access check fails, the value of @@isConcatSpreadable is ignored
25147 allowed_access = false;
25148 CompileRun("var result = [].concat(object)");
25149 ExpectTrue("Array.isArray(result)");
25150 ExpectTrue("result[0] === object");
25151 ExpectTrue("result.length === 1");
25152 ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
25153 }
25154
25155
TEST(AccessCheckedToStringTag)25156 TEST(AccessCheckedToStringTag) {
25157 v8::Isolate* isolate = CcTest::isolate();
25158 HandleScope scope(isolate);
25159 LocalContext env;
25160
25161 // Object with access check
25162 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
25163 object_template->SetAccessCheckCallback(AccessBlocker);
25164 Local<Object> object =
25165 object_template->NewInstance(env.local()).ToLocalChecked();
25166
25167 allowed_access = true;
25168 env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
25169 object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
25170 .FromJust();
25171
25172 // Access check is allowed, and the toStringTag is read
25173 CompileRun("var result = Object.prototype.toString.call(object)");
25174 ExpectString("result", "[object hello]");
25175 ExpectString("object[Symbol.toStringTag]", "hello");
25176
25177 // ToString through the API should succeed too.
25178 String::Utf8Value result_allowed(
25179 object->ObjectProtoToString(env.local()).ToLocalChecked());
25180 CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
25181
25182 // If access check fails, the value of @@toStringTag is ignored
25183 allowed_access = false;
25184 CompileRun("var result = Object.prototype.toString.call(object)");
25185 ExpectString("result", "[object Object]");
25186 ExpectTrue("object[Symbol.toStringTag] === undefined");
25187
25188 // ToString through the API should also fail.
25189 String::Utf8Value result_denied(
25190 object->ObjectProtoToString(env.local()).ToLocalChecked());
25191 CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
25192 }
25193
25194
TEST(ObjectTemplateIntrinsics)25195 TEST(ObjectTemplateIntrinsics) {
25196 v8::Isolate* isolate = CcTest::isolate();
25197 v8::HandleScope scope(isolate);
25198 LocalContext env;
25199
25200 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
25201 object_template->SetIntrinsicDataProperty(v8_str("values"),
25202 v8::kArrayProto_values);
25203 Local<Object> object =
25204 object_template->NewInstance(env.local()).ToLocalChecked();
25205
25206 CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
25207 ExpectString("typeof obj1.values", "function");
25208
25209 auto values = Local<Function>::Cast(
25210 object->Get(env.local(), v8_str("values")).ToLocalChecked());
25211 auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
25212 auto ctx = v8::Utils::OpenHandle(*env.local());
25213 CHECK_EQ(fn->GetCreationContext(), *ctx);
25214
25215 {
25216 LocalContext env2;
25217 Local<Object> object2 =
25218 object_template->NewInstance(env2.local()).ToLocalChecked();
25219 CHECK(
25220 env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
25221 ExpectString("typeof obj2.values", "function");
25222 CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
25223 *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
25224
25225 auto values2 = Local<Function>::Cast(
25226 object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
25227 auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
25228 auto ctx2 = v8::Utils::OpenHandle(*env2.local());
25229 CHECK_EQ(fn2->GetCreationContext(), *ctx2);
25230 }
25231 }
25232
25233
TEST(Proxy)25234 TEST(Proxy) {
25235 LocalContext context;
25236 v8::Isolate* isolate = CcTest::isolate();
25237 v8::HandleScope scope(isolate);
25238 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
25239 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
25240
25241 v8::Local<v8::Proxy> proxy =
25242 v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
25243 CHECK(proxy->IsProxy());
25244 CHECK(!target->IsProxy());
25245 CHECK(!proxy->IsRevoked());
25246 CHECK(proxy->GetTarget()->SameValue(target));
25247 CHECK(proxy->GetHandler()->SameValue(handler));
25248
25249 proxy->Revoke();
25250 CHECK(proxy->IsProxy());
25251 CHECK(!target->IsProxy());
25252 CHECK(proxy->IsRevoked());
25253 CHECK(proxy->GetTarget()->SameValue(target));
25254 CHECK(proxy->GetHandler()->IsNull());
25255 }
25256
CreateGarbageWithWeakCallCounter(v8::Isolate * isolate,WeakCallCounter * counter)25257 WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
25258 v8::Isolate* isolate, WeakCallCounter* counter) {
25259 v8::Locker locker(isolate);
25260 LocalContext env;
25261 HandleScope scope(isolate);
25262 WeakCallCounterAndPersistent<Value>* val =
25263 new WeakCallCounterAndPersistent<Value>(counter);
25264 val->handle.Reset(isolate, Object::New(isolate));
25265 val->handle.SetWeak(val, &WeakPointerCallback,
25266 v8::WeakCallbackType::kParameter);
25267 return val;
25268 }
25269
25270 class MemoryPressureThread : public v8::base::Thread {
25271 public:
MemoryPressureThread(v8::Isolate * isolate,v8::MemoryPressureLevel level)25272 explicit MemoryPressureThread(v8::Isolate* isolate,
25273 v8::MemoryPressureLevel level)
25274 : Thread(Options("MemoryPressureThread")),
25275 isolate_(isolate),
25276 level_(level) {}
25277
Run()25278 virtual void Run() { isolate_->MemoryPressureNotification(level_); }
25279
25280 private:
25281 v8::Isolate* isolate_;
25282 v8::MemoryPressureLevel level_;
25283 };
25284
TEST(MemoryPressure)25285 TEST(MemoryPressure) {
25286 v8::Isolate* isolate = CcTest::isolate();
25287 WeakCallCounter counter(1234);
25288
25289 // Check that critical memory pressure notification sets GC interrupt.
25290 auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
25291 CHECK(!v8::Locker::IsLocked(isolate));
25292 {
25293 v8::Locker locker(isolate);
25294 v8::HandleScope scope(isolate);
25295 LocalContext env;
25296 MemoryPressureThread memory_pressure_thread(
25297 isolate, v8::MemoryPressureLevel::kCritical);
25298 memory_pressure_thread.Start();
25299 memory_pressure_thread.Join();
25300 // This should trigger GC.
25301 CHECK_EQ(0, counter.NumberOfWeakCalls());
25302 CompileRun("(function noop() { return 0; })()");
25303 CHECK_EQ(1, counter.NumberOfWeakCalls());
25304 }
25305 delete garbage;
25306 // Check that critical memory pressure notification triggers GC.
25307 garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
25308 {
25309 v8::Locker locker(isolate);
25310 // If isolate is locked, memory pressure notification should trigger GC.
25311 CHECK_EQ(1, counter.NumberOfWeakCalls());
25312 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
25313 CHECK_EQ(2, counter.NumberOfWeakCalls());
25314 }
25315 delete garbage;
25316 // Check that moderate memory pressure notification sets GC into memory
25317 // optimizing mode.
25318 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
25319 CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
25320 // Check that disabling memory pressure returns GC into normal mode.
25321 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
25322 CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
25323 }
25324
TEST(SetIntegrityLevel)25325 TEST(SetIntegrityLevel) {
25326 LocalContext context;
25327 v8::Isolate* isolate = CcTest::isolate();
25328 v8::HandleScope scope(isolate);
25329
25330 v8::Local<v8::Object> obj = v8::Object::New(isolate);
25331 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
25332
25333 v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
25334 CHECK(!is_frozen->BooleanValue(context.local()).FromJust());
25335
25336 CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
25337 .FromJust());
25338
25339 is_frozen = CompileRun("Object.isFrozen(o)");
25340 CHECK(is_frozen->BooleanValue(context.local()).FromJust());
25341 }
25342
TEST(PrivateForApiIsNumber)25343 TEST(PrivateForApiIsNumber) {
25344 LocalContext context;
25345 v8::Isolate* isolate = CcTest::isolate();
25346 v8::HandleScope scope(isolate);
25347
25348 // Shouldn't crash.
25349 v8::Private::ForApi(isolate, v8_str("42"));
25350 }
25351