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 <memory>
32#include <string>
33
34#include "test/cctest/test-api.h"
35
36#if V8_OS_POSIX
37#include <unistd.h> // NOLINT
38#endif
39
40#include "include/v8-util.h"
41#include "src/api-inl.h"
42#include "src/arguments.h"
43#include "src/base/overflowing-math.h"
44#include "src/base/platform/platform.h"
45#include "src/compilation-cache.h"
46#include "src/debug/debug.h"
47#include "src/execution.h"
48#include "src/feedback-vector-inl.h"
49#include "src/feedback-vector.h"
50#include "src/futex-emulation.h"
51#include "src/global-handles.h"
52#include "src/heap/heap-inl.h"
53#include "src/heap/incremental-marking.h"
54#include "src/heap/local-allocator.h"
55#include "src/lookup.h"
56#include "src/objects-inl.h"
57#include "src/objects/hash-table-inl.h"
58#include "src/objects/js-array-buffer-inl.h"
59#include "src/objects/js-array-inl.h"
60#include "src/objects/js-promise-inl.h"
61#include "src/profiler/cpu-profiler.h"
62#include "src/unicode-inl.h"
63#include "src/utils.h"
64#include "src/vm-state.h"
65#include "src/wasm/wasm-js.h"
66#include "test/cctest/heap/heap-tester.h"
67#include "test/cctest/heap/heap-utils.h"
68#include "test/cctest/wasm/wasm-run-utils.h"
69#include "test/common/wasm/wasm-macro-gen.h"
70
71static const bool kLogThreading = false;
72
73using ::v8::Array;
74using ::v8::Boolean;
75using ::v8::BooleanObject;
76using ::v8::Context;
77using ::v8::Extension;
78using ::v8::Function;
79using ::v8::FunctionTemplate;
80using ::v8::HandleScope;
81using ::v8::Local;
82using ::v8::Maybe;
83using ::v8::Message;
84using ::v8::MessageCallback;
85using ::v8::Module;
86using ::v8::Name;
87using ::v8::None;
88using ::v8::Object;
89using ::v8::ObjectTemplate;
90using ::v8::Persistent;
91using ::v8::PropertyAttribute;
92using ::v8::Script;
93using ::v8::StackTrace;
94using ::v8::String;
95using ::v8::Symbol;
96using ::v8::TryCatch;
97using ::v8::Undefined;
98using ::v8::V8;
99using ::v8::Value;
100
101
102#define THREADED_PROFILED_TEST(Name) \
103 static void Test##Name(); \
104 TEST(Name##WithProfiler) { \
105 RunWithProfiler(&Test##Name); \
106 } \
107 THREADED_TEST(Name)
108
109void RunWithProfiler(void (*test)()) {
110 LocalContext env;
111 v8::HandleScope scope(env->GetIsolate());
112 v8::Local<v8::String> profile_name = v8_str("my_profile1");
113 v8::CpuProfiler* cpu_profiler = v8::CpuProfiler::New(env->GetIsolate());
114 cpu_profiler->StartProfiling(profile_name);
115 (*test)();
116 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
117 cpu_profiler->Dispose();
118}
119
120
121static int signature_callback_count;
122static Local<Value> signature_expected_receiver;
123static void IncrementingSignatureCallback(
124 const v8::FunctionCallbackInfo<v8::Value>& args) {
125 ApiTestFuzzer::Fuzz();
126 signature_callback_count++;
127 CHECK(signature_expected_receiver->Equals(
128 args.GetIsolate()->GetCurrentContext(),
129 args.Holder())
130 .FromJust());
131 CHECK(signature_expected_receiver->Equals(
132 args.GetIsolate()->GetCurrentContext(),
133 args.This())
134 .FromJust());
135 v8::Local<v8::Array> result =
136 v8::Array::New(args.GetIsolate(), args.Length());
137 for (int i = 0; i < args.Length(); i++) {
138 CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
139 v8::Integer::New(args.GetIsolate(), i), args[i])
140 .FromJust());
141 }
142 args.GetReturnValue().Set(result);
143}
144
145
146static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
147 info.GetReturnValue().Set(42);
148}
149
150
151// Tests that call v8::V8::Dispose() cannot be threaded.
152UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
153 CHECK(v8::V8::Initialize());
154 CHECK(v8::V8::Dispose());
155}
156
157
158// Tests that call v8::V8::Dispose() cannot be threaded.
159UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
160 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
161 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
162 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
163 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
164 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
165}
166
167// Tests that Smi::kZero is set up properly.
168UNINITIALIZED_TEST(SmiZero) { CHECK_EQ(i::Smi::kZero, i::Smi::kZero); }
169
170THREADED_TEST(Handles) {
171 v8::HandleScope scope(CcTest::isolate());
172 Local<Context> local_env;
173 {
174 LocalContext env;
175 local_env = env.local();
176 }
177
178 // Local context should still be live.
179 CHECK(!local_env.IsEmpty());
180 local_env->Enter();
181
182 v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
183 CHECK(!undef.IsEmpty());
184 CHECK(undef->IsUndefined());
185
186 const char* source = "1 + 2 + 3";
187 Local<Script> script = v8_compile(source);
188 CHECK_EQ(6, v8_run_int32value(script));
189
190 local_env->Exit();
191}
192
193
194THREADED_TEST(IsolateOfContext) {
195 v8::HandleScope scope(CcTest::isolate());
196 v8::Local<Context> env = Context::New(CcTest::isolate());
197
198 CHECK(!env->GetIsolate()->InContext());
199 CHECK(env->GetIsolate() == CcTest::isolate());
200 env->Enter();
201 CHECK(env->GetIsolate()->InContext());
202 CHECK(env->GetIsolate() == CcTest::isolate());
203 env->Exit();
204 CHECK(!env->GetIsolate()->InContext());
205 CHECK(env->GetIsolate() == CcTest::isolate());
206}
207
208static void TestSignatureLooped(const char* operation, Local<Value> receiver,
209 v8::Isolate* isolate) {
210 i::ScopedVector<char> source(200);
211 i::SNPrintF(source,
212 "for (var i = 0; i < 10; i++) {"
213 " %s"
214 "}",
215 operation);
216 signature_callback_count = 0;
217 signature_expected_receiver = receiver;
218 bool expected_to_throw = receiver.IsEmpty();
219 v8::TryCatch try_catch(isolate);
220 CompileRun(source.start());
221 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
222 if (!expected_to_throw) {
223 CHECK_EQ(10, signature_callback_count);
224 } else {
225 CHECK(v8_str("TypeError: Illegal invocation")
226 ->Equals(isolate->GetCurrentContext(),
227 try_catch.Exception()
228 ->ToString(isolate->GetCurrentContext())
229 .ToLocalChecked())
230 .FromJust());
231 }
232}
233
234static void TestSignatureOptimized(const char* operation, Local<Value> receiver,
235 v8::Isolate* isolate) {
236 i::ScopedVector<char> source(200);
237 i::SNPrintF(source,
238 "function test() {"
239 " %s"
240 "}"
241 "try { test() } catch(e) {}"
242 "try { test() } catch(e) {}"
243 "%%OptimizeFunctionOnNextCall(test);"
244 "test()",
245 operation);
246 signature_callback_count = 0;
247 signature_expected_receiver = receiver;
248 bool expected_to_throw = receiver.IsEmpty();
249 v8::TryCatch try_catch(isolate);
250 CompileRun(source.start());
251 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
252 if (!expected_to_throw) {
253 CHECK_EQ(3, signature_callback_count);
254 } else {
255 CHECK(v8_str("TypeError: Illegal invocation")
256 ->Equals(isolate->GetCurrentContext(),
257 try_catch.Exception()
258 ->ToString(isolate->GetCurrentContext())
259 .ToLocalChecked())
260 .FromJust());
261 }
262}
263
264static void TestSignature(const char* operation, Local<Value> receiver,
265 v8::Isolate* isolate) {
266 TestSignatureLooped(operation, receiver, isolate);
267 TestSignatureOptimized(operation, receiver, isolate);
268}
269
270THREADED_TEST(ReceiverSignature) {
271 i::FLAG_allow_natives_syntax = true;
272 LocalContext env;
273 v8::Isolate* isolate = env->GetIsolate();
274 v8::HandleScope scope(isolate);
275 // Setup templates.
276 v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
277 v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
278 v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
279 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
280 v8::Local<v8::FunctionTemplate> callback =
281 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
282 v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
283 sub_fun->Inherit(fun);
284 v8::Local<v8::FunctionTemplate> direct_sub_fun =
285 v8::FunctionTemplate::New(isolate);
286 direct_sub_fun->Inherit(fun);
287 v8::Local<v8::FunctionTemplate> unrel_fun =
288 v8::FunctionTemplate::New(isolate);
289 // Install properties.
290 v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
291 fun_proto->Set(v8_str("prop_sig"), callback_sig);
292 fun_proto->Set(v8_str("prop"), callback);
293 fun_proto->SetAccessorProperty(
294 v8_str("accessor_sig"), callback_sig, callback_sig);
295 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
296 // Instantiate templates.
297 Local<Value> fun_instance =
298 fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
299 Local<Value> sub_fun_instance =
300 sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
301 // Instance template with properties.
302 v8::Local<v8::ObjectTemplate> direct_instance_templ =
303 direct_sub_fun->InstanceTemplate();
304 direct_instance_templ->Set(v8_str("prop_sig"), callback_sig);
305 direct_instance_templ->Set(v8_str("prop"), callback);
306 direct_instance_templ->SetAccessorProperty(v8_str("accessor_sig"),
307 callback_sig, callback_sig);
308 direct_instance_templ->SetAccessorProperty(v8_str("accessor"), callback,
309 callback);
310 Local<Value> direct_instance =
311 direct_instance_templ->NewInstance(env.local()).ToLocalChecked();
312 // Setup global variables.
313 CHECK(env->Global()
314 ->Set(env.local(), v8_str("Fun"),
315 fun->GetFunction(env.local()).ToLocalChecked())
316 .FromJust());
317 CHECK(env->Global()
318 ->Set(env.local(), v8_str("UnrelFun"),
319 unrel_fun->GetFunction(env.local()).ToLocalChecked())
320 .FromJust());
321 CHECK(env->Global()
322 ->Set(env.local(), v8_str("fun_instance"), fun_instance)
323 .FromJust());
324 CHECK(env->Global()
325 ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
326 .FromJust());
327 CHECK(env->Global()
328 ->Set(env.local(), v8_str("direct_instance"), direct_instance)
329 .FromJust());
330 CompileRun(
331 "var accessor_sig_key = 'accessor_sig';"
332 "var accessor_key = 'accessor';"
333 "var prop_sig_key = 'prop_sig';"
334 "var prop_key = 'prop';"
335 ""
336 "function copy_props(obj) {"
337 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
338 " var source = Fun.prototype;"
339 " for (var i in keys) {"
340 " var key = keys[i];"
341 " var desc = Object.getOwnPropertyDescriptor(source, key);"
342 " Object.defineProperty(obj, key, desc);"
343 " }"
344 "}"
345 ""
346 "var plain = {};"
347 "copy_props(plain);"
348 "var unrelated = new UnrelFun();"
349 "copy_props(unrelated);"
350 "var inherited = { __proto__: fun_instance };"
351 "var inherited_direct = { __proto__: direct_instance };");
352 // Test with and without ICs
353 const char* test_objects[] = {
354 "fun_instance", "sub_fun_instance", "direct_instance", "plain",
355 "unrelated", "inherited", "inherited_direct"};
356 unsigned bad_signature_start_offset = 3;
357 for (unsigned i = 0; i < arraysize(test_objects); i++) {
358 i::ScopedVector<char> source(200);
359 i::SNPrintF(
360 source, "var test_object = %s; test_object", test_objects[i]);
361 Local<Value> test_object = CompileRun(source.start());
362 TestSignature("test_object.prop();", test_object, isolate);
363 TestSignature("test_object.accessor;", test_object, isolate);
364 TestSignature("test_object[accessor_key];", test_object, isolate);
365 TestSignature("test_object.accessor = 1;", test_object, isolate);
366 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
367 if (i >= bad_signature_start_offset) test_object = Local<Value>();
368 TestSignature("test_object.prop_sig();", test_object, isolate);
369 TestSignature("test_object.accessor_sig;", test_object, isolate);
370 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
371 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
372 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
373 }
374}
375
376
377THREADED_TEST(HulIgennem) {
378 LocalContext env;
379 v8::Isolate* isolate = env->GetIsolate();
380 v8::HandleScope scope(isolate);
381 v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
382 Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
383 char* value = i::NewArray<char>(undef_str->Utf8Length(isolate) + 1);
384 undef_str->WriteUtf8(isolate, value);
385 CHECK_EQ(0, strcmp(value, "undefined"));
386 i::DeleteArray(value);
387}
388
389
390THREADED_TEST(Access) {
391 LocalContext env;
392 v8::Isolate* isolate = env->GetIsolate();
393 v8::HandleScope scope(isolate);
394 Local<v8::Object> obj = v8::Object::New(isolate);
395 Local<Value> foo_before =
396 obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
397 CHECK(foo_before->IsUndefined());
398 Local<String> bar_str = v8_str("bar");
399 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
400 Local<Value> foo_after =
401 obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
402 CHECK(!foo_after->IsUndefined());
403 CHECK(foo_after->IsString());
404 CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
405
406 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).ToChecked());
407 bool result;
408 CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).To(&result));
409 CHECK(result);
410}
411
412
413THREADED_TEST(AccessElement) {
414 LocalContext env;
415 v8::HandleScope scope(env->GetIsolate());
416 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
417 Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
418 CHECK(before->IsUndefined());
419 Local<String> bar_str = v8_str("bar");
420 CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
421 Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
422 CHECK(!after->IsUndefined());
423 CHECK(after->IsString());
424 CHECK(bar_str->Equals(env.local(), after).FromJust());
425
426 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
427 CHECK(v8_str("a")
428 ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
429 .FromJust());
430 CHECK(v8_str("b")
431 ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
432 .FromJust());
433}
434
435
436THREADED_TEST(Script) {
437 LocalContext env;
438 v8::HandleScope scope(env->GetIsolate());
439 const char* source = "1 + 2 + 3";
440 Local<Script> script = v8_compile(source);
441 CHECK_EQ(6, v8_run_int32value(script));
442}
443
444
445class TestResource: public String::ExternalStringResource {
446 public:
447 explicit TestResource(uint16_t* data, int* counter = nullptr,
448 bool owning_data = true)
449 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
450 while (data[length_]) ++length_;
451 }
452
453 ~TestResource() override {
454 if (owning_data_) i::DeleteArray(data_);
455 if (counter_ != nullptr) ++*counter_;
456 }
457
458 const uint16_t* data() const override { return data_; }
459
460 size_t length() const override { return length_; }
461
462 private:
463 uint16_t* data_;
464 size_t length_;
465 int* counter_;
466 bool owning_data_;
467};
468
469
470class TestOneByteResource : public String::ExternalOneByteStringResource {
471 public:
472 explicit TestOneByteResource(const char* data, int* counter = nullptr,
473 size_t offset = 0)
474 : orig_data_(data),
475 data_(data + offset),
476 length_(strlen(data) - offset),
477 counter_(counter) {}
478
479 ~TestOneByteResource() override {
480 i::DeleteArray(orig_data_);
481 if (counter_ != nullptr) ++*counter_;
482 }
483
484 const char* data() const override { return data_; }
485
486 size_t length() const override { return length_; }
487
488 private:
489 const char* orig_data_;
490 const char* data_;
491 size_t length_;
492 int* counter_;
493};
494
495
496THREADED_TEST(ScriptUsingStringResource) {
497 int dispose_count = 0;
498 const char* c_source = "1 + 2 * 3";
499 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
500 {
501 LocalContext env;
502 v8::HandleScope scope(env->GetIsolate());
503 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
504 Local<String> source =
505 String::NewExternalTwoByte(env->GetIsolate(), resource)
506 .ToLocalChecked();
507 Local<Script> script = v8_compile(source);
508 Local<Value> value = script->Run(env.local()).ToLocalChecked();
509 CHECK(value->IsNumber());
510 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
511 CHECK(source->IsExternal());
512 CHECK_EQ(resource,
513 static_cast<TestResource*>(source->GetExternalStringResource()));
514 String::Encoding encoding = String::UNKNOWN_ENCODING;
515 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
516 source->GetExternalStringResourceBase(&encoding));
517 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
518 CcTest::CollectAllGarbage();
519 CHECK_EQ(0, dispose_count);
520 }
521 CcTest::i_isolate()->compilation_cache()->Clear();
522 CcTest::CollectAllAvailableGarbage();
523 CHECK_EQ(1, dispose_count);
524}
525
526
527THREADED_TEST(ScriptUsingOneByteStringResource) {
528 int dispose_count = 0;
529 const char* c_source = "1 + 2 * 3";
530 {
531 LocalContext env;
532 v8::HandleScope scope(env->GetIsolate());
533 TestOneByteResource* resource =
534 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
535 Local<String> source =
536 String::NewExternalOneByte(env->GetIsolate(), resource)
537 .ToLocalChecked();
538 CHECK(source->IsExternalOneByte());
539 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
540 source->GetExternalOneByteStringResource());
541 String::Encoding encoding = String::UNKNOWN_ENCODING;
542 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
543 source->GetExternalStringResourceBase(&encoding));
544 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
545 Local<Script> script = v8_compile(source);
546 Local<Value> value = script->Run(env.local()).ToLocalChecked();
547 CHECK(value->IsNumber());
548 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
549 CcTest::CollectAllGarbage();
550 CHECK_EQ(0, dispose_count);
551 }
552 CcTest::i_isolate()->compilation_cache()->Clear();
553 CcTest::CollectAllAvailableGarbage();
554 CHECK_EQ(1, dispose_count);
555}
556
557
558THREADED_TEST(ScriptMakingExternalString) {
559 int dispose_count = 0;
560 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
561 {
562 LocalContext env;
563 v8::HandleScope scope(env->GetIsolate());
564 Local<String> source =
565 String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
566 v8::NewStringType::kNormal)
567 .ToLocalChecked();
568 // Trigger GCs so that the newly allocated string moves to old gen.
569 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
570 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
571 CHECK(!source->IsExternal());
572 CHECK(!source->IsExternalOneByte());
573 String::Encoding encoding = String::UNKNOWN_ENCODING;
574 CHECK(!source->GetExternalStringResourceBase(&encoding));
575 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
576 bool success = source->MakeExternal(new TestResource(two_byte_source,
577 &dispose_count));
578 CHECK(success);
579 Local<Script> script = v8_compile(source);
580 Local<Value> value = script->Run(env.local()).ToLocalChecked();
581 CHECK(value->IsNumber());
582 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
583 CcTest::CollectAllGarbage();
584 CHECK_EQ(0, dispose_count);
585 }
586 CcTest::i_isolate()->compilation_cache()->Clear();
587 CcTest::CollectAllGarbage();
588 CHECK_EQ(1, dispose_count);
589}
590
591
592THREADED_TEST(ScriptMakingExternalOneByteString) {
593 int dispose_count = 0;
594 const char* c_source = "1 + 2 * 3";
595 {
596 LocalContext env;
597 v8::HandleScope scope(env->GetIsolate());
598 Local<String> source = v8_str(c_source);
599 // Trigger GCs so that the newly allocated string moves to old gen.
600 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
601 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
602 bool success = source->MakeExternal(
603 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
604 CHECK(success);
605 Local<Script> script = v8_compile(source);
606 Local<Value> value = script->Run(env.local()).ToLocalChecked();
607 CHECK(value->IsNumber());
608 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
609 CcTest::CollectAllGarbage();
610 CHECK_EQ(0, dispose_count);
611 }
612 CcTest::i_isolate()->compilation_cache()->Clear();
613 CcTest::CollectAllGarbage();
614 CHECK_EQ(1, dispose_count);
615}
616
617
618TEST(MakingExternalStringConditions) {
619 LocalContext env;
620 v8::HandleScope scope(env->GetIsolate());
621
622 // Free some space in the new space so that we can check freshness.
623 CcTest::CollectGarbage(i::NEW_SPACE);
624 CcTest::CollectGarbage(i::NEW_SPACE);
625
626 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
627 Local<String> tiny_local_string =
628 String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
629 v8::NewStringType::kNormal)
630 .ToLocalChecked();
631 i::DeleteArray(two_byte_string);
632
633 two_byte_string = AsciiToTwoByteString("s1234");
634 Local<String> local_string =
635 String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
636 v8::NewStringType::kNormal)
637 .ToLocalChecked();
638 i::DeleteArray(two_byte_string);
639
640 // We should refuse to externalize new space strings.
641 CHECK(!local_string->CanMakeExternal());
642 // Trigger GCs so that the newly allocated string moves to old gen.
643 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
644 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
645 // Old space strings should be accepted.
646 CHECK(local_string->CanMakeExternal());
647
648 // Tiny strings are not in-place externalizable when pointer compression is
649 // enabled.
650 CHECK_EQ(i::kTaggedSize == i::kSystemPointerSize,
651 tiny_local_string->CanMakeExternal());
652}
653
654
655TEST(MakingExternalOneByteStringConditions) {
656 LocalContext env;
657 v8::HandleScope scope(env->GetIsolate());
658
659 // Free some space in the new space so that we can check freshness.
660 CcTest::CollectGarbage(i::NEW_SPACE);
661 CcTest::CollectGarbage(i::NEW_SPACE);
662
663 Local<String> tiny_local_string = v8_str("s");
664 Local<String> local_string = v8_str("s1234");
665 // We should refuse to externalize new space strings.
666 CHECK(!local_string->CanMakeExternal());
667 // Trigger GCs so that the newly allocated string moves to old gen.
668 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
669 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
670 // Old space strings should be accepted.
671 CHECK(local_string->CanMakeExternal());
672
673 // Tiny strings are not in-place externalizable when pointer compression is
674 // enabled.
675 CHECK_EQ(i::kTaggedSize == i::kSystemPointerSize,
676 tiny_local_string->CanMakeExternal());
677}
678
679
680TEST(MakingExternalUnalignedOneByteString) {
681 LocalContext env;
682 v8::HandleScope scope(env->GetIsolate());
683
684 CompileRun("function cons(a, b) { return a + b; }"
685 "function slice(a) { return a.substring(1); }");
686 // Create a cons string that will land in old pointer space.
687 Local<String> cons = Local<String>::Cast(CompileRun(
688 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
689 // Create a sliced string that will land in old pointer space.
690 Local<String> slice = Local<String>::Cast(CompileRun(
691 "slice('abcdefghijklmnopqrstuvwxyz');"));
692
693 // Trigger GCs so that the newly allocated string moves to old gen.
694 i::heap::SimulateFullSpace(CcTest::heap()->old_space());
695 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
696 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
697
698 // Turn into external string with unaligned resource data.
699 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
700 bool success = cons->MakeExternal(
701 new TestOneByteResource(i::StrDup(c_cons), nullptr, 1));
702 CHECK(success);
703 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
704 success = slice->MakeExternal(
705 new TestOneByteResource(i::StrDup(c_slice), nullptr, 1));
706 CHECK(success);
707
708 // Trigger GCs and force evacuation.
709 CcTest::CollectAllGarbage();
710 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask,
711 i::GarbageCollectionReason::kTesting);
712}
713
714THREADED_TEST(UsingExternalString) {
715 i::Factory* factory = CcTest::i_isolate()->factory();
716 {
717 v8::HandleScope scope(CcTest::isolate());
718 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
719 Local<String> string =
720 String::NewExternalTwoByte(CcTest::isolate(),
721 new TestResource(two_byte_string))
722 .ToLocalChecked();
723 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
724 // Trigger GCs so that the newly allocated string moves to old gen.
725 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
726 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
727 i::Handle<i::String> isymbol =
728 factory->InternalizeString(istring);
729 CHECK(isymbol->IsInternalizedString());
730 }
731 CcTest::CollectAllGarbage();
732 CcTest::CollectAllGarbage();
733}
734
735
736THREADED_TEST(UsingExternalOneByteString) {
737 i::Factory* factory = CcTest::i_isolate()->factory();
738 {
739 v8::HandleScope scope(CcTest::isolate());
740 const char* one_byte_string = "test string";
741 Local<String> string =
742 String::NewExternalOneByte(
743 CcTest::isolate(),
744 new TestOneByteResource(i::StrDup(one_byte_string)))
745 .ToLocalChecked();
746 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
747 // Trigger GCs so that the newly allocated string moves to old gen.
748 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
749 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
750 i::Handle<i::String> isymbol =
751 factory->InternalizeString(istring);
752 CHECK(isymbol->IsInternalizedString());
753 }
754 CcTest::CollectAllGarbage();
755 CcTest::CollectAllGarbage();
756}
757
758
759class RandomLengthResource : public v8::String::ExternalStringResource {
760 public:
761 explicit RandomLengthResource(int length) : length_(length) {}
762 const uint16_t* data() const override { return string_; }
763 size_t length() const override { return length_; }
764
765 private:
766 uint16_t string_[10];
767 int length_;
768};
769
770
771class RandomLengthOneByteResource
772 : public v8::String::ExternalOneByteStringResource {
773 public:
774 explicit RandomLengthOneByteResource(int length) : length_(length) {}
775 const char* data() const override { return string_; }
776 size_t length() const override { return length_; }
777
778 private:
779 char string_[10];
780 int length_;
781};
782
783
784THREADED_TEST(NewExternalForVeryLongString) {
785 auto isolate = CcTest::isolate();
786 {
787 v8::HandleScope scope(isolate);
788 v8::TryCatch try_catch(isolate);
789 RandomLengthOneByteResource r(1 << 30);
790 v8::MaybeLocal<v8::String> maybe_str =
791 v8::String::NewExternalOneByte(isolate, &r);
792 CHECK(maybe_str.IsEmpty());
793 CHECK(!try_catch.HasCaught());
794 }
795
796 {
797 v8::HandleScope scope(isolate);
798 v8::TryCatch try_catch(isolate);
799 RandomLengthResource r(1 << 30);
800 v8::MaybeLocal<v8::String> maybe_str =
801 v8::String::NewExternalTwoByte(isolate, &r);
802 CHECK(maybe_str.IsEmpty());
803 CHECK(!try_catch.HasCaught());
804 }
805}
806
807TEST(ScavengeExternalString) {
808 ManualGCScope manual_gc_scope;
809 i::FLAG_stress_compaction = false;
810 i::FLAG_gc_global = false;
811 int dispose_count = 0;
812 bool in_young_generation = false;
813 {
814 v8::HandleScope scope(CcTest::isolate());
815 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
816 Local<String> string =
817 String::NewExternalTwoByte(
818 CcTest::isolate(),
819 new TestResource(two_byte_string, &dispose_count))
820 .ToLocalChecked();
821 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
822 CcTest::CollectGarbage(i::NEW_SPACE);
823 in_young_generation = i::Heap::InYoungGeneration(*istring);
824 CHECK_IMPLIES(!in_young_generation,
825 CcTest::heap()->old_space()->Contains(*istring));
826 CHECK_EQ(0, dispose_count);
827 }
828 CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
829 CHECK_EQ(1, dispose_count);
830}
831
832TEST(ScavengeExternalOneByteString) {
833 ManualGCScope manual_gc_scope;
834 i::FLAG_stress_compaction = false;
835 i::FLAG_gc_global = false;
836 int dispose_count = 0;
837 bool in_young_generation = false;
838 {
839 v8::HandleScope scope(CcTest::isolate());
840 const char* one_byte_string = "test string";
841 Local<String> string =
842 String::NewExternalOneByte(
843 CcTest::isolate(),
844 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
845 .ToLocalChecked();
846 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
847 CcTest::CollectGarbage(i::NEW_SPACE);
848 in_young_generation = i::Heap::InYoungGeneration(*istring);
849 CHECK_IMPLIES(!in_young_generation,
850 CcTest::heap()->old_space()->Contains(*istring));
851 CHECK_EQ(0, dispose_count);
852 }
853 CcTest::CollectGarbage(in_young_generation ? i::NEW_SPACE : i::OLD_SPACE);
854 CHECK_EQ(1, dispose_count);
855}
856
857
858class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
859 public:
860 // Only used by non-threaded tests, so it can use static fields.
861 static int dispose_calls;
862 static int dispose_count;
863
864 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
865 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
866
867 void Dispose() override {
868 ++dispose_calls;
869 if (dispose_) delete this;
870 }
871 private:
872 bool dispose_;
873};
874
875
876int TestOneByteResourceWithDisposeControl::dispose_count = 0;
877int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
878
879
880TEST(ExternalStringWithDisposeHandling) {
881 const char* c_source = "1 + 2 * 3";
882
883 // Use a stack allocated external string resource allocated object.
884 TestOneByteResourceWithDisposeControl::dispose_count = 0;
885 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
886 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
887 {
888 LocalContext env;
889 v8::HandleScope scope(env->GetIsolate());
890 Local<String> source =
891 String::NewExternalOneByte(env->GetIsolate(), &res_stack)
892 .ToLocalChecked();
893 Local<Script> script = v8_compile(source);
894 Local<Value> value = script->Run(env.local()).ToLocalChecked();
895 CHECK(value->IsNumber());
896 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
897 CcTest::CollectAllAvailableGarbage();
898 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
899 }
900 CcTest::i_isolate()->compilation_cache()->Clear();
901 CcTest::CollectAllAvailableGarbage();
902 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
903 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
904
905 // Use a heap allocated external string resource allocated object.
906 TestOneByteResourceWithDisposeControl::dispose_count = 0;
907 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
908 TestOneByteResource* res_heap =
909 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
910 {
911 LocalContext env;
912 v8::HandleScope scope(env->GetIsolate());
913 Local<String> source =
914 String::NewExternalOneByte(env->GetIsolate(), res_heap)
915 .ToLocalChecked();
916 Local<Script> script = v8_compile(source);
917 Local<Value> value = script->Run(env.local()).ToLocalChecked();
918 CHECK(value->IsNumber());
919 CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
920 CcTest::CollectAllAvailableGarbage();
921 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
922 }
923 CcTest::i_isolate()->compilation_cache()->Clear();
924 CcTest::CollectAllAvailableGarbage();
925 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
926 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
927}
928
929
930THREADED_TEST(StringConcat) {
931 {
932 LocalContext env;
933 v8::Isolate* isolate = env->GetIsolate();
934 v8::HandleScope scope(isolate);
935 const char* one_byte_string_1 = "function a_times_t";
936 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
937 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
938 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
939 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
940 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
941 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
942 Local<String> left = v8_str(one_byte_string_1);
943
944 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
945 Local<String> right =
946 String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
947 v8::NewStringType::kNormal)
948 .ToLocalChecked();
949 i::DeleteArray(two_byte_source);
950
951 Local<String> source = String::Concat(isolate, left, right);
952 right = String::NewExternalOneByte(
953 env->GetIsolate(),
954 new TestOneByteResource(i::StrDup(one_byte_extern_1)))
955 .ToLocalChecked();
956 source = String::Concat(isolate, source, right);
957 right = String::NewExternalTwoByte(
958 env->GetIsolate(),
959 new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
960 .ToLocalChecked();
961 source = String::Concat(isolate, source, right);
962 right = v8_str(one_byte_string_2);
963 source = String::Concat(isolate, source, right);
964
965 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
966 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
967 v8::NewStringType::kNormal)
968 .ToLocalChecked();
969 i::DeleteArray(two_byte_source);
970
971 source = String::Concat(isolate, source, right);
972 right = String::NewExternalTwoByte(
973 env->GetIsolate(),
974 new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
975 .ToLocalChecked();
976 source = String::Concat(isolate, source, right);
977 Local<Script> script = v8_compile(source);
978 Local<Value> value = script->Run(env.local()).ToLocalChecked();
979 CHECK(value->IsNumber());
980 CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
981 }
982 CcTest::i_isolate()->compilation_cache()->Clear();
983 CcTest::CollectAllGarbage();
984 CcTest::CollectAllGarbage();
985}
986
987
988THREADED_TEST(GlobalProperties) {
989 LocalContext env;
990 v8::HandleScope scope(env->GetIsolate());
991 v8::Local<v8::Object> global = env->Global();
992 CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
993 Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
994 CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
995}
996
997
998static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
999 i::Address callback) {
1000 ApiTestFuzzer::Fuzz();
1001 CheckReturnValue(info, callback);
1002 info.GetReturnValue().Set(v8_str("bad value"));
1003 info.GetReturnValue().Set(v8_num(102));
1004}
1005
1006
1007static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1008 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1009}
1010
1011
1012static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1013 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1014}
1015
1016static void construct_callback(
1017 const v8::FunctionCallbackInfo<Value>& info) {
1018 ApiTestFuzzer::Fuzz();
1019 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1020 CHECK(
1021 info.This()
1022 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
1023 .FromJust());
1024 CHECK(
1025 info.This()
1026 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
1027 .FromJust());
1028 info.GetReturnValue().Set(v8_str("bad value"));
1029 info.GetReturnValue().Set(info.This());
1030}
1031
1032
1033static void Return239Callback(
1034 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1035 ApiTestFuzzer::Fuzz();
1036 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1037 info.GetReturnValue().Set(v8_str("bad value"));
1038 info.GetReturnValue().Set(v8_num(239));
1039}
1040
1041
1042template<typename Handler>
1043static void TestFunctionTemplateInitializer(Handler handler,
1044 Handler handler_2) {
1045 // Test constructor calls.
1046 {
1047 LocalContext env;
1048 v8::Isolate* isolate = env->GetIsolate();
1049 v8::HandleScope scope(isolate);
1050
1051 Local<v8::FunctionTemplate> fun_templ =
1052 v8::FunctionTemplate::New(isolate, handler);
1053 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1054 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1055 Local<Script> script = v8_compile("obj()");
1056 for (int i = 0; i < 30; i++) {
1057 CHECK_EQ(102, v8_run_int32value(script));
1058 }
1059 }
1060 // Use SetCallHandler to initialize a function template, should work like
1061 // the previous one.
1062 {
1063 LocalContext env;
1064 v8::Isolate* isolate = env->GetIsolate();
1065 v8::HandleScope scope(isolate);
1066
1067 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1068 fun_templ->SetCallHandler(handler_2);
1069 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1070 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1071 Local<Script> script = v8_compile("obj()");
1072 for (int i = 0; i < 30; i++) {
1073 CHECK_EQ(102, v8_run_int32value(script));
1074 }
1075 }
1076}
1077
1078
1079template<typename Constructor, typename Accessor>
1080static void TestFunctionTemplateAccessor(Constructor constructor,
1081 Accessor accessor) {
1082 LocalContext env;
1083 v8::HandleScope scope(env->GetIsolate());
1084
1085 Local<v8::FunctionTemplate> fun_templ =
1086 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1087 fun_templ->SetClassName(v8_str("funky"));
1088 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1089 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1090 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1091 Local<Value> result =
1092 v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
1093 CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
1094 CompileRun("var obj_instance = new obj();");
1095 Local<Script> script;
1096 script = v8_compile("obj_instance.x");
1097 for (int i = 0; i < 30; i++) {
1098 CHECK_EQ(1, v8_run_int32value(script));
1099 }
1100 script = v8_compile("obj_instance.m");
1101 for (int i = 0; i < 30; i++) {
1102 CHECK_EQ(239, v8_run_int32value(script));
1103 }
1104}
1105
1106
1107THREADED_PROFILED_TEST(FunctionTemplate) {
1108 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1109 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1110}
1111
1112static void FunctionCallbackForProxyTest(
1113 const v8::FunctionCallbackInfo<Value>& info) {
1114 info.GetReturnValue().Set(info.This());
1115}
1116
1117THREADED_TEST(FunctionTemplateWithProxy) {
1118 LocalContext env;
1119 v8::Isolate* isolate = env->GetIsolate();
1120 v8::HandleScope scope(isolate);
1121
1122 v8::Local<v8::FunctionTemplate> function_template =
1123 v8::FunctionTemplate::New(isolate, FunctionCallbackForProxyTest);
1124 v8::Local<v8::Function> function =
1125 function_template->GetFunction(env.local()).ToLocalChecked();
1126 CHECK((*env)->Global()->Set(env.local(), v8_str("f"), function).FromJust());
1127 v8::Local<v8::Value> proxy =
1128 CompileRun("var proxy = new Proxy({}, {}); proxy");
1129 CHECK(proxy->IsProxy());
1130
1131 v8::Local<v8::Value> result = CompileRun("f(proxy)");
1132 CHECK(result->Equals(env.local(), (*env)->Global()).FromJust());
1133
1134 result = CompileRun("f.call(proxy)");
1135 CHECK(result->Equals(env.local(), proxy).FromJust());
1136
1137 result = CompileRun("Reflect.apply(f, proxy, [1])");
1138 CHECK(result->Equals(env.local(), proxy).FromJust());
1139}
1140
1141static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1142 ApiTestFuzzer::Fuzz();
1143 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1144 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1145}
1146
1147
1148template<typename Callback>
1149static void TestSimpleCallback(Callback callback) {
1150 LocalContext env;
1151 v8::Isolate* isolate = env->GetIsolate();
1152 v8::HandleScope scope(isolate);
1153
1154 v8::Local<v8::ObjectTemplate> object_template =
1155 v8::ObjectTemplate::New(isolate);
1156 object_template->Set(isolate, "callback",
1157 v8::FunctionTemplate::New(isolate, callback));
1158 v8::Local<v8::Object> object =
1159 object_template->NewInstance(env.local()).ToLocalChecked();
1160 CHECK((*env)
1161 ->Global()
1162 ->Set(env.local(), v8_str("callback_object"), object)
1163 .FromJust());
1164 v8::Local<v8::Script> script;
1165 script = v8_compile("callback_object.callback(17)");
1166 for (int i = 0; i < 30; i++) {
1167 CHECK_EQ(51424, v8_run_int32value(script));
1168 }
1169 script = v8_compile("callback_object.callback(17, 24)");
1170 for (int i = 0; i < 30; i++) {
1171 CHECK_EQ(51425, v8_run_int32value(script));
1172 }
1173}
1174
1175
1176THREADED_PROFILED_TEST(SimpleCallback) {
1177 TestSimpleCallback(SimpleCallback);
1178}
1179
1180
1181template<typename T>
1182void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1183
1184// constant return values
1185static int32_t fast_return_value_int32 = 471;
1186static uint32_t fast_return_value_uint32 = 571;
1187static const double kFastReturnValueDouble = 2.7;
1188// variable return values
1189static bool fast_return_value_bool = false;
1190enum ReturnValueOddball {
1191 kNullReturnValue,
1192 kUndefinedReturnValue,
1193 kEmptyStringReturnValue
1194};
1195static ReturnValueOddball fast_return_value_void;
1196static bool fast_return_value_object_is_empty = false;
1197
1198// Helper function to avoid compiler error: insufficient contextual information
1199// to determine type when applying FUNCTION_ADDR to a template function.
1200static i::Address address_of(v8::FunctionCallback callback) {
1201 return FUNCTION_ADDR(callback);
1202}
1203
1204template<>
1205void FastReturnValueCallback<int32_t>(
1206 const v8::FunctionCallbackInfo<v8::Value>& info) {
1207 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1208 info.GetReturnValue().Set(fast_return_value_int32);
1209}
1210
1211template<>
1212void FastReturnValueCallback<uint32_t>(
1213 const v8::FunctionCallbackInfo<v8::Value>& info) {
1214 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1215 info.GetReturnValue().Set(fast_return_value_uint32);
1216}
1217
1218template<>
1219void FastReturnValueCallback<double>(
1220 const v8::FunctionCallbackInfo<v8::Value>& info) {
1221 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1222 info.GetReturnValue().Set(kFastReturnValueDouble);
1223}
1224
1225template<>
1226void FastReturnValueCallback<bool>(
1227 const v8::FunctionCallbackInfo<v8::Value>& info) {
1228 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1229 info.GetReturnValue().Set(fast_return_value_bool);
1230}
1231
1232template<>
1233void FastReturnValueCallback<void>(
1234 const v8::FunctionCallbackInfo<v8::Value>& info) {
1235 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1236 switch (fast_return_value_void) {
1237 case kNullReturnValue:
1238 info.GetReturnValue().SetNull();
1239 break;
1240 case kUndefinedReturnValue:
1241 info.GetReturnValue().SetUndefined();
1242 break;
1243 case kEmptyStringReturnValue:
1244 info.GetReturnValue().SetEmptyString();
1245 break;
1246 }
1247}
1248
1249template<>
1250void FastReturnValueCallback<Object>(
1251 const v8::FunctionCallbackInfo<v8::Value>& info) {
1252 v8::Local<v8::Object> object;
1253 if (!fast_return_value_object_is_empty) {
1254 object = Object::New(info.GetIsolate());
1255 }
1256 info.GetReturnValue().Set(object);
1257}
1258
1259template <typename T>
1260Local<Value> TestFastReturnValues() {
1261 LocalContext env;
1262 v8::Isolate* isolate = env->GetIsolate();
1263 v8::EscapableHandleScope scope(isolate);
1264 v8::Local<v8::ObjectTemplate> object_template =
1265 v8::ObjectTemplate::New(isolate);
1266 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1267 object_template->Set(isolate, "callback",
1268 v8::FunctionTemplate::New(isolate, callback));
1269 v8::Local<v8::Object> object =
1270 object_template->NewInstance(env.local()).ToLocalChecked();
1271 CHECK((*env)
1272 ->Global()
1273 ->Set(env.local(), v8_str("callback_object"), object)
1274 .FromJust());
1275 return scope.Escape(CompileRun("callback_object.callback()"));
1276}
1277
1278
1279THREADED_PROFILED_TEST(FastReturnValues) {
1280 LocalContext env;
1281 v8::Isolate* isolate = env->GetIsolate();
1282 v8::HandleScope scope(isolate);
1283 v8::Local<v8::Value> value;
1284 // check int32_t and uint32_t
1285 int32_t int_values[] = {
1286 0, 234, -723,
1287 i::Smi::kMinValue, i::Smi::kMaxValue
1288 };
1289 for (size_t i = 0; i < arraysize(int_values); i++) {
1290 for (int modifier = -1; modifier <= 1; modifier++) {
1291 int int_value = v8::base::AddWithWraparound(int_values[i], modifier);
1292 // check int32_t
1293 fast_return_value_int32 = int_value;
1294 value = TestFastReturnValues<int32_t>();
1295 CHECK(value->IsInt32());
1296 CHECK_EQ(fast_return_value_int32,
1297 value->Int32Value(env.local()).FromJust());
1298 // check uint32_t
1299 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1300 value = TestFastReturnValues<uint32_t>();
1301 CHECK(value->IsUint32());
1302 CHECK_EQ(fast_return_value_uint32,
1303 value->Uint32Value(env.local()).FromJust());
1304 }
1305 }
1306 // check double
1307 value = TestFastReturnValues<double>();
1308 CHECK(value->IsNumber());
1309 CHECK_EQ(kFastReturnValueDouble,
1310 value->ToNumber(env.local()).ToLocalChecked()->Value());
1311 // check bool values
1312 for (int i = 0; i < 2; i++) {
1313 fast_return_value_bool = i == 0;
1314 value = TestFastReturnValues<bool>();
1315 CHECK(value->IsBoolean());
1316 CHECK_EQ(fast_return_value_bool, value->BooleanValue(isolate));
1317 }
1318 // check oddballs
1319 ReturnValueOddball oddballs[] = {
1320 kNullReturnValue,
1321 kUndefinedReturnValue,
1322 kEmptyStringReturnValue
1323 };
1324 for (size_t i = 0; i < arraysize(oddballs); i++) {
1325 fast_return_value_void = oddballs[i];
1326 value = TestFastReturnValues<void>();
1327 switch (fast_return_value_void) {
1328 case kNullReturnValue:
1329 CHECK(value->IsNull());
1330 break;
1331 case kUndefinedReturnValue:
1332 CHECK(value->IsUndefined());
1333 break;
1334 case kEmptyStringReturnValue:
1335 CHECK(value->IsString());
1336 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1337 break;
1338 }
1339 }
1340 // check handles
1341 fast_return_value_object_is_empty = false;
1342 value = TestFastReturnValues<Object>();
1343 CHECK(value->IsObject());
1344 fast_return_value_object_is_empty = true;
1345 value = TestFastReturnValues<Object>();
1346 CHECK(value->IsUndefined());
1347}
1348
1349
1350THREADED_TEST(FunctionTemplateSetLength) {
1351 LocalContext env;
1352 v8::Isolate* isolate = env->GetIsolate();
1353 v8::HandleScope scope(isolate);
1354 {
1355 Local<v8::FunctionTemplate> fun_templ =
1356 v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
1357 Local<v8::Signature>(), 23);
1358 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1359 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1360 Local<Script> script = v8_compile("obj.length");
1361 CHECK_EQ(23, v8_run_int32value(script));
1362 }
1363 {
1364 Local<v8::FunctionTemplate> fun_templ =
1365 v8::FunctionTemplate::New(isolate, handle_callback);
1366 fun_templ->SetLength(22);
1367 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1368 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1369 Local<Script> script = v8_compile("obj.length");
1370 CHECK_EQ(22, v8_run_int32value(script));
1371 }
1372 {
1373 // Without setting length it defaults to 0.
1374 Local<v8::FunctionTemplate> fun_templ =
1375 v8::FunctionTemplate::New(isolate, handle_callback);
1376 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
1377 CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
1378 Local<Script> script = v8_compile("obj.length");
1379 CHECK_EQ(0, v8_run_int32value(script));
1380 }
1381}
1382
1383
1384static void* expected_ptr;
1385static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1386 void* ptr = v8::External::Cast(*args.Data())->Value();
1387 CHECK_EQ(expected_ptr, ptr);
1388 args.GetReturnValue().Set(true);
1389}
1390
1391
1392static void TestExternalPointerWrapping() {
1393 LocalContext env;
1394 v8::Isolate* isolate = env->GetIsolate();
1395 v8::HandleScope scope(isolate);
1396
1397 v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
1398
1399 v8::Local<v8::Object> obj = v8::Object::New(isolate);
1400 CHECK(obj->Set(env.local(), v8_str("func"),
1401 v8::FunctionTemplate::New(isolate, callback, data)
1402 ->GetFunction(env.local())
1403 .ToLocalChecked())
1404 .FromJust());
1405 CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
1406
1407 CHECK(CompileRun("function foo() {\n"
1408 " for (var i = 0; i < 13; i++) obj.func();\n"
1409 "}\n"
1410 "foo(), true")
1411 ->BooleanValue(isolate));
1412}
1413
1414
1415THREADED_TEST(ExternalWrap) {
1416 // Check heap allocated object.
1417 int* ptr = new int;
1418 expected_ptr = ptr;
1419 TestExternalPointerWrapping();
1420 delete ptr;
1421
1422 // Check stack allocated object.
1423 int foo;
1424 expected_ptr = &foo;
1425 TestExternalPointerWrapping();
1426
1427 // Check not aligned addresses.
1428 const int n = 100;
1429 char* s = new char[n];
1430 for (int i = 0; i < n; i++) {
1431 expected_ptr = s + i;
1432 TestExternalPointerWrapping();
1433 }
1434
1435 delete[] s;
1436
1437 // Check several invalid addresses.
1438 expected_ptr = reinterpret_cast<void*>(1);
1439 TestExternalPointerWrapping();
1440
1441 expected_ptr = reinterpret_cast<void*>(0xDEADBEEF);
1442 TestExternalPointerWrapping();
1443
1444 expected_ptr = reinterpret_cast<void*>(0xDEADBEEF + 1);
1445 TestExternalPointerWrapping();
1446
1447#if defined(V8_HOST_ARCH_X64)
1448 // Check a value with a leading 1 bit in x64 Smi encoding.
1449 expected_ptr = reinterpret_cast<void*>(0x400000000);
1450 TestExternalPointerWrapping();
1451
1452 expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF);
1453 TestExternalPointerWrapping();
1454
1455 expected_ptr = reinterpret_cast<void*>(0xDEADBEEFDEADBEEF + 1);
1456 TestExternalPointerWrapping();
1457#endif
1458}
1459
1460
1461THREADED_TEST(FindInstanceInPrototypeChain) {
1462 LocalContext env;
1463 v8::Isolate* isolate = env->GetIsolate();
1464 v8::HandleScope scope(isolate);
1465
1466 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1467 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1468 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1469 derived->Inherit(base);
1470
1471 Local<v8::Function> base_function =
1472 base->GetFunction(env.local()).ToLocalChecked();
1473 Local<v8::Function> derived_function =
1474 derived->GetFunction(env.local()).ToLocalChecked();
1475 Local<v8::Function> other_function =
1476 other->GetFunction(env.local()).ToLocalChecked();
1477
1478 Local<v8::Object> base_instance =
1479 base_function->NewInstance(env.local()).ToLocalChecked();
1480 Local<v8::Object> derived_instance =
1481 derived_function->NewInstance(env.local()).ToLocalChecked();
1482 Local<v8::Object> derived_instance2 =
1483 derived_function->NewInstance(env.local()).ToLocalChecked();
1484 Local<v8::Object> other_instance =
1485 other_function->NewInstance(env.local()).ToLocalChecked();
1486 CHECK(
1487 derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
1488 .FromJust());
1489 CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
1490 .FromJust());
1491
1492 // base_instance is only an instance of base.
1493 CHECK(base_instance->Equals(env.local(),
1494 base_instance->FindInstanceInPrototypeChain(base))
1495 .FromJust());
1496 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1497 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1498
1499 // derived_instance is an instance of base and derived.
1500 CHECK(derived_instance->Equals(env.local(),
1501 derived_instance->FindInstanceInPrototypeChain(
1502 base))
1503 .FromJust());
1504 CHECK(derived_instance->Equals(env.local(),
1505 derived_instance->FindInstanceInPrototypeChain(
1506 derived))
1507 .FromJust());
1508 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1509
1510 // other_instance is an instance of other and its immediate
1511 // prototype derived_instance2 is an instance of base and derived.
1512 // Note, derived_instance is an instance of base and derived too,
1513 // but it comes after derived_instance2 in the prototype chain of
1514 // other_instance.
1515 CHECK(derived_instance2->Equals(
1516 env.local(),
1517 other_instance->FindInstanceInPrototypeChain(base))
1518 .FromJust());
1519 CHECK(derived_instance2->Equals(env.local(),
1520 other_instance->FindInstanceInPrototypeChain(
1521 derived))
1522 .FromJust());
1523 CHECK(other_instance->Equals(
1524 env.local(),
1525 other_instance->FindInstanceInPrototypeChain(other))
1526 .FromJust());
1527}
1528
1529
1530THREADED_TEST(TinyInteger) {
1531 LocalContext env;
1532 v8::Isolate* isolate = env->GetIsolate();
1533 v8::HandleScope scope(isolate);
1534
1535 int32_t value = 239;
1536 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1537 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1538}
1539
1540
1541THREADED_TEST(BigSmiInteger) {
1542 LocalContext env;
1543 v8::HandleScope scope(env->GetIsolate());
1544 v8::Isolate* isolate = CcTest::isolate();
1545
1546 int32_t value = i::Smi::kMaxValue;
1547 // We cannot add one to a Smi::kMaxValue without wrapping.
1548 if (i::SmiValuesAre31Bits()) {
1549 CHECK(i::Smi::IsValid(value));
1550 CHECK(!i::Smi::IsValid(value + 1));
1551
1552 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1553 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1554 }
1555}
1556
1557
1558THREADED_TEST(BigInteger) {
1559 LocalContext env;
1560 v8::HandleScope scope(env->GetIsolate());
1561 v8::Isolate* isolate = CcTest::isolate();
1562
1563 // We cannot add one to a Smi::kMaxValue without wrapping.
1564 if (i::SmiValuesAre31Bits()) {
1565 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1566 // The code will not be run in that case, due to the "if" guard.
1567 int32_t value =
1568 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1569 CHECK_GT(value, i::Smi::kMaxValue);
1570 CHECK(!i::Smi::IsValid(value));
1571
1572 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1573 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1574 }
1575}
1576
1577
1578THREADED_TEST(TinyUnsignedInteger) {
1579 LocalContext env;
1580 v8::HandleScope scope(env->GetIsolate());
1581 v8::Isolate* isolate = CcTest::isolate();
1582
1583 uint32_t value = 239;
1584
1585 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1586 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1587}
1588
1589
1590THREADED_TEST(BigUnsignedSmiInteger) {
1591 LocalContext env;
1592 v8::HandleScope scope(env->GetIsolate());
1593 v8::Isolate* isolate = CcTest::isolate();
1594
1595 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1596 CHECK(i::Smi::IsValid(value));
1597 CHECK(!i::Smi::IsValid(value + 1));
1598
1599 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1600 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1601}
1602
1603
1604THREADED_TEST(BigUnsignedInteger) {
1605 LocalContext env;
1606 v8::HandleScope scope(env->GetIsolate());
1607 v8::Isolate* isolate = CcTest::isolate();
1608
1609 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1610 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1611 CHECK(!i::Smi::IsValid(value));
1612
1613 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1614 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1615}
1616
1617
1618THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1619 LocalContext env;
1620 v8::HandleScope scope(env->GetIsolate());
1621 v8::Isolate* isolate = CcTest::isolate();
1622
1623 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1624 uint32_t value = INT32_MAX_AS_UINT + 1;
1625 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1626
1627 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1628 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1629}
1630
1631
1632THREADED_TEST(IsNativeError) {
1633 LocalContext env;
1634 v8::HandleScope scope(env->GetIsolate());
1635 v8::Local<Value> syntax_error = CompileRun(
1636 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1637 CHECK(syntax_error->IsNativeError());
1638 v8::Local<Value> not_error = CompileRun("{a:42}");
1639 CHECK(!not_error->IsNativeError());
1640 v8::Local<Value> not_object = CompileRun("42");
1641 CHECK(!not_object->IsNativeError());
1642}
1643
1644
1645THREADED_TEST(IsGeneratorFunctionOrObject) {
1646 LocalContext env;
1647 v8::HandleScope scope(env->GetIsolate());
1648
1649 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1650 v8::Local<Value> gen = CompileRun("gen");
1651 v8::Local<Value> genObj = CompileRun("gen()");
1652 v8::Local<Value> object = CompileRun("{a:42}");
1653 v8::Local<Value> func = CompileRun("func");
1654
1655 CHECK(gen->IsGeneratorFunction());
1656 CHECK(gen->IsFunction());
1657 CHECK(!gen->IsGeneratorObject());
1658
1659 CHECK(!genObj->IsGeneratorFunction());
1660 CHECK(!genObj->IsFunction());
1661 CHECK(genObj->IsGeneratorObject());
1662
1663 CHECK(!object->IsGeneratorFunction());
1664 CHECK(!object->IsFunction());
1665 CHECK(!object->IsGeneratorObject());
1666
1667 CHECK(!func->IsGeneratorFunction());
1668 CHECK(func->IsFunction());
1669 CHECK(!func->IsGeneratorObject());
1670}
1671
1672THREADED_TEST(IsAsyncFunction) {
1673 LocalContext env;
1674 v8::Isolate* isolate = env->GetIsolate();
1675 v8::HandleScope scope(isolate);
1676
1677 CompileRun("async function foo() {}");
1678 v8::Local<Value> foo = CompileRun("foo");
1679
1680 CHECK(foo->IsAsyncFunction());
1681 CHECK(foo->IsFunction());
1682 CHECK(!foo->IsGeneratorFunction());
1683 CHECK(!foo->IsGeneratorObject());
1684
1685 CompileRun("function bar() {}");
1686 v8::Local<Value> bar = CompileRun("bar");
1687
1688 CHECK(!bar->IsAsyncFunction());
1689 CHECK(bar->IsFunction());
1690}
1691
1692THREADED_TEST(ArgumentsObject) {
1693 LocalContext env;
1694 v8::HandleScope scope(env->GetIsolate());
1695 v8::Local<Value> arguments_object =
1696 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1697 CHECK(arguments_object->IsArgumentsObject());
1698 v8::Local<Value> array = CompileRun("[1,2,3]");
1699 CHECK(!array->IsArgumentsObject());
1700 v8::Local<Value> object = CompileRun("{a:42}");
1701 CHECK(!object->IsArgumentsObject());
1702}
1703
1704
1705THREADED_TEST(IsMapOrSet) {
1706 LocalContext env;
1707 v8::HandleScope scope(env->GetIsolate());
1708 v8::Local<Value> map = CompileRun("new Map()");
1709 v8::Local<Value> set = CompileRun("new Set()");
1710 v8::Local<Value> weak_map = CompileRun("new WeakMap()");
1711 v8::Local<Value> weak_set = CompileRun("new WeakSet()");
1712 CHECK(map->IsMap());
1713 CHECK(set->IsSet());
1714 CHECK(weak_map->IsWeakMap());
1715 CHECK(weak_set->IsWeakSet());
1716
1717 CHECK(!map->IsSet());
1718 CHECK(!map->IsWeakMap());
1719 CHECK(!map->IsWeakSet());
1720
1721 CHECK(!set->IsMap());
1722 CHECK(!set->IsWeakMap());
1723 CHECK(!set->IsWeakSet());
1724
1725 CHECK(!weak_map->IsMap());
1726 CHECK(!weak_map->IsSet());
1727 CHECK(!weak_map->IsWeakSet());
1728
1729 CHECK(!weak_set->IsMap());
1730 CHECK(!weak_set->IsSet());
1731 CHECK(!weak_set->IsWeakMap());
1732
1733 v8::Local<Value> object = CompileRun("{a:42}");
1734 CHECK(!object->IsMap());
1735 CHECK(!object->IsSet());
1736 CHECK(!object->IsWeakMap());
1737 CHECK(!object->IsWeakSet());
1738}
1739
1740
1741THREADED_TEST(StringObject) {
1742 LocalContext env;
1743 v8::HandleScope scope(env->GetIsolate());
1744 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1745 CHECK(boxed_string->IsStringObject());
1746 v8::Local<Value> unboxed_string = CompileRun("\"test\"");
1747 CHECK(!unboxed_string->IsStringObject());
1748 v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
1749 CHECK(!boxed_not_string->IsStringObject());
1750 v8::Local<Value> not_object = CompileRun("0");
1751 CHECK(!not_object->IsStringObject());
1752 v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1753 CHECK(!as_boxed.IsEmpty());
1754 Local<v8::String> the_string = as_boxed->ValueOf();
1755 CHECK(!the_string.IsEmpty());
1756 ExpectObject("\"test\"", the_string);
1757 v8::Local<v8::Value> new_boxed_string =
1758 v8::StringObject::New(CcTest::isolate(), the_string);
1759 CHECK(new_boxed_string->IsStringObject());
1760 as_boxed = new_boxed_string.As<v8::StringObject>();
1761 the_string = as_boxed->ValueOf();
1762 CHECK(!the_string.IsEmpty());
1763 ExpectObject("\"test\"", the_string);
1764}
1765
1766
1767TEST(StringObjectDelete) {
1768 LocalContext context;
1769 v8::HandleScope scope(context->GetIsolate());
1770 v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
1771 CHECK(boxed_string->IsStringObject());
1772 v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
1773 CHECK(!str_obj->Delete(context.local(), 2).FromJust());
1774 CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
1775}
1776
1777
1778THREADED_TEST(NumberObject) {
1779 LocalContext env;
1780 v8::HandleScope scope(env->GetIsolate());
1781 v8::Local<Value> boxed_number = CompileRun("new Number(42)");
1782 CHECK(boxed_number->IsNumberObject());
1783 v8::Local<Value> unboxed_number = CompileRun("42");
1784 CHECK(!unboxed_number->IsNumberObject());
1785 v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
1786 CHECK(!boxed_not_number->IsNumberObject());
1787 v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1788 CHECK(!as_boxed.IsEmpty());
1789 double the_number = as_boxed->ValueOf();
1790 CHECK_EQ(42.0, the_number);
1791 v8::Local<v8::Value> new_boxed_number =
1792 v8::NumberObject::New(env->GetIsolate(), 43);
1793 CHECK(new_boxed_number->IsNumberObject());
1794 as_boxed = new_boxed_number.As<v8::NumberObject>();
1795 the_number = as_boxed->ValueOf();
1796 CHECK_EQ(43.0, the_number);
1797}
1798
1799THREADED_TEST(BigIntObject) {
1800 LocalContext env;
1801 v8::Isolate* isolate = env->GetIsolate();
1802 v8::HandleScope scope(isolate);
1803 v8::Local<v8::Context> context(env.local());
1804 v8::Local<Value> boxed_bigint = CompileRun("new Object(42n)");
1805 CHECK(!boxed_bigint->IsBigInt());
1806 CHECK(boxed_bigint->IsBigIntObject());
1807 v8::Local<Value> unboxed_bigint = CompileRun("42n");
1808 CHECK(unboxed_bigint->IsBigInt());
1809 CHECK(!unboxed_bigint->IsBigIntObject());
1810 v8::Local<v8::BigIntObject> as_boxed = boxed_bigint.As<v8::BigIntObject>();
1811 CHECK(!as_boxed.IsEmpty());
1812 v8::Local<v8::BigInt> unpacked = as_boxed->ValueOf();
1813 CHECK(!unpacked.IsEmpty());
1814 v8::Local<v8::Value> new_boxed_bigint = v8::BigIntObject::New(isolate, 43);
1815 CHECK(new_boxed_bigint->IsBigIntObject());
1816 v8::Local<v8::Value> new_unboxed_bigint = v8::BigInt::New(isolate, 44);
1817 CHECK(new_unboxed_bigint->IsBigInt());
1818
1819 // Test functionality inherited from v8::Value.
1820 CHECK(unboxed_bigint->BooleanValue(isolate));
1821 v8::Local<v8::String> string =
1822 unboxed_bigint->ToString(context).ToLocalChecked();
1823 CHECK_EQ(0, strcmp("42", *v8::String::Utf8Value(isolate, string)));
1824
1825 // IntegerValue throws.
1826 CHECK(unboxed_bigint->IntegerValue(context).IsNothing());
1827}
1828
1829THREADED_TEST(BooleanObject) {
1830 LocalContext env;
1831 v8::HandleScope scope(env->GetIsolate());
1832 v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
1833 CHECK(boxed_boolean->IsBooleanObject());
1834 v8::Local<Value> unboxed_boolean = CompileRun("true");
1835 CHECK(!unboxed_boolean->IsBooleanObject());
1836 v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
1837 CHECK(!boxed_not_boolean->IsBooleanObject());
1838 v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
1839 CHECK(!as_boxed.IsEmpty());
1840 bool the_boolean = as_boxed->ValueOf();
1841 CHECK(the_boolean);
1842 v8::Local<v8::Value> boxed_true =
1843 v8::BooleanObject::New(env->GetIsolate(), true);
1844 v8::Local<v8::Value> boxed_false =
1845 v8::BooleanObject::New(env->GetIsolate(), false);
1846 CHECK(boxed_true->IsBooleanObject());
1847 CHECK(boxed_false->IsBooleanObject());
1848 as_boxed = boxed_true.As<v8::BooleanObject>();
1849 CHECK(as_boxed->ValueOf());
1850 as_boxed = boxed_false.As<v8::BooleanObject>();
1851 CHECK(!as_boxed->ValueOf());
1852}
1853
1854
1855THREADED_TEST(PrimitiveAndWrappedBooleans) {
1856 LocalContext env;
1857 v8::Isolate* isolate = env->GetIsolate();
1858 v8::HandleScope scope(isolate);
1859
1860 Local<Value> primitive_false = Boolean::New(isolate, false);
1861 CHECK(primitive_false->IsBoolean());
1862 CHECK(!primitive_false->IsBooleanObject());
1863 CHECK(!primitive_false->BooleanValue(isolate));
1864 CHECK(!primitive_false->IsTrue());
1865 CHECK(primitive_false->IsFalse());
1866
1867 Local<Value> false_value = BooleanObject::New(isolate, false);
1868 CHECK(!false_value->IsBoolean());
1869 CHECK(false_value->IsBooleanObject());
1870 CHECK(false_value->BooleanValue(isolate));
1871 CHECK(!false_value->IsTrue());
1872 CHECK(!false_value->IsFalse());
1873
1874 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1875 CHECK(!false_boolean_object->IsBoolean());
1876 CHECK(false_boolean_object->IsBooleanObject());
1877 CHECK(false_boolean_object->BooleanValue(isolate));
1878 CHECK(!false_boolean_object->ValueOf());
1879 CHECK(!false_boolean_object->IsTrue());
1880 CHECK(!false_boolean_object->IsFalse());
1881
1882 Local<Value> primitive_true = Boolean::New(isolate, true);
1883 CHECK(primitive_true->IsBoolean());
1884 CHECK(!primitive_true->IsBooleanObject());
1885 CHECK(primitive_true->BooleanValue(isolate));
1886 CHECK(primitive_true->IsTrue());
1887 CHECK(!primitive_true->IsFalse());
1888
1889 Local<Value> true_value = BooleanObject::New(isolate, true);
1890 CHECK(!true_value->IsBoolean());
1891 CHECK(true_value->IsBooleanObject());
1892 CHECK(true_value->BooleanValue(isolate));
1893 CHECK(!true_value->IsTrue());
1894 CHECK(!true_value->IsFalse());
1895
1896 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1897 CHECK(!true_boolean_object->IsBoolean());
1898 CHECK(true_boolean_object->IsBooleanObject());
1899 CHECK(true_boolean_object->BooleanValue(isolate));
1900 CHECK(true_boolean_object->ValueOf());
1901 CHECK(!true_boolean_object->IsTrue());
1902 CHECK(!true_boolean_object->IsFalse());
1903}
1904
1905
1906THREADED_TEST(Number) {
1907 LocalContext env;
1908 v8::HandleScope scope(env->GetIsolate());
1909 double PI = 3.1415926;
1910 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1911 CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
1912}
1913
1914
1915THREADED_TEST(ToNumber) {
1916 LocalContext env;
1917 v8::Isolate* isolate = CcTest::isolate();
1918 v8::HandleScope scope(isolate);
1919 Local<String> str = v8_str("3.1415926");
1920 CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
1921 v8::Local<v8::Boolean> t = v8::True(isolate);
1922 CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
1923 v8::Local<v8::Boolean> f = v8::False(isolate);
1924 CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
1925}
1926
1927
1928THREADED_TEST(Date) {
1929 LocalContext env;
1930 v8::HandleScope scope(env->GetIsolate());
1931 double PI = 3.1415926;
1932 Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
1933 CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
1934 CHECK(date.As<v8::Date>()
1935 ->Set(env.local(), v8_str("property"),
1936 v8::Integer::New(env->GetIsolate(), 42))
1937 .FromJust());
1938 CHECK_EQ(42, date.As<v8::Date>()
1939 ->Get(env.local(), v8_str("property"))
1940 .ToLocalChecked()
1941 ->Int32Value(env.local())
1942 .FromJust());
1943}
1944
1945
1946THREADED_TEST(Boolean) {
1947 LocalContext env;
1948 v8::Isolate* isolate = env->GetIsolate();
1949 v8::HandleScope scope(isolate);
1950 v8::Local<v8::Boolean> t = v8::True(isolate);
1951 CHECK(t->Value());
1952 v8::Local<v8::Boolean> f = v8::False(isolate);
1953 CHECK(!f->Value());
1954 v8::Local<v8::Primitive> u = v8::Undefined(isolate);
1955 CHECK(!u->BooleanValue(isolate));
1956 v8::Local<v8::Primitive> n = v8::Null(isolate);
1957 CHECK(!n->BooleanValue(isolate));
1958 v8::Local<String> str1 = v8_str("");
1959 CHECK(!str1->BooleanValue(isolate));
1960 v8::Local<String> str2 = v8_str("x");
1961 CHECK(str2->BooleanValue(isolate));
1962 CHECK(!v8::Number::New(isolate, 0)->BooleanValue(isolate));
1963 CHECK(v8::Number::New(isolate, -1)->BooleanValue(isolate));
1964 CHECK(v8::Number::New(isolate, 1)->BooleanValue(isolate));
1965 CHECK(v8::Number::New(isolate, 42)->BooleanValue(isolate));
1966 CHECK(!v8_compile("NaN")
1967 ->Run(env.local())
1968 .ToLocalChecked()
1969 ->BooleanValue(isolate));
1970}
1971
1972
1973static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1974 ApiTestFuzzer::Fuzz();
1975 args.GetReturnValue().Set(v8_num(13.4));
1976}
1977
1978
1979static void GetM(Local<String> name,
1980 const v8::PropertyCallbackInfo<v8::Value>& info) {
1981 ApiTestFuzzer::Fuzz();
1982 info.GetReturnValue().Set(v8_num(876));
1983}
1984
1985
1986THREADED_TEST(GlobalPrototype) {
1987 v8::Isolate* isolate = CcTest::isolate();
1988 v8::HandleScope scope(isolate);
1989 v8::Local<v8::FunctionTemplate> func_templ =
1990 v8::FunctionTemplate::New(isolate);
1991 func_templ->PrototypeTemplate()->Set(
1992 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1993 v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
1994 templ->Set(isolate, "x", v8_num(200));
1995 templ->SetAccessor(v8_str("m"), GetM);
1996 LocalContext env(nullptr, templ);
1997 v8::Local<Script> script(v8_compile("dummy()"));
1998 v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
1999 CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
2000 CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
2001 CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
2002}
2003
2004
2005THREADED_TEST(ObjectTemplate) {
2006 LocalContext env;
2007 v8::Isolate* isolate = CcTest::isolate();
2008 v8::HandleScope scope(isolate);
2009 Local<v8::FunctionTemplate> acc =
2010 v8::FunctionTemplate::New(isolate, Returns42);
2011 CHECK(env->Global()
2012 ->Set(env.local(), v8_str("acc"),
2013 acc->GetFunction(env.local()).ToLocalChecked())
2014 .FromJust());
2015
2016 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
2017 v8::Local<v8::String> class_name = v8_str("the_class_name");
2018 fun->SetClassName(class_name);
2019 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
2020 templ1->Set(isolate, "x", v8_num(10));
2021 templ1->Set(isolate, "y", v8_num(13));
2022 templ1->Set(v8_str("foo"), acc);
2023 Local<v8::Object> instance1 =
2024 templ1->NewInstance(env.local()).ToLocalChecked();
2025 CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
2026 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
2027 CHECK(CompileRun("(p.x == 10)")->BooleanValue(isolate));
2028 CHECK(CompileRun("(p.y == 13)")->BooleanValue(isolate));
2029 CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(isolate));
2030 CHECK(CompileRun("(p.foo == acc)")->BooleanValue(isolate));
2031 // Ensure that foo become a data field.
2032 CompileRun("p.foo = function() {}");
2033 Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
2034 fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
2035 Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
2036 templ2->Set(isolate, "a", v8_num(12));
2037 templ2->Set(isolate, "b", templ1);
2038 templ2->Set(v8_str("bar"), acc);
2039 templ2->SetAccessorProperty(v8_str("acc"), acc);
2040 Local<v8::Object> instance2 =
2041 templ2->NewInstance(env.local()).ToLocalChecked();
2042 CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
2043 CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(isolate));
2044 CHECK(CompileRun("(q.a == 12)")->BooleanValue(isolate));
2045 CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(isolate));
2046 CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(isolate));
2047 CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(isolate));
2048 CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(isolate));
2049 CHECK(CompileRun("(q.b !== p)")->BooleanValue(isolate));
2050 CHECK(CompileRun("(q.acc == 42)")->BooleanValue(isolate));
2051 CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(isolate));
2052 CHECK(CompileRun("(q.bar == acc)")->BooleanValue(isolate));
2053
2054 instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
2055 CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
2056 CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(isolate));
2057 CHECK(CompileRun("(q2.a == 12)")->BooleanValue(isolate));
2058 CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(isolate));
2059 CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(isolate));
2060 CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(isolate));
2061 CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(isolate));
2062 CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(isolate));
2063 CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(isolate));
2064 CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(isolate));
2065
2066 CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(isolate));
2067 CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")->BooleanValue(isolate));
2068 CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
2069 "(desc1.get === acc)")
2070 ->BooleanValue(isolate));
2071 CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
2072 "(desc2.get === acc)")
2073 ->BooleanValue(isolate));
2074}
2075
2076THREADED_TEST(IntegerValue) {
2077 LocalContext env;
2078 v8::Isolate* isolate = CcTest::isolate();
2079 v8::HandleScope scope(isolate);
2080
2081 CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
2082}
2083
2084static void GetNirk(Local<String> name,
2085 const v8::PropertyCallbackInfo<v8::Value>& info) {
2086 ApiTestFuzzer::Fuzz();
2087 info.GetReturnValue().Set(v8_num(900));
2088}
2089
2090static void GetRino(Local<String> name,
2091 const v8::PropertyCallbackInfo<v8::Value>& info) {
2092 ApiTestFuzzer::Fuzz();
2093 info.GetReturnValue().Set(v8_num(560));
2094}
2095
2096enum ObjectInstantiationMode {
2097 // Create object using ObjectTemplate::NewInstance.
2098 ObjectTemplate_NewInstance,
2099 // Create object using FunctionTemplate::NewInstance on constructor.
2100 Constructor_GetFunction_NewInstance,
2101 // Create object using new operator on constructor.
2102 Constructor_GetFunction_New
2103};
2104
2105// Test object instance creation using a function template with an instance
2106// template inherited from another function template with accessors and data
2107// properties in prototype template.
2108static void TestObjectTemplateInheritedWithPrototype(
2109 ObjectInstantiationMode mode) {
2110 LocalContext env;
2111 v8::Isolate* isolate = CcTest::isolate();
2112 v8::HandleScope scope(isolate);
2113
2114 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2115 fun_A->SetClassName(v8_str("A"));
2116 v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
2117 prototype_templ->Set(isolate, "a", v8_num(113));
2118 prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2119 prototype_templ->Set(isolate, "b", v8_num(153));
2120
2121 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2122 v8::Local<v8::String> class_name = v8_str("B");
2123 fun_B->SetClassName(class_name);
2124 fun_B->Inherit(fun_A);
2125 prototype_templ = fun_B->PrototypeTemplate();
2126 prototype_templ->Set(isolate, "c", v8_num(713));
2127 prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
2128 prototype_templ->Set(isolate, "d", v8_num(753));
2129
2130 Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
2131 templ->Set(isolate, "x", v8_num(10));
2132 templ->Set(isolate, "y", v8_num(13));
2133
2134 // Perform several iterations to trigger creation from cached boilerplate.
2135 for (int i = 0; i < 3; i++) {
2136 Local<v8::Object> instance;
2137 switch (mode) {
2138 case ObjectTemplate_NewInstance:
2139 instance = templ->NewInstance(env.local()).ToLocalChecked();
2140 break;
2141
2142 case Constructor_GetFunction_NewInstance: {
2143 Local<v8::Function> function_B =
2144 fun_B->GetFunction(env.local()).ToLocalChecked();
2145 instance = function_B->NewInstance(env.local()).ToLocalChecked();
2146 break;
2147 }
2148 case Constructor_GetFunction_New: {
2149 Local<v8::Function> function_B =
2150 fun_B->GetFunction(env.local()).ToLocalChecked();
2151 if (i == 0) {
2152 CHECK(env->Global()
2153 ->Set(env.local(), class_name, function_B)
2154 .FromJust());
2155 }
2156 instance =
2157 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2158 break;
2159 }
2160 default:
2161 UNREACHABLE();
2162 }
2163
2164 CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2165 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2166
2167 CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
2168 CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
2169
2170 CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
2171 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2172 CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
2173 CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
2174 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2175 CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
2176 }
2177}
2178
2179THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
2180 TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
2181}
2182
2183THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
2184 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
2185}
2186
2187THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
2188 TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
2189}
2190
2191// Test object instance creation using a function template without an instance
2192// template inherited from another function template.
2193static void TestObjectTemplateInheritedWithoutInstanceTemplate(
2194 ObjectInstantiationMode mode) {
2195 LocalContext env;
2196 v8::Isolate* isolate = CcTest::isolate();
2197 v8::HandleScope scope(isolate);
2198
2199 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2200 fun_A->SetClassName(v8_str("A"));
2201
2202 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2203 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2204 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2205
2206 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2207 v8::Local<v8::String> class_name = v8_str("B");
2208 fun_B->SetClassName(class_name);
2209 fun_B->Inherit(fun_A);
2210
2211 // Perform several iterations to trigger creation from cached boilerplate.
2212 for (int i = 0; i < 3; i++) {
2213 Local<v8::Object> instance;
2214 switch (mode) {
2215 case Constructor_GetFunction_NewInstance: {
2216 Local<v8::Function> function_B =
2217 fun_B->GetFunction(env.local()).ToLocalChecked();
2218 instance = function_B->NewInstance(env.local()).ToLocalChecked();
2219 break;
2220 }
2221 case Constructor_GetFunction_New: {
2222 Local<v8::Function> function_B =
2223 fun_B->GetFunction(env.local()).ToLocalChecked();
2224 if (i == 0) {
2225 CHECK(env->Global()
2226 ->Set(env.local(), class_name, function_B)
2227 .FromJust());
2228 }
2229 instance =
2230 CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
2231 break;
2232 }
2233 default:
2234 UNREACHABLE();
2235 }
2236
2237 CHECK(class_name->StrictEquals(instance->GetConstructorName()));
2238 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2239
2240 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2241 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2242 }
2243}
2244
2245THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
2246 TestObjectTemplateInheritedWithoutInstanceTemplate(
2247 Constructor_GetFunction_NewInstance);
2248}
2249
2250THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
2251 TestObjectTemplateInheritedWithoutInstanceTemplate(
2252 Constructor_GetFunction_New);
2253}
2254
2255THREADED_TEST(TestObjectTemplateClassInheritance) {
2256 LocalContext env;
2257 v8::Isolate* isolate = CcTest::isolate();
2258 v8::HandleScope scope(isolate);
2259
2260 Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2261 fun_A->SetClassName(v8_str("A"));
2262
2263 Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
2264 templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
2265 templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
2266
2267 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2268 v8::Local<v8::String> class_name = v8_str("B");
2269 fun_B->SetClassName(class_name);
2270 fun_B->Inherit(fun_A);
2271
2272 v8::Local<v8::String> subclass_name = v8_str("C");
2273 v8::Local<v8::Object> b_proto;
2274 v8::Local<v8::Object> c_proto;
2275 // Perform several iterations to make sure the cache doesn't break
2276 // subclassing.
2277 for (int i = 0; i < 3; i++) {
2278 Local<v8::Function> function_B =
2279 fun_B->GetFunction(env.local()).ToLocalChecked();
2280 if (i == 0) {
2281 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2282 CompileRun("class C extends B {}");
2283 b_proto =
2284 CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
2285 c_proto =
2286 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2287 CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
2288 }
2289 Local<v8::Object> instance =
2290 CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
2291 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2292
2293 CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2294 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2295
2296 CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2297 CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2298 }
2299}
2300
2301static void NamedPropertyGetterWhichReturns42(
2302 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2303 info.GetReturnValue().Set(v8_num(42));
2304}
2305
2306THREADED_TEST(TestObjectTemplateReflectConstruct) {
2307 LocalContext env;
2308 v8::Isolate* isolate = CcTest::isolate();
2309 v8::HandleScope scope(isolate);
2310
2311 Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2312 fun_B->InstanceTemplate()->SetHandler(
2313 v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
2314 v8::Local<v8::String> class_name = v8_str("B");
2315 fun_B->SetClassName(class_name);
2316
2317 v8::Local<v8::String> subclass_name = v8_str("C");
2318 v8::Local<v8::Object> b_proto;
2319 v8::Local<v8::Object> c_proto;
2320 // Perform several iterations to make sure the cache doesn't break
2321 // subclassing.
2322 for (int i = 0; i < 3; i++) {
2323 Local<v8::Function> function_B =
2324 fun_B->GetFunction(env.local()).ToLocalChecked();
2325 if (i == 0) {
2326 CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
2327 CompileRun("function C() {}");
2328 c_proto =
2329 CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
2330 }
2331 Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
2332 ->ToObject(env.local())
2333 .ToLocalChecked();
2334 CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
2335
2336 CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
2337 CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
2338
2339 CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
2340 CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
2341 }
2342}
2343
2344static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
2345 ApiTestFuzzer::Fuzz();
2346 args.GetReturnValue().Set(v8_num(17.2));
2347}
2348
2349
2350static void GetKnurd(Local<String> property,
2351 const v8::PropertyCallbackInfo<v8::Value>& info) {
2352 ApiTestFuzzer::Fuzz();
2353 info.GetReturnValue().Set(v8_num(15.2));
2354}
2355
2356
2357THREADED_TEST(DescriptorInheritance) {
2358 v8::Isolate* isolate = CcTest::isolate();
2359 v8::HandleScope scope(isolate);
2360 v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
2361 super->PrototypeTemplate()->Set(isolate, "flabby",
2362 v8::FunctionTemplate::New(isolate,
2363 GetFlabby));
2364 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
2365
2366 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
2367
2368 v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
2369 base1->Inherit(super);
2370 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
2371
2372 v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
2373 base2->Inherit(super);
2374 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
2375
2376 LocalContext env;
2377
2378 CHECK(env->Global()
2379 ->Set(env.local(), v8_str("s"),
2380 super->GetFunction(env.local()).ToLocalChecked())
2381 .FromJust());
2382 CHECK(env->Global()
2383 ->Set(env.local(), v8_str("base1"),
2384 base1->GetFunction(env.local()).ToLocalChecked())
2385 .FromJust());
2386 CHECK(env->Global()
2387 ->Set(env.local(), v8_str("base2"),
2388 base2->GetFunction(env.local()).ToLocalChecked())
2389 .FromJust());
2390
2391 // Checks right __proto__ chain.
2392 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
2393 ->BooleanValue(isolate));
2394 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
2395 ->BooleanValue(isolate));
2396
2397 CHECK(v8_compile("s.prototype.PI == 3.14")
2398 ->Run(env.local())
2399 .ToLocalChecked()
2400 ->BooleanValue(isolate));
2401
2402 // Instance accessor should not be visible on function object or its prototype
2403 CHECK(CompileRun("s.knurd == undefined")->BooleanValue(isolate));
2404 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue(isolate));
2405 CHECK(
2406 CompileRun("base1.prototype.knurd == undefined")->BooleanValue(isolate));
2407
2408 CHECK(env->Global()
2409 ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
2410 .ToLocalChecked()
2411 ->NewInstance(env.local())
2412 .ToLocalChecked())
2413 .FromJust());
2414 CHECK_EQ(17.2,
2415 CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
2416 CHECK(CompileRun("'flabby' in obj")->BooleanValue(isolate));
2417 CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
2418 CHECK(CompileRun("'knurd' in obj")->BooleanValue(isolate));
2419 CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
2420
2421 CHECK(env->Global()
2422 ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
2423 .ToLocalChecked()
2424 ->NewInstance(env.local())
2425 .ToLocalChecked())
2426 .FromJust());
2427 CHECK_EQ(17.2,
2428 CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
2429 CHECK(CompileRun("'flabby' in obj2")->BooleanValue(isolate));
2430 CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
2431 CHECK(CompileRun("'knurd' in obj2")->BooleanValue(isolate));
2432 CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
2433
2434 // base1 and base2 cannot cross reference to each's prototype
2435 CHECK(CompileRun("obj.v2")->IsUndefined());
2436 CHECK(CompileRun("obj2.v1")->IsUndefined());
2437}
2438
2439THREADED_TEST(DescriptorInheritance2) {
2440 LocalContext env;
2441 v8::Isolate* isolate = CcTest::isolate();
2442 v8::HandleScope scope(isolate);
2443 v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
2444 fun_A->SetClassName(v8_str("A"));
2445 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
2446 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
2447 fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
2448
2449 v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
2450 fun_B->SetClassName(v8_str("B"));
2451 fun_B->Inherit(fun_A);
2452
2453 v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
2454 fun_C->SetClassName(v8_str("C"));
2455 fun_C->Inherit(fun_B);
2456 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
2457 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
2458 fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
2459
2460 v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
2461 fun_D->SetClassName(v8_str("D"));
2462 fun_D->Inherit(fun_C);
2463
2464 v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
2465 fun_E->SetClassName(v8_str("E"));
2466 fun_E->Inherit(fun_D);
2467 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
2468 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
2469 fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
2470
2471 v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
2472 fun_F->SetClassName(v8_str("F"));
2473 fun_F->Inherit(fun_E);
2474 v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
2475 const int kDataPropertiesNumber = 100;
2476 for (int i = 0; i < kDataPropertiesNumber; i++) {
2477 v8::Local<v8::Value> val = v8_num(i);
2478 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2479 v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2480
2481 templ->Set(name, val);
2482 templ->Set(val_str, val);
2483 }
2484
2485 CHECK(env->Global()
2486 ->Set(env.local(), v8_str("F"),
2487 fun_F->GetFunction(env.local()).ToLocalChecked())
2488 .FromJust());
2489
2490 v8::Local<v8::Script> script = v8_compile("o = new F()");
2491
2492 for (int i = 0; i < 100; i++) {
2493 v8::HandleScope scope(isolate);
2494 script->Run(env.local()).ToLocalChecked();
2495 }
2496 v8::Local<v8::Object> object = script->Run(env.local())
2497 .ToLocalChecked()
2498 ->ToObject(env.local())
2499 .ToLocalChecked();
2500
2501 CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
2502 CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
2503 CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
2504
2505 CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
2506 CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
2507 CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
2508
2509 CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
2510 CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
2511 CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
2512
2513 for (int i = 0; i < kDataPropertiesNumber; i++) {
2514 v8::Local<v8::Value> val = v8_num(i);
2515 v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
2516 v8::Local<v8::String> name = String::Concat(isolate, v8_str("p"), val_str);
2517
2518 CHECK_EQ(i, object->Get(env.local(), name)
2519 .ToLocalChecked()
2520 ->IntegerValue(env.local())
2521 .FromJust());
2522 CHECK_EQ(i, object->Get(env.local(), val)
2523 .ToLocalChecked()
2524 ->IntegerValue(env.local())
2525 .FromJust());
2526 }
2527}
2528
2529
2530// Helper functions for Interceptor/Accessor interaction tests
2531
2532void SimpleAccessorGetter(Local<String> name,
2533 const v8::PropertyCallbackInfo<v8::Value>& info) {
2534 Local<Object> self = Local<Object>::Cast(info.This());
2535 info.GetReturnValue().Set(
2536 self->Get(info.GetIsolate()->GetCurrentContext(),
2537 String::Concat(info.GetIsolate(), v8_str("accessor_"), name))
2538 .ToLocalChecked());
2539}
2540
2541void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2542 const v8::PropertyCallbackInfo<void>& info) {
2543 Local<Object> self = Local<Object>::Cast(info.This());
2544 CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
2545 String::Concat(info.GetIsolate(), v8_str("accessor_"), name),
2546 value)
2547 .FromJust());
2548}
2549
2550void SymbolAccessorGetter(Local<Name> name,
2551 const v8::PropertyCallbackInfo<v8::Value>& info) {
2552 CHECK(name->IsSymbol());
2553 Local<Symbol> sym = Local<Symbol>::Cast(name);
2554 if (sym->Name()->IsUndefined())
2555 return;
2556 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2557}
2558
2559void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2560 const v8::PropertyCallbackInfo<void>& info) {
2561 CHECK(name->IsSymbol());
2562 Local<Symbol> sym = Local<Symbol>::Cast(name);
2563 if (sym->Name()->IsUndefined())
2564 return;
2565 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2566}
2567
2568void SymbolAccessorGetterReturnsDefault(
2569 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2570 CHECK(name->IsSymbol());
2571 Local<Symbol> sym = Local<Symbol>::Cast(name);
2572 if (sym->Name()->IsUndefined()) return;
2573 info.GetReturnValue().Set(info.Data());
2574}
2575
2576static void ThrowingSymbolAccessorGetter(
2577 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2578 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2579}
2580
2581
2582THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
2583 v8::Isolate* isolate = CcTest::isolate();
2584 v8::HandleScope scope(isolate);
2585 LocalContext env;
2586 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2587 i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2588 CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
2589 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2590 CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
2591 // But we should still have an AccessorInfo.
2592 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2593 i::LookupIterator it(CcTest::i_isolate(), a, name,
2594 i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2595 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2596 CHECK(it.GetAccessors()->IsAccessorInfo());
2597}
2598
2599
2600THREADED_TEST(UndefinedIsNotEnumerable) {
2601 LocalContext env;
2602 v8::HandleScope scope(env->GetIsolate());
2603 v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2604 CHECK(result->IsFalse());
2605}
2606
2607
2608v8::Local<Script> call_recursively_script;
2609static const int kTargetRecursionDepth = 100; // near maximum
2610
2611static void CallScriptRecursivelyCall(
2612 const v8::FunctionCallbackInfo<v8::Value>& args) {
2613 ApiTestFuzzer::Fuzz();
2614 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2615 int depth = args.This()
2616 ->Get(context, v8_str("depth"))
2617 .ToLocalChecked()
2618 ->Int32Value(context)
2619 .FromJust();
2620 if (depth == kTargetRecursionDepth) return;
2621 CHECK(args.This()
2622 ->Set(context, v8_str("depth"),
2623 v8::Integer::New(args.GetIsolate(), depth + 1))
2624 .FromJust());
2625 args.GetReturnValue().Set(
2626 call_recursively_script->Run(context).ToLocalChecked());
2627}
2628
2629
2630static void CallFunctionRecursivelyCall(
2631 const v8::FunctionCallbackInfo<v8::Value>& args) {
2632 ApiTestFuzzer::Fuzz();
2633 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
2634 int depth = args.This()
2635 ->Get(context, v8_str("depth"))
2636 .ToLocalChecked()
2637 ->Int32Value(context)
2638 .FromJust();
2639 if (depth == kTargetRecursionDepth) {
2640 printf("[depth = %d]\n", depth);
2641 return;
2642 }
2643 CHECK(args.This()
2644 ->Set(context, v8_str("depth"),
2645 v8::Integer::New(args.GetIsolate(), depth + 1))
2646 .FromJust());
2647 v8::Local<Value> function =
2648 args.This()
2649 ->Get(context, v8_str("callFunctionRecursively"))
2650 .ToLocalChecked();
2651 args.GetReturnValue().Set(function.As<Function>()
2652 ->Call(context, args.This(), 0, nullptr)
2653 .ToLocalChecked());
2654}
2655
2656
2657THREADED_TEST(DeepCrossLanguageRecursion) {
2658 v8::Isolate* isolate = CcTest::isolate();
2659 v8::HandleScope scope(isolate);
2660 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2661 global->Set(v8_str("callScriptRecursively"),
2662 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2663 global->Set(v8_str("callFunctionRecursively"),
2664 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2665 LocalContext env(nullptr, global);
2666
2667 CHECK(env->Global()
2668 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2669 .FromJust());
2670 call_recursively_script = v8_compile("callScriptRecursively()");
2671 call_recursively_script->Run(env.local()).ToLocalChecked();
2672 call_recursively_script = v8::Local<Script>();
2673
2674 CHECK(env->Global()
2675 ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
2676 .FromJust());
2677 CompileRun("callFunctionRecursively()");
2678}
2679
2680
2681static void ThrowingPropertyHandlerGet(
2682 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2683 // Since this interceptor is used on "with" objects, the runtime will look up
2684 // @@unscopables. Punt.
2685 if (key->IsSymbol()) return;
2686 ApiTestFuzzer::Fuzz();
2687 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2688}
2689
2690
2691static void ThrowingPropertyHandlerSet(
2692 Local<Name> key, Local<Value>,
2693 const v8::PropertyCallbackInfo<v8::Value>& info) {
2694 info.GetIsolate()->ThrowException(key);
2695 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2696}
2697
2698
2699THREADED_TEST(CallbackExceptionRegression) {
2700 v8::Isolate* isolate = CcTest::isolate();
2701 v8::HandleScope scope(isolate);
2702 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2703 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2704 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2705 LocalContext env;
2706 CHECK(env->Global()
2707 ->Set(env.local(), v8_str("obj"),
2708 obj->NewInstance(env.local()).ToLocalChecked())
2709 .FromJust());
2710 v8::Local<Value> otto =
2711 CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2712 CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
2713 v8::Local<Value> netto =
2714 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2715 CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
2716}
2717
2718
2719THREADED_TEST(FunctionPrototype) {
2720 v8::Isolate* isolate = CcTest::isolate();
2721 v8::HandleScope scope(isolate);
2722 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2723 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2724 LocalContext env;
2725 CHECK(env->Global()
2726 ->Set(env.local(), v8_str("Foo"),
2727 Foo->GetFunction(env.local()).ToLocalChecked())
2728 .FromJust());
2729 Local<Script> script = v8_compile("Foo.prototype.plak");
2730 CHECK_EQ(v8_run_int32value(script), 321);
2731}
2732
2733THREADED_TEST(InternalFields) {
2734 LocalContext env;
2735 v8::Isolate* isolate = env->GetIsolate();
2736 v8::HandleScope scope(isolate);
2737
2738 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2739 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2740 instance_templ->SetInternalFieldCount(1);
2741 Local<v8::Object> obj = templ->GetFunction(env.local())
2742 .ToLocalChecked()
2743 ->NewInstance(env.local())
2744 .ToLocalChecked();
2745 CHECK_EQ(1, obj->InternalFieldCount());
2746 CHECK(obj->GetInternalField(0)->IsUndefined());
2747 obj->SetInternalField(0, v8_num(17));
2748 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
2749}
2750
2751TEST(InternalFieldsSubclassing) {
2752 LocalContext env;
2753 v8::Isolate* isolate = env->GetIsolate();
2754 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2755 v8::HandleScope scope(isolate);
2756 for (int nof_embedder_fields = 0;
2757 nof_embedder_fields < i::JSObject::kMaxEmbedderFields;
2758 nof_embedder_fields++) {
2759 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2760 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2761 instance_templ->SetInternalFieldCount(nof_embedder_fields);
2762 Local<Function> constructor =
2763 templ->GetFunction(env.local()).ToLocalChecked();
2764 // Check that instances have the correct NOF properties.
2765 Local<v8::Object> obj =
2766 constructor->NewInstance(env.local()).ToLocalChecked();
2767
2768 i::Handle<i::JSObject> i_obj =
2769 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
2770 CHECK_EQ(nof_embedder_fields, obj->InternalFieldCount());
2771 CHECK_EQ(0, i_obj->map()->GetInObjectProperties());
2772 // Check writing and reading internal fields.
2773 for (int j = 0; j < nof_embedder_fields; j++) {
2774 CHECK(obj->GetInternalField(j)->IsUndefined());
2775 int value = 17 + j;
2776 obj->SetInternalField(j, v8_num(value));
2777 }
2778 for (int j = 0; j < nof_embedder_fields; j++) {
2779 int value = 17 + j;
2780 CHECK_EQ(value,
2781 obj->GetInternalField(j)->Int32Value(env.local()).FromJust());
2782 }
2783 CHECK(env->Global()
2784 ->Set(env.local(), v8_str("BaseClass"), constructor)
2785 .FromJust());
2786 // Create various levels of subclasses to stress instance size calculation.
2787 const int kMaxNofProperties =
2788 i::JSObject::kMaxInObjectProperties -
2789 nof_embedder_fields * i::kEmbedderDataSlotSizeInTaggedSlots;
2790 // Select only a few values to speed up the test.
2791 int sizes[] = {0,
2792 1,
2793 2,
2794 3,
2795 4,
2796 5,
2797 6,
2798 kMaxNofProperties / 4,
2799 kMaxNofProperties / 2,
2800 kMaxNofProperties - 2,
2801 kMaxNofProperties - 1,
2802 kMaxNofProperties + 1,
2803 kMaxNofProperties + 2,
2804 kMaxNofProperties * 2,
2805 kMaxNofProperties * 2};
2806 for (size_t i = 0; i < arraysize(sizes); i++) {
2807 int nof_properties = sizes[i];
2808 bool in_object_only = nof_properties <= kMaxNofProperties;
2809 std::ostringstream src;
2810 // Assembler source string for a subclass with {nof_properties}
2811 // in-object properties.
2812 src << "(function() {\n"
2813 << " class SubClass extends BaseClass {\n"
2814 << " constructor() {\n"
2815 << " super();\n";
2816 // Set {nof_properties} instance properties in the constructor.
2817 for (int j = 0; j < nof_properties; j++) {
2818 src << " this.property" << j << " = " << j << ";\n";
2819 }
2820 src << " }\n"
2821 << " };\n"
2822 << " let instance;\n"
2823 << " for (let i = 0; i < 3; i++) {\n"
2824 << " instance = new SubClass();\n"
2825 << " }"
2826 << " return instance;\n"
2827 << "})();";
2828 Local<v8::Object> value = CompileRun(src.str().c_str()).As<v8::Object>();
2829
2830 i::Handle<i::JSObject> i_value =
2831 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*value));
2832#ifdef VERIFY_HEAP
2833 i_value->HeapObjectVerify(i_isolate);
2834 i_value->map()->HeapObjectVerify(i_isolate);
2835 i_value->map()->FindRootMap(i_isolate)->HeapObjectVerify(i_isolate);
2836#endif
2837 CHECK_EQ(nof_embedder_fields, value->InternalFieldCount());
2838 if (in_object_only) {
2839 CHECK_LE(nof_properties, i_value->map()->GetInObjectProperties());
2840 } else {
2841 CHECK_LE(i_value->map()->GetInObjectProperties(), kMaxNofProperties);
2842 }
2843
2844 // Make Sure we get the precise property count.
2845 i_value->map()->FindRootMap(i_isolate)->CompleteInobjectSlackTracking(
2846 i_isolate);
2847 // TODO(cbruni): fix accounting to make this condition true.
2848 // CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
2849 if (in_object_only) {
2850 CHECK_EQ(nof_properties, i_value->map()->GetInObjectProperties());
2851 } else {
2852 CHECK_LE(i_value->map()->GetInObjectProperties(), kMaxNofProperties);
2853 }
2854 }
2855 }
2856}
2857
2858THREADED_TEST(InternalFieldsOfRegularObjects) {
2859 LocalContext env;
2860 v8::Isolate* isolate = env->GetIsolate();
2861 v8::HandleScope scope(isolate);
2862
2863 const char* sources[] = {"new Object()", "{ a: 'a property' }", "arguments"};
2864 for (size_t i = 0; i < arraysize(sources); ++i) {
2865 i::ScopedVector<char> source(128);
2866 i::SNPrintF(source, "(function() { return %s })()", sources[i]);
2867 v8::Local<v8::Object> obj = CompileRun(source.start()).As<v8::Object>();
2868 CHECK_EQ(0, obj->InternalFieldCount());
2869 }
2870}
2871
2872THREADED_TEST(GlobalObjectInternalFields) {
2873 v8::Isolate* isolate = CcTest::isolate();
2874 v8::HandleScope scope(isolate);
2875 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2876 global_template->SetInternalFieldCount(1);
2877 LocalContext env(nullptr, global_template);
2878 v8::Local<v8::Object> global_proxy = env->Global();
2879 v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2880 CHECK_EQ(1, global->InternalFieldCount());
2881 CHECK(global->GetInternalField(0)->IsUndefined());
2882 global->SetInternalField(0, v8_num(17));
2883 CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
2884}
2885
2886
2887THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2888 LocalContext env;
2889 v8::HandleScope scope(CcTest::isolate());
2890
2891 v8::Local<v8::Object> global = env->Global();
2892 CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
2893 CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
2894}
2895
2896static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
2897 void* value) {
2898 CHECK(HAS_SMI_TAG(reinterpret_cast<i::Address>(value)));
2899 obj->SetAlignedPointerInInternalField(0, value);
2900 CcTest::CollectAllGarbage();
2901 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2902}
2903
2904THREADED_TEST(InternalFieldsAlignedPointers) {
2905 LocalContext env;
2906 v8::Isolate* isolate = env->GetIsolate();
2907 v8::HandleScope scope(isolate);
2908
2909 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2910 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2911 instance_templ->SetInternalFieldCount(1);
2912 Local<v8::Object> obj = templ->GetFunction(env.local())
2913 .ToLocalChecked()
2914 ->NewInstance(env.local())
2915 .ToLocalChecked();
2916 CHECK_EQ(1, obj->InternalFieldCount());
2917
2918 CheckAlignedPointerInInternalField(obj, nullptr);
2919
2920 int* heap_allocated = new int[100];
2921 CheckAlignedPointerInInternalField(obj, heap_allocated);
2922 delete[] heap_allocated;
2923
2924 int stack_allocated[100];
2925 CheckAlignedPointerInInternalField(obj, stack_allocated);
2926
2927 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2928 CheckAlignedPointerInInternalField(obj, huge);
2929
2930 v8::Global<v8::Object> persistent(isolate, obj);
2931 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2932 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2933}
2934
2935THREADED_TEST(SetAlignedPointerInInternalFields) {
2936 LocalContext env;
2937 v8::Isolate* isolate = env->GetIsolate();
2938 v8::HandleScope scope(isolate);
2939
2940 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2941 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2942 instance_templ->SetInternalFieldCount(2);
2943 Local<v8::Object> obj = templ->GetFunction(env.local())
2944 .ToLocalChecked()
2945 ->NewInstance(env.local())
2946 .ToLocalChecked();
2947 CHECK_EQ(2, obj->InternalFieldCount());
2948
2949 int* heap_allocated_1 = new int[100];
2950 int* heap_allocated_2 = new int[100];
2951 int indices[] = {0, 1};
2952 void* values[] = {heap_allocated_1, heap_allocated_2};
2953
2954 obj->SetAlignedPointerInInternalFields(2, indices, values);
2955 CcTest::CollectAllGarbage();
2956 CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(0));
2957 CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(1));
2958
2959 indices[0] = 1;
2960 indices[1] = 0;
2961 obj->SetAlignedPointerInInternalFields(2, indices, values);
2962 CcTest::CollectAllGarbage();
2963 CHECK_EQ(heap_allocated_2, obj->GetAlignedPointerFromInternalField(0));
2964 CHECK_EQ(heap_allocated_1, obj->GetAlignedPointerFromInternalField(1));
2965
2966 delete[] heap_allocated_1;
2967 delete[] heap_allocated_2;
2968}
2969
2970static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2971 void* value) {
2972 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2973 (*env)->SetAlignedPointerInEmbedderData(index, value);
2974 CcTest::CollectAllGarbage();
2975 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2976}
2977
2978
2979static void* AlignedTestPointer(int i) {
2980 return reinterpret_cast<void*>(i * 1234);
2981}
2982
2983
2984THREADED_TEST(EmbedderDataAlignedPointers) {
2985 LocalContext env;
2986 v8::HandleScope scope(env->GetIsolate());
2987
2988 CheckAlignedPointerInEmbedderData(&env, 0, nullptr);
2989 CHECK_EQ(1, (*env)->GetNumberOfEmbedderDataFields());
2990
2991 int* heap_allocated = new int[100];
2992 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2993 CHECK_EQ(2, (*env)->GetNumberOfEmbedderDataFields());
2994 delete[] heap_allocated;
2995
2996 int stack_allocated[100];
2997 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2998 CHECK_EQ(3, (*env)->GetNumberOfEmbedderDataFields());
2999
3000 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
3001 CheckAlignedPointerInEmbedderData(&env, 3, huge);
3002 CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3003
3004 // Test growing of the embedder data's backing store.
3005 for (int i = 0; i < 100; i++) {
3006 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
3007 }
3008 CcTest::CollectAllGarbage();
3009 for (int i = 0; i < 100; i++) {
3010 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
3011 }
3012}
3013
3014static void CheckEmbedderData(LocalContext* env, int index,
3015 v8::Local<Value> data) {
3016 (*env)->SetEmbedderData(index, data);
3017 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
3018}
3019
3020
3021THREADED_TEST(EmbedderData) {
3022 LocalContext env;
3023 v8::Isolate* isolate = env->GetIsolate();
3024 v8::HandleScope scope(isolate);
3025
3026 CHECK_EQ(0, (*env)->GetNumberOfEmbedderDataFields());
3027 CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
3028 CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3029 CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
3030 CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3031 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
3032 CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3033 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
3034 CHECK_EQ(4, (*env)->GetNumberOfEmbedderDataFields());
3035 CheckEmbedderData(&env, 211, v8::Boolean::New(isolate, true));
3036 CHECK_EQ(212, (*env)->GetNumberOfEmbedderDataFields());
3037}
3038
3039
3040THREADED_TEST(IdentityHash) {
3041 LocalContext env;
3042 v8::Isolate* isolate = env->GetIsolate();
3043 v8::HandleScope scope(isolate);
3044
3045 // Ensure that the test starts with an fresh heap to test whether the hash
3046 // code is based on the address.
3047 CcTest::CollectAllGarbage();
3048 Local<v8::Object> obj = v8::Object::New(isolate);
3049 int hash = obj->GetIdentityHash();
3050 int hash1 = obj->GetIdentityHash();
3051 CHECK_EQ(hash, hash1);
3052 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
3053 // Since the identity hash is essentially a random number two consecutive
3054 // objects should not be assigned the same hash code. If the test below fails
3055 // the random number generator should be evaluated.
3056 CHECK_NE(hash, hash2);
3057 CcTest::CollectAllGarbage();
3058 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
3059 // Make sure that the identity hash is not based on the initial address of
3060 // the object alone. If the test below fails the random number generator
3061 // should be evaluated.
3062 CHECK_NE(hash, hash3);
3063 int hash4 = obj->GetIdentityHash();
3064 CHECK_EQ(hash, hash4);
3065
3066 // Check identity hashes behaviour in the presence of JS accessors.
3067 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
3068 {
3069 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
3070 Local<v8::Object> o1 = v8::Object::New(isolate);
3071 Local<v8::Object> o2 = v8::Object::New(isolate);
3072 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3073 }
3074 {
3075 CompileRun(
3076 "function cnst() { return 42; };\n"
3077 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3078 Local<v8::Object> o1 = v8::Object::New(isolate);
3079 Local<v8::Object> o2 = v8::Object::New(isolate);
3080 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3081 }
3082}
3083
3084
3085void GlobalProxyIdentityHash(bool set_in_js) {
3086 LocalContext env;
3087 v8::Isolate* isolate = env->GetIsolate();
3088 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
3089 v8::HandleScope scope(isolate);
3090 Local<Object> global_proxy = env->Global();
3091 i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
3092 CHECK(env->Global()
3093 ->Set(env.local(), v8_str("global"), global_proxy)
3094 .FromJust());
3095 int32_t hash1;
3096 if (set_in_js) {
3097 CompileRun("var m = new Set(); m.add(global);");
3098 i::Object original_hash = i_global_proxy->GetHash();
3099 CHECK(original_hash->IsSmi());
3100 hash1 = i::Smi::ToInt(original_hash);
3101 } else {
3102 hash1 = i_global_proxy->GetOrCreateHash(i_isolate)->value();
3103 }
3104 // Hash should be retained after being detached.
3105 env->DetachGlobal();
3106 int hash2 = global_proxy->GetIdentityHash();
3107 CHECK_EQ(hash1, hash2);
3108 {
3109 // Re-attach global proxy to a new context, hash should stay the same.
3110 LocalContext env2(nullptr, Local<ObjectTemplate>(), global_proxy);
3111 int hash3 = global_proxy->GetIdentityHash();
3112 CHECK_EQ(hash1, hash3);
3113 }
3114}
3115
3116
3117THREADED_TEST(GlobalProxyIdentityHash) {
3118 GlobalProxyIdentityHash(true);
3119 GlobalProxyIdentityHash(false);
3120}
3121
3122
3123TEST(SymbolIdentityHash) {
3124 LocalContext env;
3125 v8::Isolate* isolate = env->GetIsolate();
3126 v8::HandleScope scope(isolate);
3127
3128 {
3129 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3130 int hash = symbol->GetIdentityHash();
3131 int hash1 = symbol->GetIdentityHash();
3132 CHECK_EQ(hash, hash1);
3133 CcTest::CollectAllGarbage();
3134 int hash3 = symbol->GetIdentityHash();
3135 CHECK_EQ(hash, hash3);
3136 }
3137
3138 {
3139 v8::Local<v8::Symbol> js_symbol =
3140 CompileRun("Symbol('foo')").As<v8::Symbol>();
3141 int hash = js_symbol->GetIdentityHash();
3142 int hash1 = js_symbol->GetIdentityHash();
3143 CHECK_EQ(hash, hash1);
3144 CcTest::CollectAllGarbage();
3145 int hash3 = js_symbol->GetIdentityHash();
3146 CHECK_EQ(hash, hash3);
3147 }
3148}
3149
3150
3151TEST(StringIdentityHash) {
3152 LocalContext env;
3153 v8::Isolate* isolate = env->GetIsolate();
3154 v8::HandleScope scope(isolate);
3155
3156 Local<v8::String> str = v8_str("str1");
3157 int hash = str->GetIdentityHash();
3158 int hash1 = str->GetIdentityHash();
3159 CHECK_EQ(hash, hash1);
3160 CcTest::CollectAllGarbage();
3161 int hash3 = str->GetIdentityHash();
3162 CHECK_EQ(hash, hash3);
3163
3164 Local<v8::String> str2 = v8_str("str1");
3165 int hash4 = str2->GetIdentityHash();
3166 CHECK_EQ(hash, hash4);
3167}
3168
3169
3170THREADED_TEST(SymbolProperties) {
3171 LocalContext env;
3172 v8::Isolate* isolate = env->GetIsolate();
3173 v8::HandleScope scope(isolate);
3174
3175 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3176 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3177 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
3178 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
3179 v8::Local<v8::Symbol> sym4 = v8::Symbol::New(isolate, v8_str("native"));
3180
3181 CcTest::CollectAllGarbage();
3182
3183 // Check basic symbol functionality.
3184 CHECK(sym1->IsSymbol());
3185 CHECK(sym2->IsSymbol());
3186 CHECK(!obj->IsSymbol());
3187
3188 CHECK(sym1->Equals(env.local(), sym1).FromJust());
3189 CHECK(sym2->Equals(env.local(), sym2).FromJust());
3190 CHECK(!sym1->Equals(env.local(), sym2).FromJust());
3191 CHECK(!sym2->Equals(env.local(), sym1).FromJust());
3192 CHECK(sym1->StrictEquals(sym1));
3193 CHECK(sym2->StrictEquals(sym2));
3194 CHECK(!sym1->StrictEquals(sym2));
3195 CHECK(!sym2->StrictEquals(sym1));
3196
3197 CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
3198
3199 v8::Local<v8::Value> sym_val = sym2;
3200 CHECK(sym_val->IsSymbol());
3201 CHECK(sym_val->Equals(env.local(), sym2).FromJust());
3202 CHECK(sym_val->StrictEquals(sym2));
3203 CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
3204
3205 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3206 CHECK(sym_obj->IsSymbolObject());
3207 CHECK(!sym2->IsSymbolObject());
3208 CHECK(!obj->IsSymbolObject());
3209 CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
3210 CHECK(!sym_obj->StrictEquals(sym2));
3211 CHECK(v8::SymbolObject::Cast(*sym_obj)
3212 ->Equals(env.local(), sym_obj)
3213 .FromJust());
3214 CHECK(v8::SymbolObject::Cast(*sym_obj)
3215 ->ValueOf()
3216 ->Equals(env.local(), sym2)
3217 .FromJust());
3218
3219 // Make sure delete of a non-existent symbol property works.
3220 CHECK(obj->Delete(env.local(), sym1).FromJust());
3221 CHECK(!obj->Has(env.local(), sym1).FromJust());
3222
3223 CHECK(
3224 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
3225 CHECK(obj->Has(env.local(), sym1).FromJust());
3226 CHECK_EQ(1503, obj->Get(env.local(), sym1)
3227 .ToLocalChecked()
3228 ->Int32Value(env.local())
3229 .FromJust());
3230 CHECK(
3231 obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
3232 CHECK(obj->Has(env.local(), sym1).FromJust());
3233 CHECK_EQ(2002, obj->Get(env.local(), sym1)
3234 .ToLocalChecked()
3235 ->Int32Value(env.local())
3236 .FromJust());
3237 CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
3238
3239 CHECK_EQ(0u,
3240 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3241 unsigned num_props =
3242 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3243 CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
3244 .FromJust());
3245 CHECK_EQ(1u,
3246 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3247 CHECK_EQ(num_props + 1,
3248 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3249
3250 CcTest::CollectAllGarbage();
3251
3252 CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
3253 SymbolAccessorSetter)
3254 .FromJust());
3255 CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
3256 CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
3257 CHECK(obj->Get(env.local(), sym3)
3258 .ToLocalChecked()
3259 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3260 .FromJust());
3261 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3262 .ToLocalChecked()
3263 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3264 .FromJust());
3265
3266 CHECK(obj->SetNativeDataProperty(env.local(), sym4, SymbolAccessorGetter)
3267 .FromJust());
3268 CHECK(obj->Get(env.local(), sym4).ToLocalChecked()->IsUndefined());
3269 CHECK(obj->Set(env.local(), v8_str("accessor_native"),
3270 v8::Integer::New(isolate, 123))
3271 .FromJust());
3272 CHECK_EQ(123, obj->Get(env.local(), sym4)
3273 .ToLocalChecked()
3274 ->Int32Value(env.local())
3275 .FromJust());
3276 CHECK(obj->Set(env.local(), sym4, v8::Integer::New(isolate, 314)).FromJust());
3277 CHECK(obj->Get(env.local(), sym4)
3278 .ToLocalChecked()
3279 ->Equals(env.local(), v8::Integer::New(isolate, 314))
3280 .FromJust());
3281 CHECK(obj->Delete(env.local(), v8_str("accessor_native")).FromJust());
3282
3283 // Add another property and delete it afterwards to force the object in
3284 // slow case.
3285 CHECK(
3286 obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
3287 CHECK_EQ(2002, obj->Get(env.local(), sym1)
3288 .ToLocalChecked()
3289 ->Int32Value(env.local())
3290 .FromJust());
3291 CHECK_EQ(2008, obj->Get(env.local(), sym2)
3292 .ToLocalChecked()
3293 ->Int32Value(env.local())
3294 .FromJust());
3295 CHECK_EQ(2002, obj->Get(env.local(), sym1)
3296 .ToLocalChecked()
3297 ->Int32Value(env.local())
3298 .FromJust());
3299 CHECK_EQ(2u,
3300 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3301
3302 CHECK(obj->Has(env.local(), sym1).FromJust());
3303 CHECK(obj->Has(env.local(), sym2).FromJust());
3304 CHECK(obj->Has(env.local(), sym3).FromJust());
3305 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3306 CHECK(obj->Delete(env.local(), sym2).FromJust());
3307 CHECK(obj->Has(env.local(), sym1).FromJust());
3308 CHECK(!obj->Has(env.local(), sym2).FromJust());
3309 CHECK(obj->Has(env.local(), sym3).FromJust());
3310 CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
3311 CHECK_EQ(2002, obj->Get(env.local(), sym1)
3312 .ToLocalChecked()
3313 ->Int32Value(env.local())
3314 .FromJust());
3315 CHECK(obj->Get(env.local(), sym3)
3316 .ToLocalChecked()
3317 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3318 .FromJust());
3319 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3320 .ToLocalChecked()
3321 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3322 .FromJust());
3323 CHECK_EQ(2u,
3324 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3325
3326 // Symbol properties are inherited.
3327 v8::Local<v8::Object> child = v8::Object::New(isolate);
3328 CHECK(child->SetPrototype(env.local(), obj).FromJust());
3329 CHECK(child->Has(env.local(), sym1).FromJust());
3330 CHECK_EQ(2002, child->Get(env.local(), sym1)
3331 .ToLocalChecked()
3332 ->Int32Value(env.local())
3333 .FromJust());
3334 CHECK(obj->Get(env.local(), sym3)
3335 .ToLocalChecked()
3336 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3337 .FromJust());
3338 CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
3339 .ToLocalChecked()
3340 ->Equals(env.local(), v8::Integer::New(isolate, 42))
3341 .FromJust());
3342 CHECK_EQ(0u,
3343 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3344}
3345
3346
3347THREADED_TEST(SymbolTemplateProperties) {
3348 LocalContext env;
3349 v8::Isolate* isolate = env->GetIsolate();
3350 v8::HandleScope scope(isolate);
3351 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3352 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3353 CHECK(!name.IsEmpty());
3354 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3355 v8::Local<v8::Object> new_instance =
3356 foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
3357 CHECK(!new_instance.IsEmpty());
3358 CHECK(new_instance->Has(env.local(), name).FromJust());
3359}
3360
3361
3362THREADED_TEST(PrivatePropertiesOnProxies) {
3363 LocalContext env;
3364 v8::Isolate* isolate = env->GetIsolate();
3365 v8::HandleScope scope(isolate);
3366
3367 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
3368 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
3369
3370 v8::Local<v8::Proxy> proxy =
3371 v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
3372
3373 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3374 v8::Local<v8::Private> priv2 =
3375 v8::Private::New(isolate, v8_str("my-private"));
3376
3377 CcTest::CollectAllGarbage();
3378
3379 CHECK(priv2->Name()
3380 ->Equals(env.local(),
3381 v8::String::NewFromUtf8(isolate, "my-private",
3382 v8::NewStringType::kNormal)
3383 .ToLocalChecked())
3384 .FromJust());
3385
3386 // Make sure delete of a non-existent private symbol property works.
3387 proxy->DeletePrivate(env.local(), priv1).FromJust();
3388 CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
3389
3390 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3391 .FromJust());
3392 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3393 CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
3394 .ToLocalChecked()
3395 ->Int32Value(env.local())
3396 .FromJust());
3397 CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3398 .FromJust());
3399 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3400 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3401 .ToLocalChecked()
3402 ->Int32Value(env.local())
3403 .FromJust());
3404
3405 CHECK_EQ(0u,
3406 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3407 unsigned num_props =
3408 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3409 CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
3410 isolate, "bla", v8::NewStringType::kNormal)
3411 .ToLocalChecked(),
3412 v8::Integer::New(isolate, 20))
3413 .FromJust());
3414 CHECK_EQ(1u,
3415 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3416 CHECK_EQ(num_props + 1,
3417 proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3418
3419 CcTest::CollectAllGarbage();
3420
3421 // Add another property and delete it afterwards to force the object in
3422 // slow case.
3423 CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3424 .FromJust());
3425 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3426 .ToLocalChecked()
3427 ->Int32Value(env.local())
3428 .FromJust());
3429 CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
3430 .ToLocalChecked()
3431 ->Int32Value(env.local())
3432 .FromJust());
3433 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3434 .ToLocalChecked()
3435 ->Int32Value(env.local())
3436 .FromJust());
3437 CHECK_EQ(1u,
3438 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3439
3440 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3441 CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
3442 CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
3443 CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
3444 CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
3445 CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
3446 .ToLocalChecked()
3447 ->Int32Value(env.local())
3448 .FromJust());
3449 CHECK_EQ(1u,
3450 proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3451
3452 // Private properties are not inherited (for the time being).
3453 v8::Local<v8::Object> child = v8::Object::New(isolate);
3454 CHECK(child->SetPrototype(env.local(), proxy).FromJust());
3455 CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3456 CHECK_EQ(0u,
3457 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3458}
3459
3460
3461THREADED_TEST(PrivateProperties) {
3462 LocalContext env;
3463 v8::Isolate* isolate = env->GetIsolate();
3464 v8::HandleScope scope(isolate);
3465
3466 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3467 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3468 v8::Local<v8::Private> priv2 =
3469 v8::Private::New(isolate, v8_str("my-private"));
3470
3471 CcTest::CollectAllGarbage();
3472
3473 CHECK(priv2->Name()
3474 ->Equals(env.local(),
3475 v8::String::NewFromUtf8(isolate, "my-private",
3476 v8::NewStringType::kNormal)
3477 .ToLocalChecked())
3478 .FromJust());
3479
3480 // Make sure delete of a non-existent private symbol property works.
3481 obj->DeletePrivate(env.local(), priv1).FromJust();
3482 CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
3483
3484 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
3485 .FromJust());
3486 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3487 CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
3488 .ToLocalChecked()
3489 ->Int32Value(env.local())
3490 .FromJust());
3491 CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
3492 .FromJust());
3493 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3494 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3495 .ToLocalChecked()
3496 ->Int32Value(env.local())
3497 .FromJust());
3498
3499 CHECK_EQ(0u,
3500 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3501 unsigned num_props =
3502 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
3503 CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
3504 isolate, "bla", v8::NewStringType::kNormal)
3505 .ToLocalChecked(),
3506 v8::Integer::New(isolate, 20))
3507 .FromJust());
3508 CHECK_EQ(1u,
3509 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3510 CHECK_EQ(num_props + 1,
3511 obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
3512
3513 CcTest::CollectAllGarbage();
3514
3515 // Add another property and delete it afterwards to force the object in
3516 // slow case.
3517 CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
3518 .FromJust());
3519 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3520 .ToLocalChecked()
3521 ->Int32Value(env.local())
3522 .FromJust());
3523 CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
3524 .ToLocalChecked()
3525 ->Int32Value(env.local())
3526 .FromJust());
3527 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3528 .ToLocalChecked()
3529 ->Int32Value(env.local())
3530 .FromJust());
3531 CHECK_EQ(1u,
3532 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3533
3534 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3535 CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
3536 CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
3537 CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
3538 CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
3539 CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
3540 .ToLocalChecked()
3541 ->Int32Value(env.local())
3542 .FromJust());
3543 CHECK_EQ(1u,
3544 obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3545
3546 // Private properties are not inherited (for the time being).
3547 v8::Local<v8::Object> child = v8::Object::New(isolate);
3548 CHECK(child->SetPrototype(env.local(), obj).FromJust());
3549 CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
3550 CHECK_EQ(0u,
3551 child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
3552}
3553
3554
3555THREADED_TEST(GlobalSymbols) {
3556 LocalContext env;
3557 v8::Isolate* isolate = env->GetIsolate();
3558 v8::HandleScope scope(isolate);
3559
3560 v8::Local<String> name = v8_str("my-symbol");
3561 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3562 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3563 CHECK(glob2->SameValue(glob));
3564
3565 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3566 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3567 CHECK(glob_api2->SameValue(glob_api));
3568 CHECK(!glob_api->SameValue(glob));
3569
3570 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3571 CHECK(!sym->SameValue(glob));
3572
3573 CompileRun("var sym2 = Symbol.for('my-symbol')");
3574 v8::Local<Value> sym2 =
3575 env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
3576 CHECK(sym2->SameValue(glob));
3577 CHECK(!sym2->SameValue(glob_api));
3578}
3579
3580THREADED_TEST(GlobalSymbolsNoContext) {
3581 v8::Isolate* isolate = CcTest::isolate();
3582 v8::HandleScope scope(isolate);
3583
3584 v8::Local<String> name = v8_str("my-symbol");
3585 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3586 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3587 CHECK(glob2->SameValue(glob));
3588
3589 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3590 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3591 CHECK(glob_api2->SameValue(glob_api));
3592 CHECK(!glob_api->SameValue(glob));
3593}
3594
3595static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3596 const char* name) {
3597 LocalContext env;
3598 v8::Isolate* isolate = env->GetIsolate();
3599 v8::HandleScope scope(isolate);
3600
3601 v8::Local<v8::Symbol> symbol = getter(isolate);
3602 std::string script = std::string("var sym = ") + name;
3603 CompileRun(script.c_str());
3604 v8::Local<Value> value =
3605 env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
3606
3607 CHECK(!value.IsEmpty());
3608 CHECK(!symbol.IsEmpty());
3609 CHECK(value->SameValue(symbol));
3610}
3611
3612
3613THREADED_TEST(WellKnownSymbols) {
3614 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3615 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3616 CheckWellKnownSymbol(v8::Symbol::GetHasInstance, "Symbol.hasInstance");
3617 CheckWellKnownSymbol(v8::Symbol::GetIsConcatSpreadable,
3618 "Symbol.isConcatSpreadable");
3619 CheckWellKnownSymbol(v8::Symbol::GetMatch, "Symbol.match");
3620 CheckWellKnownSymbol(v8::Symbol::GetReplace, "Symbol.replace");
3621 CheckWellKnownSymbol(v8::Symbol::GetSearch, "Symbol.search");
3622 CheckWellKnownSymbol(v8::Symbol::GetSplit, "Symbol.split");
3623 CheckWellKnownSymbol(v8::Symbol::GetToPrimitive, "Symbol.toPrimitive");
3624 CheckWellKnownSymbol(v8::Symbol::GetToStringTag, "Symbol.toStringTag");
3625}
3626
3627
3628THREADED_TEST(GlobalPrivates) {
3629 i::FLAG_allow_natives_syntax = true;
3630 LocalContext env;
3631 v8::Isolate* isolate = env->GetIsolate();
3632 v8::HandleScope scope(isolate);
3633
3634 v8::Local<String> name = v8_str("my-private");
3635 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3636 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3637 CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
3638 .FromJust());
3639
3640 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3641 CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
3642
3643 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3644 CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
3645
3646 CompileRun("var intern = %CreatePrivateSymbol('my-private')");
3647 v8::Local<Value> intern =
3648 env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
3649 CHECK(!obj->Has(env.local(), intern).FromJust());
3650}
3651
3652
3653class ScopedArrayBufferContents {
3654 public:
3655 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
3656 : contents_(contents) {}
3657 ~ScopedArrayBufferContents() { free(contents_.AllocationBase()); }
3658 void* Data() const { return contents_.Data(); }
3659 size_t ByteLength() const { return contents_.ByteLength(); }
3660
3661 void* AllocationBase() const { return contents_.AllocationBase(); }
3662 size_t AllocationLength() const { return contents_.AllocationLength(); }
3663 v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3664 return contents_.AllocationMode();
3665 }
3666
3667 private:
3668 const v8::ArrayBuffer::Contents contents_;
3669};
3670
3671template <typename T>
3672static void CheckInternalFieldsAreZero(v8::Local<T> value) {
3673 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3674 for (int i = 0; i < value->InternalFieldCount(); i++) {
3675 CHECK_EQ(0, value->GetInternalField(i)
3676 ->Int32Value(CcTest::isolate()->GetCurrentContext())
3677 .FromJust());
3678 }
3679}
3680
3681
3682THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3683 LocalContext env;
3684 v8::Isolate* isolate = env->GetIsolate();
3685 v8::HandleScope handle_scope(isolate);
3686
3687 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3688 CheckInternalFieldsAreZero(ab);
3689 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3690 CHECK(!ab->IsExternal());
3691 CcTest::CollectAllGarbage();
3692
3693 ScopedArrayBufferContents ab_contents(ab->Externalize());
3694 CHECK(ab->IsExternal());
3695
3696 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3697 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3698 CHECK_NOT_NULL(data);
3699 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
3700
3701 v8::Local<v8::Value> result = CompileRun("ab.byteLength");
3702 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3703
3704 result = CompileRun(
3705 "var u8 = new Uint8Array(ab);"
3706 "u8[0] = 0xFF;"
3707 "u8[1] = 0xAA;"
3708 "u8.length");
3709 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
3710 CHECK_EQ(0xFF, data[0]);
3711 CHECK_EQ(0xAA, data[1]);
3712 data[0] = 0xCC;
3713 data[1] = 0x11;
3714 result = CompileRun("u8[0] + u8[1]");
3715 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3716}
3717
3718
3719THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3720 LocalContext env;
3721 v8::Isolate* isolate = env->GetIsolate();
3722 v8::HandleScope handle_scope(isolate);
3723
3724
3725 v8::Local<v8::Value> result = CompileRun(
3726 "var ab1 = new ArrayBuffer(2);"
3727 "var u8_a = new Uint8Array(ab1);"
3728 "u8_a[0] = 0xAA;"
3729 "u8_a[1] = 0xFF; u8_a.buffer");
3730 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3731 CheckInternalFieldsAreZero(ab1);
3732 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3733 CHECK(!ab1->IsExternal());
3734 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3735 CHECK(ab1->IsExternal());
3736
3737 result = CompileRun("ab1.byteLength");
3738 CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
3739 result = CompileRun("u8_a[0]");
3740 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
3741 result = CompileRun("u8_a[1]");
3742 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3743 result = CompileRun(
3744 "var u8_b = new Uint8Array(ab1);"
3745 "u8_b[0] = 0xBB;"
3746 "u8_a[0]");
3747 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
3748 result = CompileRun("u8_b[1]");
3749 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
3750
3751 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3752 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3753 CHECK_EQ(0xBB, ab1_data[0]);
3754 CHECK_EQ(0xFF, ab1_data[1]);
3755 ab1_data[0] = 0xCC;
3756 ab1_data[1] = 0x11;
3757 result = CompileRun("u8_a[0] + u8_a[1]");
3758 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3759}
3760
3761
3762THREADED_TEST(ArrayBuffer_External) {
3763 LocalContext env;
3764 v8::Isolate* isolate = env->GetIsolate();
3765 v8::HandleScope handle_scope(isolate);
3766
3767 i::ScopedVector<uint8_t> my_data(100);
3768 memset(my_data.start(), 0, 100);
3769 Local<v8::ArrayBuffer> ab3 =
3770 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3771 CheckInternalFieldsAreZero(ab3);
3772 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3773 CHECK(ab3->IsExternal());
3774
3775 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
3776
3777 v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
3778 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3779
3780 result = CompileRun(
3781 "var u8_b = new Uint8Array(ab3);"
3782 "u8_b[0] = 0xBB;"
3783 "u8_b[1] = 0xCC;"
3784 "u8_b.length");
3785 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
3786 CHECK_EQ(0xBB, my_data[0]);
3787 CHECK_EQ(0xCC, my_data[1]);
3788 my_data[0] = 0xCC;
3789 my_data[1] = 0x11;
3790 result = CompileRun("u8_b[0] + u8_b[1]");
3791 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
3792}
3793
3794THREADED_TEST(ArrayBuffer_DisableDetach) {
3795 LocalContext env;
3796 v8::Isolate* isolate = env->GetIsolate();
3797 v8::HandleScope handle_scope(isolate);
3798
3799 i::ScopedVector<uint8_t> my_data(100);
3800 memset(my_data.start(), 0, 100);
3801 Local<v8::ArrayBuffer> ab =
3802 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3803 CHECK(ab->IsDetachable());
3804
3805 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3806 buf->set_is_detachable(false);
3807
3808 CHECK(!ab->IsDetachable());
3809}
3810
3811static void CheckDataViewIsDetached(v8::Local<v8::DataView> dv) {
3812 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3813 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3814}
3815
3816static void CheckIsDetached(v8::Local<v8::TypedArray> ta) {
3817 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3818 CHECK_EQ(0, static_cast<int>(ta->Length()));
3819 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3820}
3821
3822static void CheckIsTypedArrayVarDetached(const char* name) {
3823 i::ScopedVector<char> source(1024);
3824 i::SNPrintF(source,
3825 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3826 name, name, name);
3827 CHECK(CompileRun(source.start())->IsTrue());
3828 v8::Local<v8::TypedArray> ta =
3829 v8::Local<v8::TypedArray>::Cast(CompileRun(name));
3830 CheckIsDetached(ta);
3831}
3832
3833template <typename TypedArray, int kElementSize>
3834static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
3835 int byteOffset, int length) {
3836 v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3837 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3838 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3839 CHECK_EQ(length, static_cast<int>(ta->Length()));
3840 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3841 return ta;
3842}
3843
3844THREADED_TEST(ArrayBuffer_DetachingApi) {
3845 LocalContext env;
3846 v8::Isolate* isolate = env->GetIsolate();
3847 v8::HandleScope handle_scope(isolate);
3848
3849 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3850
3851 v8::Local<v8::Uint8Array> u8a =
3852 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3853 v8::Local<v8::Uint8ClampedArray> u8c =
3854 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3855 v8::Local<v8::Int8Array> i8a =
3856 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3857
3858 v8::Local<v8::Uint16Array> u16a =
3859 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3860 v8::Local<v8::Int16Array> i16a =
3861 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3862
3863 v8::Local<v8::Uint32Array> u32a =
3864 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3865 v8::Local<v8::Int32Array> i32a =
3866 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3867
3868 v8::Local<v8::Float32Array> f32a =
3869 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3870 v8::Local<v8::Float64Array> f64a =
3871 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3872
3873 v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3874 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3875 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3876 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3877
3878 ScopedArrayBufferContents contents(buffer->Externalize());
3879 buffer->Detach();
3880 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3881 CheckIsDetached(u8a);
3882 CheckIsDetached(u8c);
3883 CheckIsDetached(i8a);
3884 CheckIsDetached(u16a);
3885 CheckIsDetached(i16a);
3886 CheckIsDetached(u32a);
3887 CheckIsDetached(i32a);
3888 CheckIsDetached(f32a);
3889 CheckIsDetached(f64a);
3890 CheckDataViewIsDetached(dv);
3891}
3892
3893THREADED_TEST(ArrayBuffer_DetachingScript) {
3894 LocalContext env;
3895 v8::Isolate* isolate = env->GetIsolate();
3896 v8::HandleScope handle_scope(isolate);
3897
3898 CompileRun(
3899 "var ab = new ArrayBuffer(1024);"
3900 "var u8a = new Uint8Array(ab, 1, 1023);"
3901 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3902 "var i8a = new Int8Array(ab, 1, 1023);"
3903 "var u16a = new Uint16Array(ab, 2, 511);"
3904 "var i16a = new Int16Array(ab, 2, 511);"
3905 "var u32a = new Uint32Array(ab, 4, 255);"
3906 "var i32a = new Int32Array(ab, 4, 255);"
3907 "var f32a = new Float32Array(ab, 4, 255);"
3908 "var f64a = new Float64Array(ab, 8, 127);"
3909 "var dv = new DataView(ab, 1, 1023);");
3910
3911 v8::Local<v8::ArrayBuffer> ab =
3912 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3913
3914 v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
3915
3916 ScopedArrayBufferContents contents(ab->Externalize());
3917 ab->Detach();
3918 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3919 CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
3920
3921 CheckIsTypedArrayVarDetached("u8a");
3922 CheckIsTypedArrayVarDetached("u8c");
3923 CheckIsTypedArrayVarDetached("i8a");
3924 CheckIsTypedArrayVarDetached("u16a");
3925 CheckIsTypedArrayVarDetached("i16a");
3926 CheckIsTypedArrayVarDetached("u32a");
3927 CheckIsTypedArrayVarDetached("i32a");
3928 CheckIsTypedArrayVarDetached("f32a");
3929 CheckIsTypedArrayVarDetached("f64a");
3930
3931 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3932 CheckDataViewIsDetached(dv);
3933}
3934
3935THREADED_TEST(ArrayBuffer_AllocationInformation) {
3936 LocalContext env;
3937 v8::Isolate* isolate = env->GetIsolate();
3938 v8::HandleScope handle_scope(isolate);
3939
3940 const size_t ab_size = 1024;
3941 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, ab_size);
3942 ScopedArrayBufferContents contents(ab->Externalize());
3943
3944 // Array buffers should have normal allocation mode.
3945 CHECK_EQ(contents.AllocationMode(),
3946 v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
3947 // The allocation must contain the buffer (normally they will be equal, but
3948 // this is not required by the contract).
3949 CHECK_NOT_NULL(contents.AllocationBase());
3950 const uintptr_t alloc =
3951 reinterpret_cast<uintptr_t>(contents.AllocationBase());
3952 const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
3953 CHECK_LE(alloc, data);
3954 CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
3955}
3956
3957THREADED_TEST(ArrayBuffer_ExternalizeEmpty) {
3958 LocalContext env;
3959 v8::Isolate* isolate = env->GetIsolate();
3960 v8::HandleScope handle_scope(isolate);
3961
3962 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 0);
3963 CheckInternalFieldsAreZero(ab);
3964 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3965 CHECK(!ab->IsExternal());
3966
3967 // Externalize the buffer (taking ownership of the backing store memory).
3968 ScopedArrayBufferContents ab_contents(ab->Externalize());
3969
3970 Local<v8::Uint8Array> u8a = v8::Uint8Array::New(ab, 0, 0);
3971 // Calling Buffer() will materialize the ArrayBuffer (transitioning it from
3972 // on-heap to off-heap if need be). This should not affect whether it is
3973 // marked as is_external or not.
3974 USE(u8a->Buffer());
3975
3976 CHECK(ab->IsExternal());
3977}
3978
3979class ScopedSharedArrayBufferContents {
3980 public:
3981 explicit ScopedSharedArrayBufferContents(
3982 const v8::SharedArrayBuffer::Contents& contents)
3983 : contents_(contents) {}
3984 ~ScopedSharedArrayBufferContents() { free(contents_.AllocationBase()); }
3985 void* Data() const { return contents_.Data(); }
3986 size_t ByteLength() const { return contents_.ByteLength(); }
3987
3988 void* AllocationBase() const { return contents_.AllocationBase(); }
3989 size_t AllocationLength() const { return contents_.AllocationLength(); }
3990 v8::ArrayBuffer::Allocator::AllocationMode AllocationMode() const {
3991 return contents_.AllocationMode();
3992 }
3993
3994 private:
3995 const v8::SharedArrayBuffer::Contents contents_;
3996};
3997
3998
3999THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
4000 i::FLAG_harmony_sharedarraybuffer = true;
4001 LocalContext env;
4002 v8::Isolate* isolate = env->GetIsolate();
4003 v8::HandleScope handle_scope(isolate);
4004
4005 Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
4006 CheckInternalFieldsAreZero(ab);
4007 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
4008 CHECK(!ab->IsExternal());
4009 CcTest::CollectAllGarbage();
4010
4011 ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
4012 CHECK(ab->IsExternal());
4013
4014 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
4015 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
4016 CHECK_NOT_NULL(data);
4017 CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
4018
4019 v8::Local<v8::Value> result = CompileRun("ab.byteLength");
4020 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4021
4022 result = CompileRun(
4023 "var u8 = new Uint8Array(ab);"
4024 "u8[0] = 0xFF;"
4025 "u8[1] = 0xAA;"
4026 "u8.length");
4027 CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
4028 CHECK_EQ(0xFF, data[0]);
4029 CHECK_EQ(0xAA, data[1]);
4030 data[0] = 0xCC;
4031 data[1] = 0x11;
4032 result = CompileRun("u8[0] + u8[1]");
4033 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4034}
4035
4036
4037THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
4038 i::FLAG_harmony_sharedarraybuffer = true;
4039 LocalContext env;
4040 v8::Isolate* isolate = env->GetIsolate();
4041 v8::HandleScope handle_scope(isolate);
4042
4043
4044 v8::Local<v8::Value> result = CompileRun(
4045 "var ab1 = new SharedArrayBuffer(2);"
4046 "var u8_a = new Uint8Array(ab1);"
4047 "u8_a[0] = 0xAA;"
4048 "u8_a[1] = 0xFF; u8_a.buffer");
4049 Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
4050 CheckInternalFieldsAreZero(ab1);
4051 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
4052 CHECK(!ab1->IsExternal());
4053 ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
4054 CHECK(ab1->IsExternal());
4055
4056 result = CompileRun("ab1.byteLength");
4057 CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
4058 result = CompileRun("u8_a[0]");
4059 CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
4060 result = CompileRun("u8_a[1]");
4061 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4062 result = CompileRun(
4063 "var u8_b = new Uint8Array(ab1);"
4064 "u8_b[0] = 0xBB;"
4065 "u8_a[0]");
4066 CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
4067 result = CompileRun("u8_b[1]");
4068 CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
4069
4070 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
4071 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
4072 CHECK_EQ(0xBB, ab1_data[0]);
4073 CHECK_EQ(0xFF, ab1_data[1]);
4074 ab1_data[0] = 0xCC;
4075 ab1_data[1] = 0x11;
4076 result = CompileRun("u8_a[0] + u8_a[1]");
4077 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4078}
4079
4080
4081THREADED_TEST(SharedArrayBuffer_External) {
4082 i::FLAG_harmony_sharedarraybuffer = true;
4083 LocalContext env;
4084 v8::Isolate* isolate = env->GetIsolate();
4085 v8::HandleScope handle_scope(isolate);
4086
4087 i::ScopedVector<uint8_t> my_data(100);
4088 memset(my_data.start(), 0, 100);
4089 Local<v8::SharedArrayBuffer> ab3 =
4090 v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
4091 CheckInternalFieldsAreZero(ab3);
4092 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
4093 CHECK(ab3->IsExternal());
4094
4095 CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
4096
4097 v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
4098 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4099
4100 result = CompileRun(
4101 "var u8_b = new Uint8Array(ab3);"
4102 "u8_b[0] = 0xBB;"
4103 "u8_b[1] = 0xCC;"
4104 "u8_b.length");
4105 CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
4106 CHECK_EQ(0xBB, my_data[0]);
4107 CHECK_EQ(0xCC, my_data[1]);
4108 my_data[0] = 0xCC;
4109 my_data[1] = 0x11;
4110 result = CompileRun("u8_b[0] + u8_b[1]");
4111 CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
4112}
4113
4114
4115THREADED_TEST(HiddenProperties) {
4116 LocalContext env;
4117 v8::Isolate* isolate = env->GetIsolate();
4118 v8::HandleScope scope(isolate);
4119
4120 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4121 v8::Local<v8::Private> key =
4122 v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
4123 v8::Local<v8::String> empty = v8_str("");
4124 v8::Local<v8::String> prop_name = v8_str("prop_name");
4125
4126 CcTest::CollectAllGarbage();
4127
4128 // Make sure delete of a non-existent hidden value works
4129 obj->DeletePrivate(env.local(), key).FromJust();
4130
4131 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
4132 .FromJust());
4133 CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
4134 .ToLocalChecked()
4135 ->Int32Value(env.local())
4136 .FromJust());
4137 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4138 .FromJust());
4139 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4140 .ToLocalChecked()
4141 ->Int32Value(env.local())
4142 .FromJust());
4143
4144 CcTest::CollectAllGarbage();
4145
4146 // Make sure we do not find the hidden property.
4147 CHECK(!obj->Has(env.local(), empty).FromJust());
4148 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4149 .ToLocalChecked()
4150 ->Int32Value(env.local())
4151 .FromJust());
4152 CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
4153 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4154 .ToLocalChecked()
4155 ->Int32Value(env.local())
4156 .FromJust());
4157 CHECK(
4158 obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
4159 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4160 .ToLocalChecked()
4161 ->Int32Value(env.local())
4162 .FromJust());
4163 CHECK_EQ(2003, obj->Get(env.local(), empty)
4164 .ToLocalChecked()
4165 ->Int32Value(env.local())
4166 .FromJust());
4167
4168 CcTest::CollectAllGarbage();
4169
4170 // Add another property and delete it afterwards to force the object in
4171 // slow case.
4172 CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
4173 .FromJust());
4174 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4175 .ToLocalChecked()
4176 ->Int32Value(env.local())
4177 .FromJust());
4178 CHECK_EQ(2008, obj->Get(env.local(), prop_name)
4179 .ToLocalChecked()
4180 ->Int32Value(env.local())
4181 .FromJust());
4182 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4183 .ToLocalChecked()
4184 ->Int32Value(env.local())
4185 .FromJust());
4186 CHECK(obj->Delete(env.local(), prop_name).FromJust());
4187 CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
4188 .ToLocalChecked()
4189 ->Int32Value(env.local())
4190 .FromJust());
4191
4192 CcTest::CollectAllGarbage();
4193
4194 CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
4195 .FromJust());
4196 CHECK(obj->DeletePrivate(env.local(), key).FromJust());
4197 CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4198}
4199
4200
4201THREADED_TEST(Regress97784) {
4202 // Regression test for crbug.com/97784
4203 // Messing with the Object.prototype should not have effect on
4204 // hidden properties.
4205 LocalContext env;
4206 v8::HandleScope scope(env->GetIsolate());
4207
4208 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
4209 v8::Local<v8::Private> key =
4210 v8::Private::New(env->GetIsolate(), v8_str("hidden"));
4211
4212 CompileRun(
4213 "set_called = false;"
4214 "Object.defineProperty("
4215 " Object.prototype,"
4216 " 'hidden',"
4217 " {get: function() { return 45; },"
4218 " set: function() { set_called = true; }})");
4219
4220 CHECK(!obj->HasPrivate(env.local(), key).FromJust());
4221 // Make sure that the getter and setter from Object.prototype is not invoked.
4222 // If it did we would have full access to the hidden properties in
4223 // the accessor.
4224 CHECK(
4225 obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
4226 .FromJust());
4227 ExpectFalse("set_called");
4228 CHECK_EQ(42, obj->GetPrivate(env.local(), key)
4229 .ToLocalChecked()
4230 ->Int32Value(env.local())
4231 .FromJust());
4232}
4233
4234
4235THREADED_TEST(External) {
4236 v8::HandleScope scope(CcTest::isolate());
4237 int x = 3;
4238 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
4239 LocalContext env;
4240 CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
4241 Local<Value> reext_obj = CompileRun("this.ext");
4242 v8::Local<v8::External> reext = reext_obj.As<v8::External>();
4243 int* ptr = static_cast<int*>(reext->Value());
4244 CHECK_EQ(3, x);
4245 *ptr = 10;
4246 CHECK_EQ(x, 10);
4247
4248 {
4249 i::Handle<i::Object> obj = v8::Utils::OpenHandle(*ext);
4250 CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4251 CHECK(ext->IsExternal());
4252 CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty());
4253 CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
4254 CHECK(ext->IsExternal());
4255 }
4256
4257 // Make sure unaligned pointers are wrapped properly.
4258 char* data = i::StrDup("0123456789");
4259 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
4260 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
4261 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
4262 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
4263
4264 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
4265 CHECK_EQ('0', *char_ptr);
4266 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
4267 CHECK_EQ('1', *char_ptr);
4268 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
4269 CHECK_EQ('2', *char_ptr);
4270 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
4271 CHECK_EQ('3', *char_ptr);
4272 i::DeleteArray(data);
4273}
4274
4275
4276THREADED_TEST(GlobalHandle) {
4277 v8::Isolate* isolate = CcTest::isolate();
4278 v8::Persistent<String> global;
4279 {
4280 v8::HandleScope scope(isolate);
4281 global.Reset(isolate, v8_str("str"));
4282 }
4283 {
4284 v8::HandleScope scope(isolate);
4285 CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4286 }
4287 global.Reset();
4288 {
4289 v8::HandleScope scope(isolate);
4290 global.Reset(isolate, v8_str("str"));
4291 }
4292 {
4293 v8::HandleScope scope(isolate);
4294 CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4295 }
4296 global.Reset();
4297}
4298
4299
4300THREADED_TEST(ResettingGlobalHandle) {
4301 v8::Isolate* isolate = CcTest::isolate();
4302 v8::Persistent<String> global;
4303 {
4304 v8::HandleScope scope(isolate);
4305 global.Reset(isolate, v8_str("str"));
4306 }
4307 v8::internal::GlobalHandles* global_handles =
4308 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4309 size_t initial_handle_count = global_handles->handles_count();
4310 {
4311 v8::HandleScope scope(isolate);
4312 CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4313 }
4314 {
4315 v8::HandleScope scope(isolate);
4316 global.Reset(isolate, v8_str("longer"));
4317 }
4318 CHECK_EQ(global_handles->handles_count(), initial_handle_count);
4319 {
4320 v8::HandleScope scope(isolate);
4321 CHECK_EQ(6, v8::Local<String>::New(isolate, global)->Length());
4322 }
4323 global.Reset();
4324 CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4325}
4326
4327
4328THREADED_TEST(ResettingGlobalHandleToEmpty) {
4329 v8::Isolate* isolate = CcTest::isolate();
4330 v8::Persistent<String> global;
4331 {
4332 v8::HandleScope scope(isolate);
4333 global.Reset(isolate, v8_str("str"));
4334 }
4335 v8::internal::GlobalHandles* global_handles =
4336 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4337 size_t initial_handle_count = global_handles->handles_count();
4338 {
4339 v8::HandleScope scope(isolate);
4340 CHECK_EQ(3, v8::Local<String>::New(isolate, global)->Length());
4341 }
4342 {
4343 v8::HandleScope scope(isolate);
4344 Local<String> empty;
4345 global.Reset(isolate, empty);
4346 }
4347 CHECK(global.IsEmpty());
4348 CHECK_EQ(global_handles->handles_count(), initial_handle_count - 1);
4349}
4350
4351
4352template <class T>
4353static v8::Global<T> PassUnique(v8::Global<T> unique) {
4354 return unique.Pass();
4355}
4356
4357
4358template <class T>
4359static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
4360 const v8::Persistent<T>& global) {
4361 v8::Global<String> unique(isolate, global);
4362 return unique.Pass();
4363}
4364
4365
4366THREADED_TEST(Global) {
4367 v8::Isolate* isolate = CcTest::isolate();
4368 v8::Persistent<String> global;
4369 {
4370 v8::HandleScope scope(isolate);
4371 global.Reset(isolate, v8_str("str"));
4372 }
4373 v8::internal::GlobalHandles* global_handles =
4374 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4375 size_t initial_handle_count = global_handles->handles_count();
4376 {
4377 v8::Global<String> unique(isolate, global);
4378 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4379 // Test assignment via Pass
4380 {
4381 v8::Global<String> copy = unique.Pass();
4382 CHECK(unique.IsEmpty());
4383 CHECK(copy == global);
4384 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4385 unique = copy.Pass();
4386 }
4387 // Test ctor via Pass
4388 {
4389 v8::Global<String> copy(unique.Pass());
4390 CHECK(unique.IsEmpty());
4391 CHECK(copy == global);
4392 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4393 unique = copy.Pass();
4394 }
4395 // Test pass through function call
4396 {
4397 v8::Global<String> copy = PassUnique(unique.Pass());
4398 CHECK(unique.IsEmpty());
4399 CHECK(copy == global);
4400 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4401 unique = copy.Pass();
4402 }
4403 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4404 }
4405 // Test pass from function call
4406 {
4407 v8::Global<String> unique = ReturnUnique(isolate, global);
4408 CHECK(unique == global);
4409 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4410 }
4411 CHECK_EQ(initial_handle_count, global_handles->handles_count());
4412 global.Reset();
4413}
4414
4415
4416namespace {
4417
4418class TwoPassCallbackData;
4419void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4420void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
4421
4422
4423class TwoPassCallbackData {
4424 public:
4425 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
4426 : first_pass_called_(false),
4427 second_pass_called_(false),
4428 trigger_gc_(false),
4429 instance_counter_(instance_counter) {
4430 HandleScope scope(isolate);
4431 i::ScopedVector<char> buffer(40);
4432 i::SNPrintF(buffer, "%p", static_cast<void*>(this));
4433 auto string =
4434 v8::String::NewFromUtf8(isolate, buffer.start(),
4435 v8::NewStringType::kNormal).ToLocalChecked();
4436 cell_.Reset(isolate, string);
4437 (*instance_counter_)++;
4438 }
4439
4440 ~TwoPassCallbackData() {
4441 CHECK(first_pass_called_);
4442 CHECK(second_pass_called_);
4443 CHECK(cell_.IsEmpty());
4444 (*instance_counter_)--;
4445 }
4446
4447 void FirstPass() {
4448 CHECK(!first_pass_called_);
4449 CHECK(!second_pass_called_);
4450 CHECK(!cell_.IsEmpty());
4451 cell_.Reset();
4452 first_pass_called_ = true;
4453 }
4454
4455 void SecondPass() {
4456 CHECK(first_pass_called_);
4457 CHECK(!second_pass_called_);
4458 CHECK(cell_.IsEmpty());
4459 second_pass_called_ = true;
4460 delete this;
4461 }
4462
4463 void SetWeak() {
4464 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
4465 }
4466
4467 void MarkTriggerGc() { trigger_gc_ = true; }
4468 bool trigger_gc() { return trigger_gc_; }
4469
4470 int* instance_counter() { return instance_counter_; }
4471
4472 private:
4473 bool first_pass_called_;
4474 bool second_pass_called_;
4475 bool trigger_gc_;
4476 v8::Global<v8::String> cell_;
4477 int* instance_counter_;
4478};
4479
4480
4481void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4482 ApiTestFuzzer::Fuzz();
4483 bool trigger_gc = data.GetParameter()->trigger_gc();
4484 int* instance_counter = data.GetParameter()->instance_counter();
4485 data.GetParameter()->SecondPass();
4486 if (!trigger_gc) return;
4487 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
4488 data_2->SetWeak();
4489 CcTest::CollectAllGarbage();
4490}
4491
4492
4493void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
4494 data.GetParameter()->FirstPass();
4495 data.SetSecondPassCallback(SecondPassCallback);
4496}
4497
4498} // namespace
4499
4500
4501TEST(TwoPassPhantomCallbacks) {
4502 auto isolate = CcTest::isolate();
4503 const size_t kLength = 20;
4504 int instance_counter = 0;
4505 for (size_t i = 0; i < kLength; ++i) {
4506 auto data = new TwoPassCallbackData(isolate, &instance_counter);
4507 data->SetWeak();
4508 }
4509 CHECK_EQ(static_cast<int>(kLength), instance_counter);
4510 CcTest::CollectAllGarbage();
4511 EmptyMessageQueues(isolate);
4512 CHECK_EQ(0, instance_counter);
4513}
4514
4515
4516TEST(TwoPassPhantomCallbacksNestedGc) {
4517 auto isolate = CcTest::isolate();
4518 const size_t kLength = 20;
4519 TwoPassCallbackData* array[kLength];
4520 int instance_counter = 0;
4521 for (size_t i = 0; i < kLength; ++i) {
4522 array[i] = new TwoPassCallbackData(isolate, &instance_counter);
4523 array[i]->SetWeak();
4524 }
4525 array[5]->MarkTriggerGc();
4526 array[10]->MarkTriggerGc();
4527 array[15]->MarkTriggerGc();
4528 CHECK_EQ(static_cast<int>(kLength), instance_counter);
4529 CcTest::CollectAllGarbage();
4530 EmptyMessageQueues(isolate);
4531 CHECK_EQ(0, instance_counter);
4532}
4533
4534
4535namespace {
4536
4537void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
4538
4539
4540Local<v8::Object> NewObjectForIntKey(
4541 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
4542 int key) {
4543 auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
4544 auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
4545 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
4546 return obj;
4547}
4548
4549
4550template <typename K, typename V>
4551class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
4552 public:
4553 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
4554 static const v8::PersistentContainerCallbackType kCallbackType =
4555 v8::kWeakWithInternalFields;
4556 struct WeakCallbackDataType {
4557 MapType* map;
4558 K key;
4559 };
4560 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
4561 Local<V> value) {
4562 WeakCallbackDataType* data = new WeakCallbackDataType;
4563 data->map = map;
4564 data->key = key;
4565 return data;
4566 }
4567 static MapType* MapFromWeakCallbackInfo(
4568 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4569 return data.GetParameter()->map;
4570 }
4571 static K KeyFromWeakCallbackInfo(
4572 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
4573 return data.GetParameter()->key;
4574 }
4575 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
4576 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
4577 CHECK_EQ(IntKeyToVoidPointer(key),
4578 v8::Object::GetAlignedPointerFromInternalField(value, 0));
4579 }
4580 static void OnWeakCallback(
4581 const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
4582 static void DisposeWeak(
4583 const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
4584 K key = KeyFromWeakCallbackInfo(info);
4585 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
4586 DisposeCallbackData(info.GetParameter());
4587 }
4588};
4589
4590
4591template <typename Map>
4592void TestGlobalValueMap() {
4593 LocalContext env;
4594 v8::Isolate* isolate = env->GetIsolate();
4595 v8::Global<ObjectTemplate> templ;
4596 {
4597 HandleScope scope(isolate);
4598 auto t = ObjectTemplate::New(isolate);
4599 t->SetInternalFieldCount(1);
4600 templ.Reset(isolate, t);
4601 }
4602 Map map(isolate);
4603 v8::internal::GlobalHandles* global_handles =
4604 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4605 size_t initial_handle_count = global_handles->handles_count();
4606 CHECK_EQ(0, static_cast<int>(map.Size()));
4607 {
4608 HandleScope scope(isolate);
4609 Local<v8::Object> obj = map.Get(7);
4610 CHECK(obj.IsEmpty());
4611 Local<v8::Object> expected = v8::Object::New(isolate);
4612 map.Set(7, expected);
4613 CHECK_EQ(1, static_cast<int>(map.Size()));
4614 obj = map.Get(7);
4615 CHECK(expected->Equals(env.local(), obj).FromJust());
4616 {
4617 typename Map::PersistentValueReference ref = map.GetReference(7);
4618 CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4619 }
4620 v8::Global<v8::Object> removed = map.Remove(7);
4621 CHECK_EQ(0, static_cast<int>(map.Size()));
4622 CHECK(expected == removed);
4623 removed = map.Remove(7);
4624 CHECK(removed.IsEmpty());
4625 map.Set(8, expected);
4626 CHECK_EQ(1, static_cast<int>(map.Size()));
4627 map.Set(8, expected);
4628 CHECK_EQ(1, static_cast<int>(map.Size()));
4629 {
4630 typename Map::PersistentValueReference ref;
4631 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
4632 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
4633 CHECK_EQ(1, static_cast<int>(map.Size()));
4634 CHECK(expected == removed);
4635 CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
4636 }
4637 }
4638 CHECK_EQ(initial_handle_count + 1, global_handles->handles_count());
4639 if (map.IsWeak()) {
4640 CcTest::PreciseCollectAllGarbage();
4641 } else {
4642 map.Clear();
4643 }
4644 CHECK_EQ(0, static_cast<int>(map.Size()));
4645 CHECK_EQ(initial_handle_count, global_handles->handles_count());
4646 {
4647 HandleScope scope(isolate);
4648 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
4649 map.Set(9, value);
4650 map.Clear();
4651 }
4652 CHECK_EQ(0, static_cast<int>(map.Size()));
4653 CHECK_EQ(initial_handle_count, global_handles->handles_count());
4654}
4655
4656} // namespace
4657
4658
4659TEST(GlobalValueMap) {
4660 // Default case, w/o weak callbacks:
4661 TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
4662
4663 // Custom traits with weak callbacks:
4664 typedef v8::GlobalValueMap<int, v8::Object,
4665 PhantomStdMapTraits<int, v8::Object>> WeakMap;
4666 TestGlobalValueMap<WeakMap>();
4667}
4668
4669
4670TEST(PersistentValueVector) {
4671 LocalContext env;
4672 v8::Isolate* isolate = env->GetIsolate();
4673 v8::internal::GlobalHandles* global_handles =
4674 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4675 size_t handle_count = global_handles->handles_count();
4676 HandleScope scope(isolate);
4677
4678 v8::PersistentValueVector<v8::Object> vector(isolate);
4679
4680 Local<v8::Object> obj1 = v8::Object::New(isolate);
4681 Local<v8::Object> obj2 = v8::Object::New(isolate);
4682 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
4683
4684 CHECK(vector.IsEmpty());
4685 CHECK_EQ(0, static_cast<int>(vector.Size()));
4686
4687 vector.ReserveCapacity(3);
4688 CHECK(vector.IsEmpty());
4689
4690 vector.Append(obj1);
4691 vector.Append(obj2);
4692 vector.Append(obj1);
4693 vector.Append(obj3.Pass());
4694 vector.Append(obj1);
4695
4696 CHECK(!vector.IsEmpty());
4697 CHECK_EQ(5, static_cast<int>(vector.Size()));
4698 CHECK(obj3.IsEmpty());
4699 CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
4700 CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
4701 CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
4702 CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
4703
4704 CHECK_EQ(5 + handle_count, global_handles->handles_count());
4705
4706 vector.Clear();
4707 CHECK(vector.IsEmpty());
4708 CHECK_EQ(0, static_cast<int>(vector.Size()));
4709 CHECK_EQ(handle_count, global_handles->handles_count());
4710}
4711
4712
4713THREADED_TEST(GlobalHandleUpcast) {
4714 v8::Isolate* isolate = CcTest::isolate();
4715 v8::HandleScope scope(isolate);
4716 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4717 v8::Persistent<String> global_string(isolate, local);
4718 v8::Persistent<Value>& global_value =
4719 v8::Persistent<Value>::Cast(global_string);
4720 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4721 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4722 global_string.Reset();
4723}
4724
4725
4726THREADED_TEST(HandleEquality) {
4727 v8::Isolate* isolate = CcTest::isolate();
4728 v8::Persistent<String> global1;
4729 v8::Persistent<String> global2;
4730 {
4731 v8::HandleScope scope(isolate);
4732 global1.Reset(isolate, v8_str("str"));
4733 global2.Reset(isolate, v8_str("str2"));
4734 }
4735 CHECK(global1 == global1);
4736 CHECK(!(global1 != global1));
4737 {
4738 v8::HandleScope scope(isolate);
4739 Local<String> local1 = Local<String>::New(isolate, global1);
4740 Local<String> local2 = Local<String>::New(isolate, global2);
4741
4742 CHECK(global1 == local1);
4743 CHECK(!(global1 != local1));
4744 CHECK(local1 == global1);
4745 CHECK(!(local1 != global1));
4746
4747 CHECK(!(global1 == local2));
4748 CHECK(global1 != local2);
4749 CHECK(!(local2 == global1));
4750 CHECK(local2 != global1);
4751
4752 CHECK(!(local1 == local2));
4753 CHECK(local1 != local2);
4754
4755 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4756 CHECK(local1 == anotherLocal1);
4757 CHECK(!(local1 != anotherLocal1));
4758 }
4759 global1.Reset();
4760 global2.Reset();
4761}
4762
4763
4764THREADED_TEST(LocalHandle) {
4765 v8::HandleScope scope(CcTest::isolate());
4766 v8::Local<String> local =
4767 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4768 CHECK_EQ(3, local->Length());
4769}
4770
4771
4772class WeakCallCounter {
4773 public:
4774 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
4775 int id() { return id_; }
4776 void increment() { number_of_weak_calls_++; }
4777 int NumberOfWeakCalls() { return number_of_weak_calls_; }
4778
4779 private:
4780 int id_;
4781 int number_of_weak_calls_;
4782};
4783
4784
4785template <typename T>
4786struct WeakCallCounterAndPersistent {
4787 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4788 : counter(counter) {}
4789 WeakCallCounter* counter;
4790 v8::Persistent<T> handle;
4791};
4792
4793
4794template <typename T>
4795static void WeakPointerCallback(
4796 const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
4797 CHECK_EQ(1234, data.GetParameter()->counter->id());
4798 data.GetParameter()->counter->increment();
4799 data.GetParameter()->handle.Reset();
4800}
4801
4802THREADED_TEST(ScriptException) {
4803 LocalContext env;
4804 v8::HandleScope scope(env->GetIsolate());
4805 Local<Script> script = v8_compile("throw 'panama!';");
4806 v8::TryCatch try_catch(env->GetIsolate());
4807 v8::MaybeLocal<Value> result = script->Run(env.local());
4808 CHECK(result.IsEmpty());
4809 CHECK(try_catch.HasCaught());
4810 String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
4811 CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4812}
4813
4814
4815TEST(TryCatchCustomException) {
4816 LocalContext env;
4817 v8::Isolate* isolate = env->GetIsolate();
4818 v8::HandleScope scope(isolate);
4819 v8::TryCatch try_catch(isolate);
4820 CompileRun(
4821 "function CustomError() { this.a = 'b'; }"
4822 "(function f() { throw new CustomError(); })();");
4823 CHECK(try_catch.HasCaught());
4824 CHECK(try_catch.Exception()
4825 ->ToObject(env.local())
4826 .ToLocalChecked()
4827 ->Get(env.local(), v8_str("a"))
4828 .ToLocalChecked()
4829 ->Equals(env.local(), v8_str("b"))
4830 .FromJust());
4831}
4832
4833
4834bool message_received;
4835
4836
4837static void check_message_0(v8::Local<v8::Message> message,
4838 v8::Local<Value> data) {
4839 CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
4840 .FromJust());
4841 CHECK_EQ(6.75, message->GetScriptOrigin()
4842 .ResourceName()
4843 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4844 .FromJust());
4845 CHECK(!message->IsSharedCrossOrigin());
4846 message_received = true;
4847}
4848
4849
4850THREADED_TEST(MessageHandler0) {
4851 message_received = false;
4852 v8::HandleScope scope(CcTest::isolate());
4853 CHECK(!message_received);
4854 LocalContext context;
4855 CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
4856 v8::Local<v8::Script> script =
4857 CompileWithOrigin("throw 'error'", "6.75", false);
4858 CHECK(script->Run(context.local()).IsEmpty());
4859 CHECK(message_received);
4860 // clear out the message listener
4861 CcTest::isolate()->RemoveMessageListeners(check_message_0);
4862}
4863
4864
4865static void check_message_1(v8::Local<v8::Message> message,
4866 v8::Local<Value> data) {
4867 CHECK(data->IsNumber());
4868 CHECK_EQ(1337,
4869 data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
4870 CHECK(!message->IsSharedCrossOrigin());
4871 message_received = true;
4872}
4873
4874
4875TEST(MessageHandler1) {
4876 message_received = false;
4877 v8::HandleScope scope(CcTest::isolate());
4878 CHECK(!message_received);
4879 CcTest::isolate()->AddMessageListener(check_message_1);
4880 LocalContext context;
4881 CompileRun("throw 1337;");
4882 CHECK(message_received);
4883 // clear out the message listener
4884 CcTest::isolate()->RemoveMessageListeners(check_message_1);
4885}
4886
4887
4888static void check_message_2(v8::Local<v8::Message> message,
4889 v8::Local<Value> data) {
4890 LocalContext context;
4891 CHECK(data->IsObject());
4892 v8::Local<v8::Value> hidden_property =
4893 v8::Object::Cast(*data)
4894 ->GetPrivate(
4895 context.local(),
4896 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
4897 .ToLocalChecked();
4898 CHECK(v8_str("hidden value")
4899 ->Equals(context.local(), hidden_property)
4900 .FromJust());
4901 CHECK(!message->IsSharedCrossOrigin());
4902 message_received = true;
4903}
4904
4905
4906TEST(MessageHandler2) {
4907 message_received = false;
4908 v8::HandleScope scope(CcTest::isolate());
4909 CHECK(!message_received);
4910 CcTest::isolate()->AddMessageListener(check_message_2);
4911 LocalContext context;
4912 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4913 v8::Object::Cast(*error)
4914 ->SetPrivate(context.local(),
4915 v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
4916 v8_str("hidden value"))
4917 .FromJust();
4918 CHECK(context->Global()
4919 ->Set(context.local(), v8_str("error"), error)
4920 .FromJust());
4921 CompileRun("throw error;");
4922 CHECK(message_received);
4923 // clear out the message listener
4924 CcTest::isolate()->RemoveMessageListeners(check_message_2);
4925}
4926
4927
4928static void check_message_3(v8::Local<v8::Message> message,
4929 v8::Local<Value> data) {
4930 CHECK(message->IsSharedCrossOrigin());
4931 CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4932 CHECK(message->GetScriptOrigin().Options().IsOpaque());
4933 CHECK_EQ(6.75, message->GetScriptOrigin()
4934 .ResourceName()
4935 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4936 .FromJust());
4937 CHECK_EQ(7.40, message->GetScriptOrigin()
4938 .SourceMapUrl()
4939 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4940 .FromJust());
4941 message_received = true;
4942}
4943
4944
4945TEST(MessageHandler3) {
4946 message_received = false;
4947 v8::Isolate* isolate = CcTest::isolate();
4948 v8::HandleScope scope(isolate);
4949 CHECK(!message_received);
4950 isolate->AddMessageListener(check_message_3);
4951 LocalContext context;
4952 v8::ScriptOrigin origin =
4953 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4954 v8::Integer::New(isolate, 2), v8::True(isolate),
4955 Local<v8::Integer>(), v8_str("7.40"), v8::True(isolate));
4956 v8::Local<v8::Script> script =
4957 Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4958 .ToLocalChecked();
4959 CHECK(script->Run(context.local()).IsEmpty());
4960 CHECK(message_received);
4961 // clear out the message listener
4962 isolate->RemoveMessageListeners(check_message_3);
4963}
4964
4965
4966static void check_message_4(v8::Local<v8::Message> message,
4967 v8::Local<Value> data) {
4968 CHECK(!message->IsSharedCrossOrigin());
4969 CHECK_EQ(6.75, message->GetScriptOrigin()
4970 .ResourceName()
4971 ->NumberValue(CcTest::isolate()->GetCurrentContext())
4972 .FromJust());
4973 message_received = true;
4974}
4975
4976
4977TEST(MessageHandler4) {
4978 message_received = false;
4979 v8::Isolate* isolate = CcTest::isolate();
4980 v8::HandleScope scope(isolate);
4981 CHECK(!message_received);
4982 isolate->AddMessageListener(check_message_4);
4983 LocalContext context;
4984 v8::ScriptOrigin origin =
4985 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4986 v8::Integer::New(isolate, 2), v8::False(isolate));
4987 v8::Local<v8::Script> script =
4988 Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
4989 .ToLocalChecked();
4990 CHECK(script->Run(context.local()).IsEmpty());
4991 CHECK(message_received);
4992 // clear out the message listener
4993 isolate->RemoveMessageListeners(check_message_4);
4994}
4995
4996
4997static void check_message_5a(v8::Local<v8::Message> message,
4998 v8::Local<Value> data) {
4999 CHECK(message->IsSharedCrossOrigin());
5000 CHECK_EQ(6.75, message->GetScriptOrigin()
5001 .ResourceName()
5002 ->NumberValue(CcTest::isolate()->GetCurrentContext())
5003 .FromJust());
5004 message_received = true;
5005}
5006
5007
5008static void check_message_5b(v8::Local<v8::Message> message,
5009 v8::Local<Value> data) {
5010 CHECK(!message->IsSharedCrossOrigin());
5011 CHECK_EQ(6.75, message->GetScriptOrigin()
5012 .ResourceName()
5013 ->NumberValue(CcTest::isolate()->GetCurrentContext())
5014 .FromJust());
5015 message_received = true;
5016}
5017
5018
5019TEST(MessageHandler5) {
5020 message_received = false;
5021 v8::Isolate* isolate = CcTest::isolate();
5022 v8::HandleScope scope(isolate);
5023 CHECK(!message_received);
5024 isolate->AddMessageListener(check_message_5a);
5025 LocalContext context;
5026 v8::ScriptOrigin origin1 =
5027 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5028 v8::Integer::New(isolate, 2), v8::True(isolate));
5029 v8::Local<v8::Script> script =
5030 Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
5031 .ToLocalChecked();
5032 CHECK(script->Run(context.local()).IsEmpty());
5033 CHECK(message_received);
5034 // clear out the message listener
5035 isolate->RemoveMessageListeners(check_message_5a);
5036
5037 message_received = false;
5038 isolate->AddMessageListener(check_message_5b);
5039 v8::ScriptOrigin origin2 =
5040 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
5041 v8::Integer::New(isolate, 2), v8::False(isolate));
5042 script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
5043 .ToLocalChecked();
5044 CHECK(script->Run(context.local()).IsEmpty());
5045 CHECK(message_received);
5046 // clear out the message listener
5047 isolate->RemoveMessageListeners(check_message_5b);
5048}
5049
5050
5051THREADED_TEST(GetSetProperty) {
5052 LocalContext context;
5053 v8::Isolate* isolate = context->GetIsolate();
5054 v8::HandleScope scope(isolate);
5055 CHECK(context->Global()
5056 ->Set(context.local(), v8_str("foo"), v8_num(14))
5057 .FromJust());
5058 CHECK(context->Global()
5059 ->Set(context.local(), v8_str("12"), v8_num(92))
5060 .FromJust());
5061 CHECK(context->Global()
5062 ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
5063 .FromJust());
5064 CHECK(context->Global()
5065 ->Set(context.local(), v8_num(13), v8_num(56))
5066 .FromJust());
5067 Local<Value> foo = CompileRun("this.foo");
5068 CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
5069 Local<Value> twelve = CompileRun("this[12]");
5070 CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
5071 Local<Value> sixteen = CompileRun("this[16]");
5072 CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
5073 Local<Value> thirteen = CompileRun("this[13]");
5074 CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
5075 CHECK_EQ(92, context->Global()
5076 ->Get(context.local(), v8::Integer::New(isolate, 12))
5077 .ToLocalChecked()
5078 ->Int32Value(context.local())
5079 .FromJust());
5080 CHECK_EQ(92, context->Global()
5081 ->Get(context.local(), v8_str("12"))
5082 .ToLocalChecked()
5083 ->Int32Value(context.local())
5084 .FromJust());
5085 CHECK_EQ(92, context->Global()
5086 ->Get(context.local(), v8_num(12))
5087 .ToLocalChecked()
5088 ->Int32Value(context.local())
5089 .FromJust());
5090 CHECK_EQ(32, context->Global()
5091 ->Get(context.local(), v8::Integer::New(isolate, 16))
5092 .ToLocalChecked()
5093 ->Int32Value(context.local())
5094 .FromJust());
5095 CHECK_EQ(32, context->Global()
5096 ->Get(context.local(), v8_str("16"))
5097 .ToLocalChecked()
5098 ->Int32Value(context.local())
5099 .FromJust());
5100 CHECK_EQ(32, context->Global()
5101 ->Get(context.local(), v8_num(16))
5102 .ToLocalChecked()
5103 ->Int32Value(context.local())
5104 .FromJust());
5105 CHECK_EQ(56, context->Global()
5106 ->Get(context.local(), v8::Integer::New(isolate, 13))
5107 .ToLocalChecked()
5108 ->Int32Value(context.local())
5109 .FromJust());
5110 CHECK_EQ(56, context->Global()
5111 ->Get(context.local(), v8_str("13"))
5112 .ToLocalChecked()
5113 ->Int32Value(context.local())
5114 .FromJust());
5115 CHECK_EQ(56, context->Global()
5116 ->Get(context.local(), v8_num(13))
5117 .ToLocalChecked()
5118 ->Int32Value(context.local())
5119 .FromJust());
5120}
5121
5122
5123THREADED_TEST(PropertyAttributes) {
5124 LocalContext context;
5125 v8::HandleScope scope(context->GetIsolate());
5126 // none
5127 Local<String> prop = v8_str("none");
5128 CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
5129 CHECK_EQ(v8::None, context->Global()
5130 ->GetPropertyAttributes(context.local(), prop)
5131 .FromJust());
5132 // read-only
5133 prop = v8_str("read_only");
5134 context->Global()
5135 ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
5136 .FromJust();
5137 CHECK_EQ(7, context->Global()
5138 ->Get(context.local(), prop)
5139 .ToLocalChecked()
5140 ->Int32Value(context.local())
5141 .FromJust());
5142 CHECK_EQ(v8::ReadOnly, context->Global()
5143 ->GetPropertyAttributes(context.local(), prop)
5144 .FromJust());
5145 CompileRun("read_only = 9");
5146 CHECK_EQ(7, context->Global()
5147 ->Get(context.local(), prop)
5148 .ToLocalChecked()
5149 ->Int32Value(context.local())
5150 .FromJust());
5151 CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
5152 CHECK_EQ(7, context->Global()
5153 ->Get(context.local(), prop)
5154 .ToLocalChecked()
5155 ->Int32Value(context.local())
5156 .FromJust());
5157 // dont-delete
5158 prop = v8_str("dont_delete");
5159 context->Global()
5160 ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
5161 .FromJust();
5162 CHECK_EQ(13, context->Global()
5163 ->Get(context.local(), prop)
5164 .ToLocalChecked()
5165 ->Int32Value(context.local())
5166 .FromJust());
5167 CompileRun("delete dont_delete");
5168 CHECK_EQ(13, context->Global()
5169 ->Get(context.local(), prop)
5170 .ToLocalChecked()
5171 ->Int32Value(context.local())
5172 .FromJust());
5173 CHECK_EQ(v8::DontDelete, context->Global()
5174 ->GetPropertyAttributes(context.local(), prop)
5175 .FromJust());
5176 // dont-enum
5177 prop = v8_str("dont_enum");
5178 context->Global()
5179 ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
5180 .FromJust();
5181 CHECK_EQ(v8::DontEnum, context->Global()
5182 ->GetPropertyAttributes(context.local(), prop)
5183 .FromJust());
5184 // absent
5185 prop = v8_str("absent");
5186 CHECK_EQ(v8::None, context->Global()
5187 ->GetPropertyAttributes(context.local(), prop)
5188 .FromJust());
5189 Local<Value> fake_prop = v8_num(1);
5190 CHECK_EQ(v8::None, context->Global()
5191 ->GetPropertyAttributes(context.local(), fake_prop)
5192 .FromJust());
5193 // exception
5194 TryCatch try_catch(context->GetIsolate());
5195 Local<Value> exception =
5196 CompileRun("({ toString: function() { throw 'exception';} })");
5197 CHECK(context->Global()
5198 ->GetPropertyAttributes(context.local(), exception)
5199 .IsNothing());
5200 CHECK(try_catch.HasCaught());
5201 String::Utf8Value exception_value(context->GetIsolate(),
5202 try_catch.Exception());
5203 CHECK_EQ(0, strcmp("exception", *exception_value));
5204 try_catch.Reset();
5205}
5206
5207
5208THREADED_TEST(Array) {
5209 LocalContext context;
5210 v8::HandleScope scope(context->GetIsolate());
5211 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
5212 CHECK_EQ(0u, array->Length());
5213 CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
5214 CHECK(!array->Has(context.local(), 0).FromJust());
5215 CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
5216 CHECK(!array->Has(context.local(), 100).FromJust());
5217 CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
5218 CHECK_EQ(3u, array->Length());
5219 CHECK(!array->Has(context.local(), 0).FromJust());
5220 CHECK(!array->Has(context.local(), 1).FromJust());
5221 CHECK(array->Has(context.local(), 2).FromJust());
5222 CHECK_EQ(7, array->Get(context.local(), 2)
5223 .ToLocalChecked()
5224 ->Int32Value(context.local())
5225 .FromJust());
5226 Local<Value> obj = CompileRun("[1, 2, 3]");
5227 Local<v8::Array> arr = obj.As<v8::Array>();
5228 CHECK_EQ(3u, arr->Length());
5229 CHECK_EQ(1, arr->Get(context.local(), 0)
5230 .ToLocalChecked()
5231 ->Int32Value(context.local())
5232 .FromJust());
5233 CHECK_EQ(2, arr->Get(context.local(), 1)
5234 .ToLocalChecked()
5235 ->Int32Value(context.local())
5236 .FromJust());
5237 CHECK_EQ(3, arr->Get(context.local(), 2)
5238 .ToLocalChecked()
5239 ->Int32Value(context.local())
5240 .FromJust());
5241 array = v8::Array::New(context->GetIsolate(), 27);
5242 CHECK_EQ(27u, array->Length());
5243 array = v8::Array::New(context->GetIsolate(), -27);
5244 CHECK_EQ(0u, array->Length());
5245
5246 std::vector<Local<Value>> vector = {v8_num(1), v8_num(2), v8_num(3)};
5247 array = v8::Array::New(context->GetIsolate(), vector.data(), vector.size());
5248 CHECK_EQ(vector.size(), array->Length());
5249 CHECK_EQ(1, arr->Get(context.local(), 0)
5250 .ToLocalChecked()
5251 ->Int32Value(context.local())
5252 .FromJust());
5253 CHECK_EQ(2, arr->Get(context.local(), 1)
5254 .ToLocalChecked()
5255 ->Int32Value(context.local())
5256 .FromJust());
5257 CHECK_EQ(3, arr->Get(context.local(), 2)
5258 .ToLocalChecked()
5259 ->Int32Value(context.local())
5260 .FromJust());
5261}
5262
5263
5264void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
5265 v8::EscapableHandleScope scope(args.GetIsolate());
5266 ApiTestFuzzer::Fuzz();
5267 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
5268 for (int i = 0; i < args.Length(); i++) {
5269 CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
5270 .FromJust());
5271 }
5272 args.GetReturnValue().Set(scope.Escape(result));
5273}
5274
5275
5276THREADED_TEST(Vector) {
5277 v8::Isolate* isolate = CcTest::isolate();
5278 v8::HandleScope scope(isolate);
5279 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
5280 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
5281 LocalContext context(nullptr, global);
5282
5283 const char* fun = "f()";
5284 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
5285 CHECK_EQ(0u, a0->Length());
5286
5287 const char* fun2 = "f(11)";
5288 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
5289 CHECK_EQ(1u, a1->Length());
5290 CHECK_EQ(11, a1->Get(context.local(), 0)
5291 .ToLocalChecked()
5292 ->Int32Value(context.local())
5293 .FromJust());
5294
5295 const char* fun3 = "f(12, 13)";
5296 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
5297 CHECK_EQ(2u, a2->Length());
5298 CHECK_EQ(12, a2->Get(context.local(), 0)
5299 .ToLocalChecked()
5300 ->Int32Value(context.local())
5301 .FromJust());
5302 CHECK_EQ(13, a2->Get(context.local(), 1)
5303 .ToLocalChecked()
5304 ->Int32Value(context.local())
5305 .FromJust());
5306
5307 const char* fun4 = "f(14, 15, 16)";
5308 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
5309 CHECK_EQ(3u, a3->Length());
5310 CHECK_EQ(14, a3->Get(context.local(), 0)
5311 .ToLocalChecked()
5312 ->Int32Value(context.local())
5313 .FromJust());
5314 CHECK_EQ(15, a3->Get(context.local(), 1)
5315 .ToLocalChecked()
5316 ->Int32Value(context.local())
5317 .FromJust());
5318 CHECK_EQ(16, a3->Get(context.local(), 2)
5319 .ToLocalChecked()
5320 ->Int32Value(context.local())
5321 .FromJust());
5322
5323 const char* fun5 = "f(17, 18, 19, 20)";
5324 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
5325 CHECK_EQ(4u, a4->Length());
5326 CHECK_EQ(17, a4->Get(context.local(), 0)
5327 .ToLocalChecked()
5328 ->Int32Value(context.local())
5329 .FromJust());
5330 CHECK_EQ(18, a4->Get(context.local(), 1)
5331 .ToLocalChecked()
5332 ->Int32Value(context.local())
5333 .FromJust());
5334 CHECK_EQ(19, a4->Get(context.local(), 2)
5335 .ToLocalChecked()
5336 ->Int32Value(context.local())
5337 .FromJust());
5338 CHECK_EQ(20, a4->Get(context.local(), 3)
5339 .ToLocalChecked()
5340 ->Int32Value(context.local())
5341 .FromJust());
5342}
5343
5344
5345THREADED_TEST(FunctionCall) {
5346 LocalContext context;
5347 v8::Isolate* isolate = context->GetIsolate();
5348 v8::HandleScope scope(isolate);
5349 CompileRun(
5350 "function Foo() {"
5351 " var result = [];"
5352 " for (var i = 0; i < arguments.length; i++) {"
5353 " result.push(arguments[i]);"
5354 " }"
5355 " return result;"
5356 "}"
5357 "function ReturnThisSloppy() {"
5358 " return this;"
5359 "}"
5360 "function ReturnThisStrict() {"
5361 " 'use strict';"
5362 " return this;"
5363 "}");
5364 Local<Function> Foo = Local<Function>::Cast(
5365 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5366 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
5367 context->Global()
5368 ->Get(context.local(), v8_str("ReturnThisSloppy"))
5369 .ToLocalChecked());
5370 Local<Function> ReturnThisStrict = Local<Function>::Cast(
5371 context->Global()
5372 ->Get(context.local(), v8_str("ReturnThisStrict"))
5373 .ToLocalChecked());
5374
5375 v8::Local<Value>* args0 = nullptr;
5376 Local<v8::Array> a0 = Local<v8::Array>::Cast(
5377 Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
5378 CHECK_EQ(0u, a0->Length());
5379
5380 v8::Local<Value> args1[] = {v8_num(1.1)};
5381 Local<v8::Array> a1 = Local<v8::Array>::Cast(
5382 Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
5383 CHECK_EQ(1u, a1->Length());
5384 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5385 .ToLocalChecked()
5386 ->NumberValue(context.local())
5387 .FromJust());
5388
5389 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5390 Local<v8::Array> a2 = Local<v8::Array>::Cast(
5391 Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
5392 CHECK_EQ(2u, a2->Length());
5393 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5394 .ToLocalChecked()
5395 ->NumberValue(context.local())
5396 .FromJust());
5397 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5398 .ToLocalChecked()
5399 ->NumberValue(context.local())
5400 .FromJust());
5401
5402 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5403 Local<v8::Array> a3 = Local<v8::Array>::Cast(
5404 Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
5405 CHECK_EQ(3u, a3->Length());
5406 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5407 .ToLocalChecked()
5408 ->NumberValue(context.local())
5409 .FromJust());
5410 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5411 .ToLocalChecked()
5412 ->NumberValue(context.local())
5413 .FromJust());
5414 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5415 .ToLocalChecked()
5416 ->NumberValue(context.local())
5417 .FromJust());
5418
5419 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5420 v8_num(10.11)};
5421 Local<v8::Array> a4 = Local<v8::Array>::Cast(
5422 Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
5423 CHECK_EQ(4u, a4->Length());
5424 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5425 .ToLocalChecked()
5426 ->NumberValue(context.local())
5427 .FromJust());
5428 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5429 .ToLocalChecked()
5430 ->NumberValue(context.local())
5431 .FromJust());
5432 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5433 .ToLocalChecked()
5434 ->NumberValue(context.local())
5435 .FromJust());
5436 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5437 .ToLocalChecked()
5438 ->NumberValue(context.local())
5439 .FromJust());
5440
5441 Local<v8::Value> r1 =
5442 ReturnThisSloppy
5443 ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5444 .ToLocalChecked();
5445 CHECK(r1->StrictEquals(context->Global()));
5446 Local<v8::Value> r2 =
5447 ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, nullptr)
5448 .ToLocalChecked();
5449 CHECK(r2->StrictEquals(context->Global()));
5450 Local<v8::Value> r3 =
5451 ReturnThisSloppy->Call(context.local(), v8_num(42), 0, nullptr)
5452 .ToLocalChecked();
5453 CHECK(r3->IsNumberObject());
5454 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5455 Local<v8::Value> r4 =
5456 ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, nullptr)
5457 .ToLocalChecked();
5458 CHECK(r4->IsStringObject());
5459 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5460 Local<v8::Value> r5 =
5461 ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, nullptr)
5462 .ToLocalChecked();
5463 CHECK(r5->IsBooleanObject());
5464 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5465
5466 Local<v8::Value> r6 =
5467 ReturnThisStrict
5468 ->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
5469 .ToLocalChecked();
5470 CHECK(r6->IsUndefined());
5471 Local<v8::Value> r7 =
5472 ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, nullptr)
5473 .ToLocalChecked();
5474 CHECK(r7->IsNull());
5475 Local<v8::Value> r8 =
5476 ReturnThisStrict->Call(context.local(), v8_num(42), 0, nullptr)
5477 .ToLocalChecked();
5478 CHECK(r8->StrictEquals(v8_num(42)));
5479 Local<v8::Value> r9 =
5480 ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, nullptr)
5481 .ToLocalChecked();
5482 CHECK(r9->StrictEquals(v8_str("hello")));
5483 Local<v8::Value> r10 =
5484 ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, nullptr)
5485 .ToLocalChecked();
5486 CHECK(r10->StrictEquals(v8::True(isolate)));
5487}
5488
5489
5490THREADED_TEST(ConstructCall) {
5491 LocalContext context;
5492 v8::Isolate* isolate = context->GetIsolate();
5493 v8::HandleScope scope(isolate);
5494 CompileRun(
5495 "function Foo() {"
5496 " var result = [];"
5497 " for (var i = 0; i < arguments.length; i++) {"
5498 " result.push(arguments[i]);"
5499 " }"
5500 " return result;"
5501 "}");
5502 Local<Function> Foo = Local<Function>::Cast(
5503 context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
5504
5505 v8::Local<Value>* args0 = nullptr;
5506 Local<v8::Array> a0 = Local<v8::Array>::Cast(
5507 Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
5508 CHECK_EQ(0u, a0->Length());
5509
5510 v8::Local<Value> args1[] = {v8_num(1.1)};
5511 Local<v8::Array> a1 = Local<v8::Array>::Cast(
5512 Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
5513 CHECK_EQ(1u, a1->Length());
5514 CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
5515 .ToLocalChecked()
5516 ->NumberValue(context.local())
5517 .FromJust());
5518
5519 v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
5520 Local<v8::Array> a2 = Local<v8::Array>::Cast(
5521 Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
5522 CHECK_EQ(2u, a2->Length());
5523 CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
5524 .ToLocalChecked()
5525 ->NumberValue(context.local())
5526 .FromJust());
5527 CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
5528 .ToLocalChecked()
5529 ->NumberValue(context.local())
5530 .FromJust());
5531
5532 v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
5533 Local<v8::Array> a3 = Local<v8::Array>::Cast(
5534 Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
5535 CHECK_EQ(3u, a3->Length());
5536 CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
5537 .ToLocalChecked()
5538 ->NumberValue(context.local())
5539 .FromJust());
5540 CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
5541 .ToLocalChecked()
5542 ->NumberValue(context.local())
5543 .FromJust());
5544 CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
5545 .ToLocalChecked()
5546 ->NumberValue(context.local())
5547 .FromJust());
5548
5549 v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
5550 v8_num(10.11)};
5551 Local<v8::Array> a4 = Local<v8::Array>::Cast(
5552 Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
5553 CHECK_EQ(4u, a4->Length());
5554 CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
5555 .ToLocalChecked()
5556 ->NumberValue(context.local())
5557 .FromJust());
5558 CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
5559 .ToLocalChecked()
5560 ->NumberValue(context.local())
5561 .FromJust());
5562 CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
5563 .ToLocalChecked()
5564 ->NumberValue(context.local())
5565 .FromJust());
5566 CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
5567 .ToLocalChecked()
5568 ->NumberValue(context.local())
5569 .FromJust());
5570}
5571
5572
5573THREADED_TEST(ConversionNumber) {
5574 LocalContext env;
5575 v8::Isolate* isolate = env->GetIsolate();
5576 v8::HandleScope scope(isolate);
5577 // Very large number.
5578 CompileRun("var obj = Math.pow(2,32) * 1237;");
5579 Local<Value> obj =
5580 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5581 CHECK_EQ(5312874545152.0,
5582 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5583 CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5584 CHECK_EQ(0, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5585 // Large number.
5586 CompileRun("var obj = -1234567890123;");
5587 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5588 CHECK_EQ(-1234567890123.0,
5589 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5590 CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5591 CHECK_EQ(2382691125, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5592 // Small positive integer.
5593 CompileRun("var obj = 42;");
5594 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5595 CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5596 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5597 CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5598 // Negative integer.
5599 CompileRun("var obj = -37;");
5600 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5601 CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5602 CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5603 CHECK_EQ(4294967259, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5604 // Positive non-int32 integer.
5605 CompileRun("var obj = 0x81234567;");
5606 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5607 CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5608 CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5609 CHECK_EQ(2166572391, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5610 // Fraction.
5611 CompileRun("var obj = 42.3;");
5612 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5613 CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
5614 CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5615 CHECK_EQ(42, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5616 // Large negative fraction.
5617 CompileRun("var obj = -5726623061.75;");
5618 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5619 CHECK_EQ(-5726623061.75,
5620 obj->ToNumber(env.local()).ToLocalChecked()->Value());
5621 CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
5622 CHECK_EQ(2863311531, obj->ToUint32(env.local()).ToLocalChecked()->Value());
5623}
5624
5625
5626THREADED_TEST(isNumberType) {
5627 LocalContext env;
5628 v8::HandleScope scope(env->GetIsolate());
5629 // Very large number.
5630 CompileRun("var obj = Math.pow(2,32) * 1237;");
5631 Local<Value> obj =
5632 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5633 CHECK(!obj->IsInt32());
5634 CHECK(!obj->IsUint32());
5635 // Large negative number.
5636 CompileRun("var obj = -1234567890123;");
5637 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5638 CHECK(!obj->IsInt32());
5639 CHECK(!obj->IsUint32());
5640 // Small positive integer.
5641 CompileRun("var obj = 42;");
5642 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5643 CHECK(obj->IsInt32());
5644 CHECK(obj->IsUint32());
5645 // Negative integer.
5646 CompileRun("var obj = -37;");
5647 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5648 CHECK(obj->IsInt32());
5649 CHECK(!obj->IsUint32());
5650 // Positive non-int32 integer.
5651 CompileRun("var obj = 0x81234567;");
5652 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5653 CHECK(!obj->IsInt32());
5654 CHECK(obj->IsUint32());
5655 // Fraction.
5656 CompileRun("var obj = 42.3;");
5657 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5658 CHECK(!obj->IsInt32());
5659 CHECK(!obj->IsUint32());
5660 // Large negative fraction.
5661 CompileRun("var obj = -5726623061.75;");
5662 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5663 CHECK(!obj->IsInt32());
5664 CHECK(!obj->IsUint32());
5665 // Positive zero
5666 CompileRun("var obj = 0.0;");
5667 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5668 CHECK(obj->IsInt32());
5669 CHECK(obj->IsUint32());
5670 // Negative zero
5671 CompileRun("var obj = -0.0;");
5672 obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5673 CHECK(!obj->IsInt32());
5674 CHECK(!obj->IsUint32());
5675}
5676
5677THREADED_TEST(IntegerType) {
5678 LocalContext env;
5679 v8::HandleScope scope(env->GetIsolate());
5680 Local<Value> result;
5681
5682 // Small positive integer
5683 result = CompileRun("42;");
5684 CHECK(result->IsNumber());
5685 CHECK_EQ(42, result.As<v8::Integer>()->Value());
5686 // Small negative integer
5687 result = CompileRun("-42;");
5688 CHECK(result->IsNumber());
5689 CHECK_EQ(-42, result.As<v8::Integer>()->Value());
5690 // Positive non-int32 integer
5691 result = CompileRun("1099511627776;");
5692 CHECK(result->IsNumber());
5693 CHECK_EQ(1099511627776, result.As<v8::Integer>()->Value());
5694 // Negative non-int32 integer
5695 result = CompileRun("-1099511627776;");
5696 CHECK(result->IsNumber());
5697 CHECK_EQ(-1099511627776, result.As<v8::Integer>()->Value());
5698 // Positive non-integer
5699 result = CompileRun("3.14;");
5700 CHECK(result->IsNumber());
5701 CHECK_EQ(3, result.As<v8::Integer>()->Value());
5702 // Negative non-integer
5703 result = CompileRun("-3.14;");
5704 CHECK(result->IsNumber());
5705 CHECK_EQ(-3, result.As<v8::Integer>()->Value());
5706}
5707
5708static void CheckUncle(v8::Isolate* isolate, v8::TryCatch* try_catch) {
5709 CHECK(try_catch->HasCaught());
5710 String::Utf8Value str_value(isolate, try_catch->Exception());
5711 CHECK_EQ(0, strcmp(*str_value, "uncle?"));
5712 try_catch->Reset();
5713}
5714
5715THREADED_TEST(ConversionException) {
5716 LocalContext env;
5717 v8::Isolate* isolate = env->GetIsolate();
5718 v8::HandleScope scope(isolate);
5719 CompileRun(
5720 "function TestClass() { };"
5721 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5722 "var obj = new TestClass();");
5723 Local<Value> obj =
5724 env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
5725
5726 v8::TryCatch try_catch(isolate);
5727
5728 CHECK(obj->ToString(env.local()).IsEmpty());
5729 CheckUncle(isolate, &try_catch);
5730
5731 CHECK(obj->ToNumber(env.local()).IsEmpty());
5732 CheckUncle(isolate, &try_catch);
5733
5734 CHECK(obj->ToInteger(env.local()).IsEmpty());
5735 CheckUncle(isolate, &try_catch);
5736
5737 CHECK(obj->ToUint32(env.local()).IsEmpty());
5738 CheckUncle(isolate, &try_catch);
5739
5740 CHECK(obj->ToInt32(env.local()).IsEmpty());
5741 CheckUncle(isolate, &try_catch);
5742
5743 CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
5744 CHECK(try_catch.HasCaught());
5745 try_catch.Reset();
5746
5747 CHECK(obj->Int32Value(env.local()).IsNothing());
5748 CheckUncle(isolate, &try_catch);
5749
5750 CHECK(obj->Uint32Value(env.local()).IsNothing());
5751 CheckUncle(isolate, &try_catch);
5752
5753 CHECK(obj->NumberValue(env.local()).IsNothing());
5754 CheckUncle(isolate, &try_catch);
5755
5756 CHECK(obj->IntegerValue(env.local()).IsNothing());
5757 CheckUncle(isolate, &try_catch);
5758}
5759
5760
5761void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5762 ApiTestFuzzer::Fuzz();
5763 args.GetIsolate()->ThrowException(v8_str("konto"));
5764}
5765
5766
5767void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5768 if (args.Length() < 1) {
5769 args.GetReturnValue().Set(false);
5770 return;
5771 }
5772 v8::HandleScope scope(args.GetIsolate());
5773 v8::TryCatch try_catch(args.GetIsolate());
5774 Local<Value> result =
5775 CompileRun(args[0]
5776 ->ToString(args.GetIsolate()->GetCurrentContext())
5777 .ToLocalChecked());
5778 CHECK(!try_catch.HasCaught() || result.IsEmpty());
5779 args.GetReturnValue().Set(try_catch.HasCaught());
5780}
5781
5782
5783THREADED_TEST(APICatch) {
5784 v8::Isolate* isolate = CcTest::isolate();
5785 v8::HandleScope scope(isolate);
5786 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5787 templ->Set(v8_str("ThrowFromC"),
5788 v8::FunctionTemplate::New(isolate, ThrowFromC));
5789 LocalContext context(nullptr, templ);
5790 CompileRun(
5791 "var thrown = false;"
5792 "try {"
5793 " ThrowFromC();"
5794 "} catch (e) {"
5795 " thrown = true;"
5796 "}");
5797 Local<Value> thrown = context->Global()
5798 ->Get(context.local(), v8_str("thrown"))
5799 .ToLocalChecked();
5800 CHECK(thrown->BooleanValue(isolate));
5801}
5802
5803
5804THREADED_TEST(APIThrowTryCatch) {
5805 v8::Isolate* isolate = CcTest::isolate();
5806 v8::HandleScope scope(isolate);
5807 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5808 templ->Set(v8_str("ThrowFromC"),
5809 v8::FunctionTemplate::New(isolate, ThrowFromC));
5810 LocalContext context(nullptr, templ);
5811 v8::TryCatch try_catch(isolate);
5812 CompileRun("ThrowFromC();");
5813 CHECK(try_catch.HasCaught());
5814}
5815
5816
5817// Test that a try-finally block doesn't shadow a try-catch block
5818// when setting up an external handler.
5819//
5820// BUG(271): Some of the exception propagation does not work on the
5821// ARM simulator because the simulator separates the C++ stack and the
5822// JS stack. This test therefore fails on the simulator. The test is
5823// not threaded to allow the threading tests to run on the simulator.
5824TEST(TryCatchInTryFinally) {
5825 v8::Isolate* isolate = CcTest::isolate();
5826 v8::HandleScope scope(isolate);
5827 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5828 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
5829 LocalContext context(nullptr, templ);
5830 Local<Value> result = CompileRun(
5831 "try {"
5832 " try {"
5833 " CCatcher('throw 7;');"
5834 " } finally {"
5835 " }"
5836 "} catch (e) {"
5837 "}");
5838 CHECK(result->IsTrue());
5839}
5840
5841
5842static void check_custom_error_tostring(v8::Local<v8::Message> message,
5843 v8::Local<v8::Value> data) {
5844 const char* uncaught_error = "Uncaught MyError toString";
5845 CHECK(message->Get()
5846 ->Equals(CcTest::isolate()->GetCurrentContext(),
5847 v8_str(uncaught_error))
5848 .FromJust());
5849}
5850
5851
5852TEST(CustomErrorToString) {
5853 LocalContext context;
5854 v8::HandleScope scope(context->GetIsolate());
5855 context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
5856 CompileRun(
5857 "function MyError(name, message) { "
5858 " this.name = name; "
5859 " this.message = message; "
5860 "} "
5861 "MyError.prototype = Object.create(Error.prototype); "
5862 "MyError.prototype.toString = function() { "
5863 " return 'MyError toString'; "
5864 "}; "
5865 "throw new MyError('my name', 'my message'); ");
5866 context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
5867}
5868
5869
5870static void check_custom_error_message(v8::Local<v8::Message> message,
5871 v8::Local<v8::Value> data) {
5872 const char* uncaught_error = "Uncaught MyError: my message";
5873 printf("%s\n", *v8::String::Utf8Value(CcTest::isolate(), message->Get()));
5874 CHECK(message->Get()
5875 ->Equals(CcTest::isolate()->GetCurrentContext(),
5876 v8_str(uncaught_error))
5877 .FromJust());
5878}
5879
5880
5881TEST(CustomErrorMessage) {
5882 LocalContext context;
5883 v8::HandleScope scope(context->GetIsolate());
5884 context->GetIsolate()->AddMessageListener(check_custom_error_message);
5885
5886 // Handlebars.
5887 CompileRun(
5888 "function MyError(msg) { "
5889 " this.name = 'MyError'; "
5890 " this.message = msg; "
5891 "} "
5892 "MyError.prototype = new Error(); "
5893 "throw new MyError('my message'); ");
5894
5895 // Closure.
5896 CompileRun(
5897 "function MyError(msg) { "
5898 " this.name = 'MyError'; "
5899 " this.message = msg; "
5900 "} "
5901 "inherits = function(childCtor, parentCtor) { "
5902 " function tempCtor() {}; "
5903 " tempCtor.prototype = parentCtor.prototype; "
5904 " childCtor.superClass_ = parentCtor.prototype; "
5905 " childCtor.prototype = new tempCtor(); "
5906 " childCtor.prototype.constructor = childCtor; "
5907 "}; "
5908 "inherits(MyError, Error); "
5909 "throw new MyError('my message'); ");
5910
5911 // Object.create.
5912 CompileRun(
5913 "function MyError(msg) { "
5914 " this.name = 'MyError'; "
5915 " this.message = msg; "
5916 "} "
5917 "MyError.prototype = Object.create(Error.prototype); "
5918 "throw new MyError('my message'); ");
5919
5920 context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
5921}
5922
5923
5924static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
5925 v8::Local<v8::Value> data) {
5926 CHECK(data->IsExternal());
5927 int* callcount = static_cast<int*>(data.As<v8::External>()->Value());
5928 ++*callcount;
5929
5930 const char* uncaught_error = "Uncaught exception";
5931 CHECK(message->Get()
5932 ->Equals(CcTest::isolate()->GetCurrentContext(),
5933 v8_str(uncaught_error))
5934 .FromJust());
5935 // Test that compiling code inside a message handler works.
5936 CHECK(CompileRunChecked(CcTest::isolate(), "(function(a) { return a; })(42)")
5937 ->Equals(CcTest::isolate()->GetCurrentContext(),
5938 v8::Integer::NewFromUnsigned(CcTest::isolate(), 42))
5939 .FromJust());
5940}
5941
5942
5943TEST(CustomErrorRethrowsOnToString) {
5944 int callcount = 0;
5945 LocalContext context;
5946 v8::Isolate* isolate = context->GetIsolate();
5947 v8::HandleScope scope(isolate);
5948 context->GetIsolate()->AddMessageListener(
5949 check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5950
5951 CompileRun(
5952 "var e = { toString: function() { throw e; } };"
5953 "try { throw e; } finally {}");
5954
5955 CHECK_EQ(callcount, 1);
5956 context->GetIsolate()->RemoveMessageListeners(
5957 check_custom_rethrowing_message);
5958}
5959
5960TEST(CustomErrorRethrowsOnToStringInsideVerboseTryCatch) {
5961 int callcount = 0;
5962 LocalContext context;
5963 v8::Isolate* isolate = context->GetIsolate();
5964 v8::HandleScope scope(isolate);
5965 v8::TryCatch try_catch(isolate);
5966 try_catch.SetVerbose(true);
5967 context->GetIsolate()->AddMessageListener(
5968 check_custom_rethrowing_message, v8::External::New(isolate, &callcount));
5969
5970 CompileRun(
5971 "var e = { toString: function() { throw e; } };"
5972 "try { throw e; } finally {}");
5973
5974 CHECK_EQ(callcount, 1);
5975 context->GetIsolate()->RemoveMessageListeners(
5976 check_custom_rethrowing_message);
5977}
5978
5979
5980static void receive_message(v8::Local<v8::Message> message,
5981 v8::Local<v8::Value> data) {
5982 message->Get();
5983 message_received = true;
5984}
5985
5986
5987TEST(APIThrowMessage) {
5988 message_received = false;
5989 v8::Isolate* isolate = CcTest::isolate();
5990 v8::HandleScope scope(isolate);
5991 isolate->AddMessageListener(receive_message);
5992 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5993 templ->Set(v8_str("ThrowFromC"),
5994 v8::FunctionTemplate::New(isolate, ThrowFromC));
5995 LocalContext context(nullptr, templ);
5996 CompileRun("ThrowFromC();");
5997 CHECK(message_received);
5998 isolate->RemoveMessageListeners(receive_message);
5999}
6000
6001
6002TEST(APIThrowMessageAndVerboseTryCatch) {
6003 message_received = false;
6004 v8::Isolate* isolate = CcTest::isolate();
6005 v8::HandleScope scope(isolate);
6006 isolate->AddMessageListener(receive_message);
6007 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6008 templ->Set(v8_str("ThrowFromC"),
6009 v8::FunctionTemplate::New(isolate, ThrowFromC));
6010 LocalContext context(nullptr, templ);
6011 v8::TryCatch try_catch(isolate);
6012 try_catch.SetVerbose(true);
6013 Local<Value> result = CompileRun("ThrowFromC();");
6014 CHECK(try_catch.HasCaught());
6015 CHECK(result.IsEmpty());
6016 CHECK(message_received);
6017 isolate->RemoveMessageListeners(receive_message);
6018}
6019
6020
6021TEST(APIStackOverflowAndVerboseTryCatch) {
6022 message_received = false;
6023 LocalContext context;
6024 v8::HandleScope scope(context->GetIsolate());
6025 context->GetIsolate()->AddMessageListener(receive_message);
6026 v8::TryCatch try_catch(context->GetIsolate());
6027 try_catch.SetVerbose(true);
6028 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
6029 CHECK(try_catch.HasCaught());
6030 CHECK(result.IsEmpty());
6031 CHECK(message_received);
6032 context->GetIsolate()->RemoveMessageListeners(receive_message);
6033}
6034
6035
6036THREADED_TEST(ExternalScriptException) {
6037 v8::Isolate* isolate = CcTest::isolate();
6038 v8::HandleScope scope(isolate);
6039 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6040 templ->Set(v8_str("ThrowFromC"),
6041 v8::FunctionTemplate::New(isolate, ThrowFromC));
6042 LocalContext context(nullptr, templ);
6043
6044 v8::TryCatch try_catch(isolate);
6045 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
6046 CHECK(result.IsEmpty());
6047 CHECK(try_catch.HasCaught());
6048 String::Utf8Value exception_value(isolate, try_catch.Exception());
6049 CHECK_EQ(0, strcmp("konto", *exception_value));
6050}
6051
6052
6053void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
6054 ApiTestFuzzer::Fuzz();
6055 CHECK_EQ(4, args.Length());
6056 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
6057 int count = args[0]->Int32Value(context).FromJust();
6058 int cInterval = args[2]->Int32Value(context).FromJust();
6059 if (count == 0) {
6060 args.GetIsolate()->ThrowException(v8_str("FromC"));
6061 return;
6062 } else {
6063 Local<v8::Object> global = context->Global();
6064 Local<Value> fun =
6065 global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
6066 v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
6067 if (count % cInterval == 0) {
6068 v8::TryCatch try_catch(args.GetIsolate());
6069 Local<Value> result = fun.As<Function>()
6070 ->Call(context, global, 4, argv)
6071 .FromMaybe(Local<Value>());
6072 int expected = args[3]->Int32Value(context).FromJust();
6073 if (try_catch.HasCaught()) {
6074 CHECK_EQ(expected, count);
6075 CHECK(result.IsEmpty());
6076 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
6077 } else {
6078 CHECK_NE(expected, count);
6079 }
6080 args.GetReturnValue().Set(result);
6081 return;
6082 } else {
6083 args.GetReturnValue().Set(fun.As<Function>()
6084 ->Call(context, global, 4, argv)
6085 .FromMaybe(v8::Local<v8::Value>()));
6086 return;
6087 }
6088 }
6089}
6090
6091
6092void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
6093 ApiTestFuzzer::Fuzz();
6094 CHECK_EQ(3, args.Length());
6095 v8::Isolate* isolate = args.GetIsolate();
6096 v8::Local<v8::Context> context = isolate->GetCurrentContext();
6097 bool equality = args[0]->BooleanValue(isolate);
6098 int count = args[1]->Int32Value(context).FromJust();
6099 int expected = args[2]->Int32Value(context).FromJust();
6100 if (equality) {
6101 CHECK_EQ(count, expected);
6102 } else {
6103 CHECK_NE(count, expected);
6104 }
6105}
6106
6107
6108THREADED_TEST(EvalInTryFinally) {
6109 LocalContext context;
6110 v8::HandleScope scope(context->GetIsolate());
6111 v8::TryCatch try_catch(context->GetIsolate());
6112 CompileRun(
6113 "(function() {"
6114 " try {"
6115 " eval('asldkf (*&^&*^');"
6116 " } finally {"
6117 " return;"
6118 " }"
6119 "})()");
6120 CHECK(!try_catch.HasCaught());
6121}
6122
6123
6124// This test works by making a stack of alternating JavaScript and C
6125// activations. These activations set up exception handlers with regular
6126// intervals, one interval for C activations and another for JavaScript
6127// activations. When enough activations have been created an exception is
6128// thrown and we check that the right activation catches the exception and that
6129// no other activations do. The right activation is always the topmost one with
6130// a handler, regardless of whether it is in JavaScript or C.
6131//
6132// The notation used to describe a test case looks like this:
6133//
6134// *JS[4] *C[3] @JS[2] C[1] JS[0]
6135//
6136// Each entry is an activation, either JS or C. The index is the count at that
6137// level. Stars identify activations with exception handlers, the @ identifies
6138// the exception handler that should catch the exception.
6139//
6140// BUG(271): Some of the exception propagation does not work on the
6141// ARM simulator because the simulator separates the C++ stack and the
6142// JS stack. This test therefore fails on the simulator. The test is
6143// not threaded to allow the threading tests to run on the simulator.
6144TEST(ExceptionOrder) {
6145 v8::Isolate* isolate = CcTest::isolate();
6146 v8::HandleScope scope(isolate);
6147 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6148 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
6149 templ->Set(v8_str("CThrowCountDown"),
6150 v8::FunctionTemplate::New(isolate, CThrowCountDown));
6151 LocalContext context(nullptr, templ);
6152 CompileRun(
6153 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
6154 " if (count == 0) throw 'FromJS';"
6155 " if (count % jsInterval == 0) {"
6156 " try {"
6157 " var value = CThrowCountDown(count - 1,"
6158 " jsInterval,"
6159 " cInterval,"
6160 " expected);"
6161 " check(false, count, expected);"
6162 " return value;"
6163 " } catch (e) {"
6164 " check(true, count, expected);"
6165 " }"
6166 " } else {"
6167 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
6168 " }"
6169 "}");
6170 Local<Function> fun = Local<Function>::Cast(
6171 context->Global()
6172 ->Get(context.local(), v8_str("JSThrowCountDown"))
6173 .ToLocalChecked());
6174
6175 const int argc = 4;
6176 // count jsInterval cInterval expected
6177
6178 // *JS[4] *C[3] @JS[2] C[1] JS[0]
6179 v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
6180 fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
6181
6182 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
6183 v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
6184 fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
6185
6186 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
6187 v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
6188 fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
6189
6190 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
6191 v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
6192 fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
6193
6194 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
6195 v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
6196 fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
6197
6198 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
6199 v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
6200 fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
6201}
6202
6203
6204void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
6205 ApiTestFuzzer::Fuzz();
6206 CHECK_EQ(1, args.Length());
6207 args.GetIsolate()->ThrowException(args[0]);
6208}
6209
6210
6211THREADED_TEST(ThrowValues) {
6212 v8::Isolate* isolate = CcTest::isolate();
6213 v8::HandleScope scope(isolate);
6214 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6215 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
6216 LocalContext context(nullptr, templ);
6217 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
6218 CompileRun("function Run(obj) {"
6219 " try {"
6220 " Throw(obj);"
6221 " } catch (e) {"
6222 " return e;"
6223 " }"
6224 " return 'no exception';"
6225 "}"
6226 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
6227 CHECK_EQ(5u, result->Length());
6228 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 0))
6229 .ToLocalChecked()
6230 ->IsString());
6231 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 1))
6232 .ToLocalChecked()
6233 ->IsNumber());
6234 CHECK_EQ(1, result->Get(context.local(), v8::Integer::New(isolate, 1))
6235 .ToLocalChecked()
6236 ->Int32Value(context.local())
6237 .FromJust());
6238 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 2))
6239 .ToLocalChecked()
6240 ->IsNumber());
6241 CHECK_EQ(0, result->Get(context.local(), v8::Integer::New(isolate, 2))
6242 .ToLocalChecked()
6243 ->Int32Value(context.local())
6244 .FromJust());
6245 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 3))
6246 .ToLocalChecked()
6247 ->IsNull());
6248 CHECK(result->Get(context.local(), v8::Integer::New(isolate, 4))
6249 .ToLocalChecked()
6250 ->IsUndefined());
6251}
6252
6253
6254THREADED_TEST(CatchZero) {
6255 LocalContext context;
6256 v8::HandleScope scope(context->GetIsolate());
6257 v8::TryCatch try_catch(context->GetIsolate());
6258 CHECK(!try_catch.HasCaught());
6259 CompileRun("throw 10");
6260 CHECK(try_catch.HasCaught());
6261 CHECK_EQ(10, try_catch.Exception()->Int32Value(context.local()).FromJust());
6262 try_catch.Reset();
6263 CHECK(!try_catch.HasCaught());
6264 CompileRun("throw 0");
6265 CHECK(try_catch.HasCaught());
6266 CHECK_EQ(0, try_catch.Exception()->Int32Value(context.local()).FromJust());
6267}
6268
6269
6270THREADED_TEST(CatchExceptionFromWith) {
6271 LocalContext context;
6272 v8::HandleScope scope(context->GetIsolate());
6273 v8::TryCatch try_catch(context->GetIsolate());
6274 CHECK(!try_catch.HasCaught());
6275 CompileRun("var o = {}; with (o) { throw 42; }");
6276 CHECK(try_catch.HasCaught());
6277}
6278
6279
6280THREADED_TEST(TryCatchAndFinallyHidingException) {
6281 LocalContext context;
6282 v8::HandleScope scope(context->GetIsolate());
6283 v8::TryCatch try_catch(context->GetIsolate());
6284 CHECK(!try_catch.HasCaught());
6285 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
6286 CompileRun("f({toString: function() { throw 42; }});");
6287 CHECK(!try_catch.HasCaught());
6288}
6289
6290
6291void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
6292 v8::TryCatch try_catch(args.GetIsolate());
6293}
6294
6295
6296THREADED_TEST(TryCatchAndFinally) {
6297 LocalContext context;
6298 v8::Isolate* isolate = context->GetIsolate();
6299 v8::HandleScope scope(isolate);
6300 CHECK(context->Global()
6301 ->Set(context.local(), v8_str("native_with_try_catch"),
6302 v8::FunctionTemplate::New(isolate, WithTryCatch)
6303 ->GetFunction(context.local())
6304 .ToLocalChecked())
6305 .FromJust());
6306 v8::TryCatch try_catch(isolate);
6307 CHECK(!try_catch.HasCaught());
6308 CompileRun(
6309 "try {\n"
6310 " throw new Error('a');\n"
6311 "} finally {\n"
6312 " native_with_try_catch();\n"
6313 "}\n");
6314 CHECK(try_catch.HasCaught());
6315}
6316
6317
6318static void TryCatchNested1Helper(int depth) {
6319 if (depth > 0) {
6320 v8::TryCatch try_catch(CcTest::isolate());
6321 try_catch.SetVerbose(true);
6322 TryCatchNested1Helper(depth - 1);
6323 CHECK(try_catch.HasCaught());
6324 try_catch.ReThrow();
6325 } else {
6326 CcTest::isolate()->ThrowException(v8_str("E1"));
6327 }
6328}
6329
6330
6331static void TryCatchNested2Helper(int depth) {
6332 if (depth > 0) {
6333 v8::TryCatch try_catch(CcTest::isolate());
6334 try_catch.SetVerbose(true);
6335 TryCatchNested2Helper(depth - 1);
6336 CHECK(try_catch.HasCaught());
6337 try_catch.ReThrow();
6338 } else {
6339 CompileRun("throw 'E2';");
6340 }
6341}
6342
6343
6344TEST(TryCatchNested) {
6345 v8::V8::Initialize();
6346 LocalContext context;
6347 v8::HandleScope scope(context->GetIsolate());
6348
6349 {
6350 // Test nested try-catch with a native throw in the end.
6351 v8::TryCatch try_catch(context->GetIsolate());
6352 TryCatchNested1Helper(5);
6353 CHECK(try_catch.HasCaught());
6354 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6355 try_catch.Exception()),
6356 "E1"));
6357 }
6358
6359 {
6360 // Test nested try-catch with a JavaScript throw in the end.
6361 v8::TryCatch try_catch(context->GetIsolate());
6362 TryCatchNested2Helper(5);
6363 CHECK(try_catch.HasCaught());
6364 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(),
6365 try_catch.Exception()),
6366 "E2"));
6367 }
6368}
6369
6370
6371void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
6372 CHECK(try_catch->HasCaught());
6373 Local<Message> message = try_catch->Message();
6374 Local<Value> resource = message->GetScriptOrigin().ResourceName();
6375 CHECK_EQ(
6376 0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), resource), "inner"));
6377 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(CcTest::isolate(), message->Get()),
6378 "Uncaught Error: a"));
6379 CHECK_EQ(1, message->GetLineNumber(CcTest::isolate()->GetCurrentContext())
6380 .FromJust());
6381 CHECK_EQ(0, message->GetStartColumn(CcTest::isolate()->GetCurrentContext())
6382 .FromJust());
6383}
6384
6385
6386void TryCatchMixedNestingHelper(
6387 const v8::FunctionCallbackInfo<v8::Value>& args) {
6388 ApiTestFuzzer::Fuzz();
6389 v8::TryCatch try_catch(args.GetIsolate());
6390 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
6391 CHECK(try_catch.HasCaught());
6392 TryCatchMixedNestingCheck(&try_catch);
6393 try_catch.ReThrow();
6394}
6395
6396
6397// This test ensures that an outer TryCatch in the following situation:
6398// C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
6399// does not clobber the Message object generated for the inner TryCatch.
6400// This exercises the ability of TryCatch.ReThrow() to restore the
6401// inner pending Message before throwing the exception again.
6402TEST(TryCatchMixedNesting) {
6403 v8::Isolate* isolate = CcTest::isolate();
6404 v8::HandleScope scope(isolate);
6405 v8::V8::Initialize();
6406 v8::TryCatch try_catch(isolate);
6407 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6408 templ->Set(v8_str("TryCatchMixedNestingHelper"),
6409 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
6410 LocalContext context(nullptr, templ);
6411 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
6412 TryCatchMixedNestingCheck(&try_catch);
6413}
6414
6415
6416void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
6417 ApiTestFuzzer::Fuzz();
6418 v8::TryCatch try_catch(args.GetIsolate());
6419 args.GetIsolate()->ThrowException(v8_str("boom"));
6420 CHECK(try_catch.HasCaught());
6421}
6422
6423
6424TEST(TryCatchNative) {
6425 v8::Isolate* isolate = CcTest::isolate();
6426 v8::HandleScope scope(isolate);
6427 v8::V8::Initialize();
6428 v8::TryCatch try_catch(isolate);
6429 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6430 templ->Set(v8_str("TryCatchNativeHelper"),
6431 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
6432 LocalContext context(nullptr, templ);
6433 CompileRun("TryCatchNativeHelper();");
6434 CHECK(!try_catch.HasCaught());
6435}
6436
6437
6438void TryCatchNativeResetHelper(
6439 const v8::FunctionCallbackInfo<v8::Value>& args) {
6440 ApiTestFuzzer::Fuzz();
6441 v8::TryCatch try_catch(args.GetIsolate());
6442 args.GetIsolate()->ThrowException(v8_str("boom"));
6443 CHECK(try_catch.HasCaught());
6444 try_catch.Reset();
6445 CHECK(!try_catch.HasCaught());
6446}
6447
6448
6449TEST(TryCatchNativeReset) {
6450 v8::Isolate* isolate = CcTest::isolate();
6451 v8::HandleScope scope(isolate);
6452 v8::V8::Initialize();
6453 v8::TryCatch try_catch(isolate);
6454 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6455 templ->Set(v8_str("TryCatchNativeResetHelper"),
6456 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
6457 LocalContext context(nullptr, templ);
6458 CompileRun("TryCatchNativeResetHelper();");
6459 CHECK(!try_catch.HasCaught());
6460}
6461
6462
6463THREADED_TEST(Equality) {
6464 LocalContext context;
6465 v8::Isolate* isolate = context->GetIsolate();
6466 v8::HandleScope scope(context->GetIsolate());
6467 // Check that equality works at all before relying on CHECK_EQ
6468 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6469 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6470
6471 CHECK(v8_str("a")->Equals(context.local(), v8_str("a")).FromJust());
6472 CHECK(!v8_str("a")->Equals(context.local(), v8_str("b")).FromJust());
6473 CHECK(v8_num(1)->Equals(context.local(), v8_num(1)).FromJust());
6474 CHECK(v8_num(1.00)->Equals(context.local(), v8_num(1)).FromJust());
6475 CHECK(!v8_num(1)->Equals(context.local(), v8_num(2)).FromJust());
6476
6477 // Assume String is not internalized.
6478 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
6479 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
6480 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
6481 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
6482 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
6483 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
6484 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
6485 CHECK(!not_a_number->StrictEquals(not_a_number));
6486 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
6487 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
6488
6489 v8::Local<v8::Object> obj = v8::Object::New(isolate);
6490 v8::Persistent<v8::Object> alias(isolate, obj);
6491 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
6492 alias.Reset();
6493
6494 CHECK(v8_str("a")->SameValue(v8_str("a")));
6495 CHECK(!v8_str("a")->SameValue(v8_str("b")));
6496 CHECK(!v8_str("5")->SameValue(v8_num(5)));
6497 CHECK(v8_num(1)->SameValue(v8_num(1)));
6498 CHECK(!v8_num(1)->SameValue(v8_num(2)));
6499 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
6500 CHECK(not_a_number->SameValue(not_a_number));
6501 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
6502 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
6503}
6504
6505THREADED_TEST(TypeOf) {
6506 LocalContext context;
6507 v8::Isolate* isolate = context->GetIsolate();
6508 v8::HandleScope scope(context->GetIsolate());
6509
6510 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
6511 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
6512
6513 CHECK(v8::Undefined(isolate)
6514 ->TypeOf(isolate)
6515 ->Equals(context.local(), v8_str("undefined"))
6516 .FromJust());
6517 CHECK(v8::Null(isolate)
6518 ->TypeOf(isolate)
6519 ->Equals(context.local(), v8_str("object"))
6520 .FromJust());
6521 CHECK(v8_str("str")
6522 ->TypeOf(isolate)
6523 ->Equals(context.local(), v8_str("string"))
6524 .FromJust());
6525 CHECK(v8_num(0.0)
6526 ->TypeOf(isolate)
6527 ->Equals(context.local(), v8_str("number"))
6528 .FromJust());
6529 CHECK(v8_num(1)
6530 ->TypeOf(isolate)
6531 ->Equals(context.local(), v8_str("number"))
6532 .FromJust());
6533 CHECK(v8::Object::New(isolate)
6534 ->TypeOf(isolate)
6535 ->Equals(context.local(), v8_str("object"))
6536 .FromJust());
6537 CHECK(v8::Boolean::New(isolate, true)
6538 ->TypeOf(isolate)
6539 ->Equals(context.local(), v8_str("boolean"))
6540 .FromJust());
6541 CHECK(fun->TypeOf(isolate)
6542 ->Equals(context.local(), v8_str("function"))
6543 .FromJust());
6544}
6545
6546THREADED_TEST(InstanceOf) {
6547 LocalContext env;
6548 v8::HandleScope scope(env->GetIsolate());
6549 CompileRun(
6550 "var A = {};"
6551 "var B = {};"
6552 "var C = {};"
6553 "B.__proto__ = A;"
6554 "C.__proto__ = B;"
6555 "function F() {}"
6556 "F.prototype = A;"
6557 "var G = { [Symbol.hasInstance] : null};"
6558 "var H = { [Symbol.hasInstance] : () => { throw new Error(); } };"
6559 "var J = { [Symbol.hasInstance] : () => true };"
6560 "class K {}"
6561 "var D = new K;"
6562 "class L extends K {}"
6563 "var E = new L");
6564
6565 v8::Local<v8::Object> f = v8::Local<v8::Object>::Cast(CompileRun("F"));
6566 v8::Local<v8::Object> g = v8::Local<v8::Object>::Cast(CompileRun("G"));
6567 v8::Local<v8::Object> h = v8::Local<v8::Object>::Cast(CompileRun("H"));
6568 v8::Local<v8::Object> j = v8::Local<v8::Object>::Cast(CompileRun("J"));
6569 v8::Local<v8::Object> k = v8::Local<v8::Object>::Cast(CompileRun("K"));
6570 v8::Local<v8::Object> l = v8::Local<v8::Object>::Cast(CompileRun("L"));
6571 v8::Local<v8::Value> a = v8::Local<v8::Value>::Cast(CompileRun("A"));
6572 v8::Local<v8::Value> b = v8::Local<v8::Value>::Cast(CompileRun("B"));
6573 v8::Local<v8::Value> c = v8::Local<v8::Value>::Cast(CompileRun("C"));
6574 v8::Local<v8::Value> d = v8::Local<v8::Value>::Cast(CompileRun("D"));
6575 v8::Local<v8::Value> e = v8::Local<v8::Value>::Cast(CompileRun("E"));
6576
6577 v8::TryCatch try_catch(env->GetIsolate());
6578 CHECK(!a->InstanceOf(env.local(), f).ToChecked());
6579 CHECK(b->InstanceOf(env.local(), f).ToChecked());
6580 CHECK(c->InstanceOf(env.local(), f).ToChecked());
6581 CHECK(!d->InstanceOf(env.local(), f).ToChecked());
6582 CHECK(!e->InstanceOf(env.local(), f).ToChecked());
6583 CHECK(!try_catch.HasCaught());
6584
6585 CHECK(a->InstanceOf(env.local(), g).IsNothing());
6586 CHECK(try_catch.HasCaught());
6587 try_catch.Reset();
6588
6589 CHECK(b->InstanceOf(env.local(), h).IsNothing());
6590 CHECK(try_catch.HasCaught());
6591 try_catch.Reset();
6592
6593 CHECK(v8_num(1)->InstanceOf(env.local(), j).ToChecked());
6594 CHECK(!try_catch.HasCaught());
6595
6596 CHECK(d->InstanceOf(env.local(), k).ToChecked());
6597 CHECK(e->InstanceOf(env.local(), k).ToChecked());
6598 CHECK(!d->InstanceOf(env.local(), l).ToChecked());
6599 CHECK(e->InstanceOf(env.local(), l).ToChecked());
6600 CHECK(!try_catch.HasCaught());
6601}
6602
6603THREADED_TEST(MultiRun) {
6604 LocalContext context;
6605 v8::HandleScope scope(context->GetIsolate());
6606 Local<Script> script = v8_compile("x");
6607 for (int i = 0; i < 10; i++) {
6608 script->Run(context.local()).IsEmpty();
6609 }
6610}
6611
6612
6613static void GetXValue(Local<Name> name,
6614 const v8::PropertyCallbackInfo<v8::Value>& info) {
6615 ApiTestFuzzer::Fuzz();
6616 CHECK(info.Data()
6617 ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("donut"))
6618 .FromJust());
6619 CHECK(name->Equals(CcTest::isolate()->GetCurrentContext(), v8_str("x"))
6620 .FromJust());
6621 info.GetReturnValue().Set(name);
6622}
6623
6624
6625THREADED_TEST(SimplePropertyRead) {
6626 LocalContext context;
6627 v8::Isolate* isolate = context->GetIsolate();
6628 v8::HandleScope scope(isolate);
6629 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6630 templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6631 CHECK(context->Global()
6632 ->Set(context.local(), v8_str("obj"),
6633 templ->NewInstance(context.local()).ToLocalChecked())
6634 .FromJust());
6635 Local<Script> script = v8_compile("obj.x");
6636 for (int i = 0; i < 10; i++) {
6637 Local<Value> result = script->Run(context.local()).ToLocalChecked();
6638 CHECK(result->Equals(context.local(), v8_str("x")).FromJust());
6639 }
6640}
6641
6642
6643THREADED_TEST(DefinePropertyOnAPIAccessor) {
6644 LocalContext context;
6645 v8::Isolate* isolate = context->GetIsolate();
6646 v8::HandleScope scope(isolate);
6647 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6648 templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6649 CHECK(context->Global()
6650 ->Set(context.local(), v8_str("obj"),
6651 templ->NewInstance(context.local()).ToLocalChecked())
6652 .FromJust());
6653
6654 // Uses getOwnPropertyDescriptor to check the configurable status
6655 Local<Script> script_desc = v8_compile(
6656 "var prop = Object.getOwnPropertyDescriptor( "
6657 "obj, 'x');"
6658 "prop.configurable;");
6659 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6660 CHECK(result->BooleanValue(isolate));
6661
6662 // Redefine get - but still configurable
6663 Local<Script> script_define = v8_compile(
6664 "var desc = { get: function(){return 42; },"
6665 " configurable: true };"
6666 "Object.defineProperty(obj, 'x', desc);"
6667 "obj.x");
6668 result = script_define->Run(context.local()).ToLocalChecked();
6669 CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6670
6671 // Check that the accessor is still configurable
6672 result = script_desc->Run(context.local()).ToLocalChecked();
6673 CHECK(result->BooleanValue(isolate));
6674
6675 // Redefine to a non-configurable
6676 script_define = v8_compile(
6677 "var desc = { get: function(){return 43; },"
6678 " configurable: false };"
6679 "Object.defineProperty(obj, 'x', desc);"
6680 "obj.x");
6681 result = script_define->Run(context.local()).ToLocalChecked();
6682 CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6683 result = script_desc->Run(context.local()).ToLocalChecked();
6684 CHECK(!result->BooleanValue(isolate));
6685
6686 // Make sure that it is not possible to redefine again
6687 v8::TryCatch try_catch(isolate);
6688 CHECK(script_define->Run(context.local()).IsEmpty());
6689 CHECK(try_catch.HasCaught());
6690 String::Utf8Value exception_value(isolate, try_catch.Exception());
6691 CHECK_EQ(0,
6692 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6693}
6694
6695
6696THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6697 v8::Isolate* isolate = CcTest::isolate();
6698 v8::HandleScope scope(isolate);
6699 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6700 templ->SetAccessor(v8_str("x"), GetXValue, nullptr, v8_str("donut"));
6701 LocalContext context;
6702 CHECK(context->Global()
6703 ->Set(context.local(), v8_str("obj"),
6704 templ->NewInstance(context.local()).ToLocalChecked())
6705 .FromJust());
6706
6707 Local<Script> script_desc = v8_compile(
6708 "var prop ="
6709 "Object.getOwnPropertyDescriptor( "
6710 "obj, 'x');"
6711 "prop.configurable;");
6712 Local<Value> result = script_desc->Run(context.local()).ToLocalChecked();
6713 CHECK(result->BooleanValue(isolate));
6714
6715 Local<Script> script_define = v8_compile(
6716 "var desc = {get: function(){return 42; },"
6717 " configurable: true };"
6718 "Object.defineProperty(obj, 'x', desc);"
6719 "obj.x");
6720 result = script_define->Run(context.local()).ToLocalChecked();
6721 CHECK(result->Equals(context.local(), v8_num(42)).FromJust());
6722
6723 result = script_desc->Run(context.local()).ToLocalChecked();
6724 CHECK(result->BooleanValue(isolate));
6725
6726 script_define = v8_compile(
6727 "var desc = {get: function(){return 43; },"
6728 " configurable: false };"
6729 "Object.defineProperty(obj, 'x', desc);"
6730 "obj.x");
6731 result = script_define->Run(context.local()).ToLocalChecked();
6732 CHECK(result->Equals(context.local(), v8_num(43)).FromJust());
6733
6734 result = script_desc->Run(context.local()).ToLocalChecked();
6735 CHECK(!result->BooleanValue(isolate));
6736
6737 v8::TryCatch try_catch(isolate);
6738 CHECK(script_define->Run(context.local()).IsEmpty());
6739 CHECK(try_catch.HasCaught());
6740 String::Utf8Value exception_value(isolate, try_catch.Exception());
6741 CHECK_EQ(0,
6742 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6743}
6744
6745
6746static v8::Local<v8::Object> GetGlobalProperty(LocalContext* context,
6747 char const* name) {
6748 return v8::Local<v8::Object>::Cast(
6749 (*context)
6750 ->Global()
6751 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
6752 .ToLocalChecked());
6753}
6754
6755
6756THREADED_TEST(DefineAPIAccessorOnObject) {
6757 v8::Isolate* isolate = CcTest::isolate();
6758 v8::HandleScope scope(isolate);
6759 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6760 LocalContext context;
6761
6762 CHECK(context->Global()
6763 ->Set(context.local(), v8_str("obj1"),
6764 templ->NewInstance(context.local()).ToLocalChecked())
6765 .FromJust());
6766 CompileRun("var obj2 = {};");
6767
6768 CHECK(CompileRun("obj1.x")->IsUndefined());
6769 CHECK(CompileRun("obj2.x")->IsUndefined());
6770
6771 CHECK(GetGlobalProperty(&context, "obj1")
6772 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6773 v8_str("donut"))
6774 .FromJust());
6775
6776 ExpectString("obj1.x", "x");
6777 CHECK(CompileRun("obj2.x")->IsUndefined());
6778
6779 CHECK(GetGlobalProperty(&context, "obj2")
6780 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6781 v8_str("donut"))
6782 .FromJust());
6783
6784 ExpectString("obj1.x", "x");
6785 ExpectString("obj2.x", "x");
6786
6787 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6788 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6789
6790 CompileRun(
6791 "Object.defineProperty(obj1, 'x',"
6792 "{ get: function() { return 'y'; }, configurable: true })");
6793
6794 ExpectString("obj1.x", "y");
6795 ExpectString("obj2.x", "x");
6796
6797 CompileRun(
6798 "Object.defineProperty(obj2, 'x',"
6799 "{ get: function() { return 'y'; }, configurable: true })");
6800
6801 ExpectString("obj1.x", "y");
6802 ExpectString("obj2.x", "y");
6803
6804 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6805 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6806
6807 CHECK(GetGlobalProperty(&context, "obj1")
6808 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6809 v8_str("donut"))
6810 .FromJust());
6811 CHECK(GetGlobalProperty(&context, "obj2")
6812 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6813 v8_str("donut"))
6814 .FromJust());
6815
6816 ExpectString("obj1.x", "x");
6817 ExpectString("obj2.x", "x");
6818
6819 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6820 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6821
6822 // Define getters/setters, but now make them not configurable.
6823 CompileRun(
6824 "Object.defineProperty(obj1, 'x',"
6825 "{ get: function() { return 'z'; }, configurable: false })");
6826 CompileRun(
6827 "Object.defineProperty(obj2, 'x',"
6828 "{ get: function() { return 'z'; }, configurable: false })");
6829 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6830 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6831
6832 ExpectString("obj1.x", "z");
6833 ExpectString("obj2.x", "z");
6834
6835 CHECK(!GetGlobalProperty(&context, "obj1")
6836 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6837 v8_str("donut"))
6838 .FromJust());
6839 CHECK(!GetGlobalProperty(&context, "obj2")
6840 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6841 v8_str("donut"))
6842 .FromJust());
6843
6844 ExpectString("obj1.x", "z");
6845 ExpectString("obj2.x", "z");
6846}
6847
6848
6849THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6850 v8::Isolate* isolate = CcTest::isolate();
6851 v8::HandleScope scope(isolate);
6852 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6853 LocalContext context;
6854
6855 CHECK(context->Global()
6856 ->Set(context.local(), v8_str("obj1"),
6857 templ->NewInstance(context.local()).ToLocalChecked())
6858 .FromJust());
6859 CompileRun("var obj2 = {};");
6860
6861 CHECK(GetGlobalProperty(&context, "obj1")
6862 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6863 v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6864 .FromJust());
6865 CHECK(GetGlobalProperty(&context, "obj2")
6866 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6867 v8_str("donut"), v8::DEFAULT, v8::DontDelete)
6868 .FromJust());
6869
6870 ExpectString("obj1.x", "x");
6871 ExpectString("obj2.x", "x");
6872
6873 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6874 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6875
6876 CHECK(!GetGlobalProperty(&context, "obj1")
6877 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6878 v8_str("donut"))
6879 .FromJust());
6880 CHECK(!GetGlobalProperty(&context, "obj2")
6881 ->SetAccessor(context.local(), v8_str("x"), GetXValue, nullptr,
6882 v8_str("donut"))
6883 .FromJust());
6884
6885 {
6886 v8::TryCatch try_catch(isolate);
6887 CompileRun(
6888 "Object.defineProperty(obj1, 'x',"
6889 "{get: function() { return 'func'; }})");
6890 CHECK(try_catch.HasCaught());
6891 String::Utf8Value exception_value(isolate, try_catch.Exception());
6892 CHECK_EQ(
6893 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6894 }
6895 {
6896 v8::TryCatch try_catch(isolate);
6897 CompileRun(
6898 "Object.defineProperty(obj2, 'x',"
6899 "{get: function() { return 'func'; }})");
6900 CHECK(try_catch.HasCaught());
6901 String::Utf8Value exception_value(isolate, try_catch.Exception());
6902 CHECK_EQ(
6903 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
6904 }
6905}
6906
6907
6908static void Get239Value(Local<Name> name,
6909 const v8::PropertyCallbackInfo<v8::Value>& info) {
6910 ApiTestFuzzer::Fuzz();
6911 CHECK(info.Data()
6912 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("donut"))
6913 .FromJust());
6914 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("239"))
6915 .FromJust());
6916 info.GetReturnValue().Set(name);
6917}
6918
6919
6920THREADED_TEST(ElementAPIAccessor) {
6921 v8::Isolate* isolate = CcTest::isolate();
6922 v8::HandleScope scope(isolate);
6923 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6924 LocalContext context;
6925
6926 CHECK(context->Global()
6927 ->Set(context.local(), v8_str("obj1"),
6928 templ->NewInstance(context.local()).ToLocalChecked())
6929 .FromJust());
6930 CompileRun("var obj2 = {};");
6931
6932 CHECK(GetGlobalProperty(&context, "obj1")
6933 ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6934 v8_str("donut"))
6935 .FromJust());
6936 CHECK(GetGlobalProperty(&context, "obj2")
6937 ->SetAccessor(context.local(), v8_str("239"), Get239Value, nullptr,
6938 v8_str("donut"))
6939 .FromJust());
6940
6941 ExpectString("obj1[239]", "239");
6942 ExpectString("obj2[239]", "239");
6943 ExpectString("obj1['239']", "239");
6944 ExpectString("obj2['239']", "239");
6945}
6946
6947
6948v8::Persistent<Value> xValue;
6949
6950
6951static void SetXValue(Local<Name> name, Local<Value> value,
6952 const v8::PropertyCallbackInfo<void>& info) {
6953 Local<Context> context = info.GetIsolate()->GetCurrentContext();
6954 CHECK(value->Equals(context, v8_num(4)).FromJust());
6955 CHECK(info.Data()->Equals(context, v8_str("donut")).FromJust());
6956 CHECK(name->Equals(context, v8_str("x")).FromJust());
6957 CHECK(xValue.IsEmpty());
6958 xValue.Reset(info.GetIsolate(), value);
6959}
6960
6961
6962THREADED_TEST(SimplePropertyWrite) {
6963 v8::Isolate* isolate = CcTest::isolate();
6964 v8::HandleScope scope(isolate);
6965 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6966 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6967 LocalContext context;
6968 CHECK(context->Global()
6969 ->Set(context.local(), v8_str("obj"),
6970 templ->NewInstance(context.local()).ToLocalChecked())
6971 .FromJust());
6972 Local<Script> script = v8_compile("obj.x = 4");
6973 for (int i = 0; i < 10; i++) {
6974 CHECK(xValue.IsEmpty());
6975 script->Run(context.local()).ToLocalChecked();
6976 CHECK(v8_num(4)
6977 ->Equals(context.local(),
6978 Local<Value>::New(CcTest::isolate(), xValue))
6979 .FromJust());
6980 xValue.Reset();
6981 }
6982}
6983
6984
6985THREADED_TEST(SetterOnly) {
6986 v8::Isolate* isolate = CcTest::isolate();
6987 v8::HandleScope scope(isolate);
6988 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6989 templ->SetAccessor(v8_str("x"), nullptr, SetXValue, v8_str("donut"));
6990 LocalContext context;
6991 CHECK(context->Global()
6992 ->Set(context.local(), v8_str("obj"),
6993 templ->NewInstance(context.local()).ToLocalChecked())
6994 .FromJust());
6995 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6996 for (int i = 0; i < 10; i++) {
6997 CHECK(xValue.IsEmpty());
6998 script->Run(context.local()).ToLocalChecked();
6999 CHECK(v8_num(4)
7000 ->Equals(context.local(),
7001 Local<Value>::New(CcTest::isolate(), xValue))
7002 .FromJust());
7003 xValue.Reset();
7004 }
7005}
7006
7007
7008THREADED_TEST(NoAccessors) {
7009 v8::Isolate* isolate = CcTest::isolate();
7010 v8::HandleScope scope(isolate);
7011 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7012 templ->SetAccessor(v8_str("x"),
7013 static_cast<v8::AccessorGetterCallback>(nullptr), nullptr,
7014 v8_str("donut"));
7015 LocalContext context;
7016 CHECK(context->Global()
7017 ->Set(context.local(), v8_str("obj"),
7018 templ->NewInstance(context.local()).ToLocalChecked())
7019 .FromJust());
7020 Local<Script> script = v8_compile("obj.x = 4; obj.x");
7021 for (int i = 0; i < 10; i++) {
7022 script->Run(context.local()).ToLocalChecked();
7023 }
7024}
7025
7026
7027THREADED_TEST(MultiContexts) {
7028 v8::Isolate* isolate = CcTest::isolate();
7029 v8::HandleScope scope(isolate);
7030 v8::Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7031 templ->Set(v8_str("dummy"),
7032 v8::FunctionTemplate::New(isolate, DummyCallHandler));
7033
7034 Local<String> password = v8_str("Password");
7035
7036 // Create an environment
7037 LocalContext context0(nullptr, templ);
7038 context0->SetSecurityToken(password);
7039 v8::Local<v8::Object> global0 = context0->Global();
7040 CHECK(global0->Set(context0.local(), v8_str("custom"), v8_num(1234))
7041 .FromJust());
7042 CHECK_EQ(1234, global0->Get(context0.local(), v8_str("custom"))
7043 .ToLocalChecked()
7044 ->Int32Value(context0.local())
7045 .FromJust());
7046
7047 // Create an independent environment
7048 LocalContext context1(nullptr, templ);
7049 context1->SetSecurityToken(password);
7050 v8::Local<v8::Object> global1 = context1->Global();
7051 CHECK(global1->Set(context1.local(), v8_str("custom"), v8_num(1234))
7052 .FromJust());
7053 CHECK(!global0->Equals(context1.local(), global1).FromJust());
7054 CHECK_EQ(1234, global0->Get(context1.local(), v8_str("custom"))
7055 .ToLocalChecked()
7056 ->Int32Value(context0.local())
7057 .FromJust());
7058 CHECK_EQ(1234, global1->Get(context1.local(), v8_str("custom"))
7059 .ToLocalChecked()
7060 ->Int32Value(context1.local())
7061 .FromJust());
7062
7063 // Now create a new context with the old global
7064 LocalContext context2(nullptr, templ, global1);
7065 context2->SetSecurityToken(password);
7066 v8::Local<v8::Object> global2 = context2->Global();
7067 CHECK(global1->Equals(context2.local(), global2).FromJust());
7068 CHECK_EQ(0, global1->Get(context2.local(), v8_str("custom"))
7069 .ToLocalChecked()
7070 ->Int32Value(context1.local())
7071 .FromJust());
7072 CHECK_EQ(0, global2->Get(context2.local(), v8_str("custom"))
7073 .ToLocalChecked()
7074 ->Int32Value(context2.local())
7075 .FromJust());
7076}
7077
7078
7079THREADED_TEST(FunctionPrototypeAcrossContexts) {
7080 // Make sure that functions created by cloning boilerplates cannot
7081 // communicate through their __proto__ field.
7082
7083 v8::HandleScope scope(CcTest::isolate());
7084
7085 LocalContext env0;
7086 v8::Local<v8::Object> global0 = env0->Global();
7087 v8::Local<v8::Object> object0 = global0->Get(env0.local(), v8_str("Object"))
7088 .ToLocalChecked()
7089 .As<v8::Object>();
7090 v8::Local<v8::Object> tostring0 =
7091 object0->Get(env0.local(), v8_str("toString"))
7092 .ToLocalChecked()
7093 .As<v8::Object>();
7094 v8::Local<v8::Object> proto0 =
7095 tostring0->Get(env0.local(), v8_str("__proto__"))
7096 .ToLocalChecked()
7097 .As<v8::Object>();
7098 CHECK(proto0->Set(env0.local(), v8_str("custom"), v8_num(1234)).FromJust());
7099
7100 LocalContext env1;
7101 v8::Local<v8::Object> global1 = env1->Global();
7102 v8::Local<v8::Object> object1 = global1->Get(env1.local(), v8_str("Object"))
7103 .ToLocalChecked()
7104 .As<v8::Object>();
7105 v8::Local<v8::Object> tostring1 =
7106 object1->Get(env1.local(), v8_str("toString"))
7107 .ToLocalChecked()
7108 .As<v8::Object>();
7109 v8::Local<v8::Object> proto1 =
7110 tostring1->Get(env1.local(), v8_str("__proto__"))
7111 .ToLocalChecked()
7112 .As<v8::Object>();
7113 CHECK(!proto1->Has(env1.local(), v8_str("custom")).FromJust());
7114}
7115
7116
7117THREADED_TEST(Regress892105) {
7118 // Make sure that object and array literals created by cloning
7119 // boilerplates cannot communicate through their __proto__
7120 // field. This is rather difficult to check, but we try to add stuff
7121 // to Object.prototype and Array.prototype and create a new
7122 // environment. This should succeed.
7123
7124 v8::HandleScope scope(CcTest::isolate());
7125
7126 Local<String> source = v8_str(
7127 "Object.prototype.obj = 1234;"
7128 "Array.prototype.arr = 4567;"
7129 "8901");
7130
7131 LocalContext env0;
7132 Local<Script> script0 = v8_compile(source);
7133 CHECK_EQ(8901.0, script0->Run(env0.local())
7134 .ToLocalChecked()
7135 ->NumberValue(env0.local())
7136 .FromJust());
7137
7138 LocalContext env1;
7139 Local<Script> script1 = v8_compile(source);
7140 CHECK_EQ(8901.0, script1->Run(env1.local())
7141 .ToLocalChecked()
7142 ->NumberValue(env1.local())
7143 .FromJust());
7144}
7145
7146static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
7147 args.GetReturnValue().Set(args.This());
7148}
7149
7150THREADED_TEST(UndetectableObject) {
7151 LocalContext env;
7152 v8::HandleScope scope(env->GetIsolate());
7153
7154 Local<v8::FunctionTemplate> desc =
7155 v8::FunctionTemplate::New(env->GetIsolate());
7156 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7157 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7158
7159 Local<v8::Object> obj = desc->GetFunction(env.local())
7160 .ToLocalChecked()
7161 ->NewInstance(env.local())
7162 .ToLocalChecked();
7163 CHECK(
7164 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7165
7166 ExpectString("undetectable.toString()", "[object Object]");
7167 ExpectString("typeof undetectable", "undefined");
7168 ExpectString("typeof(undetectable)", "undefined");
7169 ExpectBoolean("typeof undetectable == 'undefined'", true);
7170 ExpectBoolean("typeof undetectable == 'object'", false);
7171 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7172 ExpectBoolean("!undetectable", true);
7173
7174 ExpectObject("true&&undetectable", obj);
7175 ExpectBoolean("false&&undetectable", false);
7176 ExpectBoolean("true||undetectable", true);
7177 ExpectObject("false||undetectable", obj);
7178
7179 ExpectObject("undetectable&&true", obj);
7180 ExpectObject("undetectable&&false", obj);
7181 ExpectBoolean("undetectable||true", true);
7182 ExpectBoolean("undetectable||false", false);
7183
7184 ExpectBoolean("undetectable==null", true);
7185 ExpectBoolean("null==undetectable", true);
7186 ExpectBoolean("undetectable==undefined", true);
7187 ExpectBoolean("undefined==undetectable", true);
7188 ExpectBoolean("undetectable==undetectable", true);
7189
7190
7191 ExpectBoolean("undetectable===null", false);
7192 ExpectBoolean("null===undetectable", false);
7193 ExpectBoolean("undetectable===undefined", false);
7194 ExpectBoolean("undefined===undetectable", false);
7195 ExpectBoolean("undetectable===undetectable", true);
7196}
7197
7198
7199THREADED_TEST(VoidLiteral) {
7200 LocalContext env;
7201 v8::Isolate* isolate = env->GetIsolate();
7202 v8::HandleScope scope(isolate);
7203
7204 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7205 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7206 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7207
7208 Local<v8::Object> obj = desc->GetFunction(env.local())
7209 .ToLocalChecked()
7210 ->NewInstance(env.local())
7211 .ToLocalChecked();
7212 CHECK(
7213 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7214
7215 ExpectBoolean("undefined == void 0", true);
7216 ExpectBoolean("undetectable == void 0", true);
7217 ExpectBoolean("null == void 0", true);
7218 ExpectBoolean("undefined === void 0", true);
7219 ExpectBoolean("undetectable === void 0", false);
7220 ExpectBoolean("null === void 0", false);
7221
7222 ExpectBoolean("void 0 == undefined", true);
7223 ExpectBoolean("void 0 == undetectable", true);
7224 ExpectBoolean("void 0 == null", true);
7225 ExpectBoolean("void 0 === undefined", true);
7226 ExpectBoolean("void 0 === undetectable", false);
7227 ExpectBoolean("void 0 === null", false);
7228
7229 ExpectString(
7230 "(function() {"
7231 " try {"
7232 " return x === void 0;"
7233 " } catch(e) {"
7234 " return e.toString();"
7235 " }"
7236 "})()",
7237 "ReferenceError: x is not defined");
7238 ExpectString(
7239 "(function() {"
7240 " try {"
7241 " return void 0 === x;"
7242 " } catch(e) {"
7243 " return e.toString();"
7244 " }"
7245 "})()",
7246 "ReferenceError: x is not defined");
7247}
7248
7249
7250THREADED_TEST(ExtensibleOnUndetectable) {
7251 LocalContext env;
7252 v8::Isolate* isolate = env->GetIsolate();
7253 v8::HandleScope scope(isolate);
7254
7255 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7256 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7257 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7258
7259 Local<v8::Object> obj = desc->GetFunction(env.local())
7260 .ToLocalChecked()
7261 ->NewInstance(env.local())
7262 .ToLocalChecked();
7263 CHECK(
7264 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7265
7266 Local<String> source = v8_str(
7267 "undetectable.x = 42;"
7268 "undetectable.x");
7269
7270 Local<Script> script = v8_compile(source);
7271
7272 CHECK(v8::Integer::New(isolate, 42)
7273 ->Equals(env.local(), script->Run(env.local()).ToLocalChecked())
7274 .FromJust());
7275
7276 ExpectBoolean("Object.isExtensible(undetectable)", true);
7277
7278 source = v8_str("Object.preventExtensions(undetectable);");
7279 script = v8_compile(source);
7280 script->Run(env.local()).ToLocalChecked();
7281 ExpectBoolean("Object.isExtensible(undetectable)", false);
7282
7283 source = v8_str("undetectable.y = 2000;");
7284 script = v8_compile(source);
7285 script->Run(env.local()).ToLocalChecked();
7286 ExpectBoolean("undetectable.y == undefined", true);
7287}
7288
7289THREADED_TEST(ConstructCallWithUndetectable) {
7290 LocalContext env;
7291 v8::Isolate* isolate = env->GetIsolate();
7292 v8::HandleScope scope(isolate);
7293
7294 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7295 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7296 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
7297
7298 Local<v8::Object> obj = desc->GetFunction(env.local())
7299 .ToLocalChecked()
7300 ->NewInstance(env.local())
7301 .ToLocalChecked();
7302 CHECK(
7303 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
7304
7305 // Undetectable object cannot be called as constructor.
7306 v8::TryCatch try_catch(env->GetIsolate());
7307 CHECK(CompileRun("new undetectable()").IsEmpty());
7308 CHECK(try_catch.HasCaught());
7309 String::Utf8Value exception_value(env->GetIsolate(), try_catch.Exception());
7310 CHECK_EQ(0, strcmp("TypeError: undetectable is not a constructor",
7311 *exception_value));
7312}
7313
7314static int increment_callback_counter = 0;
7315
7316static void IncrementCounterConstructCallback(
7317 const v8::FunctionCallbackInfo<v8::Value>& args) {
7318 increment_callback_counter++;
7319 CHECK(Local<Object>::Cast(args.NewTarget())
7320 ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("counter"),
7321 v8_num(increment_callback_counter))
7322 .FromJust());
7323 args.GetReturnValue().Set(args.NewTarget());
7324}
7325
7326THREADED_TEST(SetCallAsFunctionHandlerConstructor) {
7327 LocalContext env;
7328 v8::Isolate* isolate = env->GetIsolate();
7329 v8::HandleScope scope(isolate);
7330
7331 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7332 desc->InstanceTemplate()->SetCallAsFunctionHandler(
7333 IncrementCounterConstructCallback); // callable
7334
7335 Local<v8::Object> obj = desc->GetFunction(env.local())
7336 .ToLocalChecked()
7337 ->NewInstance(env.local())
7338 .ToLocalChecked();
7339 CHECK(env->Global()->Set(env.local(), v8_str("Counter"), obj).FromJust());
7340
7341 ExpectInt32("(new Counter()).counter", 1);
7342 CHECK_EQ(1, increment_callback_counter);
7343 ExpectInt32("(new Counter()).counter", 2);
7344 CHECK_EQ(2, increment_callback_counter);
7345}
7346// The point of this test is type checking. We run it only so compilers
7347// don't complain about an unused function.
7348TEST(PersistentHandles) {
7349 LocalContext env;
7350 v8::Isolate* isolate = CcTest::isolate();
7351 v8::HandleScope scope(isolate);
7352 Local<String> str = v8_str("foo");
7353 v8::Persistent<String> p_str(isolate, str);
7354 p_str.Reset();
7355 Local<Script> scr = v8_compile("");
7356 v8::Persistent<Script> p_scr(isolate, scr);
7357 p_scr.Reset();
7358 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7359 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7360 p_templ.Reset();
7361}
7362
7363
7364static void HandleLogDelegator(
7365 const v8::FunctionCallbackInfo<v8::Value>& args) {
7366 ApiTestFuzzer::Fuzz();
7367}
7368
7369
7370THREADED_TEST(GlobalObjectTemplate) {
7371 v8::Isolate* isolate = CcTest::isolate();
7372 v8::HandleScope handle_scope(isolate);
7373 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7374 global_template->Set(v8_str("JSNI_Log"),
7375 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7376 v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
7377 Context::Scope context_scope(context);
7378 CompileRun("JSNI_Log('LOG')");
7379}
7380
7381
7382static const char* kSimpleExtensionSource =
7383 "function Foo() {"
7384 " return 4;"
7385 "}";
7386
7387
7388TEST(SimpleExtensions) {
7389 v8::HandleScope handle_scope(CcTest::isolate());
7390 v8::RegisterExtension(
7391 v8::base::make_unique<Extension>("simpletest", kSimpleExtensionSource));
7392 const char* extension_names[] = {"simpletest"};
7393 v8::ExtensionConfiguration extensions(1, extension_names);
7394 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7395 Context::Scope lock(context);
7396 v8::Local<Value> result = CompileRun("Foo()");
7397 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7398 .FromJust());
7399}
7400
7401
7402static const char* kStackTraceFromExtensionSource =
7403 "function foo() {"
7404 " throw new Error();"
7405 "}"
7406 "function bar() {"
7407 " foo();"
7408 "}";
7409
7410
7411TEST(StackTraceInExtension) {
7412 v8::HandleScope handle_scope(CcTest::isolate());
7413 v8::RegisterExtension(v8::base::make_unique<Extension>(
7414 "stacktracetest", kStackTraceFromExtensionSource));
7415 const char* extension_names[] = {"stacktracetest"};
7416 v8::ExtensionConfiguration extensions(1, extension_names);
7417 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7418 Context::Scope lock(context);
7419 CompileRun(
7420 "function user() { bar(); }"
7421 "var error;"
7422 "try{ user(); } catch (e) { error = e; }");
7423 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('foo')")));
7424 CHECK_EQ(-1, v8_run_int32value(v8_compile("error.stack.indexOf('bar')")));
7425 CHECK_NE(-1, v8_run_int32value(v8_compile("error.stack.indexOf('user')")));
7426}
7427
7428
7429TEST(NullExtensions) {
7430 v8::HandleScope handle_scope(CcTest::isolate());
7431 v8::RegisterExtension(v8::base::make_unique<Extension>("nulltest", nullptr));
7432 const char* extension_names[] = {"nulltest"};
7433 v8::ExtensionConfiguration extensions(1, extension_names);
7434 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7435 Context::Scope lock(context);
7436 v8::Local<Value> result = CompileRun("1+3");
7437 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7438 .FromJust());
7439}
7440
7441static const char* kEmbeddedExtensionSource =
7442 "function Ret54321(){return 54321;}~~@@$"
7443 "$%% THIS IS A SERIES OF NON-nullptr-TERMINATED STRINGS.";
7444static const int kEmbeddedExtensionSourceValidLen = 34;
7445
7446
7447TEST(ExtensionMissingSourceLength) {
7448 v8::HandleScope handle_scope(CcTest::isolate());
7449 v8::RegisterExtension(v8::base::make_unique<Extension>(
7450 "srclentest_fail", kEmbeddedExtensionSource));
7451 const char* extension_names[] = {"srclentest_fail"};
7452 v8::ExtensionConfiguration extensions(1, extension_names);
7453 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7454 CHECK_NULL(*context);
7455}
7456
7457
7458TEST(ExtensionWithSourceLength) {
7459 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7460 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7461 v8::HandleScope handle_scope(CcTest::isolate());
7462 i::ScopedVector<char> extension_name(32);
7463 i::SNPrintF(extension_name, "ext #%d", source_len);
7464 v8::RegisterExtension(v8::base::make_unique<Extension>(
7465 extension_name.start(), kEmbeddedExtensionSource, 0, nullptr,
7466 source_len));
7467 const char* extension_names[1] = {extension_name.start()};
7468 v8::ExtensionConfiguration extensions(1, extension_names);
7469 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7470 if (source_len == kEmbeddedExtensionSourceValidLen) {
7471 Context::Scope lock(context);
7472 v8::Local<Value> result = CompileRun("Ret54321()");
7473 CHECK(v8::Integer::New(CcTest::isolate(), 54321)
7474 ->Equals(context, result)
7475 .FromJust());
7476 } else {
7477 // Anything but exactly the right length should fail to compile.
7478 CHECK_NULL(*context);
7479 }
7480 }
7481}
7482
7483
7484static const char* kEvalExtensionSource1 =
7485 "function UseEval1() {"
7486 " var x = 42;"
7487 " return eval('x');"
7488 "}";
7489
7490
7491static const char* kEvalExtensionSource2 =
7492 "(function() {"
7493 " var x = 42;"
7494 " function e() {"
7495 " return eval('x');"
7496 " }"
7497 " this.UseEval2 = e;"
7498 "})()";
7499
7500
7501TEST(UseEvalFromExtension) {
7502 v8::HandleScope handle_scope(CcTest::isolate());
7503 v8::RegisterExtension(
7504 v8::base::make_unique<Extension>("evaltest1", kEvalExtensionSource1));
7505 v8::RegisterExtension(
7506 v8::base::make_unique<Extension>("evaltest2", kEvalExtensionSource2));
7507 const char* extension_names[] = {"evaltest1", "evaltest2"};
7508 v8::ExtensionConfiguration extensions(2, extension_names);
7509 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7510 Context::Scope lock(context);
7511 v8::Local<Value> result = CompileRun("UseEval1()");
7512 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7513 .FromJust());
7514 result = CompileRun("UseEval2()");
7515 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7516 .FromJust());
7517}
7518
7519
7520static const char* kWithExtensionSource1 =
7521 "function UseWith1() {"
7522 " var x = 42;"
7523 " with({x:87}) { return x; }"
7524 "}";
7525
7526
7527static const char* kWithExtensionSource2 =
7528 "(function() {"
7529 " var x = 42;"
7530 " function e() {"
7531 " with ({x:87}) { return x; }"
7532 " }"
7533 " this.UseWith2 = e;"
7534 "})()";
7535
7536
7537TEST(UseWithFromExtension) {
7538 v8::HandleScope handle_scope(CcTest::isolate());
7539 v8::RegisterExtension(
7540 v8::base::make_unique<Extension>("withtest1", kWithExtensionSource1));
7541 v8::RegisterExtension(
7542 v8::base::make_unique<Extension>("withtest2", kWithExtensionSource2));
7543 const char* extension_names[] = {"withtest1", "withtest2"};
7544 v8::ExtensionConfiguration extensions(2, extension_names);
7545 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7546 Context::Scope lock(context);
7547 v8::Local<Value> result = CompileRun("UseWith1()");
7548 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7549 .FromJust());
7550 result = CompileRun("UseWith2()");
7551 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 87))
7552 .FromJust());
7553}
7554
7555
7556TEST(AutoExtensions) {
7557 v8::HandleScope handle_scope(CcTest::isolate());
7558 auto extension =
7559 v8::base::make_unique<Extension>("autotest", kSimpleExtensionSource);
7560 extension->set_auto_enable(true);
7561 v8::RegisterExtension(std::move(extension));
7562 v8::Local<Context> context = Context::New(CcTest::isolate());
7563 Context::Scope lock(context);
7564 v8::Local<Value> result = CompileRun("Foo()");
7565 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 4))
7566 .FromJust());
7567}
7568
7569
7570static const char* kSyntaxErrorInExtensionSource = "[";
7571
7572
7573// Test that a syntax error in an extension does not cause a fatal
7574// error but results in an empty context.
7575TEST(SyntaxErrorExtensions) {
7576 v8::HandleScope handle_scope(CcTest::isolate());
7577 v8::RegisterExtension(v8::base::make_unique<Extension>(
7578 "syntaxerror", kSyntaxErrorInExtensionSource));
7579 const char* extension_names[] = {"syntaxerror"};
7580 v8::ExtensionConfiguration extensions(1, extension_names);
7581 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7582 CHECK(context.IsEmpty());
7583}
7584
7585
7586static const char* kExceptionInExtensionSource = "throw 42";
7587
7588
7589// Test that an exception when installing an extension does not cause
7590// a fatal error but results in an empty context.
7591TEST(ExceptionExtensions) {
7592 v8::HandleScope handle_scope(CcTest::isolate());
7593 v8::RegisterExtension(v8::base::make_unique<Extension>(
7594 "exception", kExceptionInExtensionSource));
7595 const char* extension_names[] = {"exception"};
7596 v8::ExtensionConfiguration extensions(1, extension_names);
7597 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7598 CHECK(context.IsEmpty());
7599}
7600
7601static const char* kNativeCallInExtensionSource =
7602 "function call_runtime_last_index_of(x) {"
7603 " return %StringLastIndexOf(x, 'bob');"
7604 "}";
7605
7606static const char* kNativeCallTest =
7607 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7608
7609// Test that a native runtime calls are supported in extensions.
7610TEST(NativeCallInExtensions) {
7611 v8::HandleScope handle_scope(CcTest::isolate());
7612 v8::RegisterExtension(v8::base::make_unique<Extension>(
7613 "nativecall", kNativeCallInExtensionSource));
7614 const char* extension_names[] = {"nativecall"};
7615 v8::ExtensionConfiguration extensions(1, extension_names);
7616 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7617 Context::Scope lock(context);
7618 v8::Local<Value> result = CompileRun(kNativeCallTest);
7619 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 24))
7620 .FromJust());
7621}
7622
7623
7624class NativeFunctionExtension : public Extension {
7625 public:
7626 NativeFunctionExtension(const char* name, const char* source,
7627 v8::FunctionCallback fun = &Echo)
7628 : Extension(name, source), function_(fun) {}
7629
7630 v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7631 v8::Isolate* isolate, v8::Local<v8::String> name) override {
7632 return v8::FunctionTemplate::New(isolate, function_);
7633 }
7634
7635 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7636 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7637 }
7638
7639 private:
7640 v8::FunctionCallback function_;
7641};
7642
7643
7644TEST(NativeFunctionDeclaration) {
7645 v8::HandleScope handle_scope(CcTest::isolate());
7646 const char* name = "nativedecl";
7647 v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7648 name, "native function foo();"));
7649 const char* extension_names[] = {name};
7650 v8::ExtensionConfiguration extensions(1, extension_names);
7651 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7652 Context::Scope lock(context);
7653 v8::Local<Value> result = CompileRun("foo(42);");
7654 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 42))
7655 .FromJust());
7656}
7657
7658
7659TEST(NativeFunctionDeclarationError) {
7660 v8::HandleScope handle_scope(CcTest::isolate());
7661 const char* name = "nativedeclerr";
7662 // Syntax error in extension code.
7663 v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7664 name, "native\nfunction foo();"));
7665 const char* extension_names[] = {name};
7666 v8::ExtensionConfiguration extensions(1, extension_names);
7667 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7668 CHECK(context.IsEmpty());
7669}
7670
7671
7672TEST(NativeFunctionDeclarationErrorEscape) {
7673 v8::HandleScope handle_scope(CcTest::isolate());
7674 const char* name = "nativedeclerresc";
7675 // Syntax error in extension code - escape code in "native" means that
7676 // it's not treated as a keyword.
7677 v8::RegisterExtension(v8::base::make_unique<NativeFunctionExtension>(
7678 name, "nativ\\u0065 function foo();"));
7679 const char* extension_names[] = {name};
7680 v8::ExtensionConfiguration extensions(1, extension_names);
7681 v8::Local<Context> context = Context::New(CcTest::isolate(), &extensions);
7682 CHECK(context.IsEmpty());
7683}
7684
7685
7686static void CheckDependencies(const char* name, const char* expected) {
7687 v8::HandleScope handle_scope(CcTest::isolate());
7688 v8::ExtensionConfiguration config(1, &name);
7689 LocalContext context(&config);
7690 CHECK(
7691 v8_str(expected)
7692 ->Equals(context.local(), context->Global()
7693 ->Get(context.local(), v8_str("loaded"))
7694 .ToLocalChecked())
7695 .FromJust());
7696}
7697
7698
7699/*
7700 * Configuration:
7701 *
7702 * /-- B <--\
7703 * A <- -- D <-- E
7704 * \-- C <--/
7705 */
7706THREADED_TEST(ExtensionDependency) {
7707 static const char* kEDeps[] = {"D"};
7708 v8::RegisterExtension(
7709 v8::base::make_unique<Extension>("E", "this.loaded += 'E';", 1, kEDeps));
7710 static const char* kDDeps[] = {"B", "C"};
7711 v8::RegisterExtension(
7712 v8::base::make_unique<Extension>("D", "this.loaded += 'D';", 2, kDDeps));
7713 static const char* kBCDeps[] = {"A"};
7714 v8::RegisterExtension(
7715 v8::base::make_unique<Extension>("B", "this.loaded += 'B';", 1, kBCDeps));
7716 v8::RegisterExtension(
7717 v8::base::make_unique<Extension>("C", "this.loaded += 'C';", 1, kBCDeps));
7718 v8::RegisterExtension(
7719 v8::base::make_unique<Extension>("A", "this.loaded += 'A';"));
7720 CheckDependencies("A", "undefinedA");
7721 CheckDependencies("B", "undefinedAB");
7722 CheckDependencies("C", "undefinedAC");
7723 CheckDependencies("D", "undefinedABCD");
7724 CheckDependencies("E", "undefinedABCDE");
7725 v8::HandleScope handle_scope(CcTest::isolate());
7726 static const char* exts[2] = {"C", "E"};
7727 v8::ExtensionConfiguration config(2, exts);
7728 LocalContext context(&config);
7729 CHECK(
7730 v8_str("undefinedACBDE")
7731 ->Equals(context.local(), context->Global()
7732 ->Get(context.local(), v8_str("loaded"))
7733 .ToLocalChecked())
7734 .FromJust());
7735}
7736
7737
7738static const char* kExtensionTestScript =
7739 "native function A();"
7740 "native function B();"
7741 "native function C();"
7742 "function Foo(i) {"
7743 " if (i == 0) return A();"
7744 " if (i == 1) return B();"
7745 " if (i == 2) return C();"
7746 "}";
7747
7748
7749static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7750 ApiTestFuzzer::Fuzz();
7751 if (args.IsConstructCall()) {
7752 CHECK(args.This()
7753 ->Set(args.GetIsolate()->GetCurrentContext(), v8_str("data"),
7754 args.Data())
7755 .FromJust());
7756 args.GetReturnValue().SetNull();
7757 return;
7758 }
7759 args.GetReturnValue().Set(args.Data());
7760}
7761
7762
7763class FunctionExtension : public Extension {
7764 public:
7765 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
7766 v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
7767 v8::Isolate* isolate, v8::Local<String> name) override;
7768};
7769
7770
7771static int lookup_count = 0;
7772v8::Local<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7773 v8::Isolate* isolate, v8::Local<String> name) {
7774 lookup_count++;
7775 if (name->StrictEquals(v8_str("A"))) {
7776 return v8::FunctionTemplate::New(isolate, CallFun,
7777 v8::Integer::New(isolate, 8));
7778 } else if (name->StrictEquals(v8_str("B"))) {
7779 return v8::FunctionTemplate::New(isolate, CallFun,
7780 v8::Integer::New(isolate, 7));
7781 } else if (name->StrictEquals(v8_str("C"))) {
7782 return v8::FunctionTemplate::New(isolate, CallFun,
7783 v8::Integer::New(isolate, 6));
7784 } else {
7785 return v8::Local<v8::FunctionTemplate>();
7786 }
7787}
7788
7789
7790THREADED_TEST(FunctionLookup) {
7791 v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7792 v8::HandleScope handle_scope(CcTest::isolate());
7793 static const char* exts[1] = {"functiontest"};
7794 v8::ExtensionConfiguration config(1, exts);
7795 LocalContext context(&config);
7796 CHECK_EQ(3, lookup_count);
7797 CHECK(v8::Integer::New(CcTest::isolate(), 8)
7798 ->Equals(context.local(), CompileRun("Foo(0)"))
7799 .FromJust());
7800 CHECK(v8::Integer::New(CcTest::isolate(), 7)
7801 ->Equals(context.local(), CompileRun("Foo(1)"))
7802 .FromJust());
7803 CHECK(v8::Integer::New(CcTest::isolate(), 6)
7804 ->Equals(context.local(), CompileRun("Foo(2)"))
7805 .FromJust());
7806}
7807
7808
7809THREADED_TEST(NativeFunctionConstructCall) {
7810 v8::RegisterExtension(v8::base::make_unique<FunctionExtension>());
7811 v8::HandleScope handle_scope(CcTest::isolate());
7812 static const char* exts[1] = {"functiontest"};
7813 v8::ExtensionConfiguration config(1, exts);
7814 LocalContext context(&config);
7815 for (int i = 0; i < 10; i++) {
7816 // Run a few times to ensure that allocation of objects doesn't
7817 // change behavior of a constructor function.
7818 CHECK(v8::Integer::New(CcTest::isolate(), 8)
7819 ->Equals(context.local(), CompileRun("(new A()).data"))
7820 .FromJust());
7821 CHECK(v8::Integer::New(CcTest::isolate(), 7)
7822 ->Equals(context.local(), CompileRun("(new B()).data"))
7823 .FromJust());
7824 CHECK(v8::Integer::New(CcTest::isolate(), 6)
7825 ->Equals(context.local(), CompileRun("(new C()).data"))
7826 .FromJust());
7827 }
7828}
7829
7830
7831static const char* last_location;
7832static const char* last_message;
7833void StoringErrorCallback(const char* location, const char* message) {
7834 if (last_location == nullptr) {
7835 last_location = location;
7836 last_message = message;
7837 }
7838}
7839
7840
7841// ErrorReporting creates a circular extensions configuration and
7842// tests that the fatal error handler gets called. This renders V8
7843// unusable and therefore this test cannot be run in parallel.
7844TEST(ErrorReporting) {
7845 CcTest::isolate()->SetFatalErrorHandler(StoringErrorCallback);
7846 static const char* aDeps[] = {"B"};
7847 v8::RegisterExtension(v8::base::make_unique<Extension>("A", "", 1, aDeps));
7848 static const char* bDeps[] = {"A"};
7849 v8::RegisterExtension(v8::base::make_unique<Extension>("B", "", 1, bDeps));
7850 last_location = nullptr;
7851 v8::ExtensionConfiguration config(1, bDeps);
7852 v8::Local<Context> context = Context::New(CcTest::isolate(), &config);
7853 CHECK(context.IsEmpty());
7854 CHECK(last_location);
7855}
7856
7857static size_t dcheck_count;
7858void DcheckErrorCallback(const char* file, int line, const char* message) {
7859 last_message = message;
7860 ++dcheck_count;
7861}
7862
7863TEST(DcheckErrorHandler) {
7864 V8::SetDcheckErrorHandler(DcheckErrorCallback);
7865
7866 last_message = nullptr;
7867 dcheck_count = 0;
7868
7869 DCHECK(false && "w00t");
7870#ifdef DEBUG
7871 CHECK_EQ(dcheck_count, 1);
7872 CHECK(last_message);
7873 CHECK(std::string(last_message).find("w00t") != std::string::npos);
7874#else
7875 // The DCHECK should be a noop in non-DEBUG builds.
7876 CHECK_EQ(dcheck_count, 0);
7877#endif
7878}
7879
7880static void MissingScriptInfoMessageListener(v8::Local<v8::Message> message,
7881 v8::Local<Value> data) {
7882 v8::Isolate* isolate = CcTest::isolate();
7883 Local<Context> context = isolate->GetCurrentContext();
7884 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7885 CHECK(v8::Undefined(isolate)
7886 ->Equals(context, message->GetScriptOrigin().ResourceName())
7887 .FromJust());
7888 message->GetLineNumber(context).FromJust();
7889 message->GetSourceLine(context).ToLocalChecked();
7890}
7891
7892
7893THREADED_TEST(ErrorWithMissingScriptInfo) {
7894 LocalContext context;
7895 v8::HandleScope scope(context->GetIsolate());
7896 context->GetIsolate()->AddMessageListener(MissingScriptInfoMessageListener);
7897 CompileRun("throw Error()");
7898 context->GetIsolate()->RemoveMessageListeners(
7899 MissingScriptInfoMessageListener);
7900}
7901
7902
7903struct FlagAndPersistent {
7904 bool flag;
7905 v8::Global<v8::Object> handle;
7906};
7907
7908static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
7909 data.GetParameter()->flag = true;
7910 data.GetParameter()->handle.Reset();
7911}
7912
7913static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7914 i::FLAG_stress_incremental_marking = false;
7915 // Parallel scavenge introduces too much fragmentation.
7916 i::FLAG_parallel_scavenge = false;
7917 v8::Isolate* iso = CcTest::isolate();
7918 v8::HandleScope scope(iso);
7919 v8::Local<Context> context = Context::New(iso);
7920 Context::Scope context_scope(context);
7921
7922 FlagAndPersistent object_a, object_b;
7923
7924 size_t big_heap_size = 0;
7925 size_t big_array_size = 0;
7926
7927 {
7928 v8::HandleScope handle_scope(iso);
7929 Local<Object> a(v8::Object::New(iso));
7930 Local<Object> b(v8::Object::New(iso));
7931 object_a.handle.Reset(iso, a);
7932 object_b.handle.Reset(iso, b);
7933 if (interlinked) {
7934 a->Set(context, v8_str("x"), b).FromJust();
7935 b->Set(context, v8_str("x"), a).FromJust();
7936 }
7937 if (global_gc) {
7938 CcTest::CollectAllGarbage();
7939 } else {
7940 CcTest::CollectGarbage(i::NEW_SPACE);
7941 }
7942 v8::Local<Value> big_array = v8::Array::New(CcTest::isolate(), 5000);
7943 // Verify that we created an array where the space was reserved up front.
7944 big_array_size =
7945 v8::internal::JSArray::cast(*v8::Utils::OpenHandle(*big_array))
7946 ->elements()
7947 ->Size();
7948 CHECK_LE(20000, big_array_size);
7949 a->Set(context, v8_str("y"), big_array).FromJust();
7950 big_heap_size = CcTest::heap()->SizeOfObjects();
7951 }
7952
7953 object_a.flag = false;
7954 object_b.flag = false;
7955 object_a.handle.SetWeak(&object_a, &SetFlag,
7956 v8::WeakCallbackType::kParameter);
7957 object_b.handle.SetWeak(&object_b, &SetFlag,
7958 v8::WeakCallbackType::kParameter);
7959#if __clang__
7960#pragma clang diagnostic push
7961#pragma clang diagnostic ignored "-Wdeprecated"
7962#endif
7963 // MarkIndependent is marked deprecated but we still rely on it temporarily.
7964 CHECK(!object_b.handle.IsIndependent());
7965 object_a.handle.MarkIndependent();
7966 object_b.handle.MarkIndependent();
7967 CHECK(object_b.handle.IsIndependent());
7968#if __clang__
7969#pragma clang diagnostic pop
7970#endif
7971 if (global_gc) {
7972 CcTest::CollectAllGarbage();
7973 } else {
7974 CcTest::CollectGarbage(i::NEW_SPACE);
7975 }
7976 // A single GC should be enough to reclaim the memory, since we are using
7977 // phantom handles.
7978 CHECK_GT(big_heap_size - big_array_size, CcTest::heap()->SizeOfObjects());
7979 CHECK(object_a.flag);
7980 CHECK(object_b.flag);
7981}
7982
7983TEST(IndependentWeakHandle) {
7984 IndependentWeakHandle(false, false);
7985 IndependentWeakHandle(false, true);
7986 IndependentWeakHandle(true, false);
7987 IndependentWeakHandle(true, true);
7988}
7989
7990class Trivial {
7991 public:
7992 explicit Trivial(int x) : x_(x) {}
7993
7994 int x() { return x_; }
7995 void set_x(int x) { x_ = x; }
7996
7997 private:
7998 int x_;
7999};
8000
8001
8002class Trivial2 {
8003 public:
8004 Trivial2(int x, int y) : y_(y), x_(x) {}
8005
8006 int x() { return x_; }
8007 void set_x(int x) { x_ = x; }
8008
8009 int y() { return y_; }
8010 void set_y(int y) { y_ = y; }
8011
8012 private:
8013 int y_;
8014 int x_;
8015};
8016
8017void CheckInternalFields(
8018 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
8019 v8::Persistent<v8::Object>* handle = data.GetParameter();
8020 handle->Reset();
8021 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField(0));
8022 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField(1));
8023 CHECK_EQ(42, t1->x());
8024 CHECK_EQ(103, t2->x());
8025 t1->set_x(1729);
8026 t2->set_x(33550336);
8027}
8028
8029void InternalFieldCallback(bool global_gc) {
8030 LocalContext env;
8031 v8::Isolate* isolate = env->GetIsolate();
8032 v8::HandleScope scope(isolate);
8033
8034 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
8035 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
8036 Trivial* t1;
8037 Trivial2* t2;
8038 instance_templ->SetInternalFieldCount(2);
8039 v8::Persistent<v8::Object> handle;
8040 {
8041 v8::HandleScope scope(isolate);
8042 Local<v8::Object> obj = templ->GetFunction(env.local())
8043 .ToLocalChecked()
8044 ->NewInstance(env.local())
8045 .ToLocalChecked();
8046 handle.Reset(isolate, obj);
8047 CHECK_EQ(2, obj->InternalFieldCount());
8048 CHECK(obj->GetInternalField(0)->IsUndefined());
8049 t1 = new Trivial(42);
8050 t2 = new Trivial2(103, 9);
8051
8052 obj->SetAlignedPointerInInternalField(0, t1);
8053 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
8054 CHECK_EQ(42, t1->x());
8055
8056 obj->SetAlignedPointerInInternalField(1, t2);
8057 t2 =
8058 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
8059 CHECK_EQ(103, t2->x());
8060
8061 handle.SetWeak<v8::Persistent<v8::Object>>(
8062 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
8063 }
8064 if (global_gc) {
8065 CcTest::CollectAllGarbage();
8066 } else {
8067 CcTest::CollectGarbage(i::NEW_SPACE);
8068 }
8069
8070 CHECK_EQ(1729, t1->x());
8071 CHECK_EQ(33550336, t2->x());
8072
8073 delete t1;
8074 delete t2;
8075}
8076
8077THREADED_TEST(InternalFieldCallback) {
8078 InternalFieldCallback(false);
8079 InternalFieldCallback(true);
8080}
8081
8082static void ResetUseValueAndSetFlag(
8083 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8084 // Blink will reset the handle, and then use the other handle, so they
8085 // can't use the same backing slot.
8086 data.GetParameter()->handle.Reset();
8087 data.GetParameter()->flag = true;
8088}
8089
8090void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) {
8091 using v8::Context;
8092 using v8::Local;
8093 using v8::Object;
8094
8095 v8::Isolate* iso = CcTest::isolate();
8096 v8::HandleScope scope(iso);
8097 v8::Local<Context> context = Context::New(iso);
8098 Context::Scope context_scope(context);
8099
8100 FlagAndPersistent object_a, object_b;
8101
8102 {
8103 v8::HandleScope handle_scope(iso);
8104 Local<Object> a(v8::Object::New(iso));
8105 Local<Object> b(v8::Object::New(iso));
8106 object_a.handle.Reset(iso, a);
8107 object_b.handle.Reset(iso, b);
8108 if (global_gc) {
8109 CcTest::PreciseCollectAllGarbage();
8110 } else {
8111 CcTest::CollectGarbage(i::NEW_SPACE);
8112 }
8113 }
8114
8115 object_a.flag = false;
8116 object_b.flag = false;
8117 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
8118 v8::WeakCallbackType::kParameter);
8119 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
8120 v8::WeakCallbackType::kParameter);
8121 if (!global_gc) {
8122#if __clang__
8123#pragma clang diagnostic push
8124#pragma clang diagnostic ignored "-Wdeprecated"
8125#endif
8126 // MarkIndependent is marked deprecated but we still rely on it temporarily.
8127 object_a.handle.MarkIndependent();
8128 object_b.handle.MarkIndependent();
8129 CHECK(object_b.handle.IsIndependent());
8130#if __clang__
8131#pragma clang diagnostic pop
8132#endif
8133 }
8134 if (global_gc) {
8135 CcTest::PreciseCollectAllGarbage();
8136 } else {
8137 CcTest::CollectGarbage(i::NEW_SPACE);
8138 }
8139 CHECK(object_a.flag);
8140 CHECK(object_b.flag);
8141}
8142
8143THREADED_HEAP_TEST(ResetWeakHandle) {
8144 v8::internal::heap::HeapTester::ResetWeakHandle(false);
8145 v8::internal::heap::HeapTester::ResetWeakHandle(true);
8146}
8147
8148static void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
8149
8150static void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
8151
8152static void ForceScavenge2(
8153 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8154 data.GetParameter()->flag = true;
8155 InvokeScavenge();
8156}
8157
8158static void ForceScavenge1(
8159 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8160 data.GetParameter()->handle.Reset();
8161 data.SetSecondPassCallback(ForceScavenge2);
8162}
8163
8164static void ForceMarkSweep2(
8165 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8166 data.GetParameter()->flag = true;
8167 InvokeMarkSweep();
8168}
8169
8170static void ForceMarkSweep1(
8171 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
8172 data.GetParameter()->handle.Reset();
8173 data.SetSecondPassCallback(ForceMarkSweep2);
8174}
8175
8176THREADED_TEST(GCFromWeakCallbacks) {
8177 v8::Isolate* isolate = CcTest::isolate();
8178 v8::Locker locker(CcTest::isolate());
8179 v8::HandleScope scope(isolate);
8180 v8::Local<Context> context = Context::New(isolate);
8181 Context::Scope context_scope(context);
8182
8183 static const int kNumberOfGCTypes = 2;
8184 typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
8185 Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
8186 &ForceMarkSweep1};
8187
8188 typedef void (*GCInvoker)();
8189 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
8190
8191 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
8192 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
8193 FlagAndPersistent object;
8194 {
8195 v8::HandleScope handle_scope(isolate);
8196 object.handle.Reset(isolate, v8::Object::New(isolate));
8197 }
8198 object.flag = false;
8199 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
8200 v8::WeakCallbackType::kParameter);
8201#if __clang__
8202#pragma clang diagnostic push
8203#pragma clang diagnostic ignored "-Wdeprecated"
8204#endif
8205 // MarkIndependent is marked deprecated but we still rely on it
8206 // temporarily.
8207 object.handle.MarkIndependent();
8208#if __clang__
8209#pragma clang diagnostic pop
8210#endif
8211 invoke_gc[outer_gc]();
8212 EmptyMessageQueues(isolate);
8213 CHECK(object.flag);
8214 }
8215 }
8216}
8217
8218v8::Local<Function> args_fun;
8219
8220
8221static void ArgumentsTestCallback(
8222 const v8::FunctionCallbackInfo<v8::Value>& args) {
8223 ApiTestFuzzer::Fuzz();
8224 v8::Isolate* isolate = args.GetIsolate();
8225 Local<Context> context = isolate->GetCurrentContext();
8226 CHECK_EQ(3, args.Length());
8227 CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust());
8228 CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust());
8229 CHECK(v8::Integer::New(isolate, 3)->Equals(context, args[2]).FromJust());
8230 CHECK(v8::Undefined(isolate)->Equals(context, args[3]).FromJust());
8231 v8::HandleScope scope(args.GetIsolate());
8232 CcTest::CollectAllGarbage();
8233}
8234
8235
8236THREADED_TEST(Arguments) {
8237 v8::Isolate* isolate = CcTest::isolate();
8238 v8::HandleScope scope(isolate);
8239 v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8240 global->Set(v8_str("f"),
8241 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8242 LocalContext context(nullptr, global);
8243 args_fun = context->Global()
8244 ->Get(context.local(), v8_str("f"))
8245 .ToLocalChecked()
8246 .As<Function>();
8247 v8_compile("f(1, 2, 3)")->Run(context.local()).ToLocalChecked();
8248}
8249
8250
8251static int p_getter_count;
8252static int p_getter_count2;
8253
8254
8255static void PGetter(Local<Name> name,
8256 const v8::PropertyCallbackInfo<v8::Value>& info) {
8257 ApiTestFuzzer::Fuzz();
8258 p_getter_count++;
8259 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8260 v8::Local<v8::Object> global = context->Global();
8261 CHECK(
8262 info.Holder()
8263 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8264 .FromJust());
8265 if (name->Equals(context, v8_str("p1")).FromJust()) {
8266 CHECK(info.This()
8267 ->Equals(context,
8268 global->Get(context, v8_str("o1")).ToLocalChecked())
8269 .FromJust());
8270 } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8271 CHECK(info.This()
8272 ->Equals(context,
8273 global->Get(context, v8_str("o2")).ToLocalChecked())
8274 .FromJust());
8275 } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8276 CHECK(info.This()
8277 ->Equals(context,
8278 global->Get(context, v8_str("o3")).ToLocalChecked())
8279 .FromJust());
8280 } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8281 CHECK(info.This()
8282 ->Equals(context,
8283 global->Get(context, v8_str("o4")).ToLocalChecked())
8284 .FromJust());
8285 }
8286}
8287
8288
8289static void RunHolderTest(v8::Local<v8::ObjectTemplate> obj) {
8290 ApiTestFuzzer::Fuzz();
8291 LocalContext context;
8292 CHECK(context->Global()
8293 ->Set(context.local(), v8_str("o1"),
8294 obj->NewInstance(context.local()).ToLocalChecked())
8295 .FromJust());
8296 CompileRun(
8297 "o1.__proto__ = { };"
8298 "var o2 = { __proto__: o1 };"
8299 "var o3 = { __proto__: o2 };"
8300 "var o4 = { __proto__: o3 };"
8301 "for (var i = 0; i < 10; i++) o4.p4;"
8302 "for (var i = 0; i < 10; i++) o3.p3;"
8303 "for (var i = 0; i < 10; i++) o2.p2;"
8304 "for (var i = 0; i < 10; i++) o1.p1;");
8305}
8306
8307
8308static void PGetter2(Local<Name> name,
8309 const v8::PropertyCallbackInfo<v8::Value>& info) {
8310 ApiTestFuzzer::Fuzz();
8311 p_getter_count2++;
8312 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
8313 v8::Local<v8::Object> global = context->Global();
8314 CHECK(
8315 info.Holder()
8316 ->Equals(context, global->Get(context, v8_str("o1")).ToLocalChecked())
8317 .FromJust());
8318 if (name->Equals(context, v8_str("p1")).FromJust()) {
8319 CHECK(info.This()
8320 ->Equals(context,
8321 global->Get(context, v8_str("o1")).ToLocalChecked())
8322 .FromJust());
8323 } else if (name->Equals(context, v8_str("p2")).FromJust()) {
8324 CHECK(info.This()
8325 ->Equals(context,
8326 global->Get(context, v8_str("o2")).ToLocalChecked())
8327 .FromJust());
8328 } else if (name->Equals(context, v8_str("p3")).FromJust()) {
8329 CHECK(info.This()
8330 ->Equals(context,
8331 global->Get(context, v8_str("o3")).ToLocalChecked())
8332 .FromJust());
8333 } else if (name->Equals(context, v8_str("p4")).FromJust()) {
8334 CHECK(info.This()
8335 ->Equals(context,
8336 global->Get(context, v8_str("o4")).ToLocalChecked())
8337 .FromJust());
8338 }
8339}
8340
8341
8342THREADED_TEST(GetterHolders) {
8343 v8::Isolate* isolate = CcTest::isolate();
8344 v8::HandleScope scope(isolate);
8345 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8346 obj->SetAccessor(v8_str("p1"), PGetter);
8347 obj->SetAccessor(v8_str("p2"), PGetter);
8348 obj->SetAccessor(v8_str("p3"), PGetter);
8349 obj->SetAccessor(v8_str("p4"), PGetter);
8350 p_getter_count = 0;
8351 RunHolderTest(obj);
8352 CHECK_EQ(40, p_getter_count);
8353}
8354
8355
8356THREADED_TEST(PreInterceptorHolders) {
8357 v8::Isolate* isolate = CcTest::isolate();
8358 v8::HandleScope scope(isolate);
8359 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8360 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8361 p_getter_count2 = 0;
8362 RunHolderTest(obj);
8363 CHECK_EQ(40, p_getter_count2);
8364}
8365
8366
8367THREADED_TEST(ObjectInstantiation) {
8368 v8::Isolate* isolate = CcTest::isolate();
8369 v8::HandleScope scope(isolate);
8370 v8::Local<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8371 templ->SetAccessor(v8_str("t"), PGetter2);
8372 LocalContext context;
8373 CHECK(context->Global()
8374 ->Set(context.local(), v8_str("o"),
8375 templ->NewInstance(context.local()).ToLocalChecked())
8376 .FromJust());
8377 for (int i = 0; i < 100; i++) {
8378 v8::HandleScope inner_scope(CcTest::isolate());
8379 v8::Local<v8::Object> obj =
8380 templ->NewInstance(context.local()).ToLocalChecked();
8381 CHECK(!obj->Equals(context.local(), context->Global()
8382 ->Get(context.local(), v8_str("o"))
8383 .ToLocalChecked())
8384 .FromJust());
8385 CHECK(
8386 context->Global()->Set(context.local(), v8_str("o2"), obj).FromJust());
8387 v8::Local<Value> value = CompileRun("o.__proto__ === o2.__proto__");
8388 CHECK(v8::True(isolate)->Equals(context.local(), value).FromJust());
8389 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
8390 }
8391}
8392
8393
8394static int StrCmp16(uint16_t* a, uint16_t* b) {
8395 while (true) {
8396 if (*a == 0 && *b == 0) return 0;
8397 if (*a != *b) return 0 + *a - *b;
8398 a++;
8399 b++;
8400 }
8401}
8402
8403
8404static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8405 while (true) {
8406 if (n-- == 0) return 0;
8407 if (*a == 0 && *b == 0) return 0;
8408 if (*a != *b) return 0 + *a - *b;
8409 a++;
8410 b++;
8411 }
8412}
8413
8414int GetUtf8Length(v8::Isolate* isolate, Local<String> str) {
8415 int len = str->Utf8Length(isolate);
8416 if (len < 0) {
8417 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
8418 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8419 i::String::Flatten(i_isolate, istr);
8420 len = str->Utf8Length(isolate);
8421 }
8422 return len;
8423}
8424
8425
8426THREADED_TEST(StringWrite) {
8427 LocalContext context;
8428 v8::Isolate* isolate = context->GetIsolate();
8429 v8::HandleScope scope(isolate);
8430 v8::Local<String> str = v8_str("abcde");
8431 // abc<Icelandic eth><Unicode snowman>.
8432 v8::Local<String> str2 = v8_str("abc\xC3\xB0\xE2\x98\x83");
8433 v8::Local<String> str3 =
8434 v8::String::NewFromUtf8(context->GetIsolate(), "abc\0def",
8435 v8::NewStringType::kNormal, 7)
8436 .ToLocalChecked();
8437 // "ab" + lead surrogate + "wx" + trail surrogate + "yz"
8438 uint16_t orphans[8] = {0x61, 0x62, 0xD800, 0x77, 0x78, 0xDC00, 0x79, 0x7A};
8439 v8::Local<String> orphans_str =
8440 v8::String::NewFromTwoByte(context->GetIsolate(), orphans,
8441 v8::NewStringType::kNormal, 8)
8442 .ToLocalChecked();
8443 // single lead surrogate
8444 uint16_t lead[1] = {0xD800};
8445 v8::Local<String> lead_str =
8446 v8::String::NewFromTwoByte(context->GetIsolate(), lead,
8447 v8::NewStringType::kNormal, 1)
8448 .ToLocalChecked();
8449 // single trail surrogate
8450 uint16_t trail[1] = {0xDC00};
8451 v8::Local<String> trail_str =
8452 v8::String::NewFromTwoByte(context->GetIsolate(), trail,
8453 v8::NewStringType::kNormal, 1)
8454 .ToLocalChecked();
8455 // surrogate pair
8456 uint16_t pair[2] = {0xD800, 0xDC00};
8457 v8::Local<String> pair_str =
8458 v8::String::NewFromTwoByte(context->GetIsolate(), pair,
8459 v8::NewStringType::kNormal, 2)
8460 .ToLocalChecked();
8461 const int kStride = 4; // Must match stride in for loops in JS below.
8462 CompileRun(
8463 "var left = '';"
8464 "for (var i = 0; i < 0xD800; i += 4) {"
8465 " left = left + String.fromCharCode(i);"
8466 "}");
8467 CompileRun(
8468 "var right = '';"
8469 "for (var i = 0; i < 0xD800; i += 4) {"
8470 " right = String.fromCharCode(i) + right;"
8471 "}");
8472 v8::Local<v8::Object> global = context->Global();
8473 Local<String> left_tree = global->Get(context.local(), v8_str("left"))
8474 .ToLocalChecked()
8475 .As<String>();
8476 Local<String> right_tree = global->Get(context.local(), v8_str("right"))
8477 .ToLocalChecked()
8478 .As<String>();
8479
8480 CHECK_EQ(5, str2->Length());
8481 CHECK_EQ(0xD800 / kStride, left_tree->Length());
8482 CHECK_EQ(0xD800 / kStride, right_tree->Length());
8483
8484 char buf[100];
8485 char utf8buf[0xD800 * 3];
8486 uint16_t wbuf[100];
8487 int len;
8488 int charlen;
8489
8490 memset(utf8buf, 0x1, 1000);
8491 len = v8::String::Empty(isolate)->WriteUtf8(isolate, utf8buf, sizeof(utf8buf),
8492 &charlen);
8493 CHECK_EQ(1, len);
8494 CHECK_EQ(0, charlen);
8495 CHECK_EQ(0, strcmp(utf8buf, ""));
8496
8497 memset(utf8buf, 0x1, 1000);
8498 len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8499 CHECK_EQ(9, len);
8500 CHECK_EQ(5, charlen);
8501 CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8502
8503 memset(utf8buf, 0x1, 1000);
8504 len = str2->WriteUtf8(isolate, utf8buf, 8, &charlen);
8505 CHECK_EQ(8, len);
8506 CHECK_EQ(5, charlen);
8507 CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83\x01", 9));
8508
8509 memset(utf8buf, 0x1, 1000);
8510 len = str2->WriteUtf8(isolate, utf8buf, 7, &charlen);
8511 CHECK_EQ(5, len);
8512 CHECK_EQ(4, charlen);
8513 CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8514
8515 memset(utf8buf, 0x1, 1000);
8516 len = str2->WriteUtf8(isolate, utf8buf, 6, &charlen);
8517 CHECK_EQ(5, len);
8518 CHECK_EQ(4, charlen);
8519 CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8520
8521 memset(utf8buf, 0x1, 1000);
8522 len = str2->WriteUtf8(isolate, utf8buf, 5, &charlen);
8523 CHECK_EQ(5, len);
8524 CHECK_EQ(4, charlen);
8525 CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\x01", 5));
8526
8527 memset(utf8buf, 0x1, 1000);
8528 len = str2->WriteUtf8(isolate, utf8buf, 4, &charlen);
8529 CHECK_EQ(3, len);
8530 CHECK_EQ(3, charlen);
8531 CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8532
8533 memset(utf8buf, 0x1, 1000);
8534 len = str2->WriteUtf8(isolate, utf8buf, 3, &charlen);
8535 CHECK_EQ(3, len);
8536 CHECK_EQ(3, charlen);
8537 CHECK_EQ(0, strncmp(utf8buf, "abc\x01", 4));
8538
8539 memset(utf8buf, 0x1, 1000);
8540 len = str2->WriteUtf8(isolate, utf8buf, 2, &charlen);
8541 CHECK_EQ(2, len);
8542 CHECK_EQ(2, charlen);
8543 CHECK_EQ(0, strncmp(utf8buf, "ab\x01", 3));
8544
8545 // allow orphan surrogates by default
8546 memset(utf8buf, 0x1, 1000);
8547 len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen);
8548 CHECK_EQ(13, len);
8549 CHECK_EQ(8, charlen);
8550 CHECK_EQ(0, strcmp(utf8buf, "ab\xED\xA0\x80wx\xED\xB0\x80yz"));
8551
8552 // replace orphan surrogates with Unicode replacement character
8553 memset(utf8buf, 0x1, 1000);
8554 len = orphans_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8555 String::REPLACE_INVALID_UTF8);
8556 CHECK_EQ(13, len);
8557 CHECK_EQ(8, charlen);
8558 CHECK_EQ(0, strcmp(utf8buf, "ab\xEF\xBF\xBDwx\xEF\xBF\xBDyz"));
8559
8560 // replace single lead surrogate with Unicode replacement character
8561 memset(utf8buf, 0x1, 1000);
8562 len = lead_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8563 String::REPLACE_INVALID_UTF8);
8564 CHECK_EQ(4, len);
8565 CHECK_EQ(1, charlen);
8566 CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8567
8568 // replace single trail surrogate with Unicode replacement character
8569 memset(utf8buf, 0x1, 1000);
8570 len = trail_str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8571 String::REPLACE_INVALID_UTF8);
8572 CHECK_EQ(4, len);
8573 CHECK_EQ(1, charlen);
8574 CHECK_EQ(0, strcmp(utf8buf, "\xEF\xBF\xBD"));
8575
8576 // do not replace / write anything if surrogate pair does not fit the buffer
8577 // space
8578 memset(utf8buf, 0x1, 1000);
8579 len = pair_str->WriteUtf8(isolate, utf8buf, 3, &charlen,
8580 String::REPLACE_INVALID_UTF8);
8581 CHECK_EQ(0, len);
8582 CHECK_EQ(0, charlen);
8583
8584 memset(utf8buf, 0x1, sizeof(utf8buf));
8585 len = GetUtf8Length(isolate, left_tree);
8586 int utf8_expected =
8587 (0x80 + (0x800 - 0x80) * 2 + (0xD800 - 0x800) * 3) / kStride;
8588 CHECK_EQ(utf8_expected, len);
8589 len = left_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8590 CHECK_EQ(utf8_expected, len);
8591 CHECK_EQ(0xD800 / kStride, charlen);
8592 CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8593 CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8594 CHECK_EQ(0xC0 - kStride,
8595 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8596 CHECK_EQ(1, utf8buf[utf8_expected]);
8597
8598 memset(utf8buf, 0x1, sizeof(utf8buf));
8599 len = GetUtf8Length(isolate, right_tree);
8600 CHECK_EQ(utf8_expected, len);
8601 len = right_tree->WriteUtf8(isolate, utf8buf, utf8_expected, &charlen);
8602 CHECK_EQ(utf8_expected, len);
8603 CHECK_EQ(0xD800 / kStride, charlen);
8604 CHECK_EQ(0xED, static_cast<unsigned char>(utf8buf[0]));
8605 CHECK_EQ(0x9F, static_cast<unsigned char>(utf8buf[1]));
8606 CHECK_EQ(0xC0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8607 CHECK_EQ(1, utf8buf[utf8_expected]);
8608
8609 memset(buf, 0x1, sizeof(buf));
8610 memset(wbuf, 0x1, sizeof(wbuf));
8611 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8612 CHECK_EQ(5, len);
8613 len = str->Write(isolate, wbuf);
8614 CHECK_EQ(5, len);
8615 CHECK_EQ(0, strcmp("abcde", buf));
8616 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8617 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8618
8619 memset(buf, 0x1, sizeof(buf));
8620 memset(wbuf, 0x1, sizeof(wbuf));
8621 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 4);
8622 CHECK_EQ(4, len);
8623 len = str->Write(isolate, wbuf, 0, 4);
8624 CHECK_EQ(4, len);
8625 CHECK_EQ(0, strncmp("abcd\x01", buf, 5));
8626 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8627 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8628
8629 memset(buf, 0x1, sizeof(buf));
8630 memset(wbuf, 0x1, sizeof(wbuf));
8631 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 5);
8632 CHECK_EQ(5, len);
8633 len = str->Write(isolate, wbuf, 0, 5);
8634 CHECK_EQ(5, len);
8635 CHECK_EQ(0, strncmp("abcde\x01", buf, 6));
8636 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8637 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8638
8639 memset(buf, 0x1, sizeof(buf));
8640 memset(wbuf, 0x1, sizeof(wbuf));
8641 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6);
8642 CHECK_EQ(5, len);
8643 len = str->Write(isolate, wbuf, 0, 6);
8644 CHECK_EQ(5, len);
8645 CHECK_EQ(0, strcmp("abcde", buf));
8646 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8647 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8648
8649 memset(buf, 0x1, sizeof(buf));
8650 memset(wbuf, 0x1, sizeof(wbuf));
8651 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, -1);
8652 CHECK_EQ(1, len);
8653 len = str->Write(isolate, wbuf, 4, -1);
8654 CHECK_EQ(1, len);
8655 CHECK_EQ(0, strcmp("e", buf));
8656 uint16_t answer5[] = {'e', '\0'};
8657 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8658
8659 memset(buf, 0x1, sizeof(buf));
8660 memset(wbuf, 0x1, sizeof(wbuf));
8661 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 6);
8662 CHECK_EQ(1, len);
8663 len = str->Write(isolate, wbuf, 4, 6);
8664 CHECK_EQ(1, len);
8665 CHECK_EQ(0, strcmp("e", buf));
8666 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8667
8668 memset(buf, 0x1, sizeof(buf));
8669 memset(wbuf, 0x1, sizeof(wbuf));
8670 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 4, 1);
8671 CHECK_EQ(1, len);
8672 len = str->Write(isolate, wbuf, 4, 1);
8673 CHECK_EQ(1, len);
8674 CHECK_EQ(0, strncmp("e\x01", buf, 2));
8675 uint16_t answer6[] = {'e', 0x101};
8676 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8677
8678 memset(buf, 0x1, sizeof(buf));
8679 memset(wbuf, 0x1, sizeof(wbuf));
8680 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 3, 1);
8681 CHECK_EQ(1, len);
8682 len = str->Write(isolate, wbuf, 3, 1);
8683 CHECK_EQ(1, len);
8684 CHECK_EQ(0, strncmp("d\x01", buf, 2));
8685 uint16_t answer7[] = {'d', 0x101};
8686 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8687
8688 memset(wbuf, 0x1, sizeof(wbuf));
8689 wbuf[5] = 'X';
8690 len = str->Write(isolate, wbuf, 0, 6, String::NO_NULL_TERMINATION);
8691 CHECK_EQ(5, len);
8692 CHECK_EQ('X', wbuf[5]);
8693 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8694 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8695 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8696 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8697 wbuf[5] = '\0';
8698 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8699
8700 memset(buf, 0x1, sizeof(buf));
8701 buf[5] = 'X';
8702 len = str->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf), 0, 6,
8703 String::NO_NULL_TERMINATION);
8704 CHECK_EQ(5, len);
8705 CHECK_EQ('X', buf[5]);
8706 CHECK_EQ(0, strncmp("abcde", buf, 5));
8707 CHECK_NE(0, strcmp("abcde", buf));
8708 buf[5] = '\0';
8709 CHECK_EQ(0, strcmp("abcde", buf));
8710
8711 memset(utf8buf, 0x1, sizeof(utf8buf));
8712 utf8buf[8] = 'X';
8713 len = str2->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8714 String::NO_NULL_TERMINATION);
8715 CHECK_EQ(8, len);
8716 CHECK_EQ('X', utf8buf[8]);
8717 CHECK_EQ(5, charlen);
8718 CHECK_EQ(0, strncmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83", 8));
8719 CHECK_NE(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8720 utf8buf[8] = '\0';
8721 CHECK_EQ(0, strcmp(utf8buf, "abc\xC3\xB0\xE2\x98\x83"));
8722
8723 memset(utf8buf, 0x1, sizeof(utf8buf));
8724 utf8buf[5] = 'X';
8725 len = str->WriteUtf8(isolate, utf8buf, sizeof(utf8buf), &charlen,
8726 String::NO_NULL_TERMINATION);
8727 CHECK_EQ(5, len);
8728 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8729 CHECK_EQ(5, charlen);
8730 utf8buf[5] = '\0';
8731 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8732
8733 memset(buf, 0x1, sizeof(buf));
8734 len = str3->WriteOneByte(isolate, reinterpret_cast<uint8_t*>(buf));
8735 CHECK_EQ(7, len);
8736 CHECK_EQ(0, strcmp("abc", buf));
8737 CHECK_EQ(0, buf[3]);
8738 CHECK_EQ(0, strcmp("def", buf + 4));
8739
8740 CHECK_EQ(0, str->WriteOneByte(isolate, nullptr, 0, 0,
8741 String::NO_NULL_TERMINATION));
8742 CHECK_EQ(0, str->WriteUtf8(isolate, nullptr, 0, nullptr,
8743 String::NO_NULL_TERMINATION));
8744 CHECK_EQ(0, str->Write(isolate, nullptr, 0, 0, String::NO_NULL_TERMINATION));
8745}
8746
8747
8748static void Utf16Helper(
8749 LocalContext& context, // NOLINT
8750 const char* name,
8751 const char* lengths_name,
8752 int len) {
8753 Local<v8::Array> a = Local<v8::Array>::Cast(
8754 context->Global()->Get(context.local(), v8_str(name)).ToLocalChecked());
8755 Local<v8::Array> alens =
8756 Local<v8::Array>::Cast(context->Global()
8757 ->Get(context.local(), v8_str(lengths_name))
8758 .ToLocalChecked());
8759 for (int i = 0; i < len; i++) {
8760 Local<v8::String> string =
8761 Local<v8::String>::Cast(a->Get(context.local(), i).ToLocalChecked());
8762 Local<v8::Number> expected_len = Local<v8::Number>::Cast(
8763 alens->Get(context.local(), i).ToLocalChecked());
8764 int length = GetUtf8Length(context->GetIsolate(), string);
8765 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8766 }
8767}
8768
8769void TestUtf8DecodingAgainstReference(
8770 v8::Isolate* isolate, const char* cases[],
8771 const std::vector<std::vector<uint16_t>>& unicode_expected) {
8772 for (size_t test_ix = 0; test_ix < unicode_expected.size(); ++test_ix) {
8773 v8::Local<String> str = v8_str(cases[test_ix]);
8774 CHECK_EQ(unicode_expected[test_ix].size(), str->Length());
8775
8776 std::unique_ptr<uint16_t[]> buffer(new uint16_t[str->Length()]);
8777 str->Write(isolate, buffer.get(), 0, -1, String::NO_NULL_TERMINATION);
8778
8779 for (size_t i = 0; i < unicode_expected[test_ix].size(); ++i) {
8780 CHECK_EQ(unicode_expected[test_ix][i], buffer[i]);
8781 }
8782 }
8783}
8784
8785THREADED_TEST(OverlongSequencesAndSurrogates) {
8786 LocalContext context;
8787 v8::HandleScope scope(context->GetIsolate());
8788
8789 const char* cases[] = {
8790 // Overlong 2-byte sequence.
8791 "X\xc0\xbfY\0",
8792 // Another overlong 2-byte sequence.
8793 "X\xc1\xbfY\0",
8794 // Overlong 3-byte sequence.
8795 "X\xe0\x9f\xbfY\0",
8796 // Overlong 4-byte sequence.
8797 "X\xf0\x89\xbf\xbfY\0",
8798 // Invalid 3-byte sequence (reserved for surrogates).
8799 "X\xed\xa0\x80Y\0",
8800 // Invalid 4-bytes sequence (value out of range).
8801 "X\xf4\x90\x80\x80Y\0",
8802
8803 // Start of an overlong 3-byte sequence but not enough continuation bytes.
8804 "X\xe0\x9fY\0",
8805 // Start of an overlong 4-byte sequence but not enough continuation bytes.
8806 "X\xf0\x89\xbfY\0",
8807 // Start of an invalid 3-byte sequence (reserved for surrogates) but not
8808 // enough continuation bytes.
8809 "X\xed\xa0Y\0",
8810 // Start of an invalid 4-bytes sequence (value out of range) but not
8811 // enough continuation bytes.
8812 "X\xf4\x90\x80Y\0",
8813 };
8814 const std::vector<std::vector<uint16_t>> unicode_expected = {
8815 {0x58, 0xFFFD, 0xFFFD, 0x59},
8816 {0x58, 0xFFFD, 0xFFFD, 0x59},
8817 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8818 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8819 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8820 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8821 {0x58, 0xFFFD, 0xFFFD, 0x59},
8822 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8823 {0x58, 0xFFFD, 0xFFFD, 0x59},
8824 {0x58, 0xFFFD, 0xFFFD, 0xFFFD, 0x59},
8825 };
8826 CHECK_EQ(unicode_expected.size(), arraysize(cases));
8827 TestUtf8DecodingAgainstReference(context->GetIsolate(), cases,
8828 unicode_expected);
8829}
8830
8831THREADED_TEST(Utf16) {
8832 LocalContext context;
8833 v8::HandleScope scope(context->GetIsolate());
8834 CompileRun(
8835 "var pad = '01234567890123456789';"
8836 "var p = [];"
8837 "var plens = [20, 3, 3];"
8838 "p.push('01234567890123456789');"
8839 "var lead = 0xD800;"
8840 "var trail = 0xDC00;"
8841 "p.push(String.fromCharCode(0xD800));"
8842 "p.push(String.fromCharCode(0xDC00));"
8843 "var a = [];"
8844 "var b = [];"
8845 "var c = [];"
8846 "var alens = [];"
8847 "for (var i = 0; i < 3; i++) {"
8848 " p[1] = String.fromCharCode(lead++);"
8849 " for (var j = 0; j < 3; j++) {"
8850 " p[2] = String.fromCharCode(trail++);"
8851 " a.push(p[i] + p[j]);"
8852 " b.push(p[i] + p[j]);"
8853 " c.push(p[i] + p[j]);"
8854 " alens.push(plens[i] + plens[j]);"
8855 " }"
8856 "}"
8857 "alens[5] -= 2;" // Here the surrogate pairs match up.
8858 "var a2 = [];"
8859 "var b2 = [];"
8860 "var c2 = [];"
8861 "var a2lens = [];"
8862 "for (var m = 0; m < 9; m++) {"
8863 " for (var n = 0; n < 9; n++) {"
8864 " a2.push(a[m] + a[n]);"
8865 " b2.push(b[m] + b[n]);"
8866 " var newc = 'x' + c[m] + c[n] + 'y';"
8867 " c2.push(newc.substring(1, newc.length - 1));"
8868 " var utf = alens[m] + alens[n];" // And here.
8869 // The 'n's that start with 0xDC..
8870 // are 6-8 The 'm's that end with
8871 // 0xD8.. are 1, 4 and 7
8872 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8873 " a2lens.push(utf);"
8874 " }"
8875 "}");
8876 Utf16Helper(context, "a", "alens", 9);
8877 Utf16Helper(context, "a2", "a2lens", 81);
8878}
8879
8880
8881static bool SameSymbol(Local<String> s1, Local<String> s2) {
8882 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8883 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8884 return *is1 == *is2;
8885}
8886
8887
8888THREADED_TEST(Utf16Symbol) {
8889 LocalContext context;
8890 v8::HandleScope scope(context->GetIsolate());
8891
8892 Local<String> symbol1 =
8893 v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8894 v8::NewStringType::kInternalized)
8895 .ToLocalChecked();
8896 Local<String> symbol2 =
8897 v8::String::NewFromUtf8(context->GetIsolate(), "abc",
8898 v8::NewStringType::kInternalized)
8899 .ToLocalChecked();
8900 CHECK(SameSymbol(symbol1, symbol2));
8901
8902 CompileRun(
8903 "var sym0 = 'benedictus';"
8904 "var sym0b = 'S\xC3\xB8ren';"
8905 "var sym1 = '\xED\xA0\x81\xED\xB0\x87';"
8906 "var sym2 = '\xF0\x90\x90\x88';"
8907 "var sym3 = 'x\xED\xA0\x81\xED\xB0\x87';"
8908 "var sym4 = 'x\xF0\x90\x90\x88';"
8909 "if (sym1.length != 2) throw sym1;"
8910 "if (sym1.charCodeAt(1) != 0xDC07) throw sym1.charCodeAt(1);"
8911 "if (sym2.length != 2) throw sym2;"
8912 "if (sym2.charCodeAt(1) != 0xDC08) throw sym2.charCodeAt(2);"
8913 "if (sym3.length != 3) throw sym3;"
8914 "if (sym3.charCodeAt(2) != 0xDC07) throw sym1.charCodeAt(2);"
8915 "if (sym4.length != 3) throw sym4;"
8916 "if (sym4.charCodeAt(2) != 0xDC08) throw sym2.charCodeAt(2);");
8917 Local<String> sym0 =
8918 v8::String::NewFromUtf8(context->GetIsolate(), "benedictus",
8919 v8::NewStringType::kInternalized)
8920 .ToLocalChecked();
8921 Local<String> sym0b =
8922 v8::String::NewFromUtf8(context->GetIsolate(), "S\xC3\xB8ren",
8923 v8::NewStringType::kInternalized)
8924 .ToLocalChecked();
8925 Local<String> sym1 =
8926 v8::String::NewFromUtf8(context->GetIsolate(), "\xED\xA0\x81\xED\xB0\x87",
8927 v8::NewStringType::kInternalized)
8928 .ToLocalChecked();
8929 Local<String> sym2 =
8930 v8::String::NewFromUtf8(context->GetIsolate(), "\xF0\x90\x90\x88",
8931 v8::NewStringType::kInternalized)
8932 .ToLocalChecked();
8933 Local<String> sym3 = v8::String::NewFromUtf8(context->GetIsolate(),
8934 "x\xED\xA0\x81\xED\xB0\x87",
8935 v8::NewStringType::kInternalized)
8936 .ToLocalChecked();
8937 Local<String> sym4 =
8938 v8::String::NewFromUtf8(context->GetIsolate(), "x\xF0\x90\x90\x88",
8939 v8::NewStringType::kInternalized)
8940 .ToLocalChecked();
8941 v8::Local<v8::Object> global = context->Global();
8942 Local<Value> s0 =
8943 global->Get(context.local(), v8_str("sym0")).ToLocalChecked();
8944 Local<Value> s0b =
8945 global->Get(context.local(), v8_str("sym0b")).ToLocalChecked();
8946 Local<Value> s1 =
8947 global->Get(context.local(), v8_str("sym1")).ToLocalChecked();
8948 Local<Value> s2 =
8949 global->Get(context.local(), v8_str("sym2")).ToLocalChecked();
8950 Local<Value> s3 =
8951 global->Get(context.local(), v8_str("sym3")).ToLocalChecked();
8952 Local<Value> s4 =
8953 global->Get(context.local(), v8_str("sym4")).ToLocalChecked();
8954 CHECK(SameSymbol(sym0, Local<String>::Cast(s0)));
8955 CHECK(SameSymbol(sym0b, Local<String>::Cast(s0b)));
8956 CHECK(SameSymbol(sym1, Local<String>::Cast(s1)));
8957 CHECK(SameSymbol(sym2, Local<String>::Cast(s2)));
8958 CHECK(SameSymbol(sym3, Local<String>::Cast(s3)));
8959 CHECK(SameSymbol(sym4, Local<String>::Cast(s4)));
8960}
8961
8962
8963THREADED_TEST(Utf16MissingTrailing) {
8964 LocalContext context;
8965 v8::HandleScope scope(context->GetIsolate());
8966
8967 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8968 int size = 1024 * 64;
8969 uint8_t* buffer = new uint8_t[size];
8970 for (int i = 0; i < size; i += 4) {
8971 buffer[i] = 0xF0;
8972 buffer[i + 1] = 0x9D;
8973 buffer[i + 2] = 0x80;
8974 buffer[i + 3] = 0x9E;
8975 }
8976
8977 // Now invoke the decoder without last 3 bytes
8978 v8::Local<v8::String> str =
8979 v8::String::NewFromUtf8(
8980 context->GetIsolate(), reinterpret_cast<char*>(buffer),
8981 v8::NewStringType::kNormal, size - 3).ToLocalChecked();
8982 USE(str);
8983 delete[] buffer;
8984}
8985
8986
8987THREADED_TEST(Utf16Trailing3Byte) {
8988 LocalContext context;
8989 v8::Isolate* isolate = context->GetIsolate();
8990 v8::HandleScope scope(isolate);
8991
8992 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
8993 int size = 1024 * 63;
8994 uint8_t* buffer = new uint8_t[size];
8995 for (int i = 0; i < size; i += 3) {
8996 buffer[i] = 0xE2;
8997 buffer[i + 1] = 0x80;
8998 buffer[i + 2] = 0xA6;
8999 }
9000
9001 // Now invoke the decoder without last 3 bytes
9002 v8::Local<v8::String> str =
9003 v8::String::NewFromUtf8(isolate, reinterpret_cast<char*>(buffer),
9004 v8::NewStringType::kNormal, size)
9005 .ToLocalChecked();
9006
9007 v8::String::Value value(isolate, str);
9008 CHECK_EQ(value.length(), size / 3);
9009 CHECK_EQ((*value)[value.length() - 1], 0x2026);
9010
9011 delete[] buffer;
9012}
9013
9014
9015THREADED_TEST(ToArrayIndex) {
9016 LocalContext context;
9017 v8::Isolate* isolate = context->GetIsolate();
9018 v8::HandleScope scope(isolate);
9019
9020 v8::Local<String> str = v8_str("42");
9021 v8::MaybeLocal<v8::Uint32> index = str->ToArrayIndex(context.local());
9022 CHECK(!index.IsEmpty());
9023 CHECK_EQ(42.0,
9024 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9025 str = v8_str("42asdf");
9026 index = str->ToArrayIndex(context.local());
9027 CHECK(index.IsEmpty());
9028 str = v8_str("-42");
9029 index = str->ToArrayIndex(context.local());
9030 CHECK(index.IsEmpty());
9031 str = v8_str("4294967294");
9032 index = str->ToArrayIndex(context.local());
9033 CHECK(!index.IsEmpty());
9034 CHECK_EQ(4294967294.0,
9035 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9036 v8::Local<v8::Number> num = v8::Number::New(isolate, 1);
9037 index = num->ToArrayIndex(context.local());
9038 CHECK(!index.IsEmpty());
9039 CHECK_EQ(1.0,
9040 index.ToLocalChecked()->Uint32Value(context.local()).FromJust());
9041 num = v8::Number::New(isolate, -1);
9042 index = num->ToArrayIndex(context.local());
9043 CHECK(index.IsEmpty());
9044 v8::Local<v8::Object> obj = v8::Object::New(isolate);
9045 index = obj->ToArrayIndex(context.local());
9046 CHECK(index.IsEmpty());
9047}
9048
9049static v8::MaybeLocal<Value> PrepareStackTrace42(v8::Local<Context> context,
9050 v8::Local<Value> error,
9051 v8::Local<Array> trace) {
9052 return v8::Number::New(context->GetIsolate(), 42);
9053}
9054
9055static v8::MaybeLocal<Value> PrepareStackTraceThrow(v8::Local<Context> context,
9056 v8::Local<Value> error,
9057 v8::Local<Array> trace) {
9058 v8::Isolate* isolate = context->GetIsolate();
9059 v8::Local<String> message = v8_str("42");
9060 isolate->ThrowException(v8::Exception::Error(message));
9061 return v8::MaybeLocal<Value>();
9062}
9063
9064THREADED_TEST(IsolatePrepareStackTrace) {
9065 LocalContext context;
9066 v8::Isolate* isolate = context->GetIsolate();
9067 v8::HandleScope scope(isolate);
9068
9069 isolate->SetPrepareStackTraceCallback(PrepareStackTrace42);
9070
9071 v8::Local<Value> v = CompileRun("new Error().stack");
9072
9073 CHECK(v->IsNumber());
9074 CHECK_EQ(v.As<v8::Number>()->Int32Value(context.local()).FromJust(), 42);
9075}
9076
9077THREADED_TEST(IsolatePrepareStackTraceThrow) {
9078 LocalContext context;
9079 v8::Isolate* isolate = context->GetIsolate();
9080 v8::HandleScope scope(isolate);
9081
9082 isolate->SetPrepareStackTraceCallback(PrepareStackTraceThrow);
9083
9084 v8::Local<Value> v = CompileRun("try { new Error().stack } catch (e) { e }");
9085
9086 CHECK(v->IsNativeError());
9087
9088 v8::Local<String> message = v8::Exception::CreateMessage(isolate, v)->Get();
9089
9090 CHECK(message->StrictEquals(v8_str("Uncaught Error: 42")));
9091}
9092
9093THREADED_TEST(ErrorConstruction) {
9094 LocalContext context;
9095 v8::HandleScope scope(context->GetIsolate());
9096
9097 v8::Local<String> foo = v8_str("foo");
9098 v8::Local<String> message = v8_str("message");
9099 v8::Local<Value> range_error = v8::Exception::RangeError(foo);
9100 CHECK(range_error->IsObject());
9101 CHECK(range_error.As<v8::Object>()
9102 ->Get(context.local(), message)
9103 .ToLocalChecked()
9104 ->Equals(context.local(), foo)
9105 .FromJust());
9106 v8::Local<Value> reference_error = v8::Exception::ReferenceError(foo);
9107 CHECK(reference_error->IsObject());
9108 CHECK(reference_error.As<v8::Object>()
9109 ->Get(context.local(), message)
9110 .ToLocalChecked()
9111 ->Equals(context.local(), foo)
9112 .FromJust());
9113 v8::Local<Value> syntax_error = v8::Exception::SyntaxError(foo);
9114 CHECK(syntax_error->IsObject());
9115 CHECK(syntax_error.As<v8::Object>()
9116 ->Get(context.local(), message)
9117 .ToLocalChecked()
9118 ->Equals(context.local(), foo)
9119 .FromJust());
9120 v8::Local<Value> type_error = v8::Exception::TypeError(foo);
9121 CHECK(type_error->IsObject());
9122 CHECK(type_error.As<v8::Object>()
9123 ->Get(context.local(), message)
9124 .ToLocalChecked()
9125 ->Equals(context.local(), foo)
9126 .FromJust());
9127 v8::Local<Value> error = v8::Exception::Error(foo);
9128 CHECK(error->IsObject());
9129 CHECK(error.As<v8::Object>()
9130 ->Get(context.local(), message)
9131 .ToLocalChecked()
9132 ->Equals(context.local(), foo)
9133 .FromJust());
9134}
9135
9136
9137static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
9138 ApiTestFuzzer::Fuzz();
9139 v8::Local<String> foo = v8_str("foo");
9140 v8::Local<String> message = v8_str("message");
9141 v8::Local<Value> error = v8::Exception::Error(foo);
9142 CHECK(error->IsObject());
9143 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9144 CHECK(error.As<v8::Object>()
9145 ->Get(context, message)
9146 .ToLocalChecked()
9147 ->Equals(context, foo)
9148 .FromJust());
9149 info.GetIsolate()->ThrowException(error);
9150 info.GetReturnValue().SetUndefined();
9151}
9152
9153
9154THREADED_TEST(ExceptionCreateMessage) {
9155 LocalContext context;
9156 v8::HandleScope scope(context->GetIsolate());
9157 v8::Local<String> foo_str = v8_str("foo");
9158 v8::Local<String> message_str = v8_str("message");
9159
9160 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
9161
9162 Local<v8::FunctionTemplate> fun =
9163 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
9164 v8::Local<v8::Object> global = context->Global();
9165 CHECK(global->Set(context.local(), v8_str("throwV8Exception"),
9166 fun->GetFunction(context.local()).ToLocalChecked())
9167 .FromJust());
9168
9169 TryCatch try_catch(context->GetIsolate());
9170 CompileRun(
9171 "function f1() {\n"
9172 " throwV8Exception();\n"
9173 "};\n"
9174 "f1();");
9175 CHECK(try_catch.HasCaught());
9176
9177 v8::Local<v8::Value> error = try_catch.Exception();
9178 CHECK(error->IsObject());
9179 CHECK(error.As<v8::Object>()
9180 ->Get(context.local(), message_str)
9181 .ToLocalChecked()
9182 ->Equals(context.local(), foo_str)
9183 .FromJust());
9184
9185 v8::Local<v8::Message> message =
9186 v8::Exception::CreateMessage(context->GetIsolate(), error);
9187 CHECK(!message.IsEmpty());
9188 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9189 CHECK_EQ(2, message->GetStartColumn(context.local()).FromJust());
9190
9191 v8::Local<v8::StackTrace> stackTrace = message->GetStackTrace();
9192 CHECK(!stackTrace.IsEmpty());
9193 CHECK_EQ(2, stackTrace->GetFrameCount());
9194
9195 stackTrace = v8::Exception::GetStackTrace(error);
9196 CHECK(!stackTrace.IsEmpty());
9197 CHECK_EQ(2, stackTrace->GetFrameCount());
9198
9199 context->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(false);
9200
9201 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
9202 // is false.
9203 try_catch.Reset();
9204
9205 CompileRun(
9206 "function f2() {\n"
9207 " return throwV8Exception();\n"
9208 "};\n"
9209 "f2();");
9210 CHECK(try_catch.HasCaught());
9211
9212 error = try_catch.Exception();
9213 CHECK(error->IsObject());
9214 CHECK(error.As<v8::Object>()
9215 ->Get(context.local(), message_str)
9216 .ToLocalChecked()
9217 ->Equals(context.local(), foo_str)
9218 .FromJust());
9219
9220 message = v8::Exception::CreateMessage(context->GetIsolate(), error);
9221 CHECK(!message.IsEmpty());
9222 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
9223 CHECK_EQ(9, message->GetStartColumn(context.local()).FromJust());
9224
9225 // Should be empty stack trace.
9226 stackTrace = message->GetStackTrace();
9227 CHECK(stackTrace.IsEmpty());
9228 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9229}
9230
9231
9232THREADED_TEST(ExceptionCreateMessageLength) {
9233 LocalContext context;
9234 v8::HandleScope scope(context->GetIsolate());
9235
9236 // Test that the message is not truncated.
9237 TryCatch try_catch(context->GetIsolate());
9238 CompileRun(
9239 "var message = 'm';"
9240 "while (message.length < 1000) message += message;"
9241 "throw message;");
9242 CHECK(try_catch.HasCaught());
9243
9244 CHECK_LT(1000, try_catch.Message()->Get()->Length());
9245}
9246
9247
9248static void YGetter(Local<String> name,
9249 const v8::PropertyCallbackInfo<v8::Value>& info) {
9250 ApiTestFuzzer::Fuzz();
9251 info.GetReturnValue().Set(v8_num(10));
9252}
9253
9254
9255static void YSetter(Local<String> name,
9256 Local<Value> value,
9257 const v8::PropertyCallbackInfo<void>& info) {
9258 Local<Object> this_obj = Local<Object>::Cast(info.This());
9259 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9260 if (this_obj->Has(context, name).FromJust())
9261 this_obj->Delete(context, name).FromJust();
9262 CHECK(this_obj->Set(context, name, value).FromJust());
9263}
9264
9265
9266THREADED_TEST(DeleteAccessor) {
9267 v8::Isolate* isolate = CcTest::isolate();
9268 v8::HandleScope scope(isolate);
9269 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9270 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9271 LocalContext context;
9272 v8::Local<v8::Object> holder =
9273 obj->NewInstance(context.local()).ToLocalChecked();
9274 CHECK(context->Global()
9275 ->Set(context.local(), v8_str("holder"), holder)
9276 .FromJust());
9277 v8::Local<Value> result =
9278 CompileRun("holder.y = 11; holder.y = 12; holder.y");
9279 CHECK_EQ(12u, result->Uint32Value(context.local()).FromJust());
9280}
9281
9282
9283static int trouble_nesting = 0;
9284static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9285 ApiTestFuzzer::Fuzz();
9286 trouble_nesting++;
9287
9288 // Call a JS function that throws an uncaught exception.
9289 Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
9290 Local<v8::Object> arg_this = context->Global();
9291 Local<Value> trouble_callee =
9292 (trouble_nesting == 3)
9293 ? arg_this->Get(context, v8_str("trouble_callee")).ToLocalChecked()
9294 : arg_this->Get(context, v8_str("trouble_caller")).ToLocalChecked();
9295 CHECK(trouble_callee->IsFunction());
9296 args.GetReturnValue().Set(Function::Cast(*trouble_callee)
9297 ->Call(context, arg_this, 0, nullptr)
9298 .FromMaybe(v8::Local<v8::Value>()));
9299}
9300
9301
9302static int report_count = 0;
9303static void ApiUncaughtExceptionTestListener(v8::Local<v8::Message>,
9304 v8::Local<Value>) {
9305 report_count++;
9306}
9307
9308
9309// Counts uncaught exceptions, but other tests running in parallel
9310// also have uncaught exceptions.
9311TEST(ApiUncaughtException) {
9312 report_count = 0;
9313 LocalContext env;
9314 v8::Isolate* isolate = env->GetIsolate();
9315 v8::HandleScope scope(isolate);
9316 isolate->AddMessageListener(ApiUncaughtExceptionTestListener);
9317
9318 Local<v8::FunctionTemplate> fun =
9319 v8::FunctionTemplate::New(isolate, TroubleCallback);
9320 v8::Local<v8::Object> global = env->Global();
9321 CHECK(global->Set(env.local(), v8_str("trouble"),
9322 fun->GetFunction(env.local()).ToLocalChecked())
9323 .FromJust());
9324
9325 CompileRun(
9326 "function trouble_callee() {"
9327 " var x = null;"
9328 " return x.foo;"
9329 "};"
9330 "function trouble_caller() {"
9331 " trouble();"
9332 "};");
9333 Local<Value> trouble =
9334 global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9335 CHECK(trouble->IsFunction());
9336 Local<Value> trouble_callee =
9337 global->Get(env.local(), v8_str("trouble_callee")).ToLocalChecked();
9338 CHECK(trouble_callee->IsFunction());
9339 Local<Value> trouble_caller =
9340 global->Get(env.local(), v8_str("trouble_caller")).ToLocalChecked();
9341 CHECK(trouble_caller->IsFunction());
9342 Function::Cast(*trouble_caller)
9343 ->Call(env.local(), global, 0, nullptr)
9344 .FromMaybe(v8::Local<v8::Value>());
9345 CHECK_EQ(1, report_count);
9346 isolate->RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9347}
9348
9349
9350static const char* script_resource_name = "ExceptionInNativeScript.js";
9351static void ExceptionInNativeScriptTestListener(v8::Local<v8::Message> message,
9352 v8::Local<Value>) {
9353 v8::Local<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9354 CHECK(!name_val.IsEmpty() && name_val->IsString());
9355 v8::String::Utf8Value name(v8::Isolate::GetCurrent(),
9356 message->GetScriptOrigin().ResourceName());
9357 CHECK_EQ(0, strcmp(script_resource_name, *name));
9358 v8::Local<v8::Context> context =
9359 v8::Isolate::GetCurrent()->GetCurrentContext();
9360 CHECK_EQ(3, message->GetLineNumber(context).FromJust());
9361 v8::String::Utf8Value source_line(
9362 v8::Isolate::GetCurrent(),
9363 message->GetSourceLine(context).ToLocalChecked());
9364 CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
9365}
9366
9367
9368TEST(ExceptionInNativeScript) {
9369 LocalContext env;
9370 v8::Isolate* isolate = env->GetIsolate();
9371 v8::HandleScope scope(isolate);
9372 isolate->AddMessageListener(ExceptionInNativeScriptTestListener);
9373
9374 Local<v8::FunctionTemplate> fun =
9375 v8::FunctionTemplate::New(isolate, TroubleCallback);
9376 v8::Local<v8::Object> global = env->Global();
9377 CHECK(global->Set(env.local(), v8_str("trouble"),
9378 fun->GetFunction(env.local()).ToLocalChecked())
9379 .FromJust());
9380
9381 CompileRunWithOrigin(
9382 "function trouble() {\n"
9383 " var o = {};\n"
9384 " new o.foo();\n"
9385 "};",
9386 script_resource_name);
9387 Local<Value> trouble =
9388 global->Get(env.local(), v8_str("trouble")).ToLocalChecked();
9389 CHECK(trouble->IsFunction());
9390 CHECK(Function::Cast(*trouble)
9391 ->Call(env.local(), global, 0, nullptr)
9392 .IsEmpty());
9393 isolate->RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9394}
9395
9396
9397TEST(CompilationErrorUsingTryCatchHandler) {
9398 LocalContext env;
9399 v8::HandleScope scope(env->GetIsolate());
9400 v8::TryCatch try_catch(env->GetIsolate());
9401 v8_compile("This doesn't &*&@#$&*^ compile.");
9402 CHECK(*try_catch.Exception());
9403 CHECK(try_catch.HasCaught());
9404}
9405
9406
9407TEST(TryCatchFinallyUsingTryCatchHandler) {
9408 LocalContext env;
9409 v8::HandleScope scope(env->GetIsolate());
9410 v8::TryCatch try_catch(env->GetIsolate());
9411 CompileRun("try { throw ''; } catch (e) {}");
9412 CHECK(!try_catch.HasCaught());
9413 CompileRun("try { throw ''; } finally {}");
9414 CHECK(try_catch.HasCaught());
9415 try_catch.Reset();
9416 CompileRun(
9417 "(function() {"
9418 "try { throw ''; } finally { return; }"
9419 "})()");
9420 CHECK(!try_catch.HasCaught());
9421 CompileRun(
9422 "(function()"
9423 " { try { throw ''; } finally { throw 0; }"
9424 "})()");
9425 CHECK(try_catch.HasCaught());
9426}
9427
9428
9429void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9430 v8::HandleScope scope(args.GetIsolate());
9431 CompileRun(args[0]
9432 ->ToString(args.GetIsolate()->GetCurrentContext())
9433 .ToLocalChecked());
9434}
9435
9436
9437TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9438 v8::Isolate* isolate = CcTest::isolate();
9439 v8::HandleScope scope(isolate);
9440 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9441 templ->Set(v8_str("CEvaluate"),
9442 v8::FunctionTemplate::New(isolate, CEvaluate));
9443 LocalContext context(nullptr, templ);
9444 v8::TryCatch try_catch(isolate);
9445 CompileRun("try {"
9446 " CEvaluate('throw 1;');"
9447 "} finally {"
9448 "}");
9449 CHECK(try_catch.HasCaught());
9450 CHECK(!try_catch.Message().IsEmpty());
9451 String::Utf8Value exception_value(isolate, try_catch.Exception());
9452 CHECK_EQ(0, strcmp(*exception_value, "1"));
9453 try_catch.Reset();
9454 CompileRun("try {"
9455 " CEvaluate('throw 1;');"
9456 "} finally {"
9457 " throw 2;"
9458 "}");
9459 CHECK(try_catch.HasCaught());
9460 CHECK(!try_catch.Message().IsEmpty());
9461 String::Utf8Value finally_exception_value(isolate, try_catch.Exception());
9462 CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
9463}
9464
9465
9466// For use within the TestSecurityHandler() test.
9467static bool g_security_callback_result = false;
9468static bool SecurityTestCallback(Local<v8::Context> accessing_context,
9469 Local<v8::Object> accessed_object,
9470 Local<v8::Value> data) {
9471 printf("a\n");
9472 CHECK(!data.IsEmpty() && data->IsInt32());
9473 CHECK_EQ(42, data->Int32Value(accessing_context).FromJust());
9474 return g_security_callback_result;
9475}
9476
9477
9478// SecurityHandler can't be run twice
9479TEST(SecurityHandler) {
9480 v8::Isolate* isolate = CcTest::isolate();
9481 v8::HandleScope scope0(isolate);
9482 v8::Local<v8::ObjectTemplate> global_template =
9483 v8::ObjectTemplate::New(isolate);
9484 global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42));
9485 // Create an environment
9486 v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
9487 context0->Enter();
9488
9489 v8::Local<v8::Object> global0 = context0->Global();
9490 v8::Local<Script> script0 = v8_compile("foo = 111");
9491 script0->Run(context0).ToLocalChecked();
9492 CHECK(global0->Set(context0, v8_str("0"), v8_num(999)).FromJust());
9493 v8::Local<Value> foo0 =
9494 global0->Get(context0, v8_str("foo")).ToLocalChecked();
9495 CHECK_EQ(111, foo0->Int32Value(context0).FromJust());
9496 v8::Local<Value> z0 = global0->Get(context0, v8_str("0")).ToLocalChecked();
9497 CHECK_EQ(999, z0->Int32Value(context0).FromJust());
9498
9499 // Create another environment, should fail security checks.
9500 v8::HandleScope scope1(isolate);
9501
9502 v8::Local<Context> context1 = Context::New(isolate, nullptr, global_template);
9503 context1->Enter();
9504
9505 v8::Local<v8::Object> global1 = context1->Global();
9506 global1->Set(context1, v8_str("othercontext"), global0).FromJust();
9507 // This set will fail the security check.
9508 v8::Local<Script> script1 =
9509 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9510 CHECK(script1->Run(context1).IsEmpty());
9511 g_security_callback_result = true;
9512 // This read will pass the security check.
9513 v8::Local<Value> foo1 =
9514 global0->Get(context1, v8_str("foo")).ToLocalChecked();
9515 CHECK_EQ(111, foo1->Int32Value(context0).FromJust());
9516 // This read will pass the security check.
9517 v8::Local<Value> z1 = global0->Get(context1, v8_str("0")).ToLocalChecked();
9518 CHECK_EQ(999, z1->Int32Value(context1).FromJust());
9519
9520 // Create another environment, should pass security checks.
9521 {
9522 v8::HandleScope scope2(isolate);
9523 LocalContext context2;
9524 v8::Local<v8::Object> global2 = context2->Global();
9525 CHECK(global2->Set(context2.local(), v8_str("othercontext"), global0)
9526 .FromJust());
9527 v8::Local<Script> script2 =
9528 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9529 script2->Run(context2.local()).ToLocalChecked();
9530 v8::Local<Value> foo2 =
9531 global0->Get(context2.local(), v8_str("foo")).ToLocalChecked();
9532 CHECK_EQ(333, foo2->Int32Value(context2.local()).FromJust());
9533 v8::Local<Value> z2 =
9534 global0->Get(context2.local(), v8_str("0")).ToLocalChecked();
9535 CHECK_EQ(888, z2->Int32Value(context2.local()).FromJust());
9536 }
9537
9538 context1->Exit();
9539 context0->Exit();
9540}
9541
9542
9543THREADED_TEST(SecurityChecks) {
9544 LocalContext env1;
9545 v8::HandleScope handle_scope(env1->GetIsolate());
9546 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9547
9548 Local<Value> foo = v8_str("foo");
9549 Local<Value> bar = v8_str("bar");
9550
9551 // Set to the same domain.
9552 env1->SetSecurityToken(foo);
9553
9554 // Create a function in env1.
9555 CompileRun("spy=function(){return spy;}");
9556 Local<Value> spy =
9557 env1->Global()->Get(env1.local(), v8_str("spy")).ToLocalChecked();
9558 CHECK(spy->IsFunction());
9559
9560 // Create another function accessing global objects.
9561 CompileRun("spy2=function(){return new this.Array();}");
9562 Local<Value> spy2 =
9563 env1->Global()->Get(env1.local(), v8_str("spy2")).ToLocalChecked();
9564 CHECK(spy2->IsFunction());
9565
9566 // Switch to env2 in the same domain and invoke spy on env2.
9567 {
9568 env2->SetSecurityToken(foo);
9569 // Enter env2
9570 Context::Scope scope_env2(env2);
9571 Local<Value> result = Function::Cast(*spy)
9572 ->Call(env2, env2->Global(), 0, nullptr)
9573 .ToLocalChecked();
9574 CHECK(result->IsFunction());
9575 }
9576
9577 {
9578 env2->SetSecurityToken(bar);
9579 Context::Scope scope_env2(env2);
9580
9581 // Call cross_domain_call, it should throw an exception
9582 v8::TryCatch try_catch(env1->GetIsolate());
9583 CHECK(Function::Cast(*spy2)
9584 ->Call(env2, env2->Global(), 0, nullptr)
9585 .IsEmpty());
9586 CHECK(try_catch.HasCaught());
9587 }
9588}
9589
9590
9591// Regression test case for issue 1183439.
9592THREADED_TEST(SecurityChecksForPrototypeChain) {
9593 LocalContext current;
9594 v8::HandleScope scope(current->GetIsolate());
9595 v8::Local<Context> other = Context::New(current->GetIsolate());
9596
9597 // Change context to be able to get to the Object function in the
9598 // other context without hitting the security checks.
9599 v8::Local<Value> other_object;
9600 { Context::Scope scope(other);
9601 other_object =
9602 other->Global()->Get(other, v8_str("Object")).ToLocalChecked();
9603 CHECK(other->Global()->Set(other, v8_num(42), v8_num(87)).FromJust());
9604 }
9605
9606 CHECK(current->Global()
9607 ->Set(current.local(), v8_str("other"), other->Global())
9608 .FromJust());
9609 CHECK(v8_compile("other")
9610 ->Run(current.local())
9611 .ToLocalChecked()
9612 ->Equals(current.local(), other->Global())
9613 .FromJust());
9614
9615 // Make sure the security check fails here and we get an undefined
9616 // result instead of getting the Object function. Repeat in a loop
9617 // to make sure to exercise the IC code.
9618 v8::Local<Script> access_other0 = v8_compile("other.Object");
9619 v8::Local<Script> access_other1 = v8_compile("other[42]");
9620 for (int i = 0; i < 5; i++) {
9621 CHECK(access_other0->Run(current.local()).IsEmpty());
9622 CHECK(access_other1->Run(current.local()).IsEmpty());
9623 }
9624
9625 // Create an object that has 'other' in its prototype chain and make
9626 // sure we cannot access the Object function indirectly through
9627 // that. Repeat in a loop to make sure to exercise the IC code.
9628 v8_compile(
9629 "function F() { };"
9630 "F.prototype = other;"
9631 "var f = new F();")
9632 ->Run(current.local())
9633 .ToLocalChecked();
9634 v8::Local<Script> access_f0 = v8_compile("f.Object");
9635 v8::Local<Script> access_f1 = v8_compile("f[42]");
9636 for (int j = 0; j < 5; j++) {
9637 CHECK(access_f0->Run(current.local()).IsEmpty());
9638 CHECK(access_f1->Run(current.local()).IsEmpty());
9639 }
9640
9641 // Now it gets hairy: Set the prototype for the other global object
9642 // to be the current global object. The prototype chain for 'f' now
9643 // goes through 'other' but ends up in the current global object.
9644 { Context::Scope scope(other);
9645 CHECK(other->Global()
9646 ->Set(other, v8_str("__proto__"), current->Global())
9647 .FromJust());
9648 }
9649 // Set a named and an index property on the current global
9650 // object. To force the lookup to go through the other global object,
9651 // the properties must not exist in the other global object.
9652 CHECK(current->Global()
9653 ->Set(current.local(), v8_str("foo"), v8_num(100))
9654 .FromJust());
9655 CHECK(current->Global()
9656 ->Set(current.local(), v8_num(99), v8_num(101))
9657 .FromJust());
9658 // Try to read the properties from f and make sure that the access
9659 // gets stopped by the security checks on the other global object.
9660 Local<Script> access_f2 = v8_compile("f.foo");
9661 Local<Script> access_f3 = v8_compile("f[99]");
9662 for (int k = 0; k < 5; k++) {
9663 CHECK(access_f2->Run(current.local()).IsEmpty());
9664 CHECK(access_f3->Run(current.local()).IsEmpty());
9665 }
9666}
9667
9668
9669static bool security_check_with_gc_called;
9670
9671static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context,
9672 Local<v8::Object> accessed_object,
9673 Local<v8::Value> data) {
9674 CcTest::CollectAllGarbage();
9675 security_check_with_gc_called = true;
9676 return true;
9677}
9678
9679
9680TEST(SecurityTestGCAllowed) {
9681 v8::Isolate* isolate = CcTest::isolate();
9682 v8::HandleScope handle_scope(isolate);
9683 v8::Local<v8::ObjectTemplate> object_template =
9684 v8::ObjectTemplate::New(isolate);
9685 object_template->SetAccessCheckCallback(SecurityTestCallbackWithGC);
9686
9687 v8::Local<Context> context = Context::New(isolate);
9688 v8::Context::Scope context_scope(context);
9689
9690 CHECK(context->Global()
9691 ->Set(context, v8_str("obj"),
9692 object_template->NewInstance(context).ToLocalChecked())
9693 .FromJust());
9694
9695 security_check_with_gc_called = false;
9696 CompileRun("obj[0] = new String(1002);");
9697 CHECK(security_check_with_gc_called);
9698
9699 security_check_with_gc_called = false;
9700 CHECK(CompileRun("obj[0]")
9701 ->ToString(context)
9702 .ToLocalChecked()
9703 ->Equals(context, v8_str("1002"))
9704 .FromJust());
9705 CHECK(security_check_with_gc_called);
9706}
9707
9708
9709THREADED_TEST(CrossDomainDelete) {
9710 LocalContext env1;
9711 v8::HandleScope handle_scope(env1->GetIsolate());
9712 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9713
9714 Local<Value> foo = v8_str("foo");
9715 Local<Value> bar = v8_str("bar");
9716
9717 // Set to the same domain.
9718 env1->SetSecurityToken(foo);
9719 env2->SetSecurityToken(foo);
9720
9721 CHECK(
9722 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9723 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9724
9725 // Change env2 to a different domain and delete env1.prop.
9726 env2->SetSecurityToken(bar);
9727 {
9728 Context::Scope scope_env2(env2);
9729 Local<Value> result =
9730 CompileRun("delete env1.prop");
9731 CHECK(result.IsEmpty());
9732 }
9733
9734 // Check that env1.prop still exists.
9735 Local<Value> v =
9736 env1->Global()->Get(env1.local(), v8_str("prop")).ToLocalChecked();
9737 CHECK(v->IsNumber());
9738 CHECK_EQ(3, v->Int32Value(env1.local()).FromJust());
9739}
9740
9741
9742THREADED_TEST(CrossDomainPropertyIsEnumerable) {
9743 LocalContext env1;
9744 v8::HandleScope handle_scope(env1->GetIsolate());
9745 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9746
9747 Local<Value> foo = v8_str("foo");
9748 Local<Value> bar = v8_str("bar");
9749
9750 // Set to the same domain.
9751 env1->SetSecurityToken(foo);
9752 env2->SetSecurityToken(foo);
9753
9754 CHECK(
9755 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9756 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9757
9758 // env1.prop is enumerable in env2.
9759 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9760 {
9761 Context::Scope scope_env2(env2);
9762 Local<Value> result = CompileRun(test);
9763 CHECK(result->IsTrue());
9764 }
9765
9766 // Change env2 to a different domain and test again.
9767 env2->SetSecurityToken(bar);
9768 {
9769 Context::Scope scope_env2(env2);
9770 Local<Value> result = CompileRun(test);
9771 CHECK(result.IsEmpty());
9772 }
9773}
9774
9775
9776THREADED_TEST(CrossDomainFor) {
9777 LocalContext env1;
9778 v8::HandleScope handle_scope(env1->GetIsolate());
9779 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9780
9781 Local<Value> foo = v8_str("foo");
9782 Local<Value> bar = v8_str("bar");
9783
9784 // Set to the same domain.
9785 env1->SetSecurityToken(foo);
9786 env2->SetSecurityToken(foo);
9787
9788 CHECK(
9789 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9790 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9791
9792 // Change env2 to a different domain and set env1's global object
9793 // as the __proto__ of an object in env2 and enumerate properties
9794 // in for-in. It shouldn't enumerate properties on env1's global
9795 // object. It shouldn't throw either, just silently ignore them.
9796 env2->SetSecurityToken(bar);
9797 {
9798 Context::Scope scope_env2(env2);
9799 Local<Value> result = CompileRun(
9800 "(function() {"
9801 " try {"
9802 " for (var p in env1) {"
9803 " if (p == 'prop') return false;"
9804 " }"
9805 " return true;"
9806 " } catch (e) {"
9807 " return false;"
9808 " }"
9809 "})()");
9810 CHECK(result->IsTrue());
9811 }
9812}
9813
9814
9815THREADED_TEST(CrossDomainForInOnPrototype) {
9816 LocalContext env1;
9817 v8::HandleScope handle_scope(env1->GetIsolate());
9818 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9819
9820 Local<Value> foo = v8_str("foo");
9821 Local<Value> bar = v8_str("bar");
9822
9823 // Set to the same domain.
9824 env1->SetSecurityToken(foo);
9825 env2->SetSecurityToken(foo);
9826
9827 CHECK(
9828 env1->Global()->Set(env1.local(), v8_str("prop"), v8_num(3)).FromJust());
9829 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
9830
9831 // Change env2 to a different domain and set env1's global object
9832 // as the __proto__ of an object in env2 and enumerate properties
9833 // in for-in. It shouldn't enumerate properties on env1's global
9834 // object.
9835 env2->SetSecurityToken(bar);
9836 {
9837 Context::Scope scope_env2(env2);
9838 Local<Value> result = CompileRun(
9839 "(function() {"
9840 " var obj = { '__proto__': env1 };"
9841 " try {"
9842 " for (var p in obj) {"
9843 " if (p == 'prop') return false;"
9844 " }"
9845 " return true;"
9846 " } catch (e) {"
9847 " return false;"
9848 " }"
9849 "})()");
9850 CHECK(result->IsTrue());
9851 }
9852}
9853
9854
9855TEST(ContextDetachGlobal) {
9856 LocalContext env1;
9857 v8::HandleScope handle_scope(env1->GetIsolate());
9858 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9859
9860
9861 Local<Value> foo = v8_str("foo");
9862
9863 // Set to the same domain.
9864 env1->SetSecurityToken(foo);
9865 env2->SetSecurityToken(foo);
9866
9867 // Enter env2
9868 env2->Enter();
9869
9870 // Create a function in env2 and add a reference to it in env1.
9871 Local<v8::Object> global2 = env2->Global();
9872 CHECK(global2->Set(env2, v8_str("prop"),
9873 v8::Integer::New(env2->GetIsolate(), 1))
9874 .FromJust());
9875 CompileRun("function getProp() {return prop;}");
9876
9877 CHECK(env1->Global()
9878 ->Set(env1.local(), v8_str("getProp"),
9879 global2->Get(env2, v8_str("getProp")).ToLocalChecked())
9880 .FromJust());
9881
9882 // Detach env2's global, and reuse the global object of env2
9883 env2->Exit();
9884 env2->DetachGlobal();
9885
9886 v8::Local<Context> env3 = Context::New(
9887 env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9888 env3->SetSecurityToken(v8_str("bar"));
9889
9890 env3->Enter();
9891 Local<v8::Object> global3 = env3->Global();
9892 CHECK(global2->Equals(env3, global3).FromJust());
9893 CHECK(global3->Get(env3, v8_str("prop")).ToLocalChecked()->IsUndefined());
9894 CHECK(global3->Get(env3, v8_str("getProp")).ToLocalChecked()->IsUndefined());
9895 CHECK(global3->Set(env3, v8_str("prop"),
9896 v8::Integer::New(env3->GetIsolate(), -1))
9897 .FromJust());
9898 CHECK(global3->Set(env3, v8_str("prop2"),
9899 v8::Integer::New(env3->GetIsolate(), 2))
9900 .FromJust());
9901 env3->Exit();
9902
9903 // Call getProp in env1, and it should return the value 1
9904 {
9905 Local<v8::Object> global1 = env1->Global();
9906 Local<Value> get_prop =
9907 global1->Get(env1.local(), v8_str("getProp")).ToLocalChecked();
9908 CHECK(get_prop->IsFunction());
9909 v8::TryCatch try_catch(env1->GetIsolate());
9910 Local<Value> r = Function::Cast(*get_prop)
9911 ->Call(env1.local(), global1, 0, nullptr)
9912 .ToLocalChecked();
9913 CHECK(!try_catch.HasCaught());
9914 CHECK_EQ(1, r->Int32Value(env1.local()).FromJust());
9915 }
9916
9917 // Check that env3 is not accessible from env1
9918 {
9919 v8::MaybeLocal<Value> r = global3->Get(env1.local(), v8_str("prop2"));
9920 CHECK(r.IsEmpty());
9921 }
9922}
9923
9924
9925TEST(DetachGlobal) {
9926 LocalContext env1;
9927 v8::HandleScope scope(env1->GetIsolate());
9928
9929 // Create second environment.
9930 v8::Local<Context> env2 = Context::New(env1->GetIsolate());
9931
9932 Local<Value> foo = v8_str("foo");
9933
9934 // Set same security token for env1 and env2.
9935 env1->SetSecurityToken(foo);
9936 env2->SetSecurityToken(foo);
9937
9938 // Create a property on the global object in env2.
9939 {
9940 v8::Context::Scope scope(env2);
9941 CHECK(env2->Global()
9942 ->Set(env2, v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42))
9943 .FromJust());
9944 }
9945
9946 // Create a reference to env2 global from env1 global.
9947 CHECK(env1->Global()
9948 ->Set(env1.local(), v8_str("other"), env2->Global())
9949 .FromJust());
9950
9951 // Check that we have access to other.p in env2 from env1.
9952 Local<Value> result = CompileRun("other.p");
9953 CHECK(result->IsInt32());
9954 CHECK_EQ(42, result->Int32Value(env1.local()).FromJust());
9955
9956 // Hold on to global from env2 and detach global from env2.
9957 Local<v8::Object> global2 = env2->Global();
9958 env2->DetachGlobal();
9959
9960 // Check that the global has been detached. No other.p property can
9961 // be found.
9962 result = CompileRun("other.p");
9963 CHECK(result.IsEmpty());
9964
9965 // Reuse global2 for env3.
9966 v8::Local<Context> env3 = Context::New(
9967 env1->GetIsolate(), nullptr, v8::Local<v8::ObjectTemplate>(), global2);
9968 CHECK(global2->Equals(env1.local(), env3->Global()).FromJust());
9969
9970 // Start by using the same security token for env3 as for env1 and env2.
9971 env3->SetSecurityToken(foo);
9972
9973 // Create a property on the global object in env3.
9974 {
9975 v8::Context::Scope scope(env3);
9976 CHECK(env3->Global()
9977 ->Set(env3, v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24))
9978 .FromJust());
9979 }
9980
9981 // Check that other.p is now the property in env3 and that we have access.
9982 result = CompileRun("other.p");
9983 CHECK(result->IsInt32());
9984 CHECK_EQ(24, result->Int32Value(env3).FromJust());
9985}
9986
9987
9988void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9989 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
9990 info.GetReturnValue().Set(
9991 context->Global()->Get(context, v8_str("x")).ToLocalChecked());
9992}
9993
9994
9995TEST(DetachedAccesses) {
9996 LocalContext env1;
9997 v8::HandleScope scope(env1->GetIsolate());
9998
9999 // Create second environment.
10000 Local<ObjectTemplate> inner_global_template =
10001 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
10002 inner_global_template ->SetAccessorProperty(
10003 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
10004 v8::Local<Context> env2 =
10005 Context::New(env1->GetIsolate(), nullptr, inner_global_template);
10006
10007 Local<Value> foo = v8_str("foo");
10008
10009 // Set same security token for env1 and env2.
10010 env1->SetSecurityToken(foo);
10011 env2->SetSecurityToken(foo);
10012
10013 CHECK(env1->Global()
10014 ->Set(env1.local(), v8_str("x"), v8_str("env1_x"))
10015 .FromJust());
10016
10017 {
10018 v8::Context::Scope scope(env2);
10019 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env2_x")).FromJust());
10020 CompileRun(
10021 "function bound_x() { return x; }"
10022 "function get_x() { return this.x; }"
10023 "function get_x_w() { return (function() {return this.x;})(); }");
10024 CHECK(env1->Global()
10025 ->Set(env1.local(), v8_str("bound_x"), CompileRun("bound_x"))
10026 .FromJust());
10027 CHECK(env1->Global()
10028 ->Set(env1.local(), v8_str("get_x"), CompileRun("get_x"))
10029 .FromJust());
10030 CHECK(env1->Global()
10031 ->Set(env1.local(), v8_str("get_x_w"), CompileRun("get_x_w"))
10032 .FromJust());
10033 env1->Global()
10034 ->Set(env1.local(), v8_str("this_x"),
10035 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"))
10036 .FromJust();
10037 }
10038
10039 Local<Object> env2_global = env2->Global();
10040 env2->DetachGlobal();
10041
10042 Local<Value> result;
10043 result = CompileRun("bound_x()");
10044 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10045 result = CompileRun("get_x()");
10046 CHECK(result.IsEmpty());
10047 result = CompileRun("get_x_w()");
10048 CHECK(result.IsEmpty());
10049 result = CompileRun("this_x()");
10050 CHECK(v8_str("env2_x")->Equals(env1.local(), result).FromJust());
10051
10052 // Reattach env2's proxy
10053 env2 = Context::New(env1->GetIsolate(), nullptr,
10054 v8::Local<v8::ObjectTemplate>(), env2_global);
10055 env2->SetSecurityToken(foo);
10056 {
10057 v8::Context::Scope scope(env2);
10058 CHECK(env2->Global()->Set(env2, v8_str("x"), v8_str("env3_x")).FromJust());
10059 CHECK(env2->Global()->Set(env2, v8_str("env1"), env1->Global()).FromJust());
10060 result = CompileRun(
10061 "results = [];"
10062 "for (var i = 0; i < 4; i++ ) {"
10063 " results.push(env1.bound_x());"
10064 " results.push(env1.get_x());"
10065 " results.push(env1.get_x_w());"
10066 " results.push(env1.this_x());"
10067 "}"
10068 "results");
10069 Local<v8::Array> results = Local<v8::Array>::Cast(result);
10070 CHECK_EQ(16u, results->Length());
10071 for (int i = 0; i < 16; i += 4) {
10072 CHECK(v8_str("env2_x")
10073 ->Equals(env2, results->Get(env2, i + 0).ToLocalChecked())
10074 .FromJust());
10075 CHECK(v8_str("env1_x")
10076 ->Equals(env2, results->Get(env2, i + 1).ToLocalChecked())
10077 .FromJust());
10078 CHECK(v8_str("env3_x")
10079 ->Equals(env2, results->Get(env2, i + 2).ToLocalChecked())
10080 .FromJust());
10081 CHECK(v8_str("env2_x")
10082 ->Equals(env2, results->Get(env2, i + 3).ToLocalChecked())
10083 .FromJust());
10084 }
10085 }
10086
10087 result = CompileRun(
10088 "results = [];"
10089 "for (var i = 0; i < 4; i++ ) {"
10090 " results.push(bound_x());"
10091 " results.push(get_x());"
10092 " results.push(get_x_w());"
10093 " results.push(this_x());"
10094 "}"
10095 "results");
10096 Local<v8::Array> results = Local<v8::Array>::Cast(result);
10097 CHECK_EQ(16u, results->Length());
10098 for (int i = 0; i < 16; i += 4) {
10099 CHECK(v8_str("env2_x")
10100 ->Equals(env1.local(),
10101 results->Get(env1.local(), i + 0).ToLocalChecked())
10102 .FromJust());
10103 CHECK(v8_str("env3_x")
10104 ->Equals(env1.local(),
10105 results->Get(env1.local(), i + 1).ToLocalChecked())
10106 .FromJust());
10107 CHECK(v8_str("env3_x")
10108 ->Equals(env1.local(),
10109 results->Get(env1.local(), i + 2).ToLocalChecked())
10110 .FromJust());
10111 CHECK(v8_str("env2_x")
10112 ->Equals(env1.local(),
10113 results->Get(env1.local(), i + 3).ToLocalChecked())
10114 .FromJust());
10115 }
10116
10117 result = CompileRun(
10118 "results = [];"
10119 "for (var i = 0; i < 4; i++ ) {"
10120 " results.push(this.bound_x());"
10121 " results.push(this.get_x());"
10122 " results.push(this.get_x_w());"
10123 " results.push(this.this_x());"
10124 "}"
10125 "results");
10126 results = Local<v8::Array>::Cast(result);
10127 CHECK_EQ(16u, results->Length());
10128 for (int i = 0; i < 16; i += 4) {
10129 CHECK(v8_str("env2_x")
10130 ->Equals(env1.local(),
10131 results->Get(env1.local(), i + 0).ToLocalChecked())
10132 .FromJust());
10133 CHECK(v8_str("env1_x")
10134 ->Equals(env1.local(),
10135 results->Get(env1.local(), i + 1).ToLocalChecked())
10136 .FromJust());
10137 CHECK(v8_str("env3_x")
10138 ->Equals(env1.local(),
10139 results->Get(env1.local(), i + 2).ToLocalChecked())
10140 .FromJust());
10141 CHECK(v8_str("env2_x")
10142 ->Equals(env1.local(),
10143 results->Get(env1.local(), i + 3).ToLocalChecked())
10144 .FromJust());
10145 }
10146}
10147
10148
10149static bool allowed_access = false;
10150static bool AccessBlocker(Local<v8::Context> accessing_context,
10151 Local<v8::Object> accessed_object,
10152 Local<v8::Value> data) {
10153 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
10154 return context->Global()->Equals(context, accessed_object).FromJust() ||
10155 allowed_access;
10156}
10157
10158
10159static int g_echo_value = -1;
10160
10161
10162static void EchoGetter(
10163 Local<String> name,
10164 const v8::PropertyCallbackInfo<v8::Value>& info) {
10165 info.GetReturnValue().Set(v8_num(g_echo_value));
10166}
10167
10168
10169static void EchoSetter(Local<String> name, Local<Value> value,
10170 const v8::PropertyCallbackInfo<void>& args) {
10171 if (value->IsNumber())
10172 g_echo_value =
10173 value->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
10174}
10175
10176
10177static void UnreachableGetter(
10178 Local<String> name,
10179 const v8::PropertyCallbackInfo<v8::Value>& info) {
10180 UNREACHABLE(); // This function should not be called..
10181}
10182
10183
10184static void UnreachableSetter(Local<String>,
10185 Local<Value>,
10186 const v8::PropertyCallbackInfo<void>&) {
10187 UNREACHABLE(); // This function should not be called.
10188}
10189
10190
10191static void UnreachableFunction(
10192 const v8::FunctionCallbackInfo<v8::Value>& info) {
10193 UNREACHABLE(); // This function should not be called..
10194}
10195
10196
10197TEST(AccessControl) {
10198 v8::Isolate* isolate = CcTest::isolate();
10199 v8::HandleScope handle_scope(isolate);
10200 v8::Local<v8::ObjectTemplate> global_template =
10201 v8::ObjectTemplate::New(isolate);
10202
10203 global_template->SetAccessCheckCallback(AccessBlocker);
10204
10205 // Add an accessor accessible by cross-domain JS code.
10206 global_template->SetAccessor(
10207 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10208 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10209
10210
10211 // Add an accessor that is not accessible by cross-domain JS code.
10212 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10213 UnreachableSetter, v8::Local<Value>(),
10214 v8::DEFAULT);
10215
10216 global_template->SetAccessorProperty(
10217 v8_str("blocked_js_prop"),
10218 v8::FunctionTemplate::New(isolate, UnreachableFunction),
10219 v8::FunctionTemplate::New(isolate, UnreachableFunction),
10220 v8::None,
10221 v8::DEFAULT);
10222
10223 // Create an environment
10224 v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10225 context0->Enter();
10226
10227 v8::Local<v8::Object> global0 = context0->Global();
10228
10229 // Define a property with JS getter and setter.
10230 CompileRun(
10231 "function getter() { return 'getter'; };\n"
10232 "function setter() { return 'setter'; }\n"
10233 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
10234
10235 Local<Value> getter =
10236 global0->Get(context0, v8_str("getter")).ToLocalChecked();
10237 Local<Value> setter =
10238 global0->Get(context0, v8_str("setter")).ToLocalChecked();
10239
10240 // And define normal element.
10241 CHECK(global0->Set(context0, 239, v8_str("239")).FromJust());
10242
10243 // Define an element with JS getter and setter.
10244 CompileRun(
10245 "function el_getter() { return 'el_getter'; };\n"
10246 "function el_setter() { return 'el_setter'; };\n"
10247 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
10248
10249 Local<Value> el_getter =
10250 global0->Get(context0, v8_str("el_getter")).ToLocalChecked();
10251 Local<Value> el_setter =
10252 global0->Get(context0, v8_str("el_setter")).ToLocalChecked();
10253
10254 v8::HandleScope scope1(isolate);
10255
10256 v8::Local<Context> context1 = Context::New(isolate);
10257 context1->Enter();
10258
10259 v8::Local<v8::Object> global1 = context1->Global();
10260 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10261
10262 // Access blocked property.
10263 CompileRun("other.blocked_prop = 1");
10264
10265 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10266 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10267 .IsEmpty());
10268 CHECK(
10269 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
10270
10271 // Access blocked element.
10272 CHECK(CompileRun("other[239] = 1").IsEmpty());
10273
10274 CHECK(CompileRun("other[239]").IsEmpty());
10275 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10276 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10277
10278 allowed_access = true;
10279 // Now we can enumerate the property.
10280 ExpectTrue("propertyIsEnumerable.call(other, '239')");
10281 allowed_access = false;
10282
10283 // Access a property with JS accessor.
10284 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10285
10286 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10287 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10288 .IsEmpty());
10289
10290 allowed_access = true;
10291
10292 ExpectString("other.js_accessor_p", "getter");
10293 ExpectObject(
10294 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10295 ExpectObject(
10296 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10297 ExpectUndefined(
10298 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10299
10300 allowed_access = false;
10301
10302 // Access an element with JS accessor.
10303 CHECK(CompileRun("other[42] = 2").IsEmpty());
10304
10305 CHECK(CompileRun("other[42]").IsEmpty());
10306 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10307
10308 allowed_access = true;
10309
10310 ExpectString("other[42]", "el_getter");
10311 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10312 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10313 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10314
10315 allowed_access = false;
10316
10317 v8::Local<Value> value;
10318
10319 // Access accessible property
10320 value = CompileRun("other.accessible_prop = 3");
10321 CHECK(value->IsNumber());
10322 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10323 CHECK_EQ(3, g_echo_value);
10324
10325 value = CompileRun("other.accessible_prop");
10326 CHECK(value->IsNumber());
10327 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10328
10329 value = CompileRun(
10330 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10331 CHECK(value->IsNumber());
10332 CHECK_EQ(3, value->Int32Value(context1).FromJust());
10333
10334 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10335 CHECK(value->IsTrue());
10336
10337 // Enumeration doesn't enumerate accessors from inaccessible objects in
10338 // the prototype chain even if the accessors are in themselves accessible.
10339 // Enumeration doesn't throw, it silently ignores what it can't access.
10340 value = CompileRun(
10341 "(function() {"
10342 " var obj = { '__proto__': other };"
10343 " try {"
10344 " for (var p in obj) {"
10345 " if (p == 'accessible_prop' ||"
10346 " p == 'blocked_js_prop' ||"
10347 " p == 'blocked_js_prop') {"
10348 " return false;"
10349 " }"
10350 " }"
10351 " return true;"
10352 " } catch (e) {"
10353 " return false;"
10354 " }"
10355 "})()");
10356 CHECK(value->IsTrue());
10357
10358 // Test that preventExtensions fails on a non-accessible object even if that
10359 // object is already non-extensible.
10360 CHECK(global1->Set(context1, v8_str("checked_object"),
10361 global_template->NewInstance(context1).ToLocalChecked())
10362 .FromJust());
10363 allowed_access = true;
10364 CompileRun("Object.preventExtensions(checked_object)");
10365 ExpectFalse("Object.isExtensible(checked_object)");
10366 allowed_access = false;
10367 CHECK(CompileRun("Object.preventExtensions(checked_object)").IsEmpty());
10368
10369 context1->Exit();
10370 context0->Exit();
10371}
10372
10373
10374TEST(AccessControlES5) {
10375 v8::Isolate* isolate = CcTest::isolate();
10376 v8::HandleScope handle_scope(isolate);
10377 v8::Local<v8::ObjectTemplate> global_template =
10378 v8::ObjectTemplate::New(isolate);
10379
10380 global_template->SetAccessCheckCallback(AccessBlocker);
10381
10382 // Add accessible accessor.
10383 global_template->SetAccessor(
10384 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10385 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10386
10387
10388 // Add an accessor that is not accessible by cross-domain JS code.
10389 global_template->SetAccessor(v8_str("blocked_prop"), UnreachableGetter,
10390 UnreachableSetter, v8::Local<Value>(),
10391 v8::DEFAULT);
10392
10393 // Create an environment
10394 v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10395 context0->Enter();
10396
10397 v8::Local<v8::Object> global0 = context0->Global();
10398
10399 v8::Local<Context> context1 = Context::New(isolate);
10400 context1->Enter();
10401 v8::Local<v8::Object> global1 = context1->Global();
10402 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10403
10404 // Regression test for issue 1154.
10405 CHECK(CompileRun("Object.keys(other).length == 1")->BooleanValue(isolate));
10406 CHECK(CompileRun("Object.keys(other)[0] == 'accessible_prop'")
10407 ->BooleanValue(isolate));
10408 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10409
10410 // Regression test for issue 1027.
10411 CompileRun("Object.defineProperty(\n"
10412 " other, 'blocked_prop', {configurable: false})");
10413 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10414 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10415 .IsEmpty());
10416
10417 // Regression test for issue 1171.
10418 ExpectTrue("Object.isExtensible(other)");
10419 CompileRun("Object.preventExtensions(other)");
10420 ExpectTrue("Object.isExtensible(other)");
10421
10422 // Object.seal and Object.freeze.
10423 CompileRun("Object.freeze(other)");
10424 ExpectTrue("Object.isExtensible(other)");
10425
10426 CompileRun("Object.seal(other)");
10427 ExpectTrue("Object.isExtensible(other)");
10428
10429 // Regression test for issue 1250.
10430 // Make sure that we can set the accessible accessors value using normal
10431 // assignment.
10432 CompileRun("other.accessible_prop = 42");
10433 CHECK_EQ(42, g_echo_value);
10434
10435 // [[DefineOwnProperty]] always throws for access-checked objects.
10436 CHECK(
10437 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: 43})")
10438 .IsEmpty());
10439 CHECK(CompileRun("other.accessible_prop == 42")->IsTrue());
10440 CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter.
10441}
10442
10443static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context,
10444 Local<v8::Object> global,
10445 Local<v8::Value> data) {
10446 i::PrintF("Access blocked.\n");
10447 return false;
10448}
10449
10450static bool AccessAlwaysAllowed(Local<v8::Context> accessing_context,
10451 Local<v8::Object> global,
10452 Local<v8::Value> data) {
10453 i::PrintF("Access allowed.\n");
10454 return true;
10455}
10456
10457THREADED_TEST(AccessControlGetOwnPropertyNames) {
10458 v8::Isolate* isolate = CcTest::isolate();
10459 v8::HandleScope handle_scope(isolate);
10460 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10461
10462 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10463 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10464
10465 // Add an accessor accessible by cross-domain JS code.
10466 obj_template->SetAccessor(
10467 v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Local<Value>(),
10468 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10469
10470 // Create an environment
10471 v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
10472 context0->Enter();
10473
10474 v8::Local<v8::Object> global0 = context0->Global();
10475
10476 v8::HandleScope scope1(CcTest::isolate());
10477
10478 v8::Local<Context> context1 = Context::New(isolate);
10479 context1->Enter();
10480
10481 v8::Local<v8::Object> global1 = context1->Global();
10482 CHECK(global1->Set(context1, v8_str("other"), global0).FromJust());
10483 CHECK(global1->Set(context1, v8_str("object"),
10484 obj_template->NewInstance(context1).ToLocalChecked())
10485 .FromJust());
10486
10487 v8::Local<Value> value;
10488
10489 // Attempt to get the property names of the other global object and
10490 // of an object that requires access checks. Accessing the other
10491 // global object should be blocked by access checks on the global
10492 // proxy object. Accessing the object that requires access checks
10493 // is blocked by the access checks on the object itself.
10494 value = CompileRun(
10495 "var names = Object.getOwnPropertyNames(other);"
10496 "names.length == 1 && names[0] == 'accessible_prop';");
10497 CHECK(value->BooleanValue(isolate));
10498
10499 value = CompileRun(
10500 "var names = Object.getOwnPropertyNames(object);"
10501 "names.length == 1 && names[0] == 'accessible_prop';");
10502 CHECK(value->BooleanValue(isolate));
10503
10504 context1->Exit();
10505 context0->Exit();
10506}
10507
10508
10509TEST(Regress470113) {
10510 v8::Isolate* isolate = CcTest::isolate();
10511 v8::HandleScope handle_scope(isolate);
10512 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
10513 obj_template->SetAccessCheckCallback(AccessAlwaysBlocked);
10514 LocalContext env;
10515 CHECK(env->Global()
10516 ->Set(env.local(), v8_str("prohibited"),
10517 obj_template->NewInstance(env.local()).ToLocalChecked())
10518 .FromJust());
10519
10520 {
10521 v8::TryCatch try_catch(isolate);
10522 CompileRun(
10523 "'use strict';\n"
10524 "class C extends Object {\n"
10525 " m() { super.powned = 'Powned!'; }\n"
10526 "}\n"
10527 "let c = new C();\n"
10528 "c.m.call(prohibited)");
10529
10530 CHECK(try_catch.HasCaught());
10531 }
10532}
10533
10534
10535static void ConstTenGetter(Local<String> name,
10536 const v8::PropertyCallbackInfo<v8::Value>& info) {
10537 info.GetReturnValue().Set(v8_num(10));
10538}
10539
10540
10541THREADED_TEST(CrossDomainAccessors) {
10542 v8::Isolate* isolate = CcTest::isolate();
10543 v8::HandleScope handle_scope(isolate);
10544
10545 v8::Local<v8::FunctionTemplate> func_template =
10546 v8::FunctionTemplate::New(isolate);
10547
10548 v8::Local<v8::ObjectTemplate> global_template =
10549 func_template->InstanceTemplate();
10550
10551 v8::Local<v8::ObjectTemplate> proto_template =
10552 func_template->PrototypeTemplate();
10553
10554 // Add an accessor to proto that's accessible by cross-domain JS code.
10555 proto_template->SetAccessor(v8_str("accessible"), ConstTenGetter, nullptr,
10556 v8::Local<Value>(), v8::ALL_CAN_READ);
10557
10558 // Add an accessor that is not accessible by cross-domain JS code.
10559 global_template->SetAccessor(v8_str("unreachable"), UnreachableGetter,
10560 nullptr, v8::Local<Value>(), v8::DEFAULT);
10561
10562 v8::Local<Context> context0 = Context::New(isolate, nullptr, global_template);
10563 context0->Enter();
10564
10565 Local<v8::Object> global = context0->Global();
10566 // Add a normal property that shadows 'accessible'
10567 CHECK(global->Set(context0, v8_str("accessible"), v8_num(11)).FromJust());
10568
10569 // Enter a new context.
10570 v8::HandleScope scope1(CcTest::isolate());
10571 v8::Local<Context> context1 = Context::New(isolate);
10572 context1->Enter();
10573
10574 v8::Local<v8::Object> global1 = context1->Global();
10575 CHECK(global1->Set(context1, v8_str("other"), global).FromJust());
10576
10577 // Should return 10, instead of 11
10578 v8::Local<Value> value =
10579 v8_compile("other.accessible")->Run(context1).ToLocalChecked();
10580 CHECK(value->IsNumber());
10581 CHECK_EQ(10, value->Int32Value(context1).FromJust());
10582
10583 v8::MaybeLocal<v8::Value> maybe_value =
10584 v8_compile("other.unreachable")->Run(context1);
10585 CHECK(maybe_value.IsEmpty());
10586
10587 context1->Exit();
10588 context0->Exit();
10589}
10590
10591
10592static int access_count = 0;
10593
10594static bool AccessCounter(Local<v8::Context> accessing_context,
10595 Local<v8::Object> accessed_object,
10596 Local<v8::Value> data) {
10597 access_count++;
10598 return true;
10599}
10600
10601
10602// This one is too easily disturbed by other tests.
10603TEST(AccessControlIC) {
10604 access_count = 0;
10605
10606 v8::Isolate* isolate = CcTest::isolate();
10607 v8::HandleScope handle_scope(isolate);
10608
10609 // Create an environment.
10610 v8::Local<Context> context0 = Context::New(isolate);
10611 context0->Enter();
10612
10613 // Create an object that requires access-check functions to be
10614 // called for cross-domain access.
10615 v8::Local<v8::ObjectTemplate> object_template =
10616 v8::ObjectTemplate::New(isolate);
10617 object_template->SetAccessCheckCallback(AccessCounter);
10618 Local<v8::Object> object =
10619 object_template->NewInstance(context0).ToLocalChecked();
10620
10621 v8::HandleScope scope1(isolate);
10622
10623 // Create another environment.
10624 v8::Local<Context> context1 = Context::New(isolate);
10625 context1->Enter();
10626
10627 // Make easy access to the object from the other environment.
10628 v8::Local<v8::Object> global1 = context1->Global();
10629 CHECK(global1->Set(context1, v8_str("obj"), object).FromJust());
10630
10631 v8::Local<Value> value;
10632
10633 // Check that the named access-control function is called every time.
10634 CompileRun("function testProp(obj) {"
10635 " for (var i = 0; i < 10; i++) obj.prop = 1;"
10636 " for (var j = 0; j < 10; j++) obj.prop;"
10637 " return obj.prop"
10638 "}");
10639 value = CompileRun("testProp(obj)");
10640 CHECK(value->IsNumber());
10641 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10642 CHECK_EQ(21, access_count);
10643
10644 // Check that the named access-control function is called every time.
10645 CompileRun("var p = 'prop';"
10646 "function testKeyed(obj) {"
10647 " for (var i = 0; i < 10; i++) obj[p] = 1;"
10648 " for (var j = 0; j < 10; j++) obj[p];"
10649 " return obj[p];"
10650 "}");
10651 // Use obj which requires access checks. No inline caching is used
10652 // in that case.
10653 value = CompileRun("testKeyed(obj)");
10654 CHECK(value->IsNumber());
10655 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10656 CHECK_EQ(42, access_count);
10657 // Force the inline caches into generic state and try again.
10658 CompileRun("testKeyed({ a: 0 })");
10659 CompileRun("testKeyed({ b: 0 })");
10660 value = CompileRun("testKeyed(obj)");
10661 CHECK(value->IsNumber());
10662 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10663 CHECK_EQ(63, access_count);
10664
10665 // Check that the indexed access-control function is called every time.
10666 access_count = 0;
10667
10668 CompileRun("function testIndexed(obj) {"
10669 " for (var i = 0; i < 10; i++) obj[0] = 1;"
10670 " for (var j = 0; j < 10; j++) obj[0];"
10671 " return obj[0]"
10672 "}");
10673 value = CompileRun("testIndexed(obj)");
10674 CHECK(value->IsNumber());
10675 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10676 CHECK_EQ(21, access_count);
10677 // Force the inline caches into generic state.
10678 CompileRun("testIndexed(new Array(1))");
10679 // Test that the indexed access check is called.
10680 value = CompileRun("testIndexed(obj)");
10681 CHECK(value->IsNumber());
10682 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10683 CHECK_EQ(42, access_count);
10684
10685 access_count = 0;
10686 // Check that the named access check is called when invoking
10687 // functions on an object that requires access checks.
10688 CompileRun("obj.f = function() {}");
10689 CompileRun("function testCallNormal(obj) {"
10690 " for (var i = 0; i < 10; i++) obj.f();"
10691 "}");
10692 CompileRun("testCallNormal(obj)");
10693 printf("%i\n", access_count);
10694 CHECK_EQ(11, access_count);
10695
10696 // Force obj into slow case.
10697 value = CompileRun("delete obj.prop");
10698 CHECK(value->BooleanValue(isolate));
10699 // Force inline caches into dictionary probing mode.
10700 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10701 // Test that the named access check is called.
10702 value = CompileRun("testProp(obj);");
10703 CHECK(value->IsNumber());
10704 CHECK_EQ(1, value->Int32Value(context1).FromJust());
10705 CHECK_EQ(33, access_count);
10706
10707 // Force the call inline cache into dictionary probing mode.
10708 CompileRun("o.f = function() {}; testCallNormal(o)");
10709 // Test that the named access check is still called for each
10710 // invocation of the function.
10711 value = CompileRun("testCallNormal(obj)");
10712 CHECK_EQ(43, access_count);
10713
10714 context1->Exit();
10715 context0->Exit();
10716}
10717
10718
10719THREADED_TEST(Version) { v8::V8::GetVersion(); }
10720
10721
10722static void InstanceFunctionCallback(
10723 const v8::FunctionCallbackInfo<v8::Value>& args) {
10724 ApiTestFuzzer::Fuzz();
10725 args.GetReturnValue().Set(v8_num(12));
10726}
10727
10728
10729THREADED_TEST(InstanceProperties) {
10730 LocalContext context;
10731 v8::Isolate* isolate = context->GetIsolate();
10732 v8::HandleScope handle_scope(isolate);
10733
10734 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10735 Local<ObjectTemplate> instance = t->InstanceTemplate();
10736
10737 instance->Set(v8_str("x"), v8_num(42));
10738 instance->Set(v8_str("f"),
10739 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10740
10741 Local<Value> o = t->GetFunction(context.local())
10742 .ToLocalChecked()
10743 ->NewInstance(context.local())
10744 .ToLocalChecked();
10745
10746 CHECK(context->Global()->Set(context.local(), v8_str("i"), o).FromJust());
10747 Local<Value> value = CompileRun("i.x");
10748 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
10749
10750 value = CompileRun("i.f()");
10751 CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
10752}
10753
10754
10755static void GlobalObjectInstancePropertiesGet(
10756 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10757 ApiTestFuzzer::Fuzz();
10758}
10759
10760
10761THREADED_TEST(GlobalObjectInstanceProperties) {
10762 v8::Isolate* isolate = CcTest::isolate();
10763 v8::HandleScope handle_scope(isolate);
10764
10765 Local<Value> global_object;
10766
10767 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10768 t->InstanceTemplate()->SetHandler(
10769 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10770 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10771 instance_template->Set(v8_str("x"), v8_num(42));
10772 instance_template->Set(v8_str("f"),
10773 v8::FunctionTemplate::New(isolate,
10774 InstanceFunctionCallback));
10775
10776 // The script to check how TurboFan compiles missing global function
10777 // invocations. function g is not defined and should throw on call.
10778 const char* script =
10779 "function wrapper(call) {"
10780 " var x = 0, y = 1;"
10781 " for (var i = 0; i < 1000; i++) {"
10782 " x += i * 100;"
10783 " y += i * 100;"
10784 " }"
10785 " if (call) g();"
10786 "}"
10787 "for (var i = 0; i < 17; i++) wrapper(false);"
10788 "var thrown = 0;"
10789 "try { wrapper(true); } catch (e) { thrown = 1; };"
10790 "thrown";
10791
10792 {
10793 LocalContext env(nullptr, instance_template);
10794 // Hold on to the global object so it can be used again in another
10795 // environment initialization.
10796 global_object = env->Global();
10797
10798 Local<Value> value = CompileRun("x");
10799 CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10800 value = CompileRun("f()");
10801 CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10802 value = CompileRun(script);
10803 CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10804 }
10805
10806 {
10807 // Create new environment reusing the global object.
10808 LocalContext env(nullptr, instance_template, global_object);
10809 Local<Value> value = CompileRun("x");
10810 CHECK_EQ(42, value->Int32Value(env.local()).FromJust());
10811 value = CompileRun("f()");
10812 CHECK_EQ(12, value->Int32Value(env.local()).FromJust());
10813 value = CompileRun(script);
10814 CHECK_EQ(1, value->Int32Value(env.local()).FromJust());
10815 }
10816}
10817
10818THREADED_TEST(ObjectGetOwnPropertyNames) {
10819 LocalContext context;
10820 v8::Isolate* isolate = context->GetIsolate();
10821 v8::HandleScope handle_scope(isolate);
10822
10823 v8::Local<v8::Object> value = v8::Local<v8::Object>::Cast(
10824 v8::StringObject::New(CcTest::isolate(), v8_str("test")));
10825 v8::Local<v8::Array> properties;
10826
10827 CHECK(value
10828 ->GetOwnPropertyNames(context.local(),
10829 static_cast<v8::PropertyFilter>(
10830 v8::PropertyFilter::ALL_PROPERTIES |
10831 v8::PropertyFilter::SKIP_SYMBOLS),
10832 v8::KeyConversionMode::kKeepNumbers)
10833 .ToLocal(&properties));
10834 CHECK_EQ(5u, properties->Length());
10835 v8::Local<v8::Value> property;
10836 CHECK(properties->Get(context.local(), 4).ToLocal(&property) &&
10837 property->IsString());
10838 CHECK(property.As<v8::String>()
10839 ->Equals(context.local(), v8_str("length"))
10840 .FromMaybe(false));
10841 for (int i = 0; i < 4; ++i) {
10842 v8::Local<v8::Value> property;
10843 CHECK(properties->Get(context.local(), i).ToLocal(&property) &&
10844 property->IsInt32());
10845 CHECK_EQ(property.As<v8::Int32>()->Value(), i);
10846 }
10847
10848 CHECK(value
10849 ->GetOwnPropertyNames(context.local(),
10850 v8::PropertyFilter::ONLY_ENUMERABLE,
10851 v8::KeyConversionMode::kKeepNumbers)
10852 .ToLocal(&properties));
10853 v8::Local<v8::Array> number_properties;
10854 CHECK(value
10855 ->GetOwnPropertyNames(context.local(),
10856 v8::PropertyFilter::ONLY_ENUMERABLE,
10857 v8::KeyConversionMode::kConvertToString)
10858 .ToLocal(&number_properties));
10859 CHECK_EQ(4u, properties->Length());
10860 for (int i = 0; i < 4; ++i) {
10861 v8::Local<v8::Value> property_index;
10862 v8::Local<v8::Value> property_name;
10863
10864 CHECK(number_properties->Get(context.local(), i).ToLocal(&property_name));
10865 CHECK(property_name->IsString());
10866
10867 CHECK(properties->Get(context.local(), i).ToLocal(&property_index));
10868 CHECK(property_index->IsInt32());
10869
10870 CHECK_EQ(property_index.As<v8::Int32>()->Value(), i);
10871 CHECK_EQ(property_name->ToNumber(context.local())
10872 .ToLocalChecked()
10873 .As<v8::Int32>()
10874 ->Value(),
10875 i);
10876 }
10877
10878 value = value->GetPrototype().As<v8::Object>();
10879 CHECK(value
10880 ->GetOwnPropertyNames(context.local(),
10881 static_cast<v8::PropertyFilter>(
10882 v8::PropertyFilter::ALL_PROPERTIES |
10883 v8::PropertyFilter::SKIP_SYMBOLS))
10884 .ToLocal(&properties));
10885 bool concat_found = false;
10886 bool starts_with_found = false;
10887 for (uint32_t i = 0; i < properties->Length(); ++i) {
10888 v8::Local<v8::Value> property;
10889 CHECK(properties->Get(context.local(), i).ToLocal(&property));
10890 if (!property->IsString()) continue;
10891 if (!concat_found)
10892 concat_found = property.As<v8::String>()
10893 ->Equals(context.local(), v8_str("concat"))
10894 .FromMaybe(false);
10895 if (!starts_with_found)
10896 starts_with_found = property.As<v8::String>()
10897 ->Equals(context.local(), v8_str("startsWith"))
10898 .FromMaybe(false);
10899 }
10900 CHECK(concat_found && starts_with_found);
10901}
10902
10903THREADED_TEST(CallKnownGlobalReceiver) {
10904 v8::Isolate* isolate = CcTest::isolate();
10905 v8::HandleScope handle_scope(isolate);
10906
10907 Local<Value> global_object;
10908
10909 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10910 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10911
10912 // The script to check that we leave global object not
10913 // global object proxy on stack when we deoptimize from inside
10914 // arguments evaluation.
10915 // To provoke error we need to both force deoptimization
10916 // from arguments evaluation and to force CallIC to take
10917 // CallIC_Miss code path that can't cope with global proxy.
10918 const char* script =
10919 "function bar(x, y) { try { } finally { } }"
10920 "function baz(x) { try { } finally { } }"
10921 "function bom(x) { try { } finally { } }"
10922 "function foo(x) { bar([x], bom(2)); }"
10923 "for (var i = 0; i < 10000; i++) foo(1);"
10924 "foo";
10925
10926 Local<Value> foo;
10927 {
10928 LocalContext env(nullptr, instance_template);
10929 // Hold on to the global object so it can be used again in another
10930 // environment initialization.
10931 global_object = env->Global();
10932 foo = CompileRun(script);
10933 }
10934
10935 {
10936 // Create new environment reusing the global object.
10937 LocalContext env(nullptr, instance_template, global_object);
10938 CHECK(env->Global()->Set(env.local(), v8_str("foo"), foo).FromJust());
10939 CompileRun("foo()");
10940 }
10941}
10942
10943
10944static void ShadowFunctionCallback(
10945 const v8::FunctionCallbackInfo<v8::Value>& args) {
10946 ApiTestFuzzer::Fuzz();
10947 args.GetReturnValue().Set(v8_num(42));
10948}
10949
10950
10951static int shadow_y;
10952static int shadow_y_setter_call_count;
10953static int shadow_y_getter_call_count;
10954
10955
10956static void ShadowYSetter(Local<String>,
10957 Local<Value>,
10958 const v8::PropertyCallbackInfo<void>&) {
10959 shadow_y_setter_call_count++;
10960 shadow_y = 42;
10961}
10962
10963
10964static void ShadowYGetter(Local<String> name,
10965 const v8::PropertyCallbackInfo<v8::Value>& info) {
10966 ApiTestFuzzer::Fuzz();
10967 shadow_y_getter_call_count++;
10968 info.GetReturnValue().Set(v8_num(shadow_y));
10969}
10970
10971
10972static void ShadowIndexedGet(uint32_t index,
10973 const v8::PropertyCallbackInfo<v8::Value>&) {
10974}
10975
10976
10977static void ShadowNamedGet(Local<Name> key,
10978 const v8::PropertyCallbackInfo<v8::Value>&) {}
10979
10980THREADED_TEST(ShadowObject) {
10981 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10982 v8::Isolate* isolate = CcTest::isolate();
10983 v8::HandleScope handle_scope(isolate);
10984
10985 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10986 LocalContext context(nullptr, global_template);
10987
10988 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10989 t->InstanceTemplate()->SetHandler(
10990 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10991 t->InstanceTemplate()->SetHandler(
10992 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10993 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10994 Local<ObjectTemplate> instance = t->InstanceTemplate();
10995
10996 proto->Set(v8_str("f"),
10997 v8::FunctionTemplate::New(isolate,
10998 ShadowFunctionCallback,
10999 Local<Value>()));
11000 proto->Set(v8_str("x"), v8_num(12));
11001
11002 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
11003
11004 Local<Value> o = t->GetFunction(context.local())
11005 .ToLocalChecked()
11006 ->NewInstance(context.local())
11007 .ToLocalChecked();
11008 CHECK(context->Global()
11009 ->Set(context.local(), v8_str("__proto__"), o)
11010 .FromJust());
11011
11012 Local<Value> value =
11013 CompileRun("this.propertyIsEnumerable(0)");
11014 CHECK(value->IsBoolean());
11015 CHECK(!value->BooleanValue(isolate));
11016
11017 value = CompileRun("x");
11018 CHECK_EQ(12, value->Int32Value(context.local()).FromJust());
11019
11020 value = CompileRun("f()");
11021 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11022
11023 CompileRun("y = 43");
11024 CHECK_EQ(1, shadow_y_setter_call_count);
11025 value = CompileRun("y");
11026 CHECK_EQ(1, shadow_y_getter_call_count);
11027 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11028}
11029
11030THREADED_TEST(ShadowObjectAndDataProperty) {
11031 // Lite mode doesn't make use of feedback vectors, which is what we
11032 // want to ensure has the correct form.
11033 if (i::FLAG_lite_mode) return;
11034 // This test mimics the kind of shadow property the Chromium embedder
11035 // uses for undeclared globals. The IC subsystem has special handling
11036 // for this case, using a PREMONOMORPHIC state to delay entering
11037 // MONOMORPHIC state until enough information is available to support
11038 // efficient access and good feedback for optimization.
11039 v8::Isolate* isolate = CcTest::isolate();
11040 v8::HandleScope handle_scope(isolate);
11041
11042 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11043 LocalContext context(nullptr, global_template);
11044
11045 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11046 t->InstanceTemplate()->SetHandler(
11047 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11048
11049 Local<Value> o = t->GetFunction(context.local())
11050 .ToLocalChecked()
11051 ->NewInstance(context.local())
11052 .ToLocalChecked();
11053 CHECK(context->Global()
11054 ->Set(context.local(), v8_str("__proto__"), o)
11055 .FromJust());
11056
11057 CompileRun(
11058 "function foo(x) { i = x; }"
11059 "foo(0)");
11060
11061 i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11062 v8::Utils::OpenHandle(*context->Global()
11063 ->Get(context.local(), v8_str("foo"))
11064 .ToLocalChecked())));
11065 CHECK(foo->has_feedback_vector());
11066 i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11067 i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11068 CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11069 CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11070 CompileRun("foo(1)");
11071 CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11072 // We go a bit further, checking that the form of monomorphism is
11073 // a PropertyCell in the vector. This is because we want to make sure
11074 // we didn't settle for a "poor man's monomorphism," such as a
11075 // slow_stub bailout which would mean a trip to the runtime on all
11076 // subsequent stores, and a lack of feedback for the optimizing
11077 // compiler downstream.
11078 i::HeapObject heap_object;
11079 CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11080 CHECK(heap_object->IsPropertyCell());
11081}
11082
11083THREADED_TEST(ShadowObjectAndDataPropertyTurbo) {
11084 // This test is the same as the previous one except that it triggers
11085 // optimization of {foo} after its first invocation.
11086 i::FLAG_allow_natives_syntax = true;
11087
11088 if (i::FLAG_lite_mode) return;
11089 v8::Isolate* isolate = CcTest::isolate();
11090 v8::HandleScope handle_scope(isolate);
11091
11092 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
11093 LocalContext context(nullptr, global_template);
11094
11095 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11096 t->InstanceTemplate()->SetHandler(
11097 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
11098
11099 Local<Value> o = t->GetFunction(context.local())
11100 .ToLocalChecked()
11101 ->NewInstance(context.local())
11102 .ToLocalChecked();
11103 CHECK(context->Global()
11104 ->Set(context.local(), v8_str("__proto__"), o)
11105 .FromJust());
11106
11107 CompileRun(
11108 "function foo(x) { i = x; }"
11109 "foo(0)");
11110
11111 i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
11112 v8::Utils::OpenHandle(*context->Global()
11113 ->Get(context.local(), v8_str("foo"))
11114 .ToLocalChecked())));
11115 CHECK(foo->has_feedback_vector());
11116 i::FeedbackSlot slot = i::FeedbackVector::ToSlot(0);
11117 i::FeedbackNexus nexus(foo->feedback_vector(), slot);
11118 CHECK_EQ(i::FeedbackSlotKind::kStoreGlobalSloppy, nexus.kind());
11119 CHECK_EQ(i::PREMONOMORPHIC, nexus.ic_state());
11120 CompileRun("%OptimizeFunctionOnNextCall(foo); foo(1)");
11121 CHECK_EQ(i::MONOMORPHIC, nexus.ic_state());
11122 i::HeapObject heap_object;
11123 CHECK(nexus.GetFeedback().GetHeapObject(&heap_object));
11124 CHECK(heap_object->IsPropertyCell());
11125}
11126
11127THREADED_TEST(SetPrototype) {
11128 LocalContext context;
11129 v8::Isolate* isolate = context->GetIsolate();
11130 v8::HandleScope handle_scope(isolate);
11131
11132 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11133 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11134 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11135 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11136 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11137 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11138 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11139 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11140
11141 Local<v8::Object> o0 = t0->GetFunction(context.local())
11142 .ToLocalChecked()
11143 ->NewInstance(context.local())
11144 .ToLocalChecked();
11145 Local<v8::Object> o1 = t1->GetFunction(context.local())
11146 .ToLocalChecked()
11147 ->NewInstance(context.local())
11148 .ToLocalChecked();
11149 Local<v8::Object> o2 = t2->GetFunction(context.local())
11150 .ToLocalChecked()
11151 ->NewInstance(context.local())
11152 .ToLocalChecked();
11153 Local<v8::Object> o3 = t3->GetFunction(context.local())
11154 .ToLocalChecked()
11155 ->NewInstance(context.local())
11156 .ToLocalChecked();
11157
11158 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11159 .ToLocalChecked()
11160 ->Int32Value(context.local())
11161 .FromJust());
11162 CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11163 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11164 .ToLocalChecked()
11165 ->Int32Value(context.local())
11166 .FromJust());
11167 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11168 .ToLocalChecked()
11169 ->Int32Value(context.local())
11170 .FromJust());
11171 CHECK(o1->SetPrototype(context.local(), o2).FromJust());
11172 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11173 .ToLocalChecked()
11174 ->Int32Value(context.local())
11175 .FromJust());
11176 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11177 .ToLocalChecked()
11178 ->Int32Value(context.local())
11179 .FromJust());
11180 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11181 .ToLocalChecked()
11182 ->Int32Value(context.local())
11183 .FromJust());
11184 CHECK(o2->SetPrototype(context.local(), o3).FromJust());
11185 CHECK_EQ(0, o0->Get(context.local(), v8_str("x"))
11186 .ToLocalChecked()
11187 ->Int32Value(context.local())
11188 .FromJust());
11189 CHECK_EQ(1, o0->Get(context.local(), v8_str("y"))
11190 .ToLocalChecked()
11191 ->Int32Value(context.local())
11192 .FromJust());
11193 CHECK_EQ(2, o0->Get(context.local(), v8_str("z"))
11194 .ToLocalChecked()
11195 ->Int32Value(context.local())
11196 .FromJust());
11197 CHECK_EQ(3, o0->Get(context.local(), v8_str("u"))
11198 .ToLocalChecked()
11199 ->Int32Value(context.local())
11200 .FromJust());
11201
11202 Local<Value> proto =
11203 o0->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
11204 CHECK(proto->IsObject());
11205 CHECK(proto.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11206
11207 Local<Value> proto0 = o0->GetPrototype();
11208 CHECK(proto0->IsObject());
11209 CHECK(proto0.As<v8::Object>()->Equals(context.local(), o1).FromJust());
11210
11211 Local<Value> proto1 = o1->GetPrototype();
11212 CHECK(proto1->IsObject());
11213 CHECK(proto1.As<v8::Object>()->Equals(context.local(), o2).FromJust());
11214
11215 Local<Value> proto2 = o2->GetPrototype();
11216 CHECK(proto2->IsObject());
11217 CHECK(proto2.As<v8::Object>()->Equals(context.local(), o3).FromJust());
11218}
11219
11220
11221// Getting property names of an object with a prototype chain that
11222// triggers dictionary elements in GetOwnPropertyNames() shouldn't
11223// crash the runtime.
11224THREADED_TEST(Regress91517) {
11225 i::FLAG_allow_natives_syntax = true;
11226 LocalContext context;
11227 v8::Isolate* isolate = context->GetIsolate();
11228 v8::HandleScope handle_scope(isolate);
11229
11230 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11231 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11232 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11233 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11234 t2->InstanceTemplate()->Set(v8_str("objects"),
11235 v8::ObjectTemplate::New(isolate));
11236 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11237 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11238 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11239 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11240 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11241
11242 // Force dictionary-based properties.
11243 i::ScopedVector<char> name_buf(1024);
11244 for (int i = 1; i <= 1000; i++) {
11245 i::SNPrintF(name_buf, "sdf%d", i);
11246 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11247 }
11248
11249 Local<v8::Object> o1 = t1->GetFunction(context.local())
11250 .ToLocalChecked()
11251 ->NewInstance(context.local())
11252 .ToLocalChecked();
11253 Local<v8::Object> o2 = t2->GetFunction(context.local())
11254 .ToLocalChecked()
11255 ->NewInstance(context.local())
11256 .ToLocalChecked();
11257 Local<v8::Object> o3 = t3->GetFunction(context.local())
11258 .ToLocalChecked()
11259 ->NewInstance(context.local())
11260 .ToLocalChecked();
11261 Local<v8::Object> o4 = t4->GetFunction(context.local())
11262 .ToLocalChecked()
11263 ->NewInstance(context.local())
11264 .ToLocalChecked();
11265
11266 CHECK(o4->SetPrototype(context.local(), o3).FromJust());
11267 CHECK(o3->SetPrototype(context.local(), o2).FromJust());
11268 CHECK(o2->SetPrototype(context.local(), o1).FromJust());
11269
11270 // Call the runtime version of GetOwnPropertyNames() on the natively
11271 // created object through JavaScript.
11272 CHECK(context->Global()->Set(context.local(), v8_str("obj"), o4).FromJust());
11273 // PROPERTY_FILTER_NONE = 0
11274 CompileRun("var names = %GetOwnPropertyKeys(obj, 0);");
11275
11276 ExpectInt32("names.length", 1);
11277 ExpectTrue("names.indexOf(\"baz\") >= 0");
11278 ExpectFalse("names.indexOf(\"boo\") >= 0");
11279 ExpectFalse("names.indexOf(\"foo\") >= 0");
11280 ExpectFalse("names.indexOf(\"fuz1\") >= 0");
11281 ExpectFalse("names.indexOf(\"objects\") >= 0");
11282 ExpectFalse("names.indexOf(\"fuz2\") >= 0");
11283 ExpectTrue("names[1005] == undefined");
11284}
11285
11286
11287THREADED_TEST(FunctionReadOnlyPrototype) {
11288 LocalContext context;
11289 v8::Isolate* isolate = context->GetIsolate();
11290 v8::HandleScope handle_scope(isolate);
11291
11292 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11293 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11294 t1->ReadOnlyPrototype();
11295 CHECK(context->Global()
11296 ->Set(context.local(), v8_str("func1"),
11297 t1->GetFunction(context.local()).ToLocalChecked())
11298 .FromJust());
11299 // Configured value of ReadOnly flag.
11300 CHECK(
11301 CompileRun(
11302 "(function() {"
11303 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11304 " return (descriptor['writable'] == false);"
11305 "})()")
11306 ->BooleanValue(isolate));
11307 CHECK_EQ(
11308 42,
11309 CompileRun("func1.prototype.x")->Int32Value(context.local()).FromJust());
11310 CHECK_EQ(42, CompileRun("func1.prototype = {}; func1.prototype.x")
11311 ->Int32Value(context.local())
11312 .FromJust());
11313
11314 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11315 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11316 CHECK(context->Global()
11317 ->Set(context.local(), v8_str("func2"),
11318 t2->GetFunction(context.local()).ToLocalChecked())
11319 .FromJust());
11320 // Default value of ReadOnly flag.
11321 CHECK(
11322 CompileRun(
11323 "(function() {"
11324 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11325 " return (descriptor['writable'] == true);"
11326 "})()")
11327 ->BooleanValue(isolate));
11328 CHECK_EQ(
11329 42,
11330 CompileRun("func2.prototype.x")->Int32Value(context.local()).FromJust());
11331}
11332
11333
11334THREADED_TEST(SetPrototypeThrows) {
11335 LocalContext context;
11336 v8::Isolate* isolate = context->GetIsolate();
11337 v8::HandleScope handle_scope(isolate);
11338
11339 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11340
11341 Local<v8::Object> o0 = t->GetFunction(context.local())
11342 .ToLocalChecked()
11343 ->NewInstance(context.local())
11344 .ToLocalChecked();
11345 Local<v8::Object> o1 = t->GetFunction(context.local())
11346 .ToLocalChecked()
11347 ->NewInstance(context.local())
11348 .ToLocalChecked();
11349
11350 CHECK(o0->SetPrototype(context.local(), o1).FromJust());
11351 // If setting the prototype leads to the cycle, SetPrototype should
11352 // return false and keep VM in sane state.
11353 v8::TryCatch try_catch(isolate);
11354 CHECK(o1->SetPrototype(context.local(), o0).IsNothing());
11355 CHECK(!try_catch.HasCaught());
11356 CHECK(!CcTest::i_isolate()->has_pending_exception());
11357
11358 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")
11359 ->Int32Value(context.local())
11360 .FromJust());
11361}
11362
11363
11364THREADED_TEST(FunctionRemovePrototype) {
11365 LocalContext context;
11366 v8::Isolate* isolate = context->GetIsolate();
11367 v8::HandleScope handle_scope(isolate);
11368
11369 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11370 t1->RemovePrototype();
11371 Local<v8::Function> fun = t1->GetFunction(context.local()).ToLocalChecked();
11372 CHECK(!fun->IsConstructor());
11373 CHECK(context->Global()->Set(context.local(), v8_str("fun"), fun).FromJust());
11374 CHECK(!CompileRun("'prototype' in fun")->BooleanValue(isolate));
11375
11376 v8::TryCatch try_catch(isolate);
11377 CompileRun("new fun()");
11378 CHECK(try_catch.HasCaught());
11379
11380 try_catch.Reset();
11381 CHECK(fun->NewInstance(context.local()).IsEmpty());
11382 CHECK(try_catch.HasCaught());
11383}
11384
11385
11386THREADED_TEST(GetterSetterExceptions) {
11387 LocalContext context;
11388 v8::Isolate* isolate = context->GetIsolate();
11389 v8::HandleScope handle_scope(isolate);
11390 CompileRun(
11391 "function Foo() { };"
11392 "function Throw() { throw 5; };"
11393 "var x = { };"
11394 "x.__defineSetter__('set', Throw);"
11395 "x.__defineGetter__('get', Throw);");
11396 Local<v8::Object> x = Local<v8::Object>::Cast(
11397 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked());
11398 v8::TryCatch try_catch(isolate);
11399 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11400 .IsNothing());
11401 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11402 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11403 .IsNothing());
11404 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11405 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11406 .IsNothing());
11407 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11408 CHECK(x->Set(context.local(), v8_str("set"), v8::Integer::New(isolate, 8))
11409 .IsNothing());
11410 CHECK(x->Get(context.local(), v8_str("get")).IsEmpty());
11411}
11412
11413
11414THREADED_TEST(Constructor) {
11415 LocalContext context;
11416 v8::Isolate* isolate = context->GetIsolate();
11417 v8::HandleScope handle_scope(isolate);
11418 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11419 templ->SetClassName(v8_str("Fun"));
11420 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11421 CHECK(
11422 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11423 Local<v8::Object> inst = cons->NewInstance(context.local()).ToLocalChecked();
11424 i::Handle<i::JSReceiver> obj(v8::Utils::OpenHandle(*inst));
11425 CHECK(obj->IsJSObject());
11426 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11427 CHECK(value->BooleanValue(isolate));
11428}
11429
11430
11431THREADED_TEST(FunctionDescriptorException) {
11432 LocalContext context;
11433 v8::Isolate* isolate = context->GetIsolate();
11434 v8::HandleScope handle_scope(isolate);
11435 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11436 templ->SetClassName(v8_str("Fun"));
11437 Local<Function> cons = templ->GetFunction(context.local()).ToLocalChecked();
11438 CHECK(
11439 context->Global()->Set(context.local(), v8_str("Fun"), cons).FromJust());
11440 Local<Value> value = CompileRun(
11441 "function test() {"
11442 " try {"
11443 " (new Fun()).blah()"
11444 " } catch (e) {"
11445 " var str = String(e);"
11446 // " if (str.indexOf('TypeError') == -1) return 1;"
11447 // " if (str.indexOf('[object Fun]') != -1) return 2;"
11448 // " if (str.indexOf('#<Fun>') == -1) return 3;"
11449 " return 0;"
11450 " }"
11451 " return 4;"
11452 "}"
11453 "test();");
11454 CHECK_EQ(0, value->Int32Value(context.local()).FromJust());
11455}
11456
11457
11458THREADED_TEST(EvalAliasedDynamic) {
11459 LocalContext current;
11460 v8::HandleScope scope(current->GetIsolate());
11461
11462 // Tests where aliased eval can only be resolved dynamically.
11463 Local<Script> script = v8_compile(
11464 "function f(x) { "
11465 " var foo = 2;"
11466 " with (x) { return eval('foo'); }"
11467 "}"
11468 "foo = 0;"
11469 "result1 = f(new Object());"
11470 "result2 = f(this);"
11471 "var x = new Object();"
11472 "x.eval = function(x) { return 1; };"
11473 "result3 = f(x);");
11474 script->Run(current.local()).ToLocalChecked();
11475 CHECK_EQ(2, current->Global()
11476 ->Get(current.local(), v8_str("result1"))
11477 .ToLocalChecked()
11478 ->Int32Value(current.local())
11479 .FromJust());
11480 CHECK_EQ(0, current->Global()
11481 ->Get(current.local(), v8_str("result2"))
11482 .ToLocalChecked()
11483 ->Int32Value(current.local())
11484 .FromJust());
11485 CHECK_EQ(1, current->Global()
11486 ->Get(current.local(), v8_str("result3"))
11487 .ToLocalChecked()
11488 ->Int32Value(current.local())
11489 .FromJust());
11490
11491 v8::TryCatch try_catch(current->GetIsolate());
11492 script = v8_compile(
11493 "function f(x) { "
11494 " var bar = 2;"
11495 " with (x) { return eval('bar'); }"
11496 "}"
11497 "result4 = f(this)");
11498 script->Run(current.local()).ToLocalChecked();
11499 CHECK(!try_catch.HasCaught());
11500 CHECK_EQ(2, current->Global()
11501 ->Get(current.local(), v8_str("result4"))
11502 .ToLocalChecked()
11503 ->Int32Value(current.local())
11504 .FromJust());
11505
11506 try_catch.Reset();
11507}
11508
11509
11510THREADED_TEST(CrossEval) {
11511 v8::HandleScope scope(CcTest::isolate());
11512 LocalContext other;
11513 LocalContext current;
11514
11515 Local<String> token = v8_str("<security token>");
11516 other->SetSecurityToken(token);
11517 current->SetSecurityToken(token);
11518
11519 // Set up reference from current to other.
11520 CHECK(current->Global()
11521 ->Set(current.local(), v8_str("other"), other->Global())
11522 .FromJust());
11523
11524 // Check that new variables are introduced in other context.
11525 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11526 script->Run(current.local()).ToLocalChecked();
11527 Local<Value> foo =
11528 other->Global()->Get(current.local(), v8_str("foo")).ToLocalChecked();
11529 CHECK_EQ(1234, foo->Int32Value(other.local()).FromJust());
11530 CHECK(!current->Global()->Has(current.local(), v8_str("foo")).FromJust());
11531
11532 // Check that writing to non-existing properties introduces them in
11533 // the other context.
11534 script = v8_compile("other.eval('na = 1234')");
11535 script->Run(current.local()).ToLocalChecked();
11536 CHECK_EQ(1234, other->Global()
11537 ->Get(current.local(), v8_str("na"))
11538 .ToLocalChecked()
11539 ->Int32Value(other.local())
11540 .FromJust());
11541 CHECK(!current->Global()->Has(current.local(), v8_str("na")).FromJust());
11542
11543 // Check that global variables in current context are not visible in other
11544 // context.
11545 v8::TryCatch try_catch(CcTest::isolate());
11546 script = v8_compile("var bar = 42; other.eval('bar');");
11547 CHECK(script->Run(current.local()).IsEmpty());
11548 CHECK(try_catch.HasCaught());
11549 try_catch.Reset();
11550
11551 // Check that local variables in current context are not visible in other
11552 // context.
11553 script = v8_compile(
11554 "(function() { "
11555 " var baz = 87;"
11556 " return other.eval('baz');"
11557 "})();");
11558 CHECK(script->Run(current.local()).IsEmpty());
11559 CHECK(try_catch.HasCaught());
11560 try_catch.Reset();
11561
11562 // Check that global variables in the other environment are visible
11563 // when evaluting code.
11564 CHECK(other->Global()
11565 ->Set(other.local(), v8_str("bis"), v8_num(1234))
11566 .FromJust());
11567 script = v8_compile("other.eval('bis')");
11568 CHECK_EQ(1234, script->Run(current.local())
11569 .ToLocalChecked()
11570 ->Int32Value(current.local())
11571 .FromJust());
11572 CHECK(!try_catch.HasCaught());
11573
11574 // Check that the 'this' pointer points to the global object evaluating
11575 // code.
11576 CHECK(other->Global()
11577 ->Set(current.local(), v8_str("t"), other->Global())
11578 .FromJust());
11579 script = v8_compile("other.eval('this == t')");
11580 Local<Value> result = script->Run(current.local()).ToLocalChecked();
11581 CHECK(result->IsTrue());
11582 CHECK(!try_catch.HasCaught());
11583
11584 // Check that variables introduced in with-statement are not visible in
11585 // other context.
11586 script = v8_compile("with({x:2}){other.eval('x')}");
11587 CHECK(script->Run(current.local()).IsEmpty());
11588 CHECK(try_catch.HasCaught());
11589 try_catch.Reset();
11590
11591 // Check that you cannot use 'eval.call' with another object than the
11592 // current global object.
11593 script = v8_compile("other.y = 1; eval.call(other, 'y')");
11594 CHECK(script->Run(current.local()).IsEmpty());
11595 CHECK(try_catch.HasCaught());
11596}
11597
11598
11599// Test that calling eval in a context which has been detached from
11600// its global proxy works.
11601THREADED_TEST(EvalInDetachedGlobal) {
11602 v8::Isolate* isolate = CcTest::isolate();
11603 v8::HandleScope scope(isolate);
11604
11605 v8::Local<Context> context0 = Context::New(isolate);
11606 v8::Local<Context> context1 = Context::New(isolate);
11607 Local<String> token = v8_str("<security token>");
11608 context0->SetSecurityToken(token);
11609 context1->SetSecurityToken(token);
11610
11611 // Set up function in context0 that uses eval from context0.
11612 context0->Enter();
11613 v8::Local<v8::Value> fun = CompileRun(
11614 "var x = 42;"
11615 "(function() {"
11616 " var e = eval;"
11617 " return function(s) { return e(s); }"
11618 "})()");
11619 context0->Exit();
11620
11621 // Put the function into context1 and call it before and after
11622 // detaching the global. Before detaching, the call succeeds and
11623 // after detaching undefined is returned.
11624 context1->Enter();
11625 CHECK(context1->Global()->Set(context1, v8_str("fun"), fun).FromJust());
11626 v8::Local<v8::Value> x_value = CompileRun("fun('x')");
11627 CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
11628 context0->DetachGlobal();
11629 x_value = CompileRun("fun('x')");
11630 CHECK(x_value->IsUndefined());
11631 context1->Exit();
11632}
11633
11634
11635THREADED_TEST(CrossLazyLoad) {
11636 v8::HandleScope scope(CcTest::isolate());
11637 LocalContext other;
11638 LocalContext current;
11639
11640 Local<String> token = v8_str("<security token>");
11641 other->SetSecurityToken(token);
11642 current->SetSecurityToken(token);
11643
11644 // Set up reference from current to other.
11645 CHECK(current->Global()
11646 ->Set(current.local(), v8_str("other"), other->Global())
11647 .FromJust());
11648
11649 // Trigger lazy loading in other context.
11650 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11651 Local<Value> value = script->Run(current.local()).ToLocalChecked();
11652 CHECK_EQ(42.0, value->NumberValue(current.local()).FromJust());
11653}
11654
11655
11656static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11657 ApiTestFuzzer::Fuzz();
11658 if (args.IsConstructCall()) {
11659 if (args[0]->IsInt32()) {
11660 args.GetReturnValue().Set(
11661 v8_num(-args[0]
11662 ->Int32Value(args.GetIsolate()->GetCurrentContext())
11663 .FromJust()));
11664 return;
11665 }
11666 }
11667
11668 args.GetReturnValue().Set(args[0]);
11669}
11670
11671
11672// Test that a call handler can be set for objects which will allow
11673// non-function objects created through the API to be called as
11674// functions.
11675THREADED_TEST(CallAsFunction) {
11676 LocalContext context;
11677 v8::Isolate* isolate = context->GetIsolate();
11678 v8::HandleScope scope(isolate);
11679
11680 {
11681 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11682 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11683 instance_template->SetCallAsFunctionHandler(call_as_function);
11684 Local<v8::Object> instance = t->GetFunction(context.local())
11685 .ToLocalChecked()
11686 ->NewInstance(context.local())
11687 .ToLocalChecked();
11688 CHECK(context->Global()
11689 ->Set(context.local(), v8_str("obj"), instance)
11690 .FromJust());
11691 v8::TryCatch try_catch(isolate);
11692 Local<Value> value;
11693 CHECK(!try_catch.HasCaught());
11694
11695 value = CompileRun("obj(42)");
11696 CHECK(!try_catch.HasCaught());
11697 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
11698
11699 value = CompileRun("(function(o){return o(49)})(obj)");
11700 CHECK(!try_catch.HasCaught());
11701 CHECK_EQ(49, value->Int32Value(context.local()).FromJust());
11702
11703 // test special case of call as function
11704 value = CompileRun("[obj]['0'](45)");
11705 CHECK(!try_catch.HasCaught());
11706 CHECK_EQ(45, value->Int32Value(context.local()).FromJust());
11707
11708 value = CompileRun(
11709 "obj.call = Function.prototype.call;"
11710 "obj.call(null, 87)");
11711 CHECK(!try_catch.HasCaught());
11712 CHECK_EQ(87, value->Int32Value(context.local()).FromJust());
11713
11714 // Regression tests for bug #1116356: Calling call through call/apply
11715 // must work for non-function receivers.
11716 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11717 value = CompileRun(apply_99);
11718 CHECK(!try_catch.HasCaught());
11719 CHECK_EQ(99, value->Int32Value(context.local()).FromJust());
11720
11721 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11722 value = CompileRun(call_17);
11723 CHECK(!try_catch.HasCaught());
11724 CHECK_EQ(17, value->Int32Value(context.local()).FromJust());
11725
11726 // Check that the call-as-function handler can be called through new.
11727 value = CompileRun("new obj(43)");
11728 CHECK(!try_catch.HasCaught());
11729 CHECK_EQ(-43, value->Int32Value(context.local()).FromJust());
11730
11731 // Check that the call-as-function handler can be called through
11732 // the API.
11733 v8::Local<Value> args[] = {v8_num(28)};
11734 value = instance->CallAsFunction(context.local(), instance, 1, args)
11735 .ToLocalChecked();
11736 CHECK(!try_catch.HasCaught());
11737 CHECK_EQ(28, value->Int32Value(context.local()).FromJust());
11738 }
11739
11740 {
11741 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11742 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11743 USE(instance_template);
11744 Local<v8::Object> instance = t->GetFunction(context.local())
11745 .ToLocalChecked()
11746 ->NewInstance(context.local())
11747 .ToLocalChecked();
11748 CHECK(context->Global()
11749 ->Set(context.local(), v8_str("obj2"), instance)
11750 .FromJust());
11751 v8::TryCatch try_catch(isolate);
11752 Local<Value> value;
11753 CHECK(!try_catch.HasCaught());
11754
11755 // Call an object without call-as-function handler through the JS
11756 value = CompileRun("obj2(28)");
11757 CHECK(value.IsEmpty());
11758 CHECK(try_catch.HasCaught());
11759 String::Utf8Value exception_value1(isolate, try_catch.Exception());
11760 // TODO(verwaest): Better message
11761 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
11762 try_catch.Reset();
11763
11764 // Call an object without call-as-function handler through the API
11765 v8::Local<Value> args[] = {v8_num(28)};
11766 CHECK(
11767 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11768 CHECK(try_catch.HasCaught());
11769 String::Utf8Value exception_value2(isolate, try_catch.Exception());
11770 CHECK_EQ(0,
11771 strcmp("TypeError: object is not a function", *exception_value2));
11772 try_catch.Reset();
11773 }
11774
11775 {
11776 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11777 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11778 instance_template->SetCallAsFunctionHandler(ThrowValue);
11779 Local<v8::Object> instance = t->GetFunction(context.local())
11780 .ToLocalChecked()
11781 ->NewInstance(context.local())
11782 .ToLocalChecked();
11783 CHECK(context->Global()
11784 ->Set(context.local(), v8_str("obj3"), instance)
11785 .FromJust());
11786 v8::TryCatch try_catch(isolate);
11787 Local<Value> value;
11788 CHECK(!try_catch.HasCaught());
11789
11790 // Catch the exception which is thrown by call-as-function handler
11791 value = CompileRun("obj3(22)");
11792 CHECK(try_catch.HasCaught());
11793 String::Utf8Value exception_value1(isolate, try_catch.Exception());
11794 CHECK_EQ(0, strcmp("22", *exception_value1));
11795 try_catch.Reset();
11796
11797 v8::Local<Value> args[] = {v8_num(23)};
11798 CHECK(
11799 instance->CallAsFunction(context.local(), instance, 1, args).IsEmpty());
11800 CHECK(try_catch.HasCaught());
11801 String::Utf8Value exception_value2(isolate, try_catch.Exception());
11802 CHECK_EQ(0, strcmp("23", *exception_value2));
11803 try_catch.Reset();
11804 }
11805
11806 {
11807 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11808 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11809 instance_template->SetCallAsFunctionHandler(ReturnThis);
11810 Local<v8::Object> instance = t->GetFunction(context.local())
11811 .ToLocalChecked()
11812 ->NewInstance(context.local())
11813 .ToLocalChecked();
11814
11815 Local<v8::Value> a1 =
11816 instance
11817 ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11818 nullptr)
11819 .ToLocalChecked();
11820 CHECK(a1->StrictEquals(instance));
11821 Local<v8::Value> a2 =
11822 instance->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11823 .ToLocalChecked();
11824 CHECK(a2->StrictEquals(instance));
11825 Local<v8::Value> a3 =
11826 instance->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11827 .ToLocalChecked();
11828 CHECK(a3->StrictEquals(instance));
11829 Local<v8::Value> a4 =
11830 instance->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11831 .ToLocalChecked();
11832 CHECK(a4->StrictEquals(instance));
11833 Local<v8::Value> a5 =
11834 instance->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11835 .ToLocalChecked();
11836 CHECK(a5->StrictEquals(instance));
11837 }
11838
11839 {
11840 CompileRun(
11841 "function ReturnThisSloppy() {"
11842 " return this;"
11843 "}"
11844 "function ReturnThisStrict() {"
11845 " 'use strict';"
11846 " return this;"
11847 "}");
11848 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
11849 context->Global()
11850 ->Get(context.local(), v8_str("ReturnThisSloppy"))
11851 .ToLocalChecked());
11852 Local<Function> ReturnThisStrict = Local<Function>::Cast(
11853 context->Global()
11854 ->Get(context.local(), v8_str("ReturnThisStrict"))
11855 .ToLocalChecked());
11856
11857 Local<v8::Value> a1 =
11858 ReturnThisSloppy
11859 ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11860 nullptr)
11861 .ToLocalChecked();
11862 CHECK(a1->StrictEquals(context->Global()));
11863 Local<v8::Value> a2 =
11864 ReturnThisSloppy
11865 ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11866 .ToLocalChecked();
11867 CHECK(a2->StrictEquals(context->Global()));
11868 Local<v8::Value> a3 =
11869 ReturnThisSloppy
11870 ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11871 .ToLocalChecked();
11872 CHECK(a3->IsNumberObject());
11873 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11874 Local<v8::Value> a4 =
11875 ReturnThisSloppy
11876 ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11877 .ToLocalChecked();
11878 CHECK(a4->IsStringObject());
11879 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11880 Local<v8::Value> a5 =
11881 ReturnThisSloppy
11882 ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11883 .ToLocalChecked();
11884 CHECK(a5->IsBooleanObject());
11885 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11886
11887 Local<v8::Value> a6 =
11888 ReturnThisStrict
11889 ->CallAsFunction(context.local(), v8::Undefined(isolate), 0,
11890 nullptr)
11891 .ToLocalChecked();
11892 CHECK(a6->IsUndefined());
11893 Local<v8::Value> a7 =
11894 ReturnThisStrict
11895 ->CallAsFunction(context.local(), v8::Null(isolate), 0, nullptr)
11896 .ToLocalChecked();
11897 CHECK(a7->IsNull());
11898 Local<v8::Value> a8 =
11899 ReturnThisStrict
11900 ->CallAsFunction(context.local(), v8_num(42), 0, nullptr)
11901 .ToLocalChecked();
11902 CHECK(a8->StrictEquals(v8_num(42)));
11903 Local<v8::Value> a9 =
11904 ReturnThisStrict
11905 ->CallAsFunction(context.local(), v8_str("hello"), 0, nullptr)
11906 .ToLocalChecked();
11907 CHECK(a9->StrictEquals(v8_str("hello")));
11908 Local<v8::Value> a10 =
11909 ReturnThisStrict
11910 ->CallAsFunction(context.local(), v8::True(isolate), 0, nullptr)
11911 .ToLocalChecked();
11912 CHECK(a10->StrictEquals(v8::True(isolate)));
11913 }
11914}
11915
11916
11917// Check whether a non-function object is callable.
11918THREADED_TEST(CallableObject) {
11919 LocalContext context;
11920 v8::Isolate* isolate = context->GetIsolate();
11921 v8::HandleScope scope(isolate);
11922
11923 {
11924 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11925 instance_template->SetCallAsFunctionHandler(call_as_function);
11926 Local<Object> instance =
11927 instance_template->NewInstance(context.local()).ToLocalChecked();
11928 v8::TryCatch try_catch(isolate);
11929
11930 CHECK(instance->IsCallable());
11931 CHECK(!try_catch.HasCaught());
11932 }
11933
11934 {
11935 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11936 Local<Object> instance =
11937 instance_template->NewInstance(context.local()).ToLocalChecked();
11938 v8::TryCatch try_catch(isolate);
11939
11940 CHECK(!instance->IsCallable());
11941 CHECK(!try_catch.HasCaught());
11942 }
11943
11944 {
11945 Local<FunctionTemplate> function_template =
11946 FunctionTemplate::New(isolate, call_as_function);
11947 Local<Function> function =
11948 function_template->GetFunction(context.local()).ToLocalChecked();
11949 Local<Object> instance = function;
11950 v8::TryCatch try_catch(isolate);
11951
11952 CHECK(instance->IsCallable());
11953 CHECK(!try_catch.HasCaught());
11954 }
11955
11956 {
11957 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11958 Local<Function> function =
11959 function_template->GetFunction(context.local()).ToLocalChecked();
11960 Local<Object> instance = function;
11961 v8::TryCatch try_catch(isolate);
11962
11963 CHECK(instance->IsCallable());
11964 CHECK(!try_catch.HasCaught());
11965 }
11966}
11967
11968
11969THREADED_TEST(Regress567998) {
11970 LocalContext env;
11971 v8::HandleScope scope(env->GetIsolate());
11972
11973 Local<v8::FunctionTemplate> desc =
11974 v8::FunctionTemplate::New(env->GetIsolate());
11975 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
11976 desc->InstanceTemplate()->SetCallAsFunctionHandler(ReturnThis); // callable
11977
11978 Local<v8::Object> obj = desc->GetFunction(env.local())
11979 .ToLocalChecked()
11980 ->NewInstance(env.local())
11981 .ToLocalChecked();
11982 CHECK(
11983 env->Global()->Set(env.local(), v8_str("undetectable"), obj).FromJust());
11984
11985 ExpectString("undetectable.toString()", "[object Object]");
11986 ExpectString("typeof undetectable", "undefined");
11987 ExpectString("typeof(undetectable)", "undefined");
11988 ExpectBoolean("typeof undetectable == 'undefined'", true);
11989 ExpectBoolean("typeof undetectable == 'object'", false);
11990 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
11991 ExpectBoolean("!undetectable", true);
11992
11993 ExpectObject("true&&undetectable", obj);
11994 ExpectBoolean("false&&undetectable", false);
11995 ExpectBoolean("true||undetectable", true);
11996 ExpectObject("false||undetectable", obj);
11997
11998 ExpectObject("undetectable&&true", obj);
11999 ExpectObject("undetectable&&false", obj);
12000 ExpectBoolean("undetectable||true", true);
12001 ExpectBoolean("undetectable||false", false);
12002
12003 ExpectBoolean("undetectable==null", true);
12004 ExpectBoolean("null==undetectable", true);
12005 ExpectBoolean("undetectable==undefined", true);
12006 ExpectBoolean("undefined==undetectable", true);
12007 ExpectBoolean("undetectable==undetectable", true);
12008
12009 ExpectBoolean("undetectable===null", false);
12010 ExpectBoolean("null===undetectable", false);
12011 ExpectBoolean("undetectable===undefined", false);
12012 ExpectBoolean("undefined===undetectable", false);
12013 ExpectBoolean("undetectable===undetectable", true);
12014}
12015
12016
12017static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
12018 v8::HandleScope scope(isolate);
12019 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
12020 for (int i = 0; i < iterations; i++) {
12021 Local<v8::Number> n(v8::Integer::New(isolate, 42));
12022 }
12023 return Recurse(isolate, depth - 1, iterations);
12024}
12025
12026
12027THREADED_TEST(HandleIteration) {
12028 static const int kIterations = 500;
12029 static const int kNesting = 200;
12030 LocalContext context;
12031 v8::Isolate* isolate = context->GetIsolate();
12032 v8::HandleScope scope0(isolate);
12033 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12034 {
12035 v8::HandleScope scope1(isolate);
12036 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12037 for (int i = 0; i < kIterations; i++) {
12038 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12039 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
12040 }
12041
12042 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12043 {
12044 v8::HandleScope scope2(CcTest::isolate());
12045 for (int j = 0; j < kIterations; j++) {
12046 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
12047 CHECK_EQ(j + 1 + kIterations,
12048 v8::HandleScope::NumberOfHandles(isolate));
12049 }
12050 }
12051 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
12052 }
12053 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
12054 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
12055}
12056
12057
12058static void InterceptorCallICFastApi(
12059 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12060 ApiTestFuzzer::Fuzz();
12061 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12062 int* call_count =
12063 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12064 ++(*call_count);
12065 if ((*call_count) % 20 == 0) {
12066 CcTest::CollectAllGarbage();
12067 }
12068}
12069
12070static void FastApiCallback_TrivialSignature(
12071 const v8::FunctionCallbackInfo<v8::Value>& args) {
12072 ApiTestFuzzer::Fuzz();
12073 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12074 v8::Isolate* isolate = CcTest::isolate();
12075 CHECK_EQ(isolate, args.GetIsolate());
12076 CHECK(args.This()
12077 ->Equals(isolate->GetCurrentContext(), args.Holder())
12078 .FromJust());
12079 CHECK(args.Data()
12080 ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12081 .FromJust());
12082 args.GetReturnValue().Set(
12083 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12084}
12085
12086static void FastApiCallback_SimpleSignature(
12087 const v8::FunctionCallbackInfo<v8::Value>& args) {
12088 ApiTestFuzzer::Fuzz();
12089 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12090 v8::Isolate* isolate = CcTest::isolate();
12091 CHECK_EQ(isolate, args.GetIsolate());
12092 CHECK(args.This()
12093 ->GetPrototype()
12094 ->Equals(isolate->GetCurrentContext(), args.Holder())
12095 .FromJust());
12096 CHECK(args.Data()
12097 ->Equals(isolate->GetCurrentContext(), v8_str("method_data"))
12098 .FromJust());
12099 // Note, we're using HasRealNamedProperty instead of Has to avoid
12100 // invoking the interceptor again.
12101 CHECK(args.Holder()
12102 ->HasRealNamedProperty(isolate->GetCurrentContext(), v8_str("foo"))
12103 .FromJust());
12104 args.GetReturnValue().Set(
12105 args[0]->Int32Value(isolate->GetCurrentContext()).FromJust() + 1);
12106}
12107
12108
12109// Helper to maximize the odds of object moving.
12110static void GenerateSomeGarbage() {
12111 CompileRun(
12112 "var garbage;"
12113 "for (var i = 0; i < 1000; i++) {"
12114 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12115 "}"
12116 "garbage = undefined;");
12117}
12118
12119
12120void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12121 static int count = 0;
12122 if (count++ % 3 == 0) {
12123 CcTest::CollectAllGarbage();
12124 // This should move the stub
12125 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12126 }
12127}
12128
12129
12130THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12131 LocalContext context;
12132 v8::Isolate* isolate = context->GetIsolate();
12133 v8::HandleScope scope(isolate);
12134 v8::Local<v8::ObjectTemplate> nativeobject_templ =
12135 v8::ObjectTemplate::New(isolate);
12136 nativeobject_templ->Set(isolate, "callback",
12137 v8::FunctionTemplate::New(isolate,
12138 DirectApiCallback));
12139 v8::Local<v8::Object> nativeobject_obj =
12140 nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12141 CHECK(context->Global()
12142 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12143 .FromJust());
12144 // call the api function multiple times to ensure direct call stub creation.
12145 CompileRun(
12146 "function f() {"
12147 " for (var i = 1; i <= 30; i++) {"
12148 " nativeobject.callback();"
12149 " }"
12150 "}"
12151 "f();");
12152}
12153
12154void ThrowingDirectApiCallback(
12155 const v8::FunctionCallbackInfo<v8::Value>& args) {
12156 args.GetIsolate()->ThrowException(v8_str("g"));
12157}
12158
12159THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12160 LocalContext context;
12161 v8::Isolate* isolate = context->GetIsolate();
12162 v8::HandleScope scope(isolate);
12163 v8::Local<v8::ObjectTemplate> nativeobject_templ =
12164 v8::ObjectTemplate::New(isolate);
12165 nativeobject_templ->Set(
12166 isolate, "callback",
12167 v8::FunctionTemplate::New(isolate, ThrowingDirectApiCallback));
12168 v8::Local<v8::Object> nativeobject_obj =
12169 nativeobject_templ->NewInstance(context.local()).ToLocalChecked();
12170 CHECK(context->Global()
12171 ->Set(context.local(), v8_str("nativeobject"), nativeobject_obj)
12172 .FromJust());
12173 // call the api function multiple times to ensure direct call stub creation.
12174 v8::Local<Value> result = CompileRun(
12175 "var result = '';"
12176 "function f() {"
12177 " for (var i = 1; i <= 5; i++) {"
12178 " try { nativeobject.callback(); } catch (e) { result += e; }"
12179 " }"
12180 "}"
12181 "f(); result;");
12182 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12183}
12184
12185static int p_getter_count_3;
12186
12187static Local<Value> DoDirectGetter() {
12188 if (++p_getter_count_3 % 3 == 0) {
12189 CcTest::CollectAllGarbage();
12190 GenerateSomeGarbage();
12191 }
12192 return v8_str("Direct Getter Result");
12193}
12194
12195static void DirectGetterCallback(
12196 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12197 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12198 info.GetReturnValue().Set(DoDirectGetter());
12199}
12200
12201template <typename Accessor>
12202static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12203 LocalContext context;
12204 v8::Isolate* isolate = context->GetIsolate();
12205 v8::HandleScope scope(isolate);
12206 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12207 obj->SetAccessor(v8_str("p1"), accessor);
12208 CHECK(context->Global()
12209 ->Set(context.local(), v8_str("o1"),
12210 obj->NewInstance(context.local()).ToLocalChecked())
12211 .FromJust());
12212 p_getter_count_3 = 0;
12213 v8::Local<v8::Value> result = CompileRun(
12214 "function f() {"
12215 " for (var i = 0; i < 30; i++) o1.p1;"
12216 " return o1.p1"
12217 "}"
12218 "f();");
12219 CHECK(v8_str("Direct Getter Result")
12220 ->Equals(context.local(), result)
12221 .FromJust());
12222 CHECK_EQ(31, p_getter_count_3);
12223}
12224
12225THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12226 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12227}
12228
12229void ThrowingDirectGetterCallback(
12230 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12231 info.GetIsolate()->ThrowException(v8_str("g"));
12232}
12233
12234THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12235 LocalContext context;
12236 v8::Isolate* isolate = context->GetIsolate();
12237 v8::HandleScope scope(isolate);
12238 v8::Local<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12239 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12240 CHECK(context->Global()
12241 ->Set(context.local(), v8_str("o1"),
12242 obj->NewInstance(context.local()).ToLocalChecked())
12243 .FromJust());
12244 v8::Local<Value> result = CompileRun(
12245 "var result = '';"
12246 "for (var i = 0; i < 5; i++) {"
12247 " try { o1.p1; } catch (e) { result += e; }"
12248 "}"
12249 "result;");
12250 CHECK(v8_str("ggggg")->Equals(context.local(), result).FromJust());
12251}
12252
12253THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12254 int interceptor_call_count = 0;
12255 v8::Isolate* isolate = CcTest::isolate();
12256 v8::HandleScope scope(isolate);
12257 v8::Local<v8::FunctionTemplate> fun_templ =
12258 v8::FunctionTemplate::New(isolate);
12259 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12260 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12261 v8::Local<v8::Signature>());
12262 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12263 proto_templ->Set(v8_str("method"), method_templ);
12264 v8::Local<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12265 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12266 InterceptorCallICFastApi, nullptr, nullptr, nullptr, nullptr,
12267 v8::External::New(isolate, &interceptor_call_count)));
12268 LocalContext context;
12269 v8::Local<v8::Function> fun =
12270 fun_templ->GetFunction(context.local()).ToLocalChecked();
12271 GenerateSomeGarbage();
12272 CHECK(context->Global()
12273 ->Set(context.local(), v8_str("o"),
12274 fun->NewInstance(context.local()).ToLocalChecked())
12275 .FromJust());
12276 CompileRun(
12277 "var result = 0;"
12278 "for (var i = 0; i < 100; i++) {"
12279 " result = o.method(41);"
12280 "}");
12281 CHECK_EQ(42, context->Global()
12282 ->Get(context.local(), v8_str("result"))
12283 .ToLocalChecked()
12284 ->Int32Value(context.local())
12285 .FromJust());
12286 CHECK_EQ(100, interceptor_call_count);
12287}
12288
12289THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12290 v8::Isolate* isolate = CcTest::isolate();
12291 v8::HandleScope scope(isolate);
12292 v8::Local<v8::FunctionTemplate> fun_templ =
12293 v8::FunctionTemplate::New(isolate);
12294 v8::Local<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12295 isolate, FastApiCallback_TrivialSignature, v8_str("method_data"),
12296 v8::Local<v8::Signature>());
12297 v8::Local<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12298 proto_templ->Set(v8_str("method"), method_templ);
12299 v8::Local<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12300 USE(templ);
12301 LocalContext context;
12302 v8::Local<v8::Function> fun =
12303 fun_templ->GetFunction(context.local()).ToLocalChecked();
12304 GenerateSomeGarbage();
12305 CHECK(context->Global()
12306 ->Set(context.local(), v8_str("o"),
12307 fun->NewInstance(context.local()).ToLocalChecked())
12308 .FromJust());
12309 CompileRun(
12310 "var result = 0;"
12311 "for (var i = 0; i < 100; i++) {"
12312 " result = o.method(41);"
12313 "}");
12314
12315 CHECK_EQ(42, context->Global()
12316 ->Get(context.local(), v8_str("result"))
12317 .ToLocalChecked()
12318 ->Int32Value(context.local())
12319 .FromJust());
12320}
12321
12322static void ThrowingGetter(Local<String> name,
12323 const v8::PropertyCallbackInfo<v8::Value>& info) {
12324 ApiTestFuzzer::Fuzz();
12325 info.GetIsolate()->ThrowException(Local<Value>());
12326 info.GetReturnValue().SetUndefined();
12327}
12328
12329
12330THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12331 LocalContext context;
12332 HandleScope scope(context->GetIsolate());
12333
12334 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12335 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12336 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12337
12338 Local<Object> instance = templ->GetFunction(context.local())
12339 .ToLocalChecked()
12340 ->NewInstance(context.local())
12341 .ToLocalChecked();
12342
12343 Local<Object> another = Object::New(context->GetIsolate());
12344 CHECK(another->SetPrototype(context.local(), instance).FromJust());
12345
12346 Local<Object> with_js_getter = CompileRun(
12347 "o = {};\n"
12348 "o.__defineGetter__('f', function() { throw undefined; });\n"
12349 "o\n").As<Object>();
12350 CHECK(!with_js_getter.IsEmpty());
12351
12352 TryCatch try_catch(context->GetIsolate());
12353
12354 v8::MaybeLocal<Value> result =
12355 instance->GetRealNamedProperty(context.local(), v8_str("f"));
12356 CHECK(try_catch.HasCaught());
12357 try_catch.Reset();
12358 CHECK(result.IsEmpty());
12359
12360 Maybe<PropertyAttribute> attr =
12361 instance->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12362 CHECK(!try_catch.HasCaught());
12363 CHECK(Just(None) == attr);
12364
12365 result = another->GetRealNamedProperty(context.local(), v8_str("f"));
12366 CHECK(try_catch.HasCaught());
12367 try_catch.Reset();
12368 CHECK(result.IsEmpty());
12369
12370 attr = another->GetRealNamedPropertyAttributes(context.local(), v8_str("f"));
12371 CHECK(!try_catch.HasCaught());
12372 CHECK(Just(None) == attr);
12373
12374 result = another->GetRealNamedPropertyInPrototypeChain(context.local(),
12375 v8_str("f"));
12376 CHECK(try_catch.HasCaught());
12377 try_catch.Reset();
12378 CHECK(result.IsEmpty());
12379
12380 attr = another->GetRealNamedPropertyAttributesInPrototypeChain(
12381 context.local(), v8_str("f"));
12382 CHECK(!try_catch.HasCaught());
12383 CHECK(Just(None) == attr);
12384
12385 result = another->Get(context.local(), v8_str("f"));
12386 CHECK(try_catch.HasCaught());
12387 try_catch.Reset();
12388 CHECK(result.IsEmpty());
12389
12390 result = with_js_getter->GetRealNamedProperty(context.local(), v8_str("f"));
12391 CHECK(try_catch.HasCaught());
12392 try_catch.Reset();
12393 CHECK(result.IsEmpty());
12394
12395 attr = with_js_getter->GetRealNamedPropertyAttributes(context.local(),
12396 v8_str("f"));
12397 CHECK(!try_catch.HasCaught());
12398 CHECK(Just(None) == attr);
12399
12400 result = with_js_getter->Get(context.local(), v8_str("f"));
12401 CHECK(try_catch.HasCaught());
12402 try_catch.Reset();
12403 CHECK(result.IsEmpty());
12404
12405 Local<Object> target = CompileRun("({})").As<Object>();
12406 Local<Object> handler = CompileRun("({})").As<Object>();
12407 Local<v8::Proxy> proxy =
12408 v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
12409
12410 result = target->GetRealNamedProperty(context.local(), v8_str("f"));
12411 CHECK(!try_catch.HasCaught());
12412 CHECK(result.IsEmpty());
12413
12414 result = proxy->GetRealNamedProperty(context.local(), v8_str("f"));
12415 CHECK(!try_catch.HasCaught());
12416 CHECK(result.IsEmpty());
12417}
12418
12419
12420static void ThrowingCallbackWithTryCatch(
12421 const v8::FunctionCallbackInfo<v8::Value>& args) {
12422 TryCatch try_catch(args.GetIsolate());
12423 // Verboseness is important: it triggers message delivery which can call into
12424 // external code.
12425 try_catch.SetVerbose(true);
12426 CompileRun("throw 'from JS';");
12427 CHECK(try_catch.HasCaught());
12428 CHECK(!CcTest::i_isolate()->has_pending_exception());
12429 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12430}
12431
12432
12433static int call_depth;
12434
12435
12436static void WithTryCatch(Local<Message> message, Local<Value> data) {
12437 TryCatch try_catch(CcTest::isolate());
12438}
12439
12440
12441static void ThrowFromJS(Local<Message> message, Local<Value> data) {
12442 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12443}
12444
12445
12446static void ThrowViaApi(Local<Message> message, Local<Value> data) {
12447 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12448}
12449
12450
12451static void WebKitLike(Local<Message> message, Local<Value> data) {
12452 Local<String> errorMessageString = message->Get();
12453 CHECK(!errorMessageString.IsEmpty());
12454 message->GetStackTrace();
12455 message->GetScriptOrigin().ResourceName();
12456}
12457
12458
12459THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12460 LocalContext context;
12461 v8::Isolate* isolate = context->GetIsolate();
12462 HandleScope scope(isolate);
12463
12464 Local<Function> func =
12465 FunctionTemplate::New(isolate, ThrowingCallbackWithTryCatch)
12466 ->GetFunction(context.local())
12467 .ToLocalChecked();
12468 CHECK(
12469 context->Global()->Set(context.local(), v8_str("func"), func).FromJust());
12470
12471 MessageCallback callbacks[] = {nullptr, WebKitLike, ThrowViaApi, ThrowFromJS,
12472 WithTryCatch};
12473 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12474 MessageCallback callback = callbacks[i];
12475 if (callback != nullptr) {
12476 isolate->AddMessageListener(callback);
12477 }
12478 // Some small number to control number of times message handler should
12479 // throw an exception.
12480 call_depth = 5;
12481 ExpectFalse(
12482 "var thrown = false;\n"
12483 "try { func(); } catch(e) { thrown = true; }\n"
12484 "thrown\n");
12485 if (callback != nullptr) {
12486 isolate->RemoveMessageListeners(callback);
12487 }
12488 }
12489}
12490
12491
12492static void ParentGetter(Local<String> name,
12493 const v8::PropertyCallbackInfo<v8::Value>& info) {
12494 ApiTestFuzzer::Fuzz();
12495 info.GetReturnValue().Set(v8_num(1));
12496}
12497
12498
12499static void ChildGetter(Local<String> name,
12500 const v8::PropertyCallbackInfo<v8::Value>& info) {
12501 ApiTestFuzzer::Fuzz();
12502 info.GetReturnValue().Set(v8_num(42));
12503}
12504
12505
12506THREADED_TEST(Overriding) {
12507 LocalContext context;
12508 v8::Isolate* isolate = context->GetIsolate();
12509 v8::HandleScope scope(isolate);
12510
12511 // Parent template.
12512 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12513 Local<ObjectTemplate> parent_instance_templ =
12514 parent_templ->InstanceTemplate();
12515 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12516
12517 // Template that inherits from the parent template.
12518 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12519 Local<ObjectTemplate> child_instance_templ =
12520 child_templ->InstanceTemplate();
12521 child_templ->Inherit(parent_templ);
12522 // Override 'f'. The child version of 'f' should get called for child
12523 // instances.
12524 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12525 // Add 'g' twice. The 'g' added last should get called for instances.
12526 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12527 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12528
12529 // Add 'h' as an accessor to the proto template with ReadOnly attributes
12530 // so 'h' can be shadowed on the instance object.
12531 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12532 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, nullptr,
12533 v8::Local<Value>(), v8::DEFAULT, v8::ReadOnly);
12534
12535 // Add 'i' as an accessor to the instance template with ReadOnly attributes
12536 // but the attribute does not have effect because it is duplicated with
12537 // nullptr setter.
12538 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, nullptr,
12539 v8::Local<Value>(), v8::DEFAULT,
12540 v8::ReadOnly);
12541
12542 // Instantiate the child template.
12543 Local<v8::Object> instance = child_templ->GetFunction(context.local())
12544 .ToLocalChecked()
12545 ->NewInstance(context.local())
12546 .ToLocalChecked();
12547
12548 // Check that the child function overrides the parent one.
12549 CHECK(context->Global()
12550 ->Set(context.local(), v8_str("o"), instance)
12551 .FromJust());
12552 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12553 // Check that the 'g' that was added last is hit.
12554 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12555 value = v8_compile("o.g")->Run(context.local()).ToLocalChecked();
12556 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12557
12558 // Check that 'h' cannot be shadowed.
12559 value = v8_compile("o.h = 3; o.h")->Run(context.local()).ToLocalChecked();
12560 CHECK_EQ(1, value->Int32Value(context.local()).FromJust());
12561
12562 // Check that 'i' cannot be shadowed or changed.
12563 value = v8_compile("o.i = 3; o.i")->Run(context.local()).ToLocalChecked();
12564 CHECK_EQ(42, value->Int32Value(context.local()).FromJust());
12565}
12566
12567
12568static void ShouldThrowOnErrorGetter(
12569 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12570 ApiTestFuzzer::Fuzz();
12571 v8::Isolate* isolate = info.GetIsolate();
12572 Local<Boolean> should_throw_on_error =
12573 Boolean::New(isolate, info.ShouldThrowOnError());
12574 info.GetReturnValue().Set(should_throw_on_error);
12575}
12576
12577
12578template <typename T>
12579static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value,
12580 const v8::PropertyCallbackInfo<T>& info) {
12581 ApiTestFuzzer::Fuzz();
12582 v8::Isolate* isolate = info.GetIsolate();
12583 auto context = isolate->GetCurrentContext();
12584 Local<Boolean> should_throw_on_error_value =
12585 Boolean::New(isolate, info.ShouldThrowOnError());
12586 CHECK(context->Global()
12587 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"),
12588 should_throw_on_error_value)
12589 .FromJust());
12590}
12591
12592
12593THREADED_TEST(AccessorShouldThrowOnError) {
12594 LocalContext context;
12595 v8::Isolate* isolate = context->GetIsolate();
12596 v8::HandleScope scope(isolate);
12597 Local<Object> global = context->Global();
12598
12599 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12600 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12601 instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter,
12602 ShouldThrowOnErrorSetter<void>);
12603
12604 Local<v8::Object> instance = templ->GetFunction(context.local())
12605 .ToLocalChecked()
12606 ->NewInstance(context.local())
12607 .ToLocalChecked();
12608
12609 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12610
12611 // SLOPPY mode
12612 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12613 CHECK(value->IsFalse());
12614 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12615 value = global->Get(context.local(), v8_str("should_throw_setter"))
12616 .ToLocalChecked();
12617 CHECK(value->IsFalse());
12618
12619 // STRICT mode
12620 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12621 CHECK(value->IsFalse());
12622 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12623 value = global->Get(context.local(), v8_str("should_throw_setter"))
12624 .ToLocalChecked();
12625 CHECK(value->IsTrue());
12626}
12627
12628
12629static void ShouldThrowOnErrorQuery(
12630 Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
12631 ApiTestFuzzer::Fuzz();
12632 v8::Isolate* isolate = info.GetIsolate();
12633 info.GetReturnValue().Set(v8::None);
12634
12635 auto context = isolate->GetCurrentContext();
12636 Local<Boolean> should_throw_on_error_value =
12637 Boolean::New(isolate, info.ShouldThrowOnError());
12638 CHECK(context->Global()
12639 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"),
12640 should_throw_on_error_value)
12641 .FromJust());
12642}
12643
12644
12645static void ShouldThrowOnErrorDeleter(
12646 Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
12647 ApiTestFuzzer::Fuzz();
12648 v8::Isolate* isolate = info.GetIsolate();
12649 info.GetReturnValue().Set(v8::True(isolate));
12650
12651 auto context = isolate->GetCurrentContext();
12652 Local<Boolean> should_throw_on_error_value =
12653 Boolean::New(isolate, info.ShouldThrowOnError());
12654 CHECK(context->Global()
12655 ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"),
12656 should_throw_on_error_value)
12657 .FromJust());
12658}
12659
12660
12661static void ShouldThrowOnErrorPropertyEnumerator(
12662 const v8::PropertyCallbackInfo<v8::Array>& info) {
12663 ApiTestFuzzer::Fuzz();
12664 v8::Isolate* isolate = info.GetIsolate();
12665 Local<v8::Array> names = v8::Array::New(isolate, 1);
12666 CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust());
12667 info.GetReturnValue().Set(names);
12668
12669 auto context = isolate->GetCurrentContext();
12670 Local<Boolean> should_throw_on_error_value =
12671 Boolean::New(isolate, info.ShouldThrowOnError());
12672 CHECK(context->Global()
12673 ->Set(isolate->GetCurrentContext(),
12674 v8_str("should_throw_enumerator"),
12675 should_throw_on_error_value)
12676 .FromJust());
12677}
12678
12679
12680THREADED_TEST(InterceptorShouldThrowOnError) {
12681 LocalContext context;
12682 v8::Isolate* isolate = context->GetIsolate();
12683 v8::HandleScope scope(isolate);
12684 Local<Object> global = context->Global();
12685
12686 auto interceptor_templ = v8::ObjectTemplate::New(isolate);
12687 v8::NamedPropertyHandlerConfiguration handler(
12688 ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>,
12689 ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter,
12690 ShouldThrowOnErrorPropertyEnumerator);
12691 interceptor_templ->SetHandler(handler);
12692
12693 Local<v8::Object> instance =
12694 interceptor_templ->NewInstance(context.local()).ToLocalChecked();
12695
12696 CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust());
12697
12698 // SLOPPY mode
12699 Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked();
12700 CHECK(value->IsFalse());
12701 v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked();
12702 value = global->Get(context.local(), v8_str("should_throw_setter"))
12703 .ToLocalChecked();
12704 CHECK(value->IsFalse());
12705
12706 v8_compile("delete o.f")->Run(context.local()).ToLocalChecked();
12707 value = global->Get(context.local(), v8_str("should_throw_deleter"))
12708 .ToLocalChecked();
12709 CHECK(value->IsFalse());
12710
12711 v8_compile("Object.getOwnPropertyNames(o)")
12712 ->Run(context.local())
12713 .ToLocalChecked();
12714 value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12715 .ToLocalChecked();
12716 CHECK(value->IsFalse());
12717
12718 // STRICT mode
12719 value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked();
12720 CHECK(value->IsFalse());
12721 v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked();
12722 value = global->Get(context.local(), v8_str("should_throw_setter"))
12723 .ToLocalChecked();
12724 CHECK(value->IsTrue());
12725
12726 v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked();
12727 value = global->Get(context.local(), v8_str("should_throw_deleter"))
12728 .ToLocalChecked();
12729 CHECK(value->IsTrue());
12730
12731 v8_compile("'use strict'; Object.getOwnPropertyNames(o)")
12732 ->Run(context.local())
12733 .ToLocalChecked();
12734 value = global->Get(context.local(), v8_str("should_throw_enumerator"))
12735 .ToLocalChecked();
12736 CHECK(value->IsFalse());
12737}
12738
12739static void EmptyHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {}
12740
12741TEST(CallHandlerHasNoSideEffect) {
12742 v8::Isolate* isolate = CcTest::isolate();
12743 v8::HandleScope scope(isolate);
12744 LocalContext context;
12745
12746 // Function template with call handler.
12747 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12748 templ->SetCallHandler(EmptyHandler);
12749 CHECK(context->Global()
12750 ->Set(context.local(), v8_str("f"),
12751 templ->GetFunction(context.local()).ToLocalChecked())
12752 .FromJust());
12753 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12754 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12755
12756 // Side-effect-free version.
12757 Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
12758 templ2->SetCallHandler(EmptyHandler, v8::Local<Value>(),
12759 v8::SideEffectType::kHasNoSideEffect);
12760 CHECK(context->Global()
12761 ->Set(context.local(), v8_str("f2"),
12762 templ2->GetFunction(context.local()).ToLocalChecked())
12763 .FromJust());
12764 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12765 v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12766}
12767
12768TEST(FunctionTemplateNewHasNoSideEffect) {
12769 v8::Isolate* isolate = CcTest::isolate();
12770 v8::HandleScope scope(isolate);
12771 LocalContext context;
12772
12773 // Function template with call handler.
12774 Local<v8::FunctionTemplate> templ =
12775 v8::FunctionTemplate::New(isolate, EmptyHandler);
12776 CHECK(context->Global()
12777 ->Set(context.local(), v8_str("f"),
12778 templ->GetFunction(context.local()).ToLocalChecked())
12779 .FromJust());
12780 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12781 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12782
12783 // Side-effect-free version.
12784 Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(
12785 isolate, EmptyHandler, v8::Local<Value>(), v8::Local<v8::Signature>(), 0,
12786 v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasNoSideEffect);
12787 CHECK(context->Global()
12788 ->Set(context.local(), v8_str("f2"),
12789 templ2->GetFunction(context.local()).ToLocalChecked())
12790 .FromJust());
12791 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12792 v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12793}
12794
12795TEST(FunctionTemplateNewWithCacheHasNoSideEffect) {
12796 v8::Isolate* isolate = CcTest::isolate();
12797 v8::HandleScope scope(isolate);
12798 LocalContext context;
12799 v8::Local<v8::Private> priv =
12800 v8::Private::ForApi(isolate, v8_str("Foo#draft"));
12801
12802 // Function template with call handler.
12803 Local<v8::FunctionTemplate> templ =
12804 v8::FunctionTemplate::NewWithCache(isolate, EmptyHandler, priv);
12805 CHECK(context->Global()
12806 ->Set(context.local(), v8_str("f"),
12807 templ->GetFunction(context.local()).ToLocalChecked())
12808 .FromJust());
12809 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12810 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12811
12812 // Side-effect-free version.
12813 Local<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::NewWithCache(
12814 isolate, EmptyHandler, priv, v8::Local<Value>(),
12815 v8::Local<v8::Signature>(), 0, v8::SideEffectType::kHasNoSideEffect);
12816 CHECK(context->Global()
12817 ->Set(context.local(), v8_str("f2"),
12818 templ2->GetFunction(context.local()).ToLocalChecked())
12819 .FromJust());
12820 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12821 v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12822}
12823
12824TEST(FunctionNewHasNoSideEffect) {
12825 v8::Isolate* isolate = CcTest::isolate();
12826 v8::HandleScope scope(isolate);
12827 LocalContext context;
12828
12829 // Function with side-effect.
12830 Local<Function> func =
12831 Function::New(context.local(), EmptyHandler).ToLocalChecked();
12832 CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12833 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12834 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f()"), true).IsEmpty());
12835
12836 // Side-effect-free version.
12837 Local<Function> func2 =
12838 Function::New(context.local(), EmptyHandler, Local<Value>(), 0,
12839 v8::ConstructorBehavior::kAllow,
12840 v8::SideEffectType::kHasNoSideEffect)
12841 .ToLocalChecked();
12842 CHECK(
12843 context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12844 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12845 v8::debug::EvaluateGlobal(isolate, v8_str("new f2()"), true).ToLocalChecked();
12846}
12847
12848// These handlers instantiate a function the embedder considers safe in some
12849// cases (e.g. "building object wrappers"), but those functions themselves were
12850// not explicitly marked as side-effect-free.
12851static void DefaultConstructHandler(
12852 const v8::FunctionCallbackInfo<v8::Value>& info) {
12853 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12854 v8::Context::Scope context_scope(context);
12855 v8::MaybeLocal<v8::Object> instance = Function::New(context, EmptyHandler)
12856 .ToLocalChecked()
12857 ->NewInstance(context, 0, nullptr);
12858 USE(instance);
12859}
12860
12861static void NoSideEffectConstructHandler(
12862 const v8::FunctionCallbackInfo<v8::Value>& info) {
12863 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12864 v8::Context::Scope context_scope(context);
12865 v8::MaybeLocal<v8::Object> instance =
12866 Function::New(context, EmptyHandler)
12867 .ToLocalChecked()
12868 ->NewInstanceWithSideEffectType(context, 0, nullptr,
12869 v8::SideEffectType::kHasNoSideEffect);
12870 USE(instance);
12871}
12872
12873static void NoSideEffectAndSideEffectConstructHandler(
12874 const v8::FunctionCallbackInfo<v8::Value>& info) {
12875 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
12876 v8::Context::Scope context_scope(context);
12877 // Constructs an instance in a side-effect-free way, followed by another with
12878 // side effects.
12879 v8::MaybeLocal<v8::Object> instance =
12880 Function::New(context, EmptyHandler)
12881 .ToLocalChecked()
12882 ->NewInstanceWithSideEffectType(context, 0, nullptr,
12883 v8::SideEffectType::kHasNoSideEffect);
12884 v8::MaybeLocal<v8::Object> instance2 = Function::New(context, EmptyHandler)
12885 .ToLocalChecked()
12886 ->NewInstance(context, 0, nullptr);
12887 USE(instance);
12888 USE(instance2);
12889}
12890
12891TEST(FunctionNewInstanceHasNoSideEffect) {
12892 v8::Isolate* isolate = CcTest::isolate();
12893 v8::HandleScope scope(isolate);
12894 LocalContext context;
12895
12896 // A whitelisted function that creates a new object with both side-effect
12897 // free/full instantiations. Should throw.
12898 Local<Function> func0 =
12899 Function::New(context.local(), NoSideEffectAndSideEffectConstructHandler,
12900 Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12901 v8::SideEffectType::kHasNoSideEffect)
12902 .ToLocalChecked();
12903 CHECK(context->Global()->Set(context.local(), v8_str("f"), func0).FromJust());
12904 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12905
12906 // A whitelisted function that creates a new object. Should throw.
12907 Local<Function> func =
12908 Function::New(context.local(), DefaultConstructHandler, Local<Value>(), 0,
12909 v8::ConstructorBehavior::kAllow,
12910 v8::SideEffectType::kHasNoSideEffect)
12911 .ToLocalChecked();
12912 CHECK(context->Global()->Set(context.local(), v8_str("f"), func).FromJust());
12913 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f()"), true).IsEmpty());
12914
12915 // A whitelisted function that creates a new object with explicit intent to
12916 // have no side-effects (e.g. building an "object wrapper"). Should not throw.
12917 Local<Function> func2 =
12918 Function::New(context.local(), NoSideEffectConstructHandler,
12919 Local<Value>(), 0, v8::ConstructorBehavior::kAllow,
12920 v8::SideEffectType::kHasNoSideEffect)
12921 .ToLocalChecked();
12922 CHECK(
12923 context->Global()->Set(context.local(), v8_str("f2"), func2).FromJust());
12924 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), true).ToLocalChecked();
12925
12926 // Check that side effect skipping did not leak outside to future evaluations.
12927 Local<Function> func3 =
12928 Function::New(context.local(), EmptyHandler).ToLocalChecked();
12929 CHECK(
12930 context->Global()->Set(context.local(), v8_str("f3"), func3).FromJust());
12931 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("f3()"), true).IsEmpty());
12932
12933 // Check that using side effect free NewInstance works in normal evaluation
12934 // (without throwOnSideEffect).
12935 v8::debug::EvaluateGlobal(isolate, v8_str("f2()"), false).ToLocalChecked();
12936}
12937
12938TEST(CallHandlerAsFunctionHasNoSideEffectNotSupported) {
12939 v8::Isolate* isolate = CcTest::isolate();
12940 v8::HandleScope scope(isolate);
12941 LocalContext context;
12942
12943 // Object template with call as function handler.
12944 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12945 templ->SetCallAsFunctionHandler(EmptyHandler);
12946 Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
12947 CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
12948 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12949
12950 // Side-effect-free version is not supported.
12951 i::FunctionTemplateInfo cons = i::FunctionTemplateInfo::cast(
12952 v8::Utils::OpenHandle(*templ)->constructor());
12953 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
12954 i::CallHandlerInfo handler_info =
12955 i::CallHandlerInfo::cast(cons->GetInstanceCallHandler());
12956 CHECK(!handler_info->IsSideEffectFreeCallHandlerInfo());
12957 handler_info->set_map(
12958 i::ReadOnlyRoots(heap).side_effect_free_call_handler_info_map());
12959 CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj()"), true).IsEmpty());
12960}
12961
12962static void IsConstructHandler(
12963 const v8::FunctionCallbackInfo<v8::Value>& args) {
12964 ApiTestFuzzer::Fuzz();
12965 args.GetReturnValue().Set(args.IsConstructCall());
12966}
12967
12968
12969THREADED_TEST(IsConstructCall) {
12970 v8::Isolate* isolate = CcTest::isolate();
12971 v8::HandleScope scope(isolate);
12972
12973 // Function template with call handler.
12974 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12975 templ->SetCallHandler(IsConstructHandler);
12976
12977 LocalContext context;
12978
12979 CHECK(context->Global()
12980 ->Set(context.local(), v8_str("f"),
12981 templ->GetFunction(context.local()).ToLocalChecked())
12982 .FromJust());
12983 Local<Value> value = v8_compile("f()")->Run(context.local()).ToLocalChecked();
12984 CHECK(!value->BooleanValue(isolate));
12985 value = v8_compile("new f()")->Run(context.local()).ToLocalChecked();
12986 CHECK(value->BooleanValue(isolate));
12987}
12988
12989static void NewTargetHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
12990 ApiTestFuzzer::Fuzz();
12991 args.GetReturnValue().Set(args.NewTarget());
12992}
12993
12994THREADED_TEST(NewTargetHandler) {
12995 v8::Isolate* isolate = CcTest::isolate();
12996 v8::HandleScope scope(isolate);
12997
12998 // Function template with call handler.
12999 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13000 templ->SetCallHandler(NewTargetHandler);
13001
13002 LocalContext context;
13003
13004 Local<Function> function =
13005 templ->GetFunction(context.local()).ToLocalChecked();
13006 CHECK(context->Global()
13007 ->Set(context.local(), v8_str("f"), function)
13008 .FromJust());
13009 Local<Value> value = CompileRun("f()");
13010 CHECK(value->IsUndefined());
13011 value = CompileRun("new f()");
13012 CHECK(value->IsFunction());
13013 CHECK(value == function);
13014 Local<Value> subclass = CompileRun("var g = class extends f { }; g");
13015 CHECK(subclass->IsFunction());
13016 value = CompileRun("new g()");
13017 CHECK(value->IsFunction());
13018 CHECK(value == subclass);
13019 value = CompileRun("Reflect.construct(f, [], Array)");
13020 CHECK(value->IsFunction());
13021 CHECK(value ==
13022 context->Global()
13023 ->Get(context.local(), v8_str("Array"))
13024 .ToLocalChecked());
13025}
13026
13027THREADED_TEST(ObjectProtoToString) {
13028 v8::Isolate* isolate = CcTest::isolate();
13029 v8::HandleScope scope(isolate);
13030 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13031 templ->SetClassName(v8_str("MyClass"));
13032
13033 LocalContext context;
13034
13035 Local<String> customized_tostring = v8_str("customized toString");
13036
13037 // Replace Object.prototype.toString
13038 v8_compile(
13039 "Object.prototype.toString = function() {"
13040 " return 'customized toString';"
13041 "}")
13042 ->Run(context.local())
13043 .ToLocalChecked();
13044
13045 // Normal ToString call should call replaced Object.prototype.toString
13046 Local<v8::Object> instance = templ->GetFunction(context.local())
13047 .ToLocalChecked()
13048 ->NewInstance(context.local())
13049 .ToLocalChecked();
13050 Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13051 CHECK(value->IsString() &&
13052 value->Equals(context.local(), customized_tostring).FromJust());
13053
13054 // ObjectProtoToString should not call replace toString function.
13055 value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13056 CHECK(value->IsString() &&
13057 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13058
13059 // Check global
13060 value =
13061 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13062 CHECK(value->IsString() &&
13063 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13064
13065 // Check ordinary object
13066 Local<Value> object =
13067 v8_compile("new Object()")->Run(context.local()).ToLocalChecked();
13068 value = object.As<v8::Object>()
13069 ->ObjectProtoToString(context.local())
13070 .ToLocalChecked();
13071 CHECK(value->IsString() &&
13072 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13073}
13074
13075
13076TEST(ObjectProtoToStringES6) {
13077 LocalContext context;
13078 v8::Isolate* isolate = CcTest::isolate();
13079 v8::HandleScope scope(isolate);
13080 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13081 templ->SetClassName(v8_str("MyClass"));
13082
13083 Local<String> customized_tostring = v8_str("customized toString");
13084
13085 // Replace Object.prototype.toString
13086 CompileRun(
13087 "Object.prototype.toString = function() {"
13088 " return 'customized toString';"
13089 "}");
13090
13091 // Normal ToString call should call replaced Object.prototype.toString
13092 Local<v8::Object> instance = templ->GetFunction(context.local())
13093 .ToLocalChecked()
13094 ->NewInstance(context.local())
13095 .ToLocalChecked();
13096 Local<String> value = instance->ToString(context.local()).ToLocalChecked();
13097 CHECK(value->IsString() &&
13098 value->Equals(context.local(), customized_tostring).FromJust());
13099
13100 // ObjectProtoToString should not call replace toString function.
13101 value = instance->ObjectProtoToString(context.local()).ToLocalChecked();
13102 CHECK(value->IsString() &&
13103 value->Equals(context.local(), v8_str("[object MyClass]")).FromJust());
13104
13105 // Check global
13106 value =
13107 context->Global()->ObjectProtoToString(context.local()).ToLocalChecked();
13108 CHECK(value->IsString() &&
13109 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13110
13111 // Check ordinary object
13112 Local<Value> object = CompileRun("new Object()");
13113 value = object.As<v8::Object>()
13114 ->ObjectProtoToString(context.local())
13115 .ToLocalChecked();
13116 CHECK(value->IsString() &&
13117 value->Equals(context.local(), v8_str("[object Object]")).FromJust());
13118
13119 // Check that ES6 semantics using @@toStringTag work
13120 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13121
13122#define TEST_TOSTRINGTAG(type, tag, expected) \
13123 do { \
13124 object = CompileRun("new " #type "()"); \
13125 CHECK(object.As<v8::Object>() \
13126 ->Set(context.local(), toStringTag, v8_str(#tag)) \
13127 .FromJust()); \
13128 value = object.As<v8::Object>() \
13129 ->ObjectProtoToString(context.local()) \
13130 .ToLocalChecked(); \
13131 CHECK(value->IsString() && \
13132 value->Equals(context.local(), v8_str("[object " #expected "]")) \
13133 .FromJust()); \
13134 } while (false)
13135
13136 TEST_TOSTRINGTAG(Array, Object, Object);
13137 TEST_TOSTRINGTAG(Object, Arguments, Arguments);
13138 TEST_TOSTRINGTAG(Object, Array, Array);
13139 TEST_TOSTRINGTAG(Object, Boolean, Boolean);
13140 TEST_TOSTRINGTAG(Object, Date, Date);
13141 TEST_TOSTRINGTAG(Object, Error, Error);
13142 TEST_TOSTRINGTAG(Object, Function, Function);
13143 TEST_TOSTRINGTAG(Object, Number, Number);
13144 TEST_TOSTRINGTAG(Object, RegExp, RegExp);
13145 TEST_TOSTRINGTAG(Object, String, String);
13146 TEST_TOSTRINGTAG(Object, Foo, Foo);
13147
13148#undef TEST_TOSTRINGTAG
13149
13150 Local<v8::RegExp> valueRegExp =
13151 v8::RegExp::New(context.local(), v8_str("^$"), v8::RegExp::kNone)
13152 .ToLocalChecked();
13153 Local<Value> valueNumber = v8_num(123);
13154 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
13155 Local<v8::Function> valueFunction =
13156 CompileRun("(function fn() {})").As<v8::Function>();
13157 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
13158 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
13159 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
13160
13161#define TEST_TOSTRINGTAG(type, tagValue, expected) \
13162 do { \
13163 object = CompileRun("new " #type "()"); \
13164 CHECK(object.As<v8::Object>() \
13165 ->Set(context.local(), toStringTag, tagValue) \
13166 .FromJust()); \
13167 value = object.As<v8::Object>() \
13168 ->ObjectProtoToString(context.local()) \
13169 .ToLocalChecked(); \
13170 CHECK(value->IsString() && \
13171 value->Equals(context.local(), v8_str("[object " #expected "]")) \
13172 .FromJust()); \
13173 } while (false)
13174
13175#define TEST_TOSTRINGTAG_TYPES(tagValue) \
13176 TEST_TOSTRINGTAG(Array, tagValue, Array); \
13177 TEST_TOSTRINGTAG(Object, tagValue, Object); \
13178 TEST_TOSTRINGTAG(Function, tagValue, Function); \
13179 TEST_TOSTRINGTAG(Date, tagValue, Date); \
13180 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
13181 TEST_TOSTRINGTAG(Error, tagValue, Error); \
13182
13183 // Test non-String-valued @@toStringTag
13184 TEST_TOSTRINGTAG_TYPES(valueRegExp);
13185 TEST_TOSTRINGTAG_TYPES(valueNumber);
13186 TEST_TOSTRINGTAG_TYPES(valueSymbol);
13187 TEST_TOSTRINGTAG_TYPES(valueFunction);
13188 TEST_TOSTRINGTAG_TYPES(valueObject);
13189 TEST_TOSTRINGTAG_TYPES(valueNull);
13190 TEST_TOSTRINGTAG_TYPES(valueUndef);
13191
13192#undef TEST_TOSTRINGTAG
13193#undef TEST_TOSTRINGTAG_TYPES
13194
13195 // @@toStringTag getter throws
13196 Local<Value> obj = v8::Object::New(isolate);
13197 obj.As<v8::Object>()
13198 ->SetAccessor(context.local(), toStringTag, ThrowingSymbolAccessorGetter)
13199 .FromJust();
13200 {
13201 TryCatch try_catch(isolate);
13202 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13203 CHECK(try_catch.HasCaught());
13204 }
13205
13206 // @@toStringTag getter does not throw
13207 obj = v8::Object::New(isolate);
13208 obj.As<v8::Object>()
13209 ->SetAccessor(context.local(), toStringTag,
13210 SymbolAccessorGetterReturnsDefault, nullptr, v8_str("Test"))
13211 .FromJust();
13212 {
13213 TryCatch try_catch(isolate);
13214 value = obj.As<v8::Object>()
13215 ->ObjectProtoToString(context.local())
13216 .ToLocalChecked();
13217 CHECK(value->IsString() &&
13218 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13219 CHECK(!try_catch.HasCaught());
13220 }
13221
13222 // JS @@toStringTag value
13223 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13224 {
13225 TryCatch try_catch(isolate);
13226 value = obj.As<v8::Object>()
13227 ->ObjectProtoToString(context.local())
13228 .ToLocalChecked();
13229 CHECK(value->IsString() &&
13230 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13231 CHECK(!try_catch.HasCaught());
13232 }
13233
13234 // JS @@toStringTag getter throws
13235 obj = CompileRun(
13236 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13237 " get: function() { throw 'Test'; }"
13238 "}); obj");
13239 {
13240 TryCatch try_catch(isolate);
13241 CHECK(obj.As<v8::Object>()->ObjectProtoToString(context.local()).IsEmpty());
13242 CHECK(try_catch.HasCaught());
13243 }
13244
13245 // JS @@toStringTag getter does not throw
13246 obj = CompileRun(
13247 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13248 " get: function() { return 'Test'; }"
13249 "}); obj");
13250 {
13251 TryCatch try_catch(isolate);
13252 value = obj.As<v8::Object>()
13253 ->ObjectProtoToString(context.local())
13254 .ToLocalChecked();
13255 CHECK(value->IsString() &&
13256 value->Equals(context.local(), v8_str("[object Test]")).FromJust());
13257 CHECK(!try_catch.HasCaught());
13258 }
13259}
13260
13261
13262THREADED_TEST(ObjectGetConstructorName) {
13263 v8::Isolate* isolate = CcTest::isolate();
13264 LocalContext context;
13265 v8::HandleScope scope(isolate);
13266 v8_compile(
13267 "function Parent() {};"
13268 "function Child() {};"
13269 "Child.prototype = new Parent();"
13270 "Child.prototype.constructor = Child;"
13271 "var outer = { inner: (0, function() { }) };"
13272 "var p = new Parent();"
13273 "var c = new Child();"
13274 "var x = new outer.inner();"
13275 "var proto = Child.prototype;")
13276 ->Run(context.local())
13277 .ToLocalChecked();
13278
13279 Local<v8::Value> p =
13280 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13281 CHECK(p->IsObject() &&
13282 p->ToObject(context.local())
13283 .ToLocalChecked()
13284 ->GetConstructorName()
13285 ->Equals(context.local(), v8_str("Parent"))
13286 .FromJust());
13287
13288 Local<v8::Value> c =
13289 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13290 CHECK(c->IsObject() &&
13291 c->ToObject(context.local())
13292 .ToLocalChecked()
13293 ->GetConstructorName()
13294 ->Equals(context.local(), v8_str("Child"))
13295 .FromJust());
13296
13297 Local<v8::Value> x =
13298 context->Global()->Get(context.local(), v8_str("x")).ToLocalChecked();
13299 CHECK(x->IsObject() &&
13300 x->ToObject(context.local())
13301 .ToLocalChecked()
13302 ->GetConstructorName()
13303 ->Equals(context.local(), v8_str("outer.inner"))
13304 .FromJust());
13305
13306 Local<v8::Value> child_prototype =
13307 context->Global()->Get(context.local(), v8_str("proto")).ToLocalChecked();
13308 CHECK(child_prototype->IsObject() &&
13309 child_prototype->ToObject(context.local())
13310 .ToLocalChecked()
13311 ->GetConstructorName()
13312 ->Equals(context.local(), v8_str("Parent"))
13313 .FromJust());
13314}
13315
13316
13317THREADED_TEST(SubclassGetConstructorName) {
13318 v8::Isolate* isolate = CcTest::isolate();
13319 LocalContext context;
13320 v8::HandleScope scope(isolate);
13321 v8_compile(
13322 "\"use strict\";"
13323 "class Parent {}"
13324 "class Child extends Parent {}"
13325 "var p = new Parent();"
13326 "var c = new Child();")
13327 ->Run(context.local())
13328 .ToLocalChecked();
13329
13330 Local<v8::Value> p =
13331 context->Global()->Get(context.local(), v8_str("p")).ToLocalChecked();
13332 CHECK(p->IsObject() &&
13333 p->ToObject(context.local())
13334 .ToLocalChecked()
13335 ->GetConstructorName()
13336 ->Equals(context.local(), v8_str("Parent"))
13337 .FromJust());
13338
13339 Local<v8::Value> c =
13340 context->Global()->Get(context.local(), v8_str("c")).ToLocalChecked();
13341 CHECK(c->IsObject() &&
13342 c->ToObject(context.local())
13343 .ToLocalChecked()
13344 ->GetConstructorName()
13345 ->Equals(context.local(), v8_str("Child"))
13346 .FromJust());
13347}
13348
13349
13350bool ApiTestFuzzer::fuzzing_ = false;
13351v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13352int ApiTestFuzzer::active_tests_;
13353int ApiTestFuzzer::tests_being_run_;
13354int ApiTestFuzzer::current_;
13355
13356
13357// We are in a callback and want to switch to another thread (if we
13358// are currently running the thread fuzzing test).
13359void ApiTestFuzzer::Fuzz() {
13360 if (!fuzzing_) return;
13361 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13362 test->ContextSwitch();
13363}
13364
13365
13366// Let the next thread go. Since it is also waiting on the V8 lock it may
13367// not start immediately.
13368bool ApiTestFuzzer::NextThread() {
13369 int test_position = GetNextTestNumber();
13370 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13371 if (test_position == current_) {
13372 if (kLogThreading)
13373 printf("Stay with %s\n", test_name);
13374 return false;
13375 }
13376 if (kLogThreading) {
13377 printf("Switch from %s to %s\n",
13378 test_name,
13379 RegisterThreadedTest::nth(test_position)->name());
13380 }
13381 current_ = test_position;
13382 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13383 return true;
13384}
13385
13386
13387void ApiTestFuzzer::Run() {
13388 // When it is our turn...
13389 gate_.Wait();
13390 {
13391 // ... get the V8 lock and start running the test.
13392 v8::Locker locker(CcTest::isolate());
13393 CallTest();
13394 }
13395 // This test finished.
13396 active_ = false;
13397 active_tests_--;
13398 // If it was the last then signal that fact.
13399 if (active_tests_ == 0) {
13400 all_tests_done_.Signal();
13401 } else {
13402 // Otherwise select a new test and start that.
13403 NextThread();
13404 }
13405}
13406
13407
13408static unsigned linear_congruential_generator;
13409
13410
13411void ApiTestFuzzer::SetUp(PartOfTest part) {
13412 linear_congruential_generator = i::FLAG_testing_prng_seed;
13413 fuzzing_ = true;
13414 int count = RegisterThreadedTest::count();
13415 int start = count * part / (LAST_PART + 1);
13416 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13417 active_tests_ = tests_being_run_ = end - start + 1;
13418 for (int i = 0; i < tests_being_run_; i++) {
13419 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13420 }
13421 for (int i = 0; i < active_tests_; i++) {
13422 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13423 }
13424}
13425
13426
13427static void CallTestNumber(int test_number) {
13428 (RegisterThreadedTest::nth(test_number)->callback())();
13429}
13430
13431
13432void ApiTestFuzzer::RunAllTests() {
13433 // Set off the first test.
13434 current_ = -1;
13435 NextThread();
13436 // Wait till they are all done.
13437 all_tests_done_.Wait();
13438}
13439
13440
13441int ApiTestFuzzer::GetNextTestNumber() {
13442 int next_test;
13443 do {
13444 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13445 linear_congruential_generator *= 1664525u;
13446 linear_congruential_generator += 1013904223u;
13447 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13448 return next_test;
13449}
13450
13451
13452void ApiTestFuzzer::ContextSwitch() {
13453 // If the new thread is the same as the current thread there is nothing to do.
13454 if (NextThread()) {
13455 // Now it can start.
13456 v8::Unlocker unlocker(CcTest::isolate());
13457 // Wait till someone starts us again.
13458 gate_.Wait();
13459 // And we're off.
13460 }
13461}
13462
13463
13464void ApiTestFuzzer::TearDown() {
13465 fuzzing_ = false;
13466 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13467 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13468 if (fuzzer != nullptr) fuzzer->Join();
13469 }
13470}
13471
13472void ApiTestFuzzer::CallTest() {
13473 v8::Isolate::Scope scope(CcTest::isolate());
13474 if (kLogThreading)
13475 printf("Start test %s #%d\n",
13476 RegisterThreadedTest::nth(test_number_)->name(), test_number_);
13477 CallTestNumber(test_number_);
13478 if (kLogThreading)
13479 printf("End test %s #%d\n", RegisterThreadedTest::nth(test_number_)->name(),
13480 test_number_);
13481}
13482
13483#define THREADING_TEST(INDEX, NAME) \
13484 TEST(Threading##INDEX) { \
13485 ApiTestFuzzer::SetUp(ApiTestFuzzer::NAME); \
13486 ApiTestFuzzer::RunAllTests(); \
13487 ApiTestFuzzer::TearDown(); \
13488 }
13489
13490THREADING_TEST(1, FIRST_PART)
13491THREADING_TEST(2, SECOND_PART)
13492THREADING_TEST(3, THIRD_PART)
13493THREADING_TEST(4, FOURTH_PART)
13494THREADING_TEST(5, FIFTH_PART)
13495THREADING_TEST(6, SIXTH_PART)
13496THREADING_TEST(7, SEVENTH_PART)
13497THREADING_TEST(8, EIGHTH_PART)
13498
13499#undef THREADING_TEST
13500
13501static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13502 v8::Isolate* isolate = args.GetIsolate();
13503 CHECK(v8::Locker::IsLocked(isolate));
13504 ApiTestFuzzer::Fuzz();
13505 v8::Unlocker unlocker(isolate);
13506 const char* code = "throw 7;";
13507 {
13508 v8::Locker nested_locker(isolate);
13509 v8::HandleScope scope(isolate);
13510 v8::Local<Value> exception;
13511 {
13512 v8::TryCatch try_catch(isolate);
13513 v8::Local<Value> value = CompileRun(code);
13514 CHECK(value.IsEmpty());
13515 CHECK(try_catch.HasCaught());
13516 // Make sure to wrap the exception in a new handle because
13517 // the handle returned from the TryCatch is destroyed
13518 // when the TryCatch is destroyed.
13519 exception = Local<Value>::New(isolate, try_catch.Exception());
13520 }
13521 args.GetIsolate()->ThrowException(exception);
13522 }
13523}
13524
13525
13526static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13527 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13528 ApiTestFuzzer::Fuzz();
13529 v8::Unlocker unlocker(CcTest::isolate());
13530 const char* code = "throw 7;";
13531 {
13532 v8::Locker nested_locker(CcTest::isolate());
13533 v8::HandleScope scope(args.GetIsolate());
13534 v8::Local<Value> value = CompileRun(code);
13535 CHECK(value.IsEmpty());
13536 args.GetReturnValue().Set(v8_str("foo"));
13537 }
13538}
13539
13540
13541// These are locking tests that don't need to be run again
13542// as part of the locking aggregation tests.
13543TEST(NestedLockers) {
13544 v8::Isolate* isolate = CcTest::isolate();
13545 v8::Locker locker(isolate);
13546 CHECK(v8::Locker::IsLocked(isolate));
13547 LocalContext env;
13548 v8::HandleScope scope(env->GetIsolate());
13549 Local<v8::FunctionTemplate> fun_templ =
13550 v8::FunctionTemplate::New(isolate, ThrowInJS);
13551 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13552 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13553 Local<Script> script = v8_compile("(function () {"
13554 " try {"
13555 " throw_in_js();"
13556 " return 42;"
13557 " } catch (e) {"
13558 " return e * 13;"
13559 " }"
13560 "})();");
13561 CHECK_EQ(91, script->Run(env.local())
13562 .ToLocalChecked()
13563 ->Int32Value(env.local())
13564 .FromJust());
13565}
13566
13567
13568// These are locking tests that don't need to be run again
13569// as part of the locking aggregation tests.
13570TEST(NestedLockersNoTryCatch) {
13571 v8::Locker locker(CcTest::isolate());
13572 LocalContext env;
13573 v8::HandleScope scope(env->GetIsolate());
13574 Local<v8::FunctionTemplate> fun_templ =
13575 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13576 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13577 CHECK(env->Global()->Set(env.local(), v8_str("throw_in_js"), fun).FromJust());
13578 Local<Script> script = v8_compile("(function () {"
13579 " try {"
13580 " throw_in_js();"
13581 " return 42;"
13582 " } catch (e) {"
13583 " return e * 13;"
13584 " }"
13585 "})();");
13586 CHECK_EQ(91, script->Run(env.local())
13587 .ToLocalChecked()
13588 ->Int32Value(env.local())
13589 .FromJust());
13590}
13591
13592
13593THREADED_TEST(RecursiveLocking) {
13594 v8::Locker locker(CcTest::isolate());
13595 {
13596 v8::Locker locker2(CcTest::isolate());
13597 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13598 }
13599}
13600
13601
13602static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13603 ApiTestFuzzer::Fuzz();
13604 v8::Unlocker unlocker(CcTest::isolate());
13605}
13606
13607
13608THREADED_TEST(LockUnlockLock) {
13609 {
13610 v8::Locker locker(CcTest::isolate());
13611 v8::HandleScope scope(CcTest::isolate());
13612 LocalContext env;
13613 Local<v8::FunctionTemplate> fun_templ =
13614 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13615 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13616 CHECK(env->Global()
13617 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13618 .FromJust());
13619 Local<Script> script = v8_compile("(function () {"
13620 " unlock_for_a_moment();"
13621 " return 42;"
13622 "})();");
13623 CHECK_EQ(42, script->Run(env.local())
13624 .ToLocalChecked()
13625 ->Int32Value(env.local())
13626 .FromJust());
13627 }
13628 {
13629 v8::Locker locker(CcTest::isolate());
13630 v8::HandleScope scope(CcTest::isolate());
13631 LocalContext env;
13632 Local<v8::FunctionTemplate> fun_templ =
13633 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13634 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
13635 CHECK(env->Global()
13636 ->Set(env.local(), v8_str("unlock_for_a_moment"), fun)
13637 .FromJust());
13638 Local<Script> script = v8_compile("(function () {"
13639 " unlock_for_a_moment();"
13640 " return 42;"
13641 "})();");
13642 CHECK_EQ(42, script->Run(env.local())
13643 .ToLocalChecked()
13644 ->Int32Value(env.local())
13645 .FromJust());
13646 }
13647}
13648
13649
13650static int GetGlobalObjectsCount() {
13651 int count = 0;
13652 i::HeapIterator it(CcTest::heap());
13653 for (i::HeapObject object = it.next(); !object.is_null();
13654 object = it.next()) {
13655 if (object->IsJSGlobalObject()) {
13656 i::JSGlobalObject g = i::JSGlobalObject::cast(object);
13657 // Skip dummy global object.
13658 if (g->global_dictionary()->NumberOfElements() != 0) {
13659 count++;
13660 }
13661 }
13662 }
13663 return count;
13664}
13665
13666
13667static void CheckSurvivingGlobalObjectsCount(int expected) {
13668 // We need to collect all garbage twice to be sure that everything
13669 // has been collected. This is because inline caches are cleared in
13670 // the first garbage collection but some of the maps have already
13671 // been marked at that point. Therefore some of the maps are not
13672 // collected until the second garbage collection.
13673 CcTest::CollectAllGarbage();
13674 CcTest::CollectAllGarbage();
13675 int count = GetGlobalObjectsCount();
13676 CHECK_EQ(expected, count);
13677}
13678
13679
13680TEST(DontLeakGlobalObjects) {
13681 // Regression test for issues 1139850 and 1174891.
13682
13683 i::FLAG_expose_gc = true;
13684 v8::V8::Initialize();
13685
13686 for (int i = 0; i < 5; i++) {
13687 { v8::HandleScope scope(CcTest::isolate());
13688 LocalContext context;
13689 }
13690 CcTest::isolate()->ContextDisposedNotification();
13691 CheckSurvivingGlobalObjectsCount(0);
13692
13693 { v8::HandleScope scope(CcTest::isolate());
13694 LocalContext context;
13695 v8_compile("Date")->Run(context.local()).ToLocalChecked();
13696 }
13697 CcTest::isolate()->ContextDisposedNotification();
13698 CheckSurvivingGlobalObjectsCount(0);
13699
13700 { v8::HandleScope scope(CcTest::isolate());
13701 LocalContext context;
13702 v8_compile("/aaa/")->Run(context.local()).ToLocalChecked();
13703 }
13704 CcTest::isolate()->ContextDisposedNotification();
13705 CheckSurvivingGlobalObjectsCount(0);
13706
13707 { v8::HandleScope scope(CcTest::isolate());
13708 const char* extension_list[] = { "v8/gc" };
13709 v8::ExtensionConfiguration extensions(1, extension_list);
13710 LocalContext context(&extensions);
13711 v8_compile("gc();")->Run(context.local()).ToLocalChecked();
13712 }
13713 CcTest::isolate()->ContextDisposedNotification();
13714 CheckSurvivingGlobalObjectsCount(0);
13715 }
13716}
13717
13718
13719TEST(CopyablePersistent) {
13720 LocalContext context;
13721 v8::Isolate* isolate = context->GetIsolate();
13722 i::GlobalHandles* globals =
13723 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13724 size_t initial_handles = globals->handles_count();
13725 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13726 CopyableObject;
13727 {
13728 CopyableObject handle1;
13729 {
13730 v8::HandleScope scope(isolate);
13731 handle1.Reset(isolate, v8::Object::New(isolate));
13732 }
13733 CHECK_EQ(initial_handles + 1, globals->handles_count());
13734 CopyableObject handle2;
13735 handle2 = handle1;
13736 CHECK(handle1 == handle2);
13737 CHECK_EQ(initial_handles + 2, globals->handles_count());
13738 CopyableObject handle3(handle2);
13739 CHECK(handle1 == handle3);
13740 CHECK_EQ(initial_handles + 3, globals->handles_count());
13741 }
13742 // Verify autodispose
13743 CHECK_EQ(initial_handles, globals->handles_count());
13744}
13745
13746
13747static void WeakApiCallback(
13748 const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
13749 data.GetParameter()->Reset();
13750 delete data.GetParameter();
13751}
13752
13753
13754TEST(WeakCallbackApi) {
13755 LocalContext context;
13756 v8::Isolate* isolate = context->GetIsolate();
13757 i::GlobalHandles* globals =
13758 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13759 size_t initial_handles = globals->handles_count();
13760 {
13761 v8::HandleScope scope(isolate);
13762 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13763 CHECK(
13764 obj->Set(context.local(), v8_str("key"), v8::Integer::New(isolate, 231))
13765 .FromJust());
13766 v8::Persistent<v8::Object>* handle =
13767 new v8::Persistent<v8::Object>(isolate, obj);
13768 handle->SetWeak<v8::Persistent<v8::Object>>(
13769 handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
13770 }
13771 CcTest::PreciseCollectAllGarbage();
13772 // Verify disposed.
13773 CHECK_EQ(initial_handles, globals->handles_count());
13774}
13775
13776
13777v8::Persistent<v8::Object> some_object;
13778v8::Persistent<v8::Object> bad_handle;
13779
13780
13781void NewPersistentHandleCallback2(
13782 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13783 v8::HandleScope scope(data.GetIsolate());
13784 bad_handle.Reset(data.GetIsolate(), some_object);
13785}
13786
13787
13788void NewPersistentHandleCallback1(
13789 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13790 data.GetParameter()->Reset();
13791 data.SetSecondPassCallback(NewPersistentHandleCallback2);
13792}
13793
13794
13795THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13796 LocalContext context;
13797 v8::Isolate* isolate = context->GetIsolate();
13798
13799 v8::Persistent<v8::Object> handle1, handle2;
13800 {
13801 v8::HandleScope scope(isolate);
13802 some_object.Reset(isolate, v8::Object::New(isolate));
13803 handle1.Reset(isolate, v8::Object::New(isolate));
13804 handle2.Reset(isolate, v8::Object::New(isolate));
13805 }
13806 // Note: order is implementation dependent alas: currently
13807 // global handle nodes are processed by PostGarbageCollectionProcessing
13808 // in reverse allocation order, so if second allocated handle is deleted,
13809 // weak callback of the first handle would be able to 'reallocate' it.
13810 handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
13811 v8::WeakCallbackType::kParameter);
13812 handle2.Reset();
13813 CcTest::CollectAllGarbage();
13814}
13815
13816
13817v8::Persistent<v8::Object> to_be_disposed;
13818
13819
13820void DisposeAndForceGcCallback2(
13821 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13822 to_be_disposed.Reset();
13823 CcTest::CollectAllGarbage();
13824}
13825
13826
13827void DisposeAndForceGcCallback1(
13828 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13829 data.GetParameter()->Reset();
13830 data.SetSecondPassCallback(DisposeAndForceGcCallback2);
13831}
13832
13833
13834THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13835 LocalContext context;
13836 v8::Isolate* isolate = context->GetIsolate();
13837
13838 v8::Persistent<v8::Object> handle1, handle2;
13839 {
13840 v8::HandleScope scope(isolate);
13841 handle1.Reset(isolate, v8::Object::New(isolate));
13842 handle2.Reset(isolate, v8::Object::New(isolate));
13843 }
13844 handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
13845 v8::WeakCallbackType::kParameter);
13846 to_be_disposed.Reset(isolate, handle2);
13847 CcTest::CollectAllGarbage();
13848}
13849
13850void DisposingCallback(
13851 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13852 data.GetParameter()->Reset();
13853}
13854
13855void HandleCreatingCallback2(
13856 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13857 v8::HandleScope scope(data.GetIsolate());
13858 v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
13859}
13860
13861
13862void HandleCreatingCallback1(
13863 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
13864 data.GetParameter()->Reset();
13865 data.SetSecondPassCallback(HandleCreatingCallback2);
13866}
13867
13868
13869THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13870 v8::Locker locker(CcTest::isolate());
13871 LocalContext context;
13872 v8::Isolate* isolate = context->GetIsolate();
13873
13874 v8::Persistent<v8::Object> handle1, handle2, handle3;
13875 {
13876 v8::HandleScope scope(isolate);
13877 handle3.Reset(isolate, v8::Object::New(isolate));
13878 handle2.Reset(isolate, v8::Object::New(isolate));
13879 handle1.Reset(isolate, v8::Object::New(isolate));
13880 }
13881 handle2.SetWeak(&handle2, DisposingCallback,
13882 v8::WeakCallbackType::kParameter);
13883 handle3.SetWeak(&handle3, HandleCreatingCallback1,
13884 v8::WeakCallbackType::kParameter);
13885 CcTest::CollectAllGarbage();
13886 EmptyMessageQueues(isolate);
13887}
13888
13889
13890THREADED_TEST(CheckForCrossContextObjectLiterals) {
13891 v8::V8::Initialize();
13892
13893 const int nof = 2;
13894 const char* sources[nof] = {
13895 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13896 "Object()"
13897 };
13898
13899 for (int i = 0; i < nof; i++) {
13900 const char* source = sources[i];
13901 { v8::HandleScope scope(CcTest::isolate());
13902 LocalContext context;
13903 CompileRun(source);
13904 }
13905 { v8::HandleScope scope(CcTest::isolate());
13906 LocalContext context;
13907 CompileRun(source);
13908 }
13909 }
13910}
13911
13912
13913static v8::Local<Value> NestedScope(v8::Local<Context> env) {
13914 v8::EscapableHandleScope inner(env->GetIsolate());
13915 env->Enter();
13916 v8::Local<Value> three = v8_num(3);
13917 v8::Local<Value> value = inner.Escape(three);
13918 env->Exit();
13919 return value;
13920}
13921
13922
13923THREADED_TEST(NestedHandleScopeAndContexts) {
13924 v8::Isolate* isolate = CcTest::isolate();
13925 v8::HandleScope outer(isolate);
13926 v8::Local<Context> env = Context::New(isolate);
13927 env->Enter();
13928 v8::Local<Value> value = NestedScope(env);
13929 v8::Local<String> str(value->ToString(env).ToLocalChecked());
13930 CHECK(!str.IsEmpty());
13931 env->Exit();
13932}
13933
13934static v8::base::HashMap* code_map = nullptr;
13935static v8::base::HashMap* jitcode_line_info = nullptr;
13936static int saw_bar = 0;
13937static int move_events = 0;
13938
13939
13940static bool FunctionNameIs(const char* expected,
13941 const v8::JitCodeEvent* event) {
13942 // Log lines for functions are of the general form:
13943 // "LazyCompile:<type><function_name>" or Function:<type><function_name>,
13944 // where the type is one of "*", "~" or "".
13945 static const char* kPreamble;
13946 if (!i::FLAG_lazy) {
13947 kPreamble = "Function:";
13948 } else {
13949 kPreamble = "LazyCompile:";
13950 }
13951 static size_t kPreambleLen = strlen(kPreamble);
13952
13953 if (event->name.len < kPreambleLen ||
13954 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13955 return false;
13956 }
13957
13958 const char* tail = event->name.str + kPreambleLen;
13959 size_t tail_len = event->name.len - kPreambleLen;
13960 size_t expected_len = strlen(expected);
13961 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13962 --tail_len;
13963 ++tail;
13964 }
13965
13966 // Check for tails like 'bar :1'.
13967 if (tail_len > expected_len + 2 &&
13968 tail[expected_len] == ' ' &&
13969 tail[expected_len + 1] == ':' &&
13970 tail[expected_len + 2] &&
13971 !strncmp(tail, expected, expected_len)) {
13972 return true;
13973 }
13974
13975 if (tail_len != expected_len)
13976 return false;
13977
13978 return strncmp(tail, expected, expected_len) == 0;
13979}
13980
13981
13982static void event_handler(const v8::JitCodeEvent* event) {
13983 CHECK_NOT_NULL(event);
13984 CHECK_NOT_NULL(code_map);
13985 CHECK_NOT_NULL(jitcode_line_info);
13986
13987 class DummyJitCodeLineInfo {
13988 };
13989
13990 switch (event->type) {
13991 case v8::JitCodeEvent::CODE_ADDED: {
13992 CHECK_NOT_NULL(event->code_start);
13993 CHECK_NE(0, static_cast<int>(event->code_len));
13994 CHECK_NOT_NULL(event->name.str);
13995 v8::base::HashMap::Entry* entry = code_map->LookupOrInsert(
13996 event->code_start, i::ComputePointerHash(event->code_start));
13997 entry->value = reinterpret_cast<void*>(event->code_len);
13998
13999 if (FunctionNameIs("bar", event)) {
14000 ++saw_bar;
14001 }
14002 }
14003 break;
14004
14005 case v8::JitCodeEvent::CODE_MOVED: {
14006 uint32_t hash = i::ComputePointerHash(event->code_start);
14007 // We would like to never see code move that we haven't seen before,
14008 // but the code creation event does not happen until the line endings
14009 // have been calculated (this is so that we can report the line in the
14010 // script at which the function source is found, see
14011 // Compiler::RecordFunctionCompilation) and the line endings
14012 // calculations can cause a GC, which can move the newly created code
14013 // before its existence can be logged.
14014 v8::base::HashMap::Entry* entry =
14015 code_map->Lookup(event->code_start, hash);
14016 if (entry != nullptr) {
14017 ++move_events;
14018
14019 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14020 code_map->Remove(event->code_start, hash);
14021
14022 entry = code_map->LookupOrInsert(
14023 event->new_code_start,
14024 i::ComputePointerHash(event->new_code_start));
14025 entry->value = reinterpret_cast<void*>(event->code_len);
14026 }
14027 }
14028 break;
14029
14030 case v8::JitCodeEvent::CODE_REMOVED:
14031 // Object/code removal events are currently not dispatched from the GC.
14032 UNREACHABLE();
14033
14034 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14035 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14036 // record it in jitcode_line_info.
14037 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14038 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14039 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14040 temp_event->user_data = line_info;
14041 v8::base::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
14042 line_info, i::ComputePointerHash(line_info));
14043 entry->value = reinterpret_cast<void*>(line_info);
14044 }
14045 break;
14046 // For these two events, we will check whether the event->user_data
14047 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14048 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14049 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14050 CHECK_NOT_NULL(event->user_data);
14051 uint32_t hash = i::ComputePointerHash(event->user_data);
14052 v8::base::HashMap::Entry* entry =
14053 jitcode_line_info->Lookup(event->user_data, hash);
14054 CHECK_NOT_NULL(entry);
14055 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14056 }
14057 break;
14058
14059 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14060 CHECK_NOT_NULL(event->user_data);
14061 uint32_t hash = i::ComputePointerHash(event->user_data);
14062 v8::base::HashMap::Entry* entry =
14063 jitcode_line_info->Lookup(event->user_data, hash);
14064 CHECK_NOT_NULL(entry);
14065 }
14066 break;
14067
14068 default:
14069 // Impossible event.
14070 UNREACHABLE();
14071 }
14072}
14073
14074
14075UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14076 i::FLAG_stress_compaction = true;
14077 i::FLAG_incremental_marking = false;
14078 if (i::FLAG_never_compact) return;
14079 const char* script =
14080 "function bar() {"
14081 " var sum = 0;"
14082 " for (i = 0; i < 10; ++i)"
14083 " sum = foo(i);"
14084 " return sum;"
14085 "}"
14086 "function foo(i) { return i; };"
14087 "bar();";
14088
14089 // Run this test in a new isolate to make sure we don't
14090 // have remnants of state from other code.
14091 v8::Isolate::CreateParams create_params;
14092 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
14093 v8::Isolate* isolate = v8::Isolate::New(create_params);
14094 isolate->Enter();
14095 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14096 i::Heap* heap = i_isolate->heap();
14097
14098 // Start with a clean slate.
14099 heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14100
14101 {
14102 v8::HandleScope scope(isolate);
14103 v8::base::HashMap code;
14104 code_map = &code;
14105
14106 v8::base::HashMap lineinfo;
14107 jitcode_line_info = &lineinfo;
14108
14109 saw_bar = 0;
14110 move_events = 0;
14111
14112 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14113
14114 // Generate new code objects sparsely distributed across several
14115 // different fragmented code-space pages.
14116 const int kIterations = 10;
14117 for (int i = 0; i < kIterations; ++i) {
14118 LocalContext env(isolate);
14119 i::AlwaysAllocateScope always_allocate(i_isolate);
14120 CompileRun(script);
14121
14122 // Keep a strong reference to the code object in the handle scope.
14123 i::Handle<i::JSFunction> bar(i::Handle<i::JSFunction>::cast(
14124 v8::Utils::OpenHandle(*env->Global()
14125 ->Get(env.local(), v8_str("bar"))
14126 .ToLocalChecked())));
14127 i::Handle<i::JSFunction> foo(i::Handle<i::JSFunction>::cast(
14128 v8::Utils::OpenHandle(*env->Global()
14129 ->Get(env.local(), v8_str("foo"))
14130 .ToLocalChecked())));
14131
14132 i::PagedSpace* foo_owning_space = reinterpret_cast<i::PagedSpace*>(
14133 i::Page::FromHeapObject(foo->abstract_code())->owner());
14134 i::PagedSpace* bar_owning_space = reinterpret_cast<i::PagedSpace*>(
14135 i::Page::FromHeapObject(bar->abstract_code())->owner());
14136 CHECK_EQ(foo_owning_space, bar_owning_space);
14137 i::heap::SimulateFullSpace(foo_owning_space);
14138
14139 // Clear the compilation cache to get more wastage.
14140 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14141 }
14142
14143 // Force code movement.
14144 heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
14145
14146 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14147
14148 CHECK_LE(kIterations, saw_bar);
14149 CHECK_LT(0, move_events);
14150
14151 code_map = nullptr;
14152 jitcode_line_info = nullptr;
14153 }
14154
14155 isolate->Exit();
14156 isolate->Dispose();
14157
14158 // Do this in a new isolate.
14159 isolate = v8::Isolate::New(create_params);
14160 isolate->Enter();
14161
14162 // Verify that we get callbacks for existing code objects when we
14163 // request enumeration of existing code.
14164 {
14165 v8::HandleScope scope(isolate);
14166 LocalContext env(isolate);
14167 CompileRun(script);
14168
14169 // Now get code through initial iteration.
14170 v8::base::HashMap code;
14171 code_map = &code;
14172
14173 v8::base::HashMap lineinfo;
14174 jitcode_line_info = &lineinfo;
14175
14176 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14177 event_handler);
14178 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, nullptr);
14179
14180 jitcode_line_info = nullptr;
14181 // We expect that we got some events. Note that if we could get code removal
14182 // notifications, we could compare two collections, one created by listening
14183 // from the time of creation of an isolate, and the other by subscribing
14184 // with EnumExisting.
14185 CHECK_LT(0u, code.occupancy());
14186
14187 code_map = nullptr;
14188 }
14189
14190 isolate->Exit();
14191 isolate->Dispose();
14192}
14193
14194TEST(ExternalAllocatedMemory) {
14195 v8::Isolate* isolate = CcTest::isolate();
14196 v8::HandleScope outer(isolate);
14197 v8::Local<Context> env(Context::New(isolate));
14198 CHECK(!env.IsEmpty());
14199 const int64_t kSize = 1024*1024;
14200 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14201 CHECK_EQ(baseline + kSize,
14202 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14203 CHECK_EQ(baseline,
14204 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14205 const int64_t kTriggerGCSize =
14206 CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14207 CHECK_EQ(baseline + kTriggerGCSize,
14208 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
14209 CHECK_EQ(baseline,
14210 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
14211}
14212
14213
14214TEST(Regress51719) {
14215 i::FLAG_incremental_marking = false;
14216 CcTest::InitializeVM();
14217
14218 const int64_t kTriggerGCSize =
14219 CcTest::i_isolate()->heap()->external_memory_hard_limit() + 1;
14220 v8::Isolate* isolate = CcTest::isolate();
14221 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize);
14222}
14223
14224// Regression test for issue 54, object templates with embedder fields
14225// but no accessors or interceptors did not get their embedder field
14226// count set on instances.
14227THREADED_TEST(Regress54) {
14228 LocalContext context;
14229 v8::Isolate* isolate = context->GetIsolate();
14230 v8::HandleScope outer(isolate);
14231 static v8::Persistent<v8::ObjectTemplate> templ;
14232 if (templ.IsEmpty()) {
14233 v8::EscapableHandleScope inner(isolate);
14234 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14235 local->SetInternalFieldCount(1);
14236 templ.Reset(isolate, inner.Escape(local));
14237 }
14238 v8::Local<v8::Object> result =
14239 v8::Local<v8::ObjectTemplate>::New(isolate, templ)
14240 ->NewInstance(context.local())
14241 .ToLocalChecked();
14242 CHECK_EQ(1, result->InternalFieldCount());
14243}
14244
14245
14246// If part of the threaded tests, this test makes ThreadingTest fail
14247// on mac.
14248TEST(CatchStackOverflow) {
14249 LocalContext context;
14250 v8::HandleScope scope(context->GetIsolate());
14251 v8::TryCatch try_catch(context->GetIsolate());
14252 v8::Local<v8::Value> result = CompileRun(
14253 "function f() {"
14254 " return f();"
14255 "}"
14256 ""
14257 "f();");
14258 CHECK(result.IsEmpty());
14259}
14260
14261
14262static void CheckTryCatchSourceInfo(v8::Local<v8::Script> script,
14263 const char* resource_name,
14264 int line_offset) {
14265 v8::HandleScope scope(CcTest::isolate());
14266 v8::TryCatch try_catch(CcTest::isolate());
14267 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
14268 CHECK(script->Run(context).IsEmpty());
14269 CHECK(try_catch.HasCaught());
14270 v8::Local<v8::Message> message = try_catch.Message();
14271 CHECK(!message.IsEmpty());
14272 CHECK_EQ(10 + line_offset, message->GetLineNumber(context).FromJust());
14273 CHECK_EQ(91, message->GetStartPosition());
14274 CHECK_EQ(92, message->GetEndPosition());
14275 CHECK_EQ(2, message->GetStartColumn(context).FromJust());
14276 CHECK_EQ(3, message->GetEndColumn(context).FromJust());
14277 v8::String::Utf8Value line(CcTest::isolate(),
14278 message->GetSourceLine(context).ToLocalChecked());
14279 CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
14280 v8::String::Utf8Value name(CcTest::isolate(),
14281 message->GetScriptOrigin().ResourceName());
14282 CHECK_EQ(0, strcmp(resource_name, *name));
14283}
14284
14285
14286THREADED_TEST(TryCatchSourceInfo) {
14287 LocalContext context;
14288 v8::HandleScope scope(context->GetIsolate());
14289 v8::Local<v8::String> source = v8_str(
14290 "function Foo() {\n"
14291 " return Bar();\n"
14292 "}\n"
14293 "\n"
14294 "function Bar() {\n"
14295 " return Baz();\n"
14296 "}\n"
14297 "\n"
14298 "function Baz() {\n"
14299 " throw 'nirk';\n"
14300 "}\n"
14301 "\n"
14302 "Foo();\n");
14303
14304 const char* resource_name;
14305 v8::Local<v8::Script> script;
14306 resource_name = "test.js";
14307 script = CompileWithOrigin(source, resource_name, false);
14308 CheckTryCatchSourceInfo(script, resource_name, 0);
14309
14310 resource_name = "test1.js";
14311 v8::ScriptOrigin origin1(v8_str(resource_name));
14312 script =
14313 v8::Script::Compile(context.local(), source, &origin1).ToLocalChecked();
14314 CheckTryCatchSourceInfo(script, resource_name, 0);
14315
14316 resource_name = "test2.js";
14317 v8::ScriptOrigin origin2(v8_str(resource_name),
14318 v8::Integer::New(context->GetIsolate(), 7));
14319 script =
14320 v8::Script::Compile(context.local(), source, &origin2).ToLocalChecked();
14321 CheckTryCatchSourceInfo(script, resource_name, 7);
14322}
14323
14324
14325THREADED_TEST(TryCatchSourceInfoForEOSError) {
14326 LocalContext context;
14327 v8::HandleScope scope(context->GetIsolate());
14328 v8::TryCatch try_catch(context->GetIsolate());
14329 CHECK(v8::Script::Compile(context.local(), v8_str("!\n")).IsEmpty());
14330 CHECK(try_catch.HasCaught());
14331 v8::Local<v8::Message> message = try_catch.Message();
14332 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
14333 CHECK_EQ(0, message->GetStartColumn(context.local()).FromJust());
14334}
14335
14336
14337THREADED_TEST(CompilationCache) {
14338 LocalContext context;
14339 v8::HandleScope scope(context->GetIsolate());
14340 v8::Local<v8::String> source0 = v8_str("1234");
14341 v8::Local<v8::String> source1 = v8_str("1234");
14342 v8::Local<v8::Script> script0 = CompileWithOrigin(source0, "test.js", false);
14343 v8::Local<v8::Script> script1 = CompileWithOrigin(source1, "test.js", false);
14344 v8::Local<v8::Script> script2 = v8::Script::Compile(context.local(), source0)
14345 .ToLocalChecked(); // different origin
14346 CHECK_EQ(1234, script0->Run(context.local())
14347 .ToLocalChecked()
14348 ->Int32Value(context.local())
14349 .FromJust());
14350 CHECK_EQ(1234, script1->Run(context.local())
14351 .ToLocalChecked()
14352 ->Int32Value(context.local())
14353 .FromJust());
14354 CHECK_EQ(1234, script2->Run(context.local())
14355 .ToLocalChecked()
14356 ->Int32Value(context.local())
14357 .FromJust());
14358}
14359
14360
14361static void FunctionNameCallback(
14362 const v8::FunctionCallbackInfo<v8::Value>& args) {
14363 ApiTestFuzzer::Fuzz();
14364 args.GetReturnValue().Set(v8_num(42));
14365}
14366
14367
14368THREADED_TEST(CallbackFunctionName) {
14369 LocalContext context;
14370 v8::Isolate* isolate = context->GetIsolate();
14371 v8::HandleScope scope(isolate);
14372 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14373 t->Set(v8_str("asdf"),
14374 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14375 CHECK(context->Global()
14376 ->Set(context.local(), v8_str("obj"),
14377 t->NewInstance(context.local()).ToLocalChecked())
14378 .FromJust());
14379 v8::Local<v8::Value> value = CompileRun("obj.asdf.name");
14380 CHECK(value->IsString());
14381 v8::String::Utf8Value name(isolate, value);
14382 CHECK_EQ(0, strcmp("asdf", *name));
14383}
14384
14385
14386THREADED_TEST(DateAccess) {
14387 LocalContext context;
14388 v8::HandleScope scope(context->GetIsolate());
14389 v8::Local<v8::Value> date =
14390 v8::Date::New(context.local(), 1224744689038.0).ToLocalChecked();
14391 CHECK(date->IsDate());
14392 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14393}
14394
14395void CheckIsSymbolAt(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14396 unsigned index, const char* name) {
14397 v8::Local<v8::Context> context = isolate->GetCurrentContext();
14398 v8::Local<v8::Value> value =
14399 properties->Get(context, v8::Integer::New(isolate, index))
14400 .ToLocalChecked();
14401 CHECK(value->IsSymbol());
14402 v8::String::Utf8Value symbol_name(isolate,
14403 Local<Symbol>::Cast(value)->Name());
14404 if (strcmp(name, *symbol_name) != 0) {
14405 FATAL("properties[%u] was Symbol('%s') instead of Symbol('%s').", index,
14406 name, *symbol_name);
14407 }
14408}
14409
14410void CheckStringArray(v8::Isolate* isolate, v8::Local<v8::Array> properties,
14411 unsigned length, const char* names[]) {
14412 v8::Local<v8::Context> context = isolate->GetCurrentContext();
14413 CHECK_EQ(length, properties->Length());
14414 for (unsigned i = 0; i < length; i++) {
14415 v8::Local<v8::Value> value =
14416 properties->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
14417 if (names[i] == nullptr) {
14418 DCHECK(value->IsSymbol());
14419 } else {
14420 v8::String::Utf8Value elm(isolate, value);
14421 if (strcmp(names[i], *elm) != 0) {
14422 FATAL("properties[%u] was '%s' instead of '%s'.", i, *elm, names[i]);
14423 }
14424 }
14425 }
14426}
14427
14428void CheckProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14429 unsigned length, const char* names[]) {
14430 v8::Local<v8::Context> context = isolate->GetCurrentContext();
14431 v8::Local<v8::Object> obj = val.As<v8::Object>();
14432 v8::Local<v8::Array> props = obj->GetPropertyNames(context).ToLocalChecked();
14433 CheckStringArray(isolate, props, length, names);
14434}
14435
14436
14437void CheckOwnProperties(v8::Isolate* isolate, v8::Local<v8::Value> val,
14438 unsigned elmc, const char* elmv[]) {
14439 v8::Local<v8::Context> context = isolate->GetCurrentContext();
14440 v8::Local<v8::Object> obj = val.As<v8::Object>();
14441 v8::Local<v8::Array> props =
14442 obj->GetOwnPropertyNames(context).ToLocalChecked();
14443 CHECK_EQ(elmc, props->Length());
14444 for (unsigned i = 0; i < elmc; i++) {
14445 v8::String::Utf8Value elm(
14446 isolate,
14447 props->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked());
14448 CHECK_EQ(0, strcmp(elmv[i], *elm));
14449 }
14450}
14451
14452
14453THREADED_TEST(PropertyEnumeration) {
14454 LocalContext context;
14455 v8::Isolate* isolate = context->GetIsolate();
14456 v8::HandleScope scope(isolate);
14457 v8::Local<v8::Value> obj = CompileRun(
14458 "var result = [];"
14459 "result[0] = {};"
14460 "result[1] = {a: 1, b: 2};"
14461 "result[2] = [1, 2, 3];"
14462 "var proto = {x: 1, y: 2, z: 3};"
14463 "var x = { __proto__: proto, w: 0, z: 1 };"
14464 "result[3] = x;"
14465 "result[4] = {21350:1};"
14466 "x = Object.create(null);"
14467 "x.a = 1; x[12345678] = 1;"
14468 "result[5] = x;"
14469 "result;");
14470 v8::Local<v8::Array> elms = obj.As<v8::Array>();
14471 CHECK_EQ(6u, elms->Length());
14472 int elmc0 = 0;
14473 const char** elmv0 = nullptr;
14474 CheckProperties(
14475 isolate,
14476 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14477 elmc0, elmv0);
14478 CheckOwnProperties(
14479 isolate,
14480 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14481 elmc0, elmv0);
14482 int elmc1 = 2;
14483 const char* elmv1[] = {"a", "b"};
14484 CheckProperties(
14485 isolate,
14486 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14487 elmc1, elmv1);
14488 CheckOwnProperties(
14489 isolate,
14490 elms->Get(context.local(), v8::Integer::New(isolate, 1)).ToLocalChecked(),
14491 elmc1, elmv1);
14492 int elmc2 = 3;
14493 const char* elmv2[] = {"0", "1", "2"};
14494 CheckProperties(
14495 isolate,
14496 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14497 elmc2, elmv2);
14498 CheckOwnProperties(
14499 isolate,
14500 elms->Get(context.local(), v8::Integer::New(isolate, 2)).ToLocalChecked(),
14501 elmc2, elmv2);
14502 int elmc3 = 4;
14503 const char* elmv3[] = {"w", "z", "x", "y"};
14504 CheckProperties(
14505 isolate,
14506 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14507 elmc3, elmv3);
14508 int elmc4 = 2;
14509 const char* elmv4[] = {"w", "z"};
14510 CheckOwnProperties(
14511 isolate,
14512 elms->Get(context.local(), v8::Integer::New(isolate, 3)).ToLocalChecked(),
14513 elmc4, elmv4);
14514 // Dictionary elements.
14515 int elmc5 = 1;
14516 const char* elmv5[] = {"21350"};
14517 CheckProperties(
14518 isolate,
14519 elms->Get(context.local(), v8::Integer::New(isolate, 4)).ToLocalChecked(),
14520 elmc5, elmv5);
14521 // Dictionary properties.
14522 int elmc6 = 2;
14523 const char* elmv6[] = {"12345678", "a"};
14524 CheckProperties(
14525 isolate,
14526 elms->Get(context.local(), v8::Integer::New(isolate, 5)).ToLocalChecked(),
14527 elmc6, elmv6);
14528}
14529
14530
14531THREADED_TEST(PropertyEnumeration2) {
14532 LocalContext context;
14533 v8::Isolate* isolate = context->GetIsolate();
14534 v8::HandleScope scope(isolate);
14535 v8::Local<v8::Value> obj = CompileRun(
14536 "var result = [];"
14537 "result[0] = {};"
14538 "result[1] = {a: 1, b: 2};"
14539 "result[2] = [1, 2, 3];"
14540 "var proto = {x: 1, y: 2, z: 3};"
14541 "var x = { __proto__: proto, w: 0, z: 1 };"
14542 "result[3] = x;"
14543 "result;");
14544 v8::Local<v8::Array> elms = obj.As<v8::Array>();
14545 CHECK_EQ(4u, elms->Length());
14546 int elmc0 = 0;
14547 const char** elmv0 = nullptr;
14548 CheckProperties(
14549 isolate,
14550 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked(),
14551 elmc0, elmv0);
14552
14553 v8::Local<v8::Value> val =
14554 elms->Get(context.local(), v8::Integer::New(isolate, 0)).ToLocalChecked();
14555 v8::Local<v8::Array> props =
14556 val.As<v8::Object>()->GetPropertyNames(context.local()).ToLocalChecked();
14557 CHECK_EQ(0u, props->Length());
14558 for (uint32_t i = 0; i < props->Length(); i++) {
14559 printf("p[%u]\n", i);
14560 }
14561}
14562
14563THREADED_TEST(GetPropertyNames) {
14564 LocalContext context;
14565 v8::Isolate* isolate = context->GetIsolate();
14566 v8::HandleScope scope(isolate);
14567 v8::Local<v8::Value> result = CompileRun(
14568 "var result = {0: 0, 1: 1, a: 2, b: 3};"
14569 "result[2**32] = '4294967296';"
14570 "result[2**32-1] = '4294967295';"
14571 "result[2**32-2] = '4294967294';"
14572 "result[Symbol('symbol')] = true;"
14573 "result.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14574 "result;");
14575 v8::Local<v8::Object> object = result.As<v8::Object>();
14576 v8::PropertyFilter default_filter =
14577 static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14578 v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14579
14580 v8::Local<v8::Array> properties =
14581 object->GetPropertyNames(context.local()).ToLocalChecked();
14582 const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14583 "b", "4294967296", "4294967295", "2",
14584 "3", "c", "d"};
14585 CheckStringArray(isolate, properties, 11, expected_properties1);
14586
14587 properties =
14588 object
14589 ->GetPropertyNames(context.local(),
14590 v8::KeyCollectionMode::kIncludePrototypes,
14591 default_filter, v8::IndexFilter::kIncludeIndices)
14592 .ToLocalChecked();
14593 CheckStringArray(isolate, properties, 11, expected_properties1);
14594
14595 properties = object
14596 ->GetPropertyNames(context.local(),
14597 v8::KeyCollectionMode::kIncludePrototypes,
14598 include_symbols_filter,
14599 v8::IndexFilter::kIncludeIndices)
14600 .ToLocalChecked();
14601 const char* expected_properties1_1[] = {
14602 "0", "1", "4294967294", "a", "b", "4294967296",
14603 "4294967295", nullptr, "2", "3", "c", "d"};
14604 CheckStringArray(isolate, properties, 12, expected_properties1_1);
14605 CheckIsSymbolAt(isolate, properties, 7, "symbol");
14606
14607 properties =
14608 object
14609 ->GetPropertyNames(context.local(),
14610 v8::KeyCollectionMode::kIncludePrototypes,
14611 default_filter, v8::IndexFilter::kSkipIndices)
14612 .ToLocalChecked();
14613 const char* expected_properties2[] = {"a", "b", "4294967296",
14614 "4294967295", "c", "d"};
14615 CheckStringArray(isolate, properties, 6, expected_properties2);
14616
14617 properties = object
14618 ->GetPropertyNames(context.local(),
14619 v8::KeyCollectionMode::kIncludePrototypes,
14620 include_symbols_filter,
14621 v8::IndexFilter::kSkipIndices)
14622 .ToLocalChecked();
14623 const char* expected_properties2_1[] = {
14624 "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14625 CheckStringArray(isolate, properties, 7, expected_properties2_1);
14626 CheckIsSymbolAt(isolate, properties, 4, "symbol");
14627
14628 properties =
14629 object
14630 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14631 default_filter, v8::IndexFilter::kIncludeIndices)
14632 .ToLocalChecked();
14633 const char* expected_properties3[] = {
14634 "0", "1", "4294967294", "a", "b", "4294967296", "4294967295",
14635 };
14636 CheckStringArray(isolate, properties, 7, expected_properties3);
14637
14638 properties = object
14639 ->GetPropertyNames(
14640 context.local(), v8::KeyCollectionMode::kOwnOnly,
14641 include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14642 .ToLocalChecked();
14643 const char* expected_properties3_1[] = {
14644 "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14645 CheckStringArray(isolate, properties, 8, expected_properties3_1);
14646 CheckIsSymbolAt(isolate, properties, 7, "symbol");
14647
14648 properties =
14649 object
14650 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14651 default_filter, v8::IndexFilter::kSkipIndices)
14652 .ToLocalChecked();
14653 const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14654 CheckStringArray(isolate, properties, 4, expected_properties4);
14655
14656 properties = object
14657 ->GetPropertyNames(
14658 context.local(), v8::KeyCollectionMode::kOwnOnly,
14659 include_symbols_filter, v8::IndexFilter::kSkipIndices)
14660 .ToLocalChecked();
14661 const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14662 nullptr};
14663 CheckStringArray(isolate, properties, 5, expected_properties4_1);
14664 CheckIsSymbolAt(isolate, properties, 4, "symbol");
14665}
14666
14667THREADED_TEST(ProxyGetPropertyNames) {
14668 LocalContext context;
14669 v8::Isolate* isolate = context->GetIsolate();
14670 v8::HandleScope scope(isolate);
14671 v8::Local<v8::Value> result = CompileRun(
14672 "var target = {0: 0, 1: 1, a: 2, b: 3};"
14673 "target[2**32] = '4294967296';"
14674 "target[2**32-1] = '4294967295';"
14675 "target[2**32-2] = '4294967294';"
14676 "target[Symbol('symbol')] = true;"
14677 "target.__proto__ = {__proto__:null, 2: 4, 3: 5, c: 6, d: 7};"
14678 "var result = new Proxy(target, {});"
14679 "result;");
14680 v8::Local<v8::Object> object = result.As<v8::Object>();
14681 v8::PropertyFilter default_filter =
14682 static_cast<v8::PropertyFilter>(v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS);
14683 v8::PropertyFilter include_symbols_filter = v8::ONLY_ENUMERABLE;
14684
14685 v8::Local<v8::Array> properties =
14686 object->GetPropertyNames(context.local()).ToLocalChecked();
14687 const char* expected_properties1[] = {"0", "1", "4294967294", "a",
14688 "b", "4294967296", "4294967295", "2",
14689 "3", "c", "d"};
14690 CheckStringArray(isolate, properties, 11, expected_properties1);
14691
14692 properties =
14693 object
14694 ->GetPropertyNames(context.local(),
14695 v8::KeyCollectionMode::kIncludePrototypes,
14696 default_filter, v8::IndexFilter::kIncludeIndices)
14697 .ToLocalChecked();
14698 CheckStringArray(isolate, properties, 11, expected_properties1);
14699
14700 properties = object
14701 ->GetPropertyNames(context.local(),
14702 v8::KeyCollectionMode::kIncludePrototypes,
14703 include_symbols_filter,
14704 v8::IndexFilter::kIncludeIndices)
14705 .ToLocalChecked();
14706 const char* expected_properties1_1[] = {
14707 "0", "1", "4294967294", "a", "b", "4294967296",
14708 "4294967295", nullptr, "2", "3", "c", "d"};
14709 CheckStringArray(isolate, properties, 12, expected_properties1_1);
14710 CheckIsSymbolAt(isolate, properties, 7, "symbol");
14711
14712 properties =
14713 object
14714 ->GetPropertyNames(context.local(),
14715 v8::KeyCollectionMode::kIncludePrototypes,
14716 default_filter, v8::IndexFilter::kSkipIndices)
14717 .ToLocalChecked();
14718 const char* expected_properties2[] = {"a", "b", "4294967296",
14719 "4294967295", "c", "d"};
14720 CheckStringArray(isolate, properties, 6, expected_properties2);
14721
14722 properties = object
14723 ->GetPropertyNames(context.local(),
14724 v8::KeyCollectionMode::kIncludePrototypes,
14725 include_symbols_filter,
14726 v8::IndexFilter::kSkipIndices)
14727 .ToLocalChecked();
14728 const char* expected_properties2_1[] = {
14729 "a", "b", "4294967296", "4294967295", nullptr, "c", "d"};
14730 CheckStringArray(isolate, properties, 7, expected_properties2_1);
14731 CheckIsSymbolAt(isolate, properties, 4, "symbol");
14732
14733 properties =
14734 object
14735 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14736 default_filter, v8::IndexFilter::kIncludeIndices)
14737 .ToLocalChecked();
14738 const char* expected_properties3[] = {"0", "1", "4294967294", "a",
14739 "b", "4294967296", "4294967295"};
14740 CheckStringArray(isolate, properties, 7, expected_properties3);
14741
14742 properties = object
14743 ->GetPropertyNames(
14744 context.local(), v8::KeyCollectionMode::kOwnOnly,
14745 include_symbols_filter, v8::IndexFilter::kIncludeIndices)
14746 .ToLocalChecked();
14747 const char* expected_properties3_1[] = {
14748 "0", "1", "4294967294", "a", "b", "4294967296", "4294967295", nullptr};
14749 CheckStringArray(isolate, properties, 8, expected_properties3_1);
14750 CheckIsSymbolAt(isolate, properties, 7, "symbol");
14751
14752 properties =
14753 object
14754 ->GetPropertyNames(context.local(), v8::KeyCollectionMode::kOwnOnly,
14755 default_filter, v8::IndexFilter::kSkipIndices)
14756 .ToLocalChecked();
14757 const char* expected_properties4[] = {"a", "b", "4294967296", "4294967295"};
14758 CheckStringArray(isolate, properties, 4, expected_properties4);
14759
14760 properties = object
14761 ->GetPropertyNames(
14762 context.local(), v8::KeyCollectionMode::kOwnOnly,
14763 include_symbols_filter, v8::IndexFilter::kSkipIndices)
14764 .ToLocalChecked();
14765 const char* expected_properties4_1[] = {"a", "b", "4294967296", "4294967295",
14766 nullptr};
14767 CheckStringArray(isolate, properties, 5, expected_properties4_1);
14768 CheckIsSymbolAt(isolate, properties, 4, "symbol");
14769}
14770
14771THREADED_TEST(AccessChecksReenabledCorrectly) {
14772 LocalContext context;
14773 v8::Isolate* isolate = context->GetIsolate();
14774 v8::HandleScope scope(isolate);
14775 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14776 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
14777 templ->Set(v8_str("a"), v8_str("a"));
14778 // Add more than 8 (see kMaxFastProperties) properties
14779 // so that the constructor will force copying map.
14780 // Cannot sprintf, gcc complains unsafety.
14781 char buf[4];
14782 for (char i = '0'; i <= '9' ; i++) {
14783 buf[0] = i;
14784 for (char j = '0'; j <= '9'; j++) {
14785 buf[1] = j;
14786 for (char k = '0'; k <= '9'; k++) {
14787 buf[2] = k;
14788 buf[3] = 0;
14789 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14790 }
14791 }
14792 }
14793
14794 Local<v8::Object> instance_1 =
14795 templ->NewInstance(context.local()).ToLocalChecked();
14796 CHECK(context->Global()
14797 ->Set(context.local(), v8_str("obj_1"), instance_1)
14798 .FromJust());
14799
14800 Local<Value> value_1 = CompileRun("obj_1.a");
14801 CHECK(value_1.IsEmpty());
14802
14803 Local<v8::Object> instance_2 =
14804 templ->NewInstance(context.local()).ToLocalChecked();
14805 CHECK(context->Global()
14806 ->Set(context.local(), v8_str("obj_2"), instance_2)
14807 .FromJust());
14808
14809 Local<Value> value_2 = CompileRun("obj_2.a");
14810 CHECK(value_2.IsEmpty());
14811}
14812
14813
14814// This tests that we do not allow dictionary load/call inline caches
14815// to use functions that have not yet been compiled. The potential
14816// problem of loading a function that has not yet been compiled can
14817// arise because we share code between contexts via the compilation
14818// cache.
14819THREADED_TEST(DictionaryICLoadedFunction) {
14820 v8::HandleScope scope(CcTest::isolate());
14821 // Test LoadIC.
14822 for (int i = 0; i < 2; i++) {
14823 LocalContext context;
14824 CHECK(context->Global()
14825 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14826 .FromJust());
14827 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14828 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14829 }
14830 // Test CallIC.
14831 for (int i = 0; i < 2; i++) {
14832 LocalContext context;
14833 CHECK(context->Global()
14834 ->Set(context.local(), v8_str("tmp"), v8::True(CcTest::isolate()))
14835 .FromJust());
14836 context->Global()->Delete(context.local(), v8_str("tmp")).FromJust();
14837 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14838 }
14839}
14840
14841
14842// Test that cross-context new calls use the context of the callee to
14843// create the new JavaScript object.
14844THREADED_TEST(CrossContextNew) {
14845 v8::Isolate* isolate = CcTest::isolate();
14846 v8::HandleScope scope(isolate);
14847 v8::Local<Context> context0 = Context::New(isolate);
14848 v8::Local<Context> context1 = Context::New(isolate);
14849
14850 // Allow cross-domain access.
14851 Local<String> token = v8_str("<security token>");
14852 context0->SetSecurityToken(token);
14853 context1->SetSecurityToken(token);
14854
14855 // Set an 'x' property on the Object prototype and define a
14856 // constructor function in context0.
14857 context0->Enter();
14858 CompileRun("Object.prototype.x = 42; function C() {};");
14859 context0->Exit();
14860
14861 // Call the constructor function from context0 and check that the
14862 // result has the 'x' property.
14863 context1->Enter();
14864 CHECK(context1->Global()
14865 ->Set(context1, v8_str("other"), context0->Global())
14866 .FromJust());
14867 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14868 CHECK(value->IsInt32());
14869 CHECK_EQ(42, value->Int32Value(context1).FromJust());
14870 context1->Exit();
14871}
14872
14873
14874// Verify that we can clone an object
14875TEST(ObjectClone) {
14876 LocalContext env;
14877 v8::Isolate* isolate = env->GetIsolate();
14878 v8::HandleScope scope(isolate);
14879
14880 const char* sample =
14881 "var rv = {};" \
14882 "rv.alpha = 'hello';" \
14883 "rv.beta = 123;" \
14884 "rv;";
14885
14886 // Create an object, verify basics.
14887 Local<Value> val = CompileRun(sample);
14888 CHECK(val->IsObject());
14889 Local<v8::Object> obj = val.As<v8::Object>();
14890 obj->Set(env.local(), v8_str("gamma"), v8_str("cloneme")).FromJust();
14891
14892 CHECK(v8_str("hello")
14893 ->Equals(env.local(),
14894 obj->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14895 .FromJust());
14896 CHECK(v8::Integer::New(isolate, 123)
14897 ->Equals(env.local(),
14898 obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14899 .FromJust());
14900 CHECK(v8_str("cloneme")
14901 ->Equals(env.local(),
14902 obj->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14903 .FromJust());
14904
14905 // Clone it.
14906 Local<v8::Object> clone = obj->Clone();
14907 CHECK(v8_str("hello")
14908 ->Equals(env.local(),
14909 clone->Get(env.local(), v8_str("alpha")).ToLocalChecked())
14910 .FromJust());
14911 CHECK(v8::Integer::New(isolate, 123)
14912 ->Equals(env.local(),
14913 clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14914 .FromJust());
14915 CHECK(v8_str("cloneme")
14916 ->Equals(env.local(),
14917 clone->Get(env.local(), v8_str("gamma")).ToLocalChecked())
14918 .FromJust());
14919
14920 // Set a property on the clone, verify each object.
14921 CHECK(clone->Set(env.local(), v8_str("beta"), v8::Integer::New(isolate, 456))
14922 .FromJust());
14923 CHECK(v8::Integer::New(isolate, 123)
14924 ->Equals(env.local(),
14925 obj->Get(env.local(), v8_str("beta")).ToLocalChecked())
14926 .FromJust());
14927 CHECK(v8::Integer::New(isolate, 456)
14928 ->Equals(env.local(),
14929 clone->Get(env.local(), v8_str("beta")).ToLocalChecked())
14930 .FromJust());
14931}
14932
14933
14934class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
14935 public:
14936 explicit OneByteVectorResource(i::Vector<const char> vector)
14937 : data_(vector) {}
14938 ~OneByteVectorResource() override = default;
14939 size_t length() const override { return data_.length(); }
14940 const char* data() const override { return data_.start(); }
14941 void Dispose() override {}
14942
14943 private:
14944 i::Vector<const char> data_;
14945};
14946
14947
14948class UC16VectorResource : public v8::String::ExternalStringResource {
14949 public:
14950 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14951 : data_(vector) {}
14952 ~UC16VectorResource() override = default;
14953 size_t length() const override { return data_.length(); }
14954 const i::uc16* data() const override { return data_.start(); }
14955 void Dispose() override {}
14956
14957 private:
14958 i::Vector<const i::uc16> data_;
14959};
14960
14961static void MorphAString(i::String string,
14962 OneByteVectorResource* one_byte_resource,
14963 UC16VectorResource* uc16_resource) {
14964 i::Isolate* isolate = CcTest::i_isolate();
14965 CHECK(i::StringShape(string).IsExternal());
14966 i::ReadOnlyRoots roots(CcTest::heap());
14967 if (string->IsOneByteRepresentation()) {
14968 // Check old map is not internalized or long.
14969 CHECK(string->map() == roots.external_one_byte_string_map());
14970 // Morph external string to be TwoByte string.
14971 string->set_map(roots.external_string_map());
14972 i::ExternalTwoByteString morphed = i::ExternalTwoByteString::cast(string);
14973 CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14974 morphed->SetResource(isolate, uc16_resource);
14975 } else {
14976 // Check old map is not internalized or long.
14977 CHECK(string->map() == roots.external_string_map());
14978 // Morph external string to be one-byte string.
14979 string->set_map(roots.external_one_byte_string_map());
14980 i::ExternalOneByteString morphed = i::ExternalOneByteString::cast(string);
14981 CcTest::heap()->UpdateExternalString(morphed, string->length(), 0);
14982 morphed->SetResource(isolate, one_byte_resource);
14983 }
14984}
14985
14986// Test that we can still flatten a string if the components it is built up
14987// from have been turned into 16 bit strings in the mean time.
14988THREADED_TEST(MorphCompositeStringTest) {
14989 char utf_buffer[129];
14990 const char* c_string = "Now is the time for all good men"
14991 " to come to the aid of the party";
14992 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14993 {
14994 LocalContext env;
14995 i::Factory* factory = CcTest::i_isolate()->factory();
14996 v8::Isolate* isolate = env->GetIsolate();
14997 i::Isolate* i_isolate = CcTest::i_isolate();
14998 v8::HandleScope scope(isolate);
14999 OneByteVectorResource one_byte_resource(
15000 i::Vector<const char>(c_string, i::StrLength(c_string)));
15001 UC16VectorResource uc16_resource(
15002 i::Vector<const uint16_t>(two_byte_string, i::StrLength(c_string)));
15003
15004 Local<String> lhs(v8::Utils::ToLocal(
15005 factory->NewExternalStringFromOneByte(&one_byte_resource)
15006 .ToHandleChecked()));
15007 Local<String> rhs(v8::Utils::ToLocal(
15008 factory->NewExternalStringFromOneByte(&one_byte_resource)
15009 .ToHandleChecked()));
15010
15011 CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
15012 CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
15013
15014 CompileRun(
15015 "var cons = lhs + rhs;"
15016 "var slice = lhs.substring(1, lhs.length - 1);"
15017 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15018
15019 CHECK(lhs->IsOneByte());
15020 CHECK(rhs->IsOneByte());
15021
15022 i::String ilhs = *v8::Utils::OpenHandle(*lhs);
15023 i::String irhs = *v8::Utils::OpenHandle(*rhs);
15024 MorphAString(ilhs, &one_byte_resource, &uc16_resource);
15025 MorphAString(irhs, &one_byte_resource, &uc16_resource);
15026
15027 // This should UTF-8 without flattening, since everything is ASCII.
15028 Local<String> cons =
15029 v8_compile("cons")->Run(env.local()).ToLocalChecked().As<String>();
15030 CHECK_EQ(128, cons->Utf8Length(isolate));
15031 int nchars = -1;
15032 CHECK_EQ(129, cons->WriteUtf8(isolate, utf_buffer, -1, &nchars));
15033 CHECK_EQ(128, nchars);
15034 CHECK_EQ(0, strcmp(
15035 utf_buffer,
15036 "Now is the time for all good men to come to the aid of the party"
15037 "Now is the time for all good men to come to the aid of the party"));
15038
15039 // Now do some stuff to make sure the strings are flattened, etc.
15040 CompileRun(
15041 "/[^a-z]/.test(cons);"
15042 "/[^a-z]/.test(slice);"
15043 "/[^a-z]/.test(slice_on_cons);");
15044 const char* expected_cons =
15045 "Now is the time for all good men to come to the aid of the party"
15046 "Now is the time for all good men to come to the aid of the party";
15047 const char* expected_slice =
15048 "ow is the time for all good men to come to the aid of the part";
15049 const char* expected_slice_on_cons =
15050 "ow is the time for all good men to come to the aid of the party"
15051 "Now is the time for all good men to come to the aid of the part";
15052 CHECK(v8_str(expected_cons)
15053 ->Equals(env.local(), env->Global()
15054 ->Get(env.local(), v8_str("cons"))
15055 .ToLocalChecked())
15056 .FromJust());
15057 CHECK(v8_str(expected_slice)
15058 ->Equals(env.local(), env->Global()
15059 ->Get(env.local(), v8_str("slice"))
15060 .ToLocalChecked())
15061 .FromJust());
15062 CHECK(v8_str(expected_slice_on_cons)
15063 ->Equals(env.local(),
15064 env->Global()
15065 ->Get(env.local(), v8_str("slice_on_cons"))
15066 .ToLocalChecked())
15067 .FromJust());
15068
15069 // This avoids the GC from trying to free a stack allocated resource.
15070 if (ilhs->IsExternalOneByteString())
15071 i::ExternalOneByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15072 else
15073 i::ExternalTwoByteString::cast(ilhs)->SetResource(i_isolate, nullptr);
15074 if (irhs->IsExternalOneByteString())
15075 i::ExternalOneByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15076 else
15077 i::ExternalTwoByteString::cast(irhs)->SetResource(i_isolate, nullptr);
15078 }
15079 i::DeleteArray(two_byte_string);
15080}
15081
15082
15083TEST(CompileExternalTwoByteSource) {
15084 LocalContext context;
15085 v8::HandleScope scope(context->GetIsolate());
15086
15087 // This is a very short list of sources, which currently is to check for a
15088 // regression caused by r2703.
15089 const char* one_byte_sources[] = {
15090 "0.5",
15091 "-0.5", // This mainly testes PushBack in the Scanner.
15092 "--0.5", // This mainly testes PushBack in the Scanner.
15093 nullptr};
15094
15095 // Compile the sources as external two byte strings.
15096 for (int i = 0; one_byte_sources[i] != nullptr; i++) {
15097 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15098 TestResource* uc16_resource = new TestResource(two_byte_string);
15099 v8::Local<v8::String> source =
15100 v8::String::NewExternalTwoByte(context->GetIsolate(), uc16_resource)
15101 .ToLocalChecked();
15102 v8::Script::Compile(context.local(), source).FromMaybe(Local<Script>());
15103 }
15104}
15105
15106// Test that we cannot set a property on the global object if there
15107// is a read-only property in the prototype chain.
15108TEST(ReadOnlyPropertyInGlobalProto) {
15109 v8::Isolate* isolate = CcTest::isolate();
15110 v8::HandleScope scope(isolate);
15111 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15112 LocalContext context(nullptr, templ);
15113 v8::Local<v8::Object> global = context->Global();
15114 v8::Local<v8::Object> global_proto = v8::Local<v8::Object>::Cast(
15115 global->Get(context.local(), v8_str("__proto__")).ToLocalChecked());
15116 global_proto->DefineOwnProperty(context.local(), v8_str("x"),
15117 v8::Integer::New(isolate, 0), v8::ReadOnly)
15118 .FromJust();
15119 global_proto->DefineOwnProperty(context.local(), v8_str("y"),
15120 v8::Integer::New(isolate, 0), v8::ReadOnly)
15121 .FromJust();
15122 // Check without 'eval' or 'with'.
15123 v8::Local<v8::Value> res =
15124 CompileRun("function f() { x = 42; return x; }; f()");
15125 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15126 // Check with 'eval'.
15127 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15128 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15129 // Check with 'with'.
15130 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15131 CHECK(v8::Integer::New(isolate, 0)->Equals(context.local(), res).FromJust());
15132}
15133
15134
15135TEST(CreateDataProperty) {
15136 LocalContext env;
15137 v8::Isolate* isolate = env->GetIsolate();
15138 v8::HandleScope handle_scope(isolate);
15139
15140 CompileRun(
15141 "var a = {};"
15142 "var b = [];"
15143 "Object.defineProperty(a, 'foo', {value: 23});"
15144 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15145
15146 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15147 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15148 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15149 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15150 {
15151 // Can't change a non-configurable properties.
15152 v8::TryCatch try_catch(isolate);
15153 CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
15154 v8::Integer::New(isolate, 42)).FromJust());
15155 CHECK(!try_catch.HasCaught());
15156 CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
15157 v8::Integer::New(isolate, 42)).FromJust());
15158 CHECK(!try_catch.HasCaught());
15159 v8::Local<v8::Value> val =
15160 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15161 CHECK(val->IsNumber());
15162 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15163 }
15164
15165 {
15166 // Set a regular property.
15167 v8::TryCatch try_catch(isolate);
15168 CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
15169 v8::Integer::New(isolate, 42)).FromJust());
15170 CHECK(!try_catch.HasCaught());
15171 v8::Local<v8::Value> val =
15172 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15173 CHECK(val->IsNumber());
15174 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15175 }
15176
15177 {
15178 // Set an indexed property.
15179 v8::TryCatch try_catch(isolate);
15180 CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
15181 v8::Integer::New(isolate, 42)).FromJust());
15182 CHECK(!try_catch.HasCaught());
15183 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15184 CHECK(val->IsNumber());
15185 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15186 }
15187
15188 {
15189 // Special cases for arrays.
15190 v8::TryCatch try_catch(isolate);
15191 CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
15192 v8::Integer::New(isolate, 1)).FromJust());
15193 CHECK(!try_catch.HasCaught());
15194 }
15195 {
15196 // Special cases for arrays: index exceeds the array's length
15197 v8::TryCatch try_catch(isolate);
15198 CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
15199 .FromJust());
15200 CHECK(!try_catch.HasCaught());
15201 CHECK_EQ(2U, arr->Length());
15202 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15203 CHECK(val->IsNumber());
15204 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15205
15206 // Set an existing entry.
15207 CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
15208 .FromJust());
15209 CHECK(!try_catch.HasCaught());
15210 val = arr->Get(env.local(), 0).ToLocalChecked();
15211 CHECK(val->IsNumber());
15212 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15213 }
15214
15215 CompileRun("Object.freeze(a);");
15216 {
15217 // Can't change non-extensible objects.
15218 v8::TryCatch try_catch(isolate);
15219 CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
15220 v8::Integer::New(isolate, 42)).FromJust());
15221 CHECK(!try_catch.HasCaught());
15222 }
15223
15224 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15225 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15226 v8::Local<v8::Object> access_checked =
15227 templ->NewInstance(env.local()).ToLocalChecked();
15228 {
15229 v8::TryCatch try_catch(isolate);
15230 CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
15231 v8::Integer::New(isolate, 42))
15232 .IsNothing());
15233 CHECK(try_catch.HasCaught());
15234 }
15235}
15236
15237
15238TEST(DefineOwnProperty) {
15239 LocalContext env;
15240 v8::Isolate* isolate = env->GetIsolate();
15241 v8::HandleScope handle_scope(isolate);
15242
15243 CompileRun(
15244 "var a = {};"
15245 "var b = [];"
15246 "Object.defineProperty(a, 'foo', {value: 23});"
15247 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
15248
15249 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15250 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15251 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15252 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15253 {
15254 // Can't change a non-configurable properties.
15255 v8::TryCatch try_catch(isolate);
15256 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
15257 v8::Integer::New(isolate, 42)).FromJust());
15258 CHECK(!try_catch.HasCaught());
15259 CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
15260 v8::Integer::New(isolate, 42)).FromJust());
15261 CHECK(!try_catch.HasCaught());
15262 v8::Local<v8::Value> val =
15263 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
15264 CHECK(val->IsNumber());
15265 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15266 }
15267
15268 {
15269 // Set a regular property.
15270 v8::TryCatch try_catch(isolate);
15271 CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
15272 v8::Integer::New(isolate, 42)).FromJust());
15273 CHECK(!try_catch.HasCaught());
15274 v8::Local<v8::Value> val =
15275 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
15276 CHECK(val->IsNumber());
15277 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15278 }
15279
15280 {
15281 // Set an indexed property.
15282 v8::TryCatch try_catch(isolate);
15283 CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
15284 v8::Integer::New(isolate, 42)).FromJust());
15285 CHECK(!try_catch.HasCaught());
15286 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15287 CHECK(val->IsNumber());
15288 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15289 }
15290
15291 {
15292 // Special cases for arrays.
15293 v8::TryCatch try_catch(isolate);
15294 CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
15295 v8::Integer::New(isolate, 1)).FromJust());
15296 CHECK(!try_catch.HasCaught());
15297 }
15298 {
15299 // Special cases for arrays: index exceeds the array's length
15300 v8::TryCatch try_catch(isolate);
15301 CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
15302 v8::Integer::New(isolate, 23)).FromJust());
15303 CHECK(!try_catch.HasCaught());
15304 CHECK_EQ(2U, arr->Length());
15305 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
15306 CHECK(val->IsNumber());
15307 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15308
15309 // Set an existing entry.
15310 CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
15311 v8::Integer::New(isolate, 42)).FromJust());
15312 CHECK(!try_catch.HasCaught());
15313 val = arr->Get(env.local(), 0).ToLocalChecked();
15314 CHECK(val->IsNumber());
15315 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15316 }
15317
15318 {
15319 // Set a non-writable property.
15320 v8::TryCatch try_catch(isolate);
15321 CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
15322 v8::Integer::New(isolate, 42),
15323 v8::ReadOnly).FromJust());
15324 CHECK(!try_catch.HasCaught());
15325 v8::Local<v8::Value> val =
15326 obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
15327 CHECK(val->IsNumber());
15328 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15329 CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
15330 env.local(), v8_str("lala")).FromJust());
15331 CHECK(!try_catch.HasCaught());
15332 }
15333
15334 CompileRun("Object.freeze(a);");
15335 {
15336 // Can't change non-extensible objects.
15337 v8::TryCatch try_catch(isolate);
15338 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
15339 v8::Integer::New(isolate, 42)).FromJust());
15340 CHECK(!try_catch.HasCaught());
15341 }
15342
15343 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15344 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15345 v8::Local<v8::Object> access_checked =
15346 templ->NewInstance(env.local()).ToLocalChecked();
15347 {
15348 v8::TryCatch try_catch(isolate);
15349 CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
15350 v8::Integer::New(isolate, 42))
15351 .IsNothing());
15352 CHECK(try_catch.HasCaught());
15353 }
15354}
15355
15356TEST(DefineProperty) {
15357 LocalContext env;
15358 v8::Isolate* isolate = env->GetIsolate();
15359 v8::HandleScope handle_scope(isolate);
15360
15361 v8::Local<v8::Name> p;
15362
15363 CompileRun(
15364 "var a = {};"
15365 "var b = [];"
15366 "Object.defineProperty(a, 'v1', {value: 23});"
15367 "Object.defineProperty(a, 'v2', {value: 23, configurable: true});");
15368
15369 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
15370 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
15371 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
15372 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
15373
15374 v8::PropertyDescriptor desc(v8_num(42));
15375 {
15376 // Use a data descriptor.
15377
15378 // Cannot change a non-configurable property.
15379 p = v8_str("v1");
15380 v8::TryCatch try_catch(isolate);
15381 CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
15382 CHECK(!try_catch.HasCaught());
15383 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15384 CHECK(val->IsNumber());
15385 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
15386
15387 // Change a configurable property.
15388 p = v8_str("v2");
15389 obj->DefineProperty(env.local(), p, desc).FromJust();
15390 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15391 CHECK(!try_catch.HasCaught());
15392 val = obj->Get(env.local(), p).ToLocalChecked();
15393 CHECK(val->IsNumber());
15394 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15395
15396 // Check that missing writable has default value false.
15397 p = v8_str("v12");
15398 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15399 CHECK(!try_catch.HasCaught());
15400 val = obj->Get(env.local(), p).ToLocalChecked();
15401 CHECK(val->IsNumber());
15402 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15403 v8::PropertyDescriptor desc2(v8_num(43));
15404 CHECK(!obj->DefineProperty(env.local(), p, desc2).FromJust());
15405 val = obj->Get(env.local(), p).ToLocalChecked();
15406 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15407 CHECK(!try_catch.HasCaught());
15408 }
15409
15410 {
15411 // Set a regular property.
15412 p = v8_str("v3");
15413 v8::TryCatch try_catch(isolate);
15414 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15415 CHECK(!try_catch.HasCaught());
15416 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15417 CHECK(val->IsNumber());
15418 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15419 }
15420
15421 {
15422 // Set an indexed property.
15423 v8::TryCatch try_catch(isolate);
15424 CHECK(obj->DefineProperty(env.local(), v8_str("1"), desc).FromJust());
15425 CHECK(!try_catch.HasCaught());
15426 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
15427 CHECK(val->IsNumber());
15428 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15429 }
15430
15431 {
15432 // No special case when changing array length.
15433 v8::TryCatch try_catch(isolate);
15434 // Use a writable descriptor, otherwise the next test, that changes
15435 // the array length will fail.
15436 v8::PropertyDescriptor desc(v8_num(42), true);
15437 CHECK(arr->DefineProperty(env.local(), v8_str("length"), desc).FromJust());
15438 CHECK(!try_catch.HasCaught());
15439 }
15440
15441 {
15442 // Special cases for arrays: index exceeds the array's length.
15443 v8::TryCatch try_catch(isolate);
15444 CHECK(arr->DefineProperty(env.local(), v8_str("100"), desc).FromJust());
15445 CHECK(!try_catch.HasCaught());
15446 CHECK_EQ(101U, arr->Length());
15447 v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
15448 CHECK(val->IsNumber());
15449 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15450
15451 // Set an existing entry.
15452 CHECK(arr->DefineProperty(env.local(), v8_str("0"), desc).FromJust());
15453 CHECK(!try_catch.HasCaught());
15454 val = arr->Get(env.local(), 0).ToLocalChecked();
15455 CHECK(val->IsNumber());
15456 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15457 }
15458
15459 {
15460 // Use a generic descriptor.
15461 v8::PropertyDescriptor desc_generic;
15462
15463 p = v8_str("v4");
15464 v8::TryCatch try_catch(isolate);
15465 CHECK(obj->DefineProperty(env.local(), p, desc_generic).FromJust());
15466 CHECK(!try_catch.HasCaught());
15467 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15468 CHECK(val->IsUndefined());
15469
15470 obj->Set(env.local(), p, v8_num(1)).FromJust();
15471 CHECK(!try_catch.HasCaught());
15472
15473 val = obj->Get(env.local(), p).ToLocalChecked();
15474 CHECK(val->IsUndefined());
15475 CHECK(!try_catch.HasCaught());
15476 }
15477
15478 {
15479 // Use a data descriptor with undefined value.
15480 v8::PropertyDescriptor desc_empty(v8::Undefined(isolate));
15481
15482 v8::TryCatch try_catch(isolate);
15483 CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15484 CHECK(!try_catch.HasCaught());
15485 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15486 CHECK(val->IsUndefined());
15487 CHECK(!try_catch.HasCaught());
15488 }
15489
15490 {
15491 // Use a descriptor with attribute == v8::ReadOnly.
15492 v8::PropertyDescriptor desc_read_only(v8_num(42), false);
15493 desc_read_only.set_enumerable(true);
15494 desc_read_only.set_configurable(true);
15495
15496 p = v8_str("v5");
15497 v8::TryCatch try_catch(isolate);
15498 CHECK(obj->DefineProperty(env.local(), p, desc_read_only).FromJust());
15499 CHECK(!try_catch.HasCaught());
15500 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15501 CHECK(val->IsNumber());
15502 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
15503 CHECK_EQ(v8::ReadOnly,
15504 obj->GetPropertyAttributes(env.local(), p).FromJust());
15505 CHECK(!try_catch.HasCaught());
15506 }
15507
15508 {
15509 // Use an accessor descriptor with empty handles.
15510 v8::PropertyDescriptor desc_empty(v8::Undefined(isolate),
15511 v8::Undefined(isolate));
15512
15513 p = v8_str("v6");
15514 v8::TryCatch try_catch(isolate);
15515 CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15516 CHECK(!try_catch.HasCaught());
15517 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15518 CHECK(val->IsUndefined());
15519 CHECK(!try_catch.HasCaught());
15520 }
15521
15522 {
15523 // Use an accessor descriptor.
15524 CompileRun(
15525 "var set = function(x) {this.val = 2*x;};"
15526 "var get = function() {return this.val || 0;};");
15527
15528 v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15529 env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15530 v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
15531 env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
15532 v8::PropertyDescriptor desc(get, set);
15533
15534 p = v8_str("v7");
15535 v8::TryCatch try_catch(isolate);
15536 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15537 CHECK(!try_catch.HasCaught());
15538
15539 v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
15540 CHECK(val->IsNumber());
15541 CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
15542 CHECK(!try_catch.HasCaught());
15543
15544 obj->Set(env.local(), p, v8_num(7)).FromJust();
15545 CHECK(!try_catch.HasCaught());
15546
15547 val = obj->Get(env.local(), p).ToLocalChecked();
15548 CHECK(val->IsNumber());
15549 CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
15550 CHECK(!try_catch.HasCaught());
15551 }
15552
15553 {
15554 // Redefine an existing property.
15555
15556 // desc = {value: 42, enumerable: true}
15557 v8::PropertyDescriptor desc(v8_num(42));
15558 desc.set_enumerable(true);
15559
15560 p = v8_str("v8");
15561 v8::TryCatch try_catch(isolate);
15562 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15563 CHECK(!try_catch.HasCaught());
15564
15565 // desc = {enumerable: true}
15566 v8::PropertyDescriptor desc_true((v8::Local<v8::Value>()));
15567 desc_true.set_enumerable(true);
15568
15569 // Successful redefinition because all present attributes have the same
15570 // value as the current descriptor.
15571 CHECK(obj->DefineProperty(env.local(), p, desc_true).FromJust());
15572 CHECK(!try_catch.HasCaught());
15573
15574 // desc = {}
15575 v8::PropertyDescriptor desc_empty;
15576 // Successful redefinition because no attributes are overwritten in the
15577 // current descriptor.
15578 CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15579 CHECK(!try_catch.HasCaught());
15580
15581 // desc = {enumerable: false}
15582 v8::PropertyDescriptor desc_false((v8::Local<v8::Value>()));
15583 desc_false.set_enumerable(false);
15584 // Not successful because we cannot define a different value for enumerable.
15585 CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
15586 CHECK(!try_catch.HasCaught());
15587 }
15588
15589 {
15590 // Redefine a property that has a getter.
15591 CompileRun("var get = function() {};");
15592 v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
15593 env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
15594
15595 // desc = {get: function() {}}
15596 v8::PropertyDescriptor desc(get, v8::Local<v8::Function>());
15597 v8::TryCatch try_catch(isolate);
15598
15599 p = v8_str("v9");
15600 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15601 CHECK(!try_catch.HasCaught());
15602
15603 // desc_empty = {}
15604 // Successful because we are not redefining the current getter.
15605 v8::PropertyDescriptor desc_empty;
15606 CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
15607 CHECK(!try_catch.HasCaught());
15608
15609 // desc = {get: function() {}}
15610 // Successful because we redefine the getter with its current value.
15611 CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
15612 CHECK(!try_catch.HasCaught());
15613
15614 // desc = {get: undefined}
15615 v8::PropertyDescriptor desc_undefined(v8::Undefined(isolate),
15616 v8::Local<v8::Function>());
15617 // Not successful because we cannot redefine with the current value of get
15618 // with undefined.
15619 CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).FromJust());
15620 CHECK(!try_catch.HasCaught());
15621 }
15622
15623 CompileRun("Object.freeze(a);");
15624 {
15625 // We cannot change non-extensible objects.
15626 v8::TryCatch try_catch(isolate);
15627 CHECK(!obj->DefineProperty(env.local(), v8_str("v10"), desc).FromJust());
15628 CHECK(!try_catch.HasCaught());
15629 }
15630
15631 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15632 templ->SetAccessCheckCallback(AccessAlwaysBlocked);
15633 v8::Local<v8::Object> access_checked =
15634 templ->NewInstance(env.local()).ToLocalChecked();
15635 {
15636 v8::TryCatch try_catch(isolate);
15637 CHECK(access_checked->DefineProperty(env.local(), v8_str("v11"), desc)
15638 .IsNothing());
15639 CHECK(try_catch.HasCaught());
15640 }
15641}
15642
15643THREADED_TEST(GetCurrentContextWhenNotInContext) {
15644 i::Isolate* isolate = CcTest::i_isolate();
15645 CHECK_NOT_NULL(isolate);
15646 CHECK(isolate->context().is_null());
15647 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15648 v8::HandleScope scope(v8_isolate);
15649 // The following should not crash, but return an empty handle.
15650 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15651 CHECK(current.IsEmpty());
15652}
15653
15654
15655// Check that a variable declaration with no explicit initialization
15656// value does shadow an existing property in the prototype chain.
15657THREADED_TEST(InitGlobalVarInProtoChain) {
15658 LocalContext context;
15659 v8::HandleScope scope(context->GetIsolate());
15660 // Introduce a variable in the prototype chain.
15661 CompileRun("__proto__.x = 42");
15662 v8::Local<v8::Value> result = CompileRun("var x = 43; x");
15663 CHECK(!result->IsUndefined());
15664 CHECK_EQ(43, result->Int32Value(context.local()).FromJust());
15665}
15666
15667
15668// Regression test for issue 398.
15669// If a function is added to an object, creating a constant function
15670// field, and the result is cloned, replacing the constant function on the
15671// original should not affect the clone.
15672// See http://code.google.com/p/v8/issues/detail?id=398
15673THREADED_TEST(ReplaceConstantFunction) {
15674 LocalContext context;
15675 v8::Isolate* isolate = context->GetIsolate();
15676 v8::HandleScope scope(isolate);
15677 v8::Local<v8::Object> obj = v8::Object::New(isolate);
15678 v8::Local<v8::FunctionTemplate> func_templ =
15679 v8::FunctionTemplate::New(isolate);
15680 v8::Local<v8::String> foo_string = v8_str("foo");
15681 obj->Set(context.local(), foo_string,
15682 func_templ->GetFunction(context.local()).ToLocalChecked())
15683 .FromJust();
15684 v8::Local<v8::Object> obj_clone = obj->Clone();
15685 obj_clone->Set(context.local(), foo_string, v8_str("Hello")).FromJust();
15686 CHECK(!obj->Get(context.local(), foo_string).ToLocalChecked()->IsUndefined());
15687}
15688
15689
15690static void CheckElementValue(i::Isolate* isolate,
15691 int expected,
15692 i::Handle<i::Object> obj,
15693 int offset) {
15694 i::Object element =
15695 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15696 CHECK_EQ(expected, i::Smi::ToInt(element));
15697}
15698
15699
15700template <class ExternalArrayClass, class ElementType>
15701static void ObjectWithExternalArrayTestHelper(Local<Context> context,
15702 v8::Local<Object> obj,
15703 int element_count,
15704 i::ExternalArrayType array_type,
15705 int64_t low, int64_t high) {
15706 i::Handle<i::JSReceiver> jsobj = v8::Utils::OpenHandle(*obj);
15707 v8::Isolate* v8_isolate = context->GetIsolate();
15708 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
15709 obj->Set(context, v8_str("field"), v8::Int32::New(v8_isolate, 1503))
15710 .FromJust();
15711 CHECK(context->Global()->Set(context, v8_str("ext_array"), obj).FromJust());
15712 v8::Local<v8::Value> result = CompileRun("ext_array.field");
15713 CHECK_EQ(1503, result->Int32Value(context).FromJust());
15714 result = CompileRun("ext_array[1]");
15715 CHECK_EQ(1, result->Int32Value(context).FromJust());
15716
15717 // Check assigned smis
15718 result = CompileRun("for (var i = 0; i < 8; i++) {"
15719 " ext_array[i] = i;"
15720 "}"
15721 "var sum = 0;"
15722 "for (var i = 0; i < 8; i++) {"
15723 " sum += ext_array[i];"
15724 "}"
15725 "sum;");
15726
15727 CHECK_EQ(28, result->Int32Value(context).FromJust());
15728 // Check pass through of assigned smis
15729 result = CompileRun("var sum = 0;"
15730 "for (var i = 0; i < 8; i++) {"
15731 " sum += ext_array[i] = ext_array[i] = -i;"
15732 "}"
15733 "sum;");
15734 CHECK_EQ(-28, result->Int32Value(context).FromJust());
15735
15736
15737 // Check assigned smis in reverse order
15738 result = CompileRun("for (var i = 8; --i >= 0; ) {"
15739 " ext_array[i] = i;"
15740 "}"
15741 "var sum = 0;"
15742 "for (var i = 0; i < 8; i++) {"
15743 " sum += ext_array[i];"
15744 "}"
15745 "sum;");
15746 CHECK_EQ(28, result->Int32Value(context).FromJust());
15747
15748 // Check pass through of assigned HeapNumbers
15749 result = CompileRun("var sum = 0;"
15750 "for (var i = 0; i < 16; i+=2) {"
15751 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15752 "}"
15753 "sum;");
15754 CHECK_EQ(-28, result->Int32Value(context).FromJust());
15755
15756 // Check assigned HeapNumbers
15757 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15758 " ext_array[i] = (i * 0.5);"
15759 "}"
15760 "var sum = 0;"
15761 "for (var i = 0; i < 16; i+=2) {"
15762 " sum += ext_array[i];"
15763 "}"
15764 "sum;");
15765 CHECK_EQ(28, result->Int32Value(context).FromJust());
15766
15767 // Check assigned HeapNumbers in reverse order
15768 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15769 " ext_array[i] = (i * 0.5);"
15770 "}"
15771 "var sum = 0;"
15772 "for (var i = 0; i < 16; i+=2) {"
15773 " sum += ext_array[i];"
15774 "}"
15775 "sum;");
15776 CHECK_EQ(28, result->Int32Value(context).FromJust());
15777
15778 i::ScopedVector<char> test_buf(1024);
15779
15780 // Check legal boundary conditions.
15781 // The repeated loads and stores ensure the ICs are exercised.
15782 const char* boundary_program =
15783 "var res = 0;"
15784 "for (var i = 0; i < 16; i++) {"
15785 " ext_array[i] = %lld;"
15786 " if (i > 8) {"
15787 " res = ext_array[i];"
15788 " }"
15789 "}"
15790 "res;";
15791 i::SNPrintF(test_buf,
15792 boundary_program,
15793 low);
15794 result = CompileRun(test_buf.start());
15795 CHECK_EQ(low, result->IntegerValue(context).FromJust());
15796
15797 i::SNPrintF(test_buf,
15798 boundary_program,
15799 high);
15800 result = CompileRun(test_buf.start());
15801 CHECK_EQ(high, result->IntegerValue(context).FromJust());
15802
15803 // Check misprediction of type in IC.
15804 result = CompileRun("var tmp_array = ext_array;"
15805 "var sum = 0;"
15806 "for (var i = 0; i < 8; i++) {"
15807 " tmp_array[i] = i;"
15808 " sum += tmp_array[i];"
15809 " if (i == 4) {"
15810 " tmp_array = {};"
15811 " }"
15812 "}"
15813 "sum;");
15814 // Force GC to trigger verification.
15815 CcTest::CollectAllGarbage();
15816 CHECK_EQ(28, result->Int32Value(context).FromJust());
15817
15818 // Make sure out-of-range loads do not throw.
15819 i::SNPrintF(test_buf,
15820 "var caught_exception = false;"
15821 "try {"
15822 " ext_array[%d];"
15823 "} catch (e) {"
15824 " caught_exception = true;"
15825 "}"
15826 "caught_exception;",
15827 element_count);
15828 result = CompileRun(test_buf.start());
15829 CHECK(!result->BooleanValue(v8_isolate));
15830
15831 // Make sure out-of-range stores do not throw.
15832 i::SNPrintF(test_buf,
15833 "var caught_exception = false;"
15834 "try {"
15835 " ext_array[%d] = 1;"
15836 "} catch (e) {"
15837 " caught_exception = true;"
15838 "}"
15839 "caught_exception;",
15840 element_count);
15841 result = CompileRun(test_buf.start());
15842 CHECK(!result->BooleanValue(v8_isolate));
15843
15844 // Check other boundary conditions, values and operations.
15845 result = CompileRun("for (var i = 0; i < 8; i++) {"
15846 " ext_array[7] = undefined;"
15847 "}"
15848 "ext_array[7];");
15849 CHECK_EQ(0, result->Int32Value(context).FromJust());
15850 if (array_type == i::kExternalFloat64Array ||
15851 array_type == i::kExternalFloat32Array) {
15852 CHECK(std::isnan(
15853 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
15854 } else {
15855 CheckElementValue(isolate, 0, jsobj, 7);
15856 }
15857
15858 result = CompileRun("for (var i = 0; i < 8; i++) {"
15859 " ext_array[6] = '2.3';"
15860 "}"
15861 "ext_array[6];");
15862 CHECK_EQ(2, result->Int32Value(context).FromJust());
15863 CHECK_EQ(2,
15864 static_cast<int>(
15865 i::Object::GetElement(
15866 isolate, jsobj, 6).ToHandleChecked()->Number()));
15867
15868 if (array_type != i::kExternalFloat32Array &&
15869 array_type != i::kExternalFloat64Array) {
15870 // Though the specification doesn't state it, be explicit about
15871 // converting NaNs and +/-Infinity to zero.
15872 result = CompileRun("for (var i = 0; i < 8; i++) {"
15873 " ext_array[i] = 5;"
15874 "}"
15875 "for (var i = 0; i < 8; i++) {"
15876 " ext_array[i] = NaN;"
15877 "}"
15878 "ext_array[5];");
15879 CHECK_EQ(0, result->Int32Value(context).FromJust());
15880 CheckElementValue(isolate, 0, jsobj, 5);
15881
15882 result = CompileRun("for (var i = 0; i < 8; i++) {"
15883 " ext_array[i] = 5;"
15884 "}"
15885 "for (var i = 0; i < 8; i++) {"
15886 " ext_array[i] = Infinity;"
15887 "}"
15888 "ext_array[5];");
15889 int expected_value =
15890 (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
15891 CHECK_EQ(expected_value, result->Int32Value(context).FromJust());
15892 CheckElementValue(isolate, expected_value, jsobj, 5);
15893
15894 result = CompileRun("for (var i = 0; i < 8; i++) {"
15895 " ext_array[i] = 5;"
15896 "}"
15897 "for (var i = 0; i < 8; i++) {"
15898 " ext_array[i] = -Infinity;"
15899 "}"
15900 "ext_array[5];");
15901 CHECK_EQ(0, result->Int32Value(context).FromJust());
15902 CheckElementValue(isolate, 0, jsobj, 5);
15903
15904 // Check truncation behavior of integral arrays.
15905 const char* unsigned_data =
15906 "var source_data = [0.6, 10.6];"
15907 "var expected_results = [0, 10];";
15908 const char* signed_data =
15909 "var source_data = [0.6, 10.6, -0.6, -10.6];"
15910 "var expected_results = [0, 10, 0, -10];";
15911 const char* pixel_data =
15912 "var source_data = [0.6, 10.6];"
15913 "var expected_results = [1, 11];";
15914 bool is_unsigned = (array_type == i::kExternalUint8Array ||
15915 array_type == i::kExternalUint16Array ||
15916 array_type == i::kExternalUint32Array);
15917 bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
15918
15919 i::SNPrintF(test_buf,
15920 "%s"
15921 "var all_passed = true;"
15922 "for (var i = 0; i < source_data.length; i++) {"
15923 " for (var j = 0; j < 8; j++) {"
15924 " ext_array[j] = source_data[i];"
15925 " }"
15926 " all_passed = all_passed &&"
15927 " (ext_array[5] == expected_results[i]);"
15928 "}"
15929 "all_passed;",
15930 (is_unsigned ?
15931 unsigned_data :
15932 (is_pixel_data ? pixel_data : signed_data)));
15933 result = CompileRun(test_buf.start());
15934 CHECK(result->BooleanValue(v8_isolate));
15935 }
15936
15937 i::Handle<ExternalArrayClass> array(
15938 ExternalArrayClass::cast(i::Handle<i::JSObject>::cast(jsobj)->elements()),
15939 isolate);
15940 for (int i = 0; i < element_count; i++) {
15941 array->set(i, static_cast<ElementType>(i));
15942 }
15943
15944 bool old_natives_flag_sentry = i::FLAG_allow_natives_syntax;
15945 i::FLAG_allow_natives_syntax = true;
15946
15947 // Test complex assignments
15948 result = CompileRun(
15949 "function ee_op_test_complex_func(sum) {"
15950 " for (var i = 0; i < 40; ++i) {"
15951 " sum += (ext_array[i] += 1);"
15952 " sum += (ext_array[i] -= 1);"
15953 " } "
15954 " return sum;"
15955 "}"
15956 "sum=0;"
15957 "sum=ee_op_test_complex_func(sum);"
15958 "sum=ee_op_test_complex_func(sum);"
15959 "%OptimizeFunctionOnNextCall(ee_op_test_complex_func);"
15960 "sum=ee_op_test_complex_func(sum);"
15961 "sum;");
15962 CHECK_EQ(4800, result->Int32Value(context).FromJust());
15963
15964 // Test count operations
15965 result = CompileRun(
15966 "function ee_op_test_count_func(sum) {"
15967 " for (var i = 0; i < 40; ++i) {"
15968 " sum += (++ext_array[i]);"
15969 " sum += (--ext_array[i]);"
15970 " } "
15971 " return sum;"
15972 "}"
15973 "sum=0;"
15974 "sum=ee_op_test_count_func(sum);"
15975 "sum=ee_op_test_count_func(sum);"
15976 "%OptimizeFunctionOnNextCall(ee_op_test_count_func);"
15977 "sum=ee_op_test_count_func(sum);"
15978 "sum;");
15979 CHECK_EQ(4800, result->Int32Value(context).FromJust());
15980
15981 i::FLAG_allow_natives_syntax = old_natives_flag_sentry;
15982
15983 result = CompileRun("ext_array[3] = 33;"
15984 "delete ext_array[3];"
15985 "ext_array[3];");
15986 CHECK_EQ(33, result->Int32Value(context).FromJust());
15987
15988 result = CompileRun(
15989 "ext_array[0] = 10; ext_array[1] = 11;"
15990 "ext_array[2] = 12; ext_array[3] = 13;"
15991 "try { ext_array.__defineGetter__('2', function() { return 120; }); }"
15992 "catch (e) { }"
15993 "ext_array[2];");
15994 CHECK_EQ(12, result->Int32Value(context).FromJust());
15995
15996 result = CompileRun("var js_array = new Array(40);"
15997 "js_array[0] = 77;"
15998 "js_array;");
15999 CHECK_EQ(77, v8::Object::Cast(*result)
16000 ->Get(context, v8_str("0"))
16001 .ToLocalChecked()
16002 ->Int32Value(context)
16003 .FromJust());
16004
16005 result = CompileRun("ext_array[1] = 23;"
16006 "ext_array.__proto__ = [];"
16007 "js_array.__proto__ = ext_array;"
16008 "js_array.concat(ext_array);");
16009 CHECK_EQ(77, v8::Object::Cast(*result)
16010 ->Get(context, v8_str("0"))
16011 .ToLocalChecked()
16012 ->Int32Value(context)
16013 .FromJust());
16014 CHECK_EQ(23, v8::Object::Cast(*result)
16015 ->Get(context, v8_str("1"))
16016 .ToLocalChecked()
16017 ->Int32Value(context)
16018 .FromJust());
16019
16020 result = CompileRun("ext_array[1] = 23;");
16021 CHECK_EQ(23, result->Int32Value(context).FromJust());
16022}
16023
16024
16025template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
16026 class ElementType>
16027static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
16028 ElementType low, ElementType high) {
16029 i::FLAG_allow_natives_syntax = true;
16030 LocalContext context;
16031 i::Isolate* isolate = CcTest::i_isolate();
16032 i::Factory* factory = isolate->factory();
16033 v8::HandleScope scope(context->GetIsolate());
16034 const int kElementCount = 260;
16035 i::Handle<i::JSTypedArray> jsobj =
16036 factory->NewJSTypedArray(elements_kind, kElementCount);
16037 i::Handle<FixedTypedArrayClass> fixed_array(
16038 FixedTypedArrayClass::cast(jsobj->elements()), isolate);
16039 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16040 fixed_array->map()->instance_type());
16041 CHECK_EQ(kElementCount, fixed_array->length());
16042 CcTest::CollectAllGarbage();
16043 for (int i = 0; i < kElementCount; i++) {
16044 fixed_array->set(i, static_cast<ElementType>(i));
16045 }
16046 // Force GC to trigger verification.
16047 CcTest::CollectAllGarbage();
16048 for (int i = 0; i < kElementCount; i++) {
16049 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16050 static_cast<int64_t>(fixed_array->get_scalar(i)));
16051 }
16052 v8::Local<v8::Object> obj = v8::Utils::ToLocal(jsobj);
16053
16054 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16055 context.local(), obj, kElementCount, array_type,
16056 static_cast<int64_t>(low),
16057 static_cast<int64_t>(high));
16058}
16059
16060
16061THREADED_TEST(FixedUint8Array) {
16062 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16063 i::kExternalUint8Array, 0x0, 0xFF);
16064}
16065
16066
16067THREADED_TEST(FixedUint8ClampedArray) {
16068 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16069 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16070 i::kExternalUint8ClampedArray, 0x0, 0xFF);
16071}
16072
16073
16074THREADED_TEST(FixedInt8Array) {
16075 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16076 i::kExternalInt8Array, -0x80, 0x7F);
16077}
16078
16079
16080THREADED_TEST(FixedUint16Array) {
16081 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16082 i::kExternalUint16Array, 0x0, 0xFFFF);
16083}
16084
16085
16086THREADED_TEST(FixedInt16Array) {
16087 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16088 i::kExternalInt16Array, -0x8000, 0x7FFF);
16089}
16090
16091
16092THREADED_TEST(FixedUint32Array) {
16093 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16094 i::kExternalUint32Array, 0x0, UINT_MAX);
16095}
16096
16097
16098THREADED_TEST(FixedInt32Array) {
16099 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16100 i::kExternalInt32Array, INT_MIN, INT_MAX);
16101}
16102
16103
16104THREADED_TEST(FixedFloat32Array) {
16105 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16106 i::kExternalFloat32Array, -500, 500);
16107}
16108
16109
16110THREADED_TEST(FixedFloat64Array) {
16111 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16112 i::kExternalFloat64Array, -500, 500);
16113}
16114
16115
16116template <typename ElementType, typename TypedArray, class ExternalArrayClass,
16117 class ArrayBufferType>
16118void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
16119 int64_t high) {
16120 const int kElementCount = 50;
16121
16122 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16123
16124 LocalContext env;
16125 v8::Isolate* isolate = env->GetIsolate();
16126 v8::HandleScope handle_scope(isolate);
16127
16128 Local<ArrayBufferType> ab =
16129 ArrayBufferType::New(isolate, backing_store.start(),
16130 (kElementCount + 2) * sizeof(ElementType));
16131 Local<TypedArray> ta =
16132 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16133 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16134 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16135 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
16136 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
16137 CHECK(ab->Equals(env.local(), ta->Buffer()).FromJust());
16138
16139 ElementType* data = backing_store.start() + 2;
16140 for (int i = 0; i < kElementCount; i++) {
16141 data[i] = static_cast<ElementType>(i);
16142 }
16143
16144 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16145 env.local(), ta, kElementCount, array_type, low, high);
16146}
16147
16148
16149THREADED_TEST(Uint8Array) {
16150 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16151 v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16152}
16153
16154
16155THREADED_TEST(Int8Array) {
16156 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16157 v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
16158}
16159
16160
16161THREADED_TEST(Uint16Array) {
16162 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16163 v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
16164}
16165
16166
16167THREADED_TEST(Int16Array) {
16168 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16169 v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
16170 0x7FFF);
16171}
16172
16173
16174THREADED_TEST(Uint32Array) {
16175 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16176 v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
16177}
16178
16179
16180THREADED_TEST(Int32Array) {
16181 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16182 v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16183 INT_MAX);
16184}
16185
16186
16187THREADED_TEST(Float32Array) {
16188 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16189 v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
16190}
16191
16192
16193THREADED_TEST(Float64Array) {
16194 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16195 v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
16196}
16197
16198
16199THREADED_TEST(Uint8ClampedArray) {
16200 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16201 i::FixedUint8ClampedArray, v8::ArrayBuffer>(
16202 i::kExternalUint8ClampedArray, 0, 0xFF);
16203}
16204
16205
16206THREADED_TEST(DataView) {
16207 const int kSize = 50;
16208
16209 i::ScopedVector<uint8_t> backing_store(kSize+2);
16210
16211 LocalContext env;
16212 v8::Isolate* isolate = env->GetIsolate();
16213 v8::HandleScope handle_scope(isolate);
16214
16215 Local<v8::ArrayBuffer> ab =
16216 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16217 Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
16218 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16219 CHECK_EQ(2u, dv->ByteOffset());
16220 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16221 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16222}
16223
16224
16225THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
16226 LocalContext env;
16227 v8::Isolate* isolate = env->GetIsolate();
16228 v8::HandleScope handle_scope(isolate);
16229
16230 // Make sure the pointer looks like a heap object
16231 uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
16232
16233 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16234 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16235
16236 // Should not crash
16237 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16238 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16239 CcTest::CollectAllGarbage();
16240 CcTest::CollectAllGarbage();
16241
16242 // Should not move the pointer
16243 CHECK_EQ(ab->GetContents().Data(), store_ptr);
16244}
16245
16246
16247THREADED_TEST(SkipArrayBufferDuringScavenge) {
16248 LocalContext env;
16249 v8::Isolate* isolate = env->GetIsolate();
16250 v8::HandleScope handle_scope(isolate);
16251
16252 // Make sure the pointer looks like a heap object
16253 Local<v8::Object> tmp = v8::Object::New(isolate);
16254 uint8_t* store_ptr =
16255 reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
16256
16257 // Make `store_ptr` point to from space
16258 CcTest::CollectGarbage(i::NEW_SPACE);
16259
16260 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
16261 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
16262
16263 // Should not crash,
16264 // i.e. backing store pointer should not be treated as a heap object pointer
16265 CcTest::CollectGarbage(i::NEW_SPACE); // in survivor space now
16266 CcTest::CollectGarbage(i::NEW_SPACE); // in old gen now
16267
16268 // Use `ab` to silence compiler warning
16269 CHECK_EQ(ab->GetContents().Data(), store_ptr);
16270}
16271
16272
16273THREADED_TEST(SharedUint8Array) {
16274 i::FLAG_harmony_sharedarraybuffer = true;
16275 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,
16276 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
16277}
16278
16279
16280THREADED_TEST(SharedInt8Array) {
16281 i::FLAG_harmony_sharedarraybuffer = true;
16282 TypedArrayTestHelper<int8_t, v8::Int8Array, i::FixedInt8Array,
16283 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
16284 0x7F);
16285}
16286
16287
16288THREADED_TEST(SharedUint16Array) {
16289 i::FLAG_harmony_sharedarraybuffer = true;
16290 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::FixedUint16Array,
16291 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
16292 0xFFFF);
16293}
16294
16295
16296THREADED_TEST(SharedInt16Array) {
16297 i::FLAG_harmony_sharedarraybuffer = true;
16298 TypedArrayTestHelper<int16_t, v8::Int16Array, i::FixedInt16Array,
16299 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
16300 0x7FFF);
16301}
16302
16303
16304THREADED_TEST(SharedUint32Array) {
16305 i::FLAG_harmony_sharedarraybuffer = true;
16306 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::FixedUint32Array,
16307 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
16308 UINT_MAX);
16309}
16310
16311
16312THREADED_TEST(SharedInt32Array) {
16313 i::FLAG_harmony_sharedarraybuffer = true;
16314 TypedArrayTestHelper<int32_t, v8::Int32Array, i::FixedInt32Array,
16315 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
16316 INT_MAX);
16317}
16318
16319
16320THREADED_TEST(SharedFloat32Array) {
16321 i::FLAG_harmony_sharedarraybuffer = true;
16322 TypedArrayTestHelper<float, v8::Float32Array, i::FixedFloat32Array,
16323 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
16324 500);
16325}
16326
16327
16328THREADED_TEST(SharedFloat64Array) {
16329 i::FLAG_harmony_sharedarraybuffer = true;
16330 TypedArrayTestHelper<double, v8::Float64Array, i::FixedFloat64Array,
16331 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
16332 500);
16333}
16334
16335
16336THREADED_TEST(SharedUint8ClampedArray) {
16337 i::FLAG_harmony_sharedarraybuffer = true;
16338 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
16339 i::FixedUint8ClampedArray, v8::SharedArrayBuffer>(
16340 i::kExternalUint8ClampedArray, 0, 0xFF);
16341}
16342
16343
16344THREADED_TEST(SharedDataView) {
16345 i::FLAG_harmony_sharedarraybuffer = true;
16346 const int kSize = 50;
16347
16348 i::ScopedVector<uint8_t> backing_store(kSize + 2);
16349
16350 LocalContext env;
16351 v8::Isolate* isolate = env->GetIsolate();
16352 v8::HandleScope handle_scope(isolate);
16353
16354 Local<v8::SharedArrayBuffer> ab =
16355 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16356 Local<v8::DataView> dv =
16357 v8::DataView::New(ab, 2, kSize);
16358 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16359 CHECK_EQ(2u, dv->ByteOffset());
16360 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16361 CHECK(ab->Equals(env.local(), dv->Buffer()).FromJust());
16362}
16363
16364#define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16365 THREADED_TEST(Is##View) { \
16366 LocalContext env; \
16367 v8::Isolate* isolate = env->GetIsolate(); \
16368 v8::HandleScope handle_scope(isolate); \
16369 \
16370 Local<Value> result = CompileRun( \
16371 "var ab = new ArrayBuffer(128);" \
16372 "new " #View "(ab)"); \
16373 CHECK(result->IsArrayBufferView()); \
16374 CHECK(result->Is##View()); \
16375 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16376 }
16377
16378IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16379IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16380IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16381IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16382IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16383IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16384IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16385IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16386IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16387IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16388
16389#undef IS_ARRAY_BUFFER_VIEW_TEST
16390
16391
16392
16393THREADED_TEST(ScriptContextDependence) {
16394 LocalContext c1;
16395 v8::HandleScope scope(c1->GetIsolate());
16396 const char *source = "foo";
16397 v8::Local<v8::Script> dep = v8_compile(source);
16398 v8::ScriptCompiler::Source script_source(
16399 v8::String::NewFromUtf8(c1->GetIsolate(), source,
16400 v8::NewStringType::kNormal)
16401 .ToLocalChecked());
16402 v8::Local<v8::UnboundScript> indep =
16403 v8::ScriptCompiler::CompileUnboundScript(c1->GetIsolate(), &script_source)
16404 .ToLocalChecked();
16405 c1->Global()
16406 ->Set(c1.local(), v8::String::NewFromUtf8(c1->GetIsolate(), "foo",
16407 v8::NewStringType::kNormal)
16408 .ToLocalChecked(),
16409 v8::Integer::New(c1->GetIsolate(), 100))
16410 .FromJust();
16411 CHECK_EQ(
16412 dep->Run(c1.local()).ToLocalChecked()->Int32Value(c1.local()).FromJust(),
16413 100);
16414 CHECK_EQ(indep->BindToCurrentContext()
16415 ->Run(c1.local())
16416 .ToLocalChecked()
16417 ->Int32Value(c1.local())
16418 .FromJust(),
16419 100);
16420 LocalContext c2;
16421 c2->Global()
16422 ->Set(c2.local(), v8::String::NewFromUtf8(c2->GetIsolate(), "foo",
16423 v8::NewStringType::kNormal)
16424 .ToLocalChecked(),
16425 v8::Integer::New(c2->GetIsolate(), 101))
16426 .FromJust();
16427 CHECK_EQ(
16428 dep->Run(c2.local()).ToLocalChecked()->Int32Value(c2.local()).FromJust(),
16429 100);
16430 CHECK_EQ(indep->BindToCurrentContext()
16431 ->Run(c2.local())
16432 .ToLocalChecked()
16433 ->Int32Value(c2.local())
16434 .FromJust(),
16435 101);
16436}
16437
16438
16439THREADED_TEST(StackTrace) {
16440 LocalContext context;
16441 v8::HandleScope scope(context->GetIsolate());
16442 v8::TryCatch try_catch(context->GetIsolate());
16443 const char *source = "function foo() { FAIL.FAIL; }; foo();";
16444 v8::Local<v8::String> src = v8_str(source);
16445 v8::Local<v8::String> origin = v8_str("stack-trace-test");
16446 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
16447 CHECK(v8::ScriptCompiler::CompileUnboundScript(context->GetIsolate(),
16448 &script_source)
16449 .ToLocalChecked()
16450 ->BindToCurrentContext()
16451 ->Run(context.local())
16452 .IsEmpty());
16453 CHECK(try_catch.HasCaught());
16454 v8::String::Utf8Value stack(
16455 context->GetIsolate(),
16456 try_catch.StackTrace(context.local()).ToLocalChecked());
16457 CHECK_NOT_NULL(strstr(*stack, "at foo (stack-trace-test"));
16458}
16459
16460
16461// Checks that a StackFrame has certain expected values.
16462void checkStackFrame(const char* expected_script_name,
16463 const char* expected_func_name, int expected_line_number,
16464 int expected_column, bool is_eval, bool is_constructor,
16465 v8::Local<v8::StackFrame> frame) {
16466 v8::HandleScope scope(CcTest::isolate());
16467 v8::String::Utf8Value func_name(CcTest::isolate(), frame->GetFunctionName());
16468 v8::String::Utf8Value script_name(CcTest::isolate(), frame->GetScriptName());
16469 if (*script_name == nullptr) {
16470 // The situation where there is no associated script, like for evals.
16471 CHECK_NULL(expected_script_name);
16472 } else {
16473 CHECK_NOT_NULL(strstr(*script_name, expected_script_name));
16474 }
16475 CHECK_NOT_NULL(strstr(*func_name, expected_func_name));
16476 CHECK_EQ(expected_line_number, frame->GetLineNumber());
16477 CHECK_EQ(expected_column, frame->GetColumn());
16478 CHECK_EQ(is_eval, frame->IsEval());
16479 CHECK_EQ(is_constructor, frame->IsConstructor());
16480}
16481
16482
16483void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16484 v8::HandleScope scope(args.GetIsolate());
16485 const char* origin = "capture-stack-trace-test";
16486 const int kOverviewTest = 1;
16487 const int kDetailedTest = 2;
16488 const int kFunctionName = 3;
16489 const int kDisplayName = 4;
16490 const int kFunctionNameAndDisplayName = 5;
16491 const int kDisplayNameIsNotString = 6;
16492 const int kFunctionNameIsNotString = 7;
16493
16494 CHECK_EQ(args.Length(), 1);
16495
16496 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
16497 v8::Isolate* isolate = args.GetIsolate();
16498 int testGroup = args[0]->Int32Value(context).FromJust();
16499 if (testGroup == kOverviewTest) {
16500 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16501 args.GetIsolate(), 10, v8::StackTrace::kOverview);
16502 CHECK_EQ(4, stackTrace->GetFrameCount());
16503 checkStackFrame(origin, "bar", 2, 10, false, false,
16504 stackTrace->GetFrame(args.GetIsolate(), 0));
16505 checkStackFrame(origin, "foo", 6, 3, false, true,
16506 stackTrace->GetFrame(isolate, 1));
16507 // This is the source string inside the eval which has the call to foo.
16508 checkStackFrame(nullptr, "", 1, 1, true, false,
16509 stackTrace->GetFrame(isolate, 2));
16510 // The last frame is an anonymous function which has the initial eval call.
16511 checkStackFrame(origin, "", 8, 7, false, false,
16512 stackTrace->GetFrame(isolate, 3));
16513 } else if (testGroup == kDetailedTest) {
16514 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16515 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
16516 CHECK_EQ(4, stackTrace->GetFrameCount());
16517 checkStackFrame(origin, "bat", 4, 22, false, false,
16518 stackTrace->GetFrame(isolate, 0));
16519 checkStackFrame(origin, "baz", 8, 3, false, true,
16520 stackTrace->GetFrame(isolate, 1));
16521 bool is_eval = true;
16522 // This is the source string inside the eval which has the call to baz.
16523 checkStackFrame(nullptr, "", 1, 1, is_eval, false,
16524 stackTrace->GetFrame(isolate, 2));
16525 // The last frame is an anonymous function which has the initial eval call.
16526 checkStackFrame(origin, "", 10, 1, false, false,
16527 stackTrace->GetFrame(isolate, 3));
16528 } else if (testGroup == kFunctionName) {
16529 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16530 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16531 CHECK_EQ(3, stackTrace->GetFrameCount());
16532 checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16533 stackTrace->GetFrame(isolate, 0));
16534 } else if (testGroup == kDisplayName) {
16535 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16536 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16537 CHECK_EQ(3, stackTrace->GetFrameCount());
16538 checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16539 stackTrace->GetFrame(isolate, 0));
16540 } else if (testGroup == kFunctionNameAndDisplayName) {
16541 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16542 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16543 CHECK_EQ(3, stackTrace->GetFrameCount());
16544 checkStackFrame(nullptr, "function.displayName", 3, 1, true, false,
16545 stackTrace->GetFrame(isolate, 0));
16546 } else if (testGroup == kDisplayNameIsNotString) {
16547 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16548 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16549 CHECK_EQ(3, stackTrace->GetFrameCount());
16550 checkStackFrame(nullptr, "function.name", 3, 1, true, false,
16551 stackTrace->GetFrame(isolate, 0));
16552 } else if (testGroup == kFunctionNameIsNotString) {
16553 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
16554 args.GetIsolate(), 5, v8::StackTrace::kOverview);
16555 CHECK_EQ(3, stackTrace->GetFrameCount());
16556 checkStackFrame(nullptr, "", 3, 1, true, false,
16557 stackTrace->GetFrame(isolate, 0));
16558 }
16559}
16560
16561
16562// Tests the C++ StackTrace API.
16563// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16564// THREADED_TEST(CaptureStackTrace) {
16565TEST(CaptureStackTrace) {
16566 v8::Isolate* isolate = CcTest::isolate();
16567 v8::HandleScope scope(isolate);
16568 v8::Local<v8::String> origin = v8_str("capture-stack-trace-test");
16569 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16570 templ->Set(v8_str("AnalyzeStackInNativeCode"),
16571 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
16572 LocalContext context(nullptr, templ);
16573
16574 // Test getting OVERVIEW information. Should ignore information that is not
16575 // script name, function name, line number, and column offset.
16576 const char *overview_source =
16577 "function bar() {\n"
16578 " var y; AnalyzeStackInNativeCode(1);\n"
16579 "}\n"
16580 "function foo() {\n"
16581 "\n"
16582 " bar();\n"
16583 "}\n"
16584 "var x;eval('new foo();');";
16585 v8::Local<v8::String> overview_src = v8_str(overview_source);
16586 v8::ScriptCompiler::Source script_source(overview_src,
16587 v8::ScriptOrigin(origin));
16588 v8::Local<Value> overview_result(
16589 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source)
16590 .ToLocalChecked()
16591 ->BindToCurrentContext()
16592 ->Run(context.local())
16593 .ToLocalChecked());
16594 CHECK(!overview_result.IsEmpty());
16595 CHECK(overview_result->IsObject());
16596
16597 // Test getting DETAILED information.
16598 const char *detailed_source =
16599 "function bat() {AnalyzeStackInNativeCode(2);\n"
16600 "}\n"
16601 "\n"
16602 "function baz() {\n"
16603 " bat();\n"
16604 "}\n"
16605 "eval('new baz();');";
16606 v8::Local<v8::String> detailed_src = v8_str(detailed_source);
16607 // Make the script using a non-zero line and column offset.
16608 v8::Local<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
16609 v8::Local<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
16610 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16611 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
16612 v8::Local<v8::UnboundScript> detailed_script(
16613 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source2)
16614 .ToLocalChecked());
16615 v8::Local<Value> detailed_result(detailed_script->BindToCurrentContext()
16616 ->Run(context.local())
16617 .ToLocalChecked());
16618 CHECK(!detailed_result.IsEmpty());
16619 CHECK(detailed_result->IsObject());
16620
16621 // Test using function.name and function.displayName in stack trace
16622 const char* function_name_source =
16623 "function bar(function_name, display_name, testGroup) {\n"
16624 " var f = new Function(`AnalyzeStackInNativeCode(${testGroup});`);\n"
16625 " if (function_name) {\n"
16626 " Object.defineProperty(f, 'name', { value: function_name });\n"
16627 " }\n"
16628 " if (display_name) {\n"
16629 " f.displayName = display_name;"
16630 " }\n"
16631 " f()\n"
16632 "}\n"
16633 "bar('function.name', undefined, 3);\n"
16634 "bar(undefined, 'function.displayName', 4);\n"
16635 "bar('function.name', 'function.displayName', 5);\n"
16636 "bar('function.name', 239, 6);\n"
16637 "bar(239, undefined, 7);\n";
16638 v8::Local<v8::String> function_name_src =
16639 v8::String::NewFromUtf8(isolate, function_name_source,
16640 v8::NewStringType::kNormal)
16641 .ToLocalChecked();
16642 v8::ScriptCompiler::Source script_source3(function_name_src,
16643 v8::ScriptOrigin(origin));
16644 v8::Local<Value> function_name_result(
16645 v8::ScriptCompiler::CompileUnboundScript(isolate, &script_source3)
16646 .ToLocalChecked()
16647 ->BindToCurrentContext()
16648 ->Run(context.local())
16649 .ToLocalChecked());
16650 CHECK(!function_name_result.IsEmpty());
16651}
16652
16653
16654static void StackTraceForUncaughtExceptionListener(
16655 v8::Local<v8::Message> message, v8::Local<Value>) {
16656 report_count++;
16657 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16658 CHECK_EQ(2, stack_trace->GetFrameCount());
16659 checkStackFrame("origin", "foo", 2, 3, false, false,
16660 stack_trace->GetFrame(message->GetIsolate(), 0));
16661 checkStackFrame("origin", "bar", 5, 3, false, false,
16662 stack_trace->GetFrame(message->GetIsolate(), 1));
16663}
16664
16665
16666TEST(CaptureStackTraceForUncaughtException) {
16667 report_count = 0;
16668 LocalContext env;
16669 v8::Isolate* isolate = env->GetIsolate();
16670 v8::HandleScope scope(isolate);
16671 isolate->AddMessageListener(StackTraceForUncaughtExceptionListener);
16672 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16673
16674 CompileRunWithOrigin(
16675 "function foo() {\n"
16676 " throw 1;\n"
16677 "};\n"
16678 "function bar() {\n"
16679 " foo();\n"
16680 "};",
16681 "origin");
16682 v8::Local<v8::Object> global = env->Global();
16683 Local<Value> trouble =
16684 global->Get(env.local(), v8_str("bar")).ToLocalChecked();
16685 CHECK(trouble->IsFunction());
16686 CHECK(Function::Cast(*trouble)
16687 ->Call(env.local(), global, 0, nullptr)
16688 .IsEmpty());
16689 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16690 isolate->RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16691 CHECK_EQ(1, report_count);
16692}
16693
16694TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16695 LocalContext env;
16696 v8::Isolate* isolate = env->GetIsolate();
16697 v8::HandleScope scope(isolate);
16698 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 1024,
16699 v8::StackTrace::kDetailed);
16700
16701 CompileRun(
16702 "var setters = ['column', 'lineNumber', 'scriptName',\n"
16703 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16704 " 'isConstructor'];\n"
16705 "for (var i = 0; i < setters.length; i++) {\n"
16706 " var prop = setters[i];\n"
16707 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16708 "}\n");
16709 CompileRun("throw 'exception';");
16710 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16711}
16712
16713static int asm_warning_triggered = 0;
16714
16715static void AsmJsWarningListener(v8::Local<v8::Message> message,
16716 v8::Local<Value>) {
16717 DCHECK_EQ(v8::Isolate::kMessageWarning, message->ErrorLevel());
16718 asm_warning_triggered = 1;
16719}
16720
16721TEST(AsmJsWarning) {
16722 i::FLAG_validate_asm = true;
16723 if (i::FLAG_suppress_asm_messages) return;
16724
16725 LocalContext env;
16726 v8::Isolate* isolate = env->GetIsolate();
16727 v8::HandleScope scope(isolate);
16728
16729 asm_warning_triggered = 0;
16730 isolate->AddMessageListenerWithErrorLevel(AsmJsWarningListener,
16731 v8::Isolate::kMessageAll);
16732 CompileRun(
16733 "function module() {\n"
16734 " 'use asm';\n"
16735 " var x = 'hi';\n"
16736 " return {};\n"
16737 "}\n"
16738 "module();");
16739 DCHECK_EQ(1, asm_warning_triggered);
16740 isolate->RemoveMessageListeners(AsmJsWarningListener);
16741}
16742
16743static int error_level_message_count = 0;
16744static int expected_error_level = 0;
16745
16746static void ErrorLevelListener(v8::Local<v8::Message> message,
16747 v8::Local<Value>) {
16748 DCHECK_EQ(expected_error_level, message->ErrorLevel());
16749 ++error_level_message_count;
16750}
16751
16752TEST(ErrorLevelWarning) {
16753 LocalContext env;
16754 v8::Isolate* isolate = env->GetIsolate();
16755 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
16756 v8::HandleScope scope(isolate);
16757
16758 const char* source = "fake = 1;";
16759 v8::Local<v8::Script> lscript = CompileWithOrigin(source, "test", false);
16760 i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
16761 v8::Utils::OpenHandle(*lscript->GetUnboundScript()));
16762 CHECK(obj->script()->IsScript());
16763 i::Handle<i::Script> script(i::Script::cast(obj->script()), i_isolate);
16764
16765 int levels[] = {
16766 v8::Isolate::kMessageLog, v8::Isolate::kMessageInfo,
16767 v8::Isolate::kMessageDebug, v8::Isolate::kMessageWarning,
16768 };
16769 error_level_message_count = 0;
16770 isolate->AddMessageListenerWithErrorLevel(ErrorLevelListener,
16771 v8::Isolate::kMessageAll);
16772 for (size_t i = 0; i < arraysize(levels); i++) {
16773 i::MessageLocation location(script, 0, 0);
16774 i::Handle<i::String> msg(i_isolate->factory()->InternalizeOneByteString(
16775 i::StaticCharVector("test")));
16776 i::Handle<i::JSMessageObject> message =
16777 i::MessageHandler::MakeMessageObject(
16778 i_isolate, i::MessageTemplate::kAsmJsInvalid, &location, msg,
16779 i::Handle<i::FixedArray>::null());
16780 message->set_error_level(levels[i]);
16781 expected_error_level = levels[i];
16782 i::MessageHandler::ReportMessage(i_isolate, &location, message);
16783 }
16784 isolate->RemoveMessageListeners(ErrorLevelListener);
16785 DCHECK_EQ(arraysize(levels), error_level_message_count);
16786}
16787
16788static void StackTraceFunctionNameListener(v8::Local<v8::Message> message,
16789 v8::Local<Value>) {
16790 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16791 v8::Isolate* isolate = message->GetIsolate();
16792 CHECK_EQ(5, stack_trace->GetFrameCount());
16793 checkStackFrame("origin", "foo:0", 4, 7, false, false,
16794 stack_trace->GetFrame(isolate, 0));
16795 checkStackFrame("origin", "foo:1", 5, 27, false, false,
16796 stack_trace->GetFrame(isolate, 1));
16797 checkStackFrame("origin", "foo", 5, 27, false, false,
16798 stack_trace->GetFrame(isolate, 2));
16799 checkStackFrame("origin", "foo", 5, 27, false, false,
16800 stack_trace->GetFrame(isolate, 3));
16801 checkStackFrame("origin", "", 1, 14, false, false,
16802 stack_trace->GetFrame(isolate, 4));
16803}
16804
16805
16806TEST(GetStackTraceContainsFunctionsWithFunctionName) {
16807 LocalContext env;
16808 v8::Isolate* isolate = env->GetIsolate();
16809 v8::HandleScope scope(isolate);
16810
16811 CompileRunWithOrigin(
16812 "function gen(name, counter) {\n"
16813 " var f = function foo() {\n"
16814 " if (counter === 0)\n"
16815 " throw 1;\n"
16816 " gen(name, counter - 1)();\n"
16817 " };\n"
16818 " if (counter == 3) {\n"
16819 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
16820 " } else {\n"
16821 " Object.defineProperty(f, 'name', {writable:true});\n"
16822 " if (counter == 2)\n"
16823 " f.name = 42;\n"
16824 " else\n"
16825 " f.name = name + ':' + counter;\n"
16826 " }\n"
16827 " return f;\n"
16828 "};",
16829 "origin");
16830
16831 isolate->AddMessageListener(StackTraceFunctionNameListener);
16832 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16833 CompileRunWithOrigin("gen('foo', 3)();", "origin");
16834 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16835 isolate->RemoveMessageListeners(StackTraceFunctionNameListener);
16836}
16837
16838
16839static void RethrowStackTraceHandler(v8::Local<v8::Message> message,
16840 v8::Local<v8::Value> data) {
16841 // Use the frame where JavaScript is called from.
16842 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16843 CHECK(!stack_trace.IsEmpty());
16844 int frame_count = stack_trace->GetFrameCount();
16845 CHECK_EQ(3, frame_count);
16846 int line_number[] = {1, 2, 5};
16847 for (int i = 0; i < frame_count; i++) {
16848 CHECK_EQ(line_number[i],
16849 stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16850 }
16851}
16852
16853
16854// Test that we only return the stack trace at the site where the exception
16855// is first thrown (not where it is rethrown).
16856TEST(RethrowStackTrace) {
16857 LocalContext env;
16858 v8::Isolate* isolate = env->GetIsolate();
16859 v8::HandleScope scope(isolate);
16860 // We make sure that
16861 // - the stack trace of the ReferenceError in g() is reported.
16862 // - the stack trace is not overwritten when e1 is rethrown by t().
16863 // - the stack trace of e2 does not overwrite that of e1.
16864 const char* source =
16865 "function g() { error; } \n"
16866 "function f() { g(); } \n"
16867 "function t(e) { throw e; } \n"
16868 "try { \n"
16869 " f(); \n"
16870 "} catch (e1) { \n"
16871 " try { \n"
16872 " error; \n"
16873 " } catch (e2) { \n"
16874 " t(e1); \n"
16875 " } \n"
16876 "} \n";
16877 isolate->AddMessageListener(RethrowStackTraceHandler);
16878 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16879 CompileRun(source);
16880 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16881 isolate->RemoveMessageListeners(RethrowStackTraceHandler);
16882}
16883
16884
16885static void RethrowPrimitiveStackTraceHandler(v8::Local<v8::Message> message,
16886 v8::Local<v8::Value> data) {
16887 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16888 CHECK(!stack_trace.IsEmpty());
16889 int frame_count = stack_trace->GetFrameCount();
16890 CHECK_EQ(2, frame_count);
16891 int line_number[] = {3, 7};
16892 for (int i = 0; i < frame_count; i++) {
16893 CHECK_EQ(line_number[i],
16894 stack_trace->GetFrame(message->GetIsolate(), i)->GetLineNumber());
16895 }
16896}
16897
16898
16899// Test that we do not recognize identity for primitive exceptions.
16900TEST(RethrowPrimitiveStackTrace) {
16901 LocalContext env;
16902 v8::Isolate* isolate = env->GetIsolate();
16903 v8::HandleScope scope(isolate);
16904 // We do not capture stack trace for non Error objects on creation time.
16905 // Instead, we capture the stack trace on last throw.
16906 const char* source =
16907 "function g() { throw 404; } \n"
16908 "function f() { g(); } \n"
16909 "function t(e) { throw e; } \n"
16910 "try { \n"
16911 " f(); \n"
16912 "} catch (e1) { \n"
16913 " t(e1) \n"
16914 "} \n";
16915 isolate->AddMessageListener(RethrowPrimitiveStackTraceHandler);
16916 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16917 CompileRun(source);
16918 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16919 isolate->RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16920}
16921
16922
16923static void RethrowExistingStackTraceHandler(v8::Local<v8::Message> message,
16924 v8::Local<v8::Value> data) {
16925 // Use the frame where JavaScript is called from.
16926 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16927 CHECK(!stack_trace.IsEmpty());
16928 CHECK_EQ(1, stack_trace->GetFrameCount());
16929 CHECK_EQ(1, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
16930}
16931
16932
16933// Test that the stack trace is captured when the error object is created and
16934// not where it is thrown.
16935TEST(RethrowExistingStackTrace) {
16936 LocalContext env;
16937 v8::Isolate* isolate = env->GetIsolate();
16938 v8::HandleScope scope(isolate);
16939 const char* source =
16940 "var e = new Error(); \n"
16941 "throw e; \n";
16942 isolate->AddMessageListener(RethrowExistingStackTraceHandler);
16943 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16944 CompileRun(source);
16945 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16946 isolate->RemoveMessageListeners(RethrowExistingStackTraceHandler);
16947}
16948
16949
16950static void RethrowBogusErrorStackTraceHandler(v8::Local<v8::Message> message,
16951 v8::Local<v8::Value> data) {
16952 // Use the frame where JavaScript is called from.
16953 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
16954 CHECK(!stack_trace.IsEmpty());
16955 CHECK_EQ(1, stack_trace->GetFrameCount());
16956 CHECK_EQ(2, stack_trace->GetFrame(message->GetIsolate(), 0)->GetLineNumber());
16957}
16958
16959
16960// Test that the stack trace is captured where the bogus Error object is thrown.
16961TEST(RethrowBogusErrorStackTrace) {
16962 LocalContext env;
16963 v8::Isolate* isolate = env->GetIsolate();
16964 v8::HandleScope scope(isolate);
16965 const char* source =
16966 "var e = {__proto__: new Error()} \n"
16967 "throw e; \n";
16968 isolate->AddMessageListener(RethrowBogusErrorStackTraceHandler);
16969 isolate->SetCaptureStackTraceForUncaughtExceptions(true);
16970 CompileRun(source);
16971 isolate->SetCaptureStackTraceForUncaughtExceptions(false);
16972 isolate->RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16973}
16974
16975
16976v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
16977int promise_reject_counter = 0;
16978int promise_revoke_counter = 0;
16979int promise_reject_after_resolved_counter = 0;
16980int promise_resolve_after_resolved_counter = 0;
16981int promise_reject_msg_line_number = -1;
16982int promise_reject_msg_column_number = -1;
16983int promise_reject_line_number = -1;
16984int promise_reject_column_number = -1;
16985int promise_reject_frame_count = -1;
16986bool promise_reject_is_shared_cross_origin = false;
16987
16988void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
16989 v8::Local<v8::Object> global = CcTest::global();
16990 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
16991 CHECK_NE(v8::Promise::PromiseState::kPending,
16992 reject_message.GetPromise()->State());
16993 switch (reject_message.GetEvent()) {
16994 case v8::kPromiseRejectWithNoHandler: {
16995 promise_reject_counter++;
16996 global->Set(context, v8_str("rejected"), reject_message.GetPromise())
16997 .FromJust();
16998 global->Set(context, v8_str("value"), reject_message.GetValue())
16999 .FromJust();
17000 v8::Local<v8::Message> message = v8::Exception::CreateMessage(
17001 CcTest::isolate(), reject_message.GetValue());
17002 v8::Local<v8::StackTrace> stack_trace = message->GetStackTrace();
17003
17004 promise_reject_msg_line_number =
17005 message->GetLineNumber(context).FromJust();
17006 promise_reject_msg_column_number =
17007 message->GetStartColumn(context).FromJust() + 1;
17008 promise_reject_is_shared_cross_origin =
17009 message->IsSharedCrossOrigin();
17010
17011 if (!stack_trace.IsEmpty()) {
17012 promise_reject_frame_count = stack_trace->GetFrameCount();
17013 if (promise_reject_frame_count > 0) {
17014 CHECK(stack_trace->GetFrame(CcTest::isolate(), 0)
17015 ->GetScriptName()
17016 ->Equals(context, v8_str("pro"))
17017 .FromJust());
17018 promise_reject_line_number =
17019 stack_trace->GetFrame(CcTest::isolate(), 0)->GetLineNumber();
17020 promise_reject_column_number =
17021 stack_trace->GetFrame(CcTest::isolate(), 0)->GetColumn();
17022 } else {
17023 promise_reject_line_number = -1;
17024 promise_reject_column_number = -1;
17025 }
17026 }
17027 break;
17028 }
17029 case v8::kPromiseHandlerAddedAfterReject: {
17030 promise_revoke_counter++;
17031 global->Set(context, v8_str("revoked"), reject_message.GetPromise())
17032 .FromJust();
17033 CHECK(reject_message.GetValue().IsEmpty());
17034 break;
17035 }
17036 case v8::kPromiseRejectAfterResolved: {
17037 promise_reject_after_resolved_counter++;
17038 break;
17039 }
17040 case v8::kPromiseResolveAfterResolved: {
17041 promise_resolve_after_resolved_counter++;
17042 break;
17043 }
17044 }
17045}
17046
17047
17048v8::Local<v8::Promise> GetPromise(const char* name) {
17049 return v8::Local<v8::Promise>::Cast(
17050 CcTest::global()
17051 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(name))
17052 .ToLocalChecked());
17053}
17054
17055
17056v8::Local<v8::Value> RejectValue() {
17057 return CcTest::global()
17058 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17059 .ToLocalChecked();
17060}
17061
17062
17063void ResetPromiseStates() {
17064 promise_reject_counter = 0;
17065 promise_revoke_counter = 0;
17066 promise_reject_after_resolved_counter = 0;
17067 promise_resolve_after_resolved_counter = 0;
17068 promise_reject_msg_line_number = -1;
17069 promise_reject_msg_column_number = -1;
17070 promise_reject_line_number = -1;
17071 promise_reject_column_number = -1;
17072 promise_reject_frame_count = -1;
17073
17074 v8::Local<v8::Object> global = CcTest::global();
17075 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17076 global->Set(context, v8_str("rejected"), v8_str("")).FromJust();
17077 global->Set(context, v8_str("value"), v8_str("")).FromJust();
17078 global->Set(context, v8_str("revoked"), v8_str("")).FromJust();
17079}
17080
17081
17082TEST(PromiseRejectCallback) {
17083 LocalContext env;
17084 v8::Isolate* isolate = env->GetIsolate();
17085 v8::HandleScope scope(isolate);
17086
17087 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17088
17089 ResetPromiseStates();
17090
17091 // Create promise p0.
17092 CompileRun(
17093 "var reject; \n"
17094 "var p0 = new Promise( \n"
17095 " function(res, rej) { \n"
17096 " reject = rej; \n"
17097 " } \n"
17098 "); \n");
17099 CHECK(!GetPromise("p0")->HasHandler());
17100 CHECK_EQ(0, promise_reject_counter);
17101 CHECK_EQ(0, promise_revoke_counter);
17102
17103 // Add resolve handler (and default reject handler) to p0.
17104 CompileRun("var p1 = p0.then(function(){});");
17105 CHECK(GetPromise("p0")->HasHandler());
17106 CHECK(!GetPromise("p1")->HasHandler());
17107 CHECK_EQ(0, promise_reject_counter);
17108 CHECK_EQ(0, promise_revoke_counter);
17109
17110 // Reject p0.
17111 CompileRun("reject('ppp');");
17112 CHECK(GetPromise("p0")->HasHandler());
17113 CHECK(!GetPromise("p1")->HasHandler());
17114 CHECK_EQ(1, promise_reject_counter);
17115 CHECK_EQ(0, promise_revoke_counter);
17116 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
17117 CHECK(
17118 GetPromise("rejected")->Equals(env.local(), GetPromise("p1")).FromJust());
17119 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17120
17121 // Reject p0 again. Callback is not triggered again.
17122 CompileRun("reject();");
17123 CHECK(GetPromise("p0")->HasHandler());
17124 CHECK(!GetPromise("p1")->HasHandler());
17125 CHECK_EQ(1, promise_reject_counter);
17126 CHECK_EQ(0, promise_revoke_counter);
17127
17128 // Add resolve handler to p1.
17129 CompileRun("var p2 = p1.then(function(){});");
17130 CHECK(GetPromise("p0")->HasHandler());
17131 CHECK(GetPromise("p1")->HasHandler());
17132 CHECK(!GetPromise("p2")->HasHandler());
17133 CHECK_EQ(2, promise_reject_counter);
17134 CHECK_EQ(1, promise_revoke_counter);
17135 CHECK(
17136 GetPromise("rejected")->Equals(env.local(), GetPromise("p2")).FromJust());
17137 CHECK(RejectValue()->Equals(env.local(), v8_str("ppp")).FromJust());
17138 CHECK(
17139 GetPromise("revoked")->Equals(env.local(), GetPromise("p1")).FromJust());
17140
17141 ResetPromiseStates();
17142
17143 // Create promise q0.
17144 CompileRun(
17145 "var q0 = new Promise( \n"
17146 " function(res, rej) { \n"
17147 " reject = rej; \n"
17148 " } \n"
17149 "); \n");
17150 CHECK(!GetPromise("q0")->HasHandler());
17151 CHECK_EQ(0, promise_reject_counter);
17152 CHECK_EQ(0, promise_revoke_counter);
17153
17154 // Add reject handler to q0.
17155 CompileRun("var q1 = q0.catch(function() {});");
17156 CHECK(GetPromise("q0")->HasHandler());
17157 CHECK(!GetPromise("q1")->HasHandler());
17158 CHECK_EQ(0, promise_reject_counter);
17159 CHECK_EQ(0, promise_revoke_counter);
17160
17161 // Reject q0.
17162 CompileRun("reject('qq')");
17163 CHECK(GetPromise("q0")->HasHandler());
17164 CHECK(!GetPromise("q1")->HasHandler());
17165 CHECK_EQ(0, promise_reject_counter);
17166 CHECK_EQ(0, promise_revoke_counter);
17167
17168 // Add a new reject handler, which rejects by returning Promise.reject().
17169 // The returned promise q_ triggers a reject callback at first, only to
17170 // revoke it when returning it causes q2 to be rejected.
17171 CompileRun(
17172 "var q_;"
17173 "var q2 = q0.catch( \n"
17174 " function() { \n"
17175 " q_ = Promise.reject('qqq'); \n"
17176 " return q_; \n"
17177 " } \n"
17178 "); \n");
17179 CHECK(GetPromise("q0")->HasHandler());
17180 CHECK(!GetPromise("q1")->HasHandler());
17181 CHECK(!GetPromise("q2")->HasHandler());
17182 CHECK(GetPromise("q_")->HasHandler());
17183 CHECK_EQ(2, promise_reject_counter);
17184 CHECK_EQ(1, promise_revoke_counter);
17185 CHECK(
17186 GetPromise("rejected")->Equals(env.local(), GetPromise("q2")).FromJust());
17187 CHECK(
17188 GetPromise("revoked")->Equals(env.local(), GetPromise("q_")).FromJust());
17189 CHECK(RejectValue()->Equals(env.local(), v8_str("qqq")).FromJust());
17190
17191 // Add a reject handler to the resolved q1, which rejects by throwing.
17192 CompileRun(
17193 "var q3 = q1.then( \n"
17194 " function() { \n"
17195 " throw 'qqqq'; \n"
17196 " } \n"
17197 "); \n");
17198 CHECK(GetPromise("q0")->HasHandler());
17199 CHECK(GetPromise("q1")->HasHandler());
17200 CHECK(!GetPromise("q2")->HasHandler());
17201 CHECK(!GetPromise("q3")->HasHandler());
17202 CHECK_EQ(3, promise_reject_counter);
17203 CHECK_EQ(1, promise_revoke_counter);
17204 CHECK(
17205 GetPromise("rejected")->Equals(env.local(), GetPromise("q3")).FromJust());
17206 CHECK(RejectValue()->Equals(env.local(), v8_str("qqqq")).FromJust());
17207
17208 ResetPromiseStates();
17209
17210 // Create promise r0, which has three handlers, two of which handle rejects.
17211 CompileRun(
17212 "var r0 = new Promise( \n"
17213 " function(res, rej) { \n"
17214 " reject = rej; \n"
17215 " } \n"
17216 "); \n"
17217 "var r1 = r0.catch(function() {}); \n"
17218 "var r2 = r0.then(function() {}); \n"
17219 "var r3 = r0.then(function() {}, \n"
17220 " function() {}); \n");
17221 CHECK(GetPromise("r0")->HasHandler());
17222 CHECK(!GetPromise("r1")->HasHandler());
17223 CHECK(!GetPromise("r2")->HasHandler());
17224 CHECK(!GetPromise("r3")->HasHandler());
17225 CHECK_EQ(0, promise_reject_counter);
17226 CHECK_EQ(0, promise_revoke_counter);
17227
17228 // Reject r0.
17229 CompileRun("reject('rrr')");
17230 CHECK(GetPromise("r0")->HasHandler());
17231 CHECK(!GetPromise("r1")->HasHandler());
17232 CHECK(!GetPromise("r2")->HasHandler());
17233 CHECK(!GetPromise("r3")->HasHandler());
17234 CHECK_EQ(1, promise_reject_counter);
17235 CHECK_EQ(0, promise_revoke_counter);
17236 CHECK(
17237 GetPromise("rejected")->Equals(env.local(), GetPromise("r2")).FromJust());
17238 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17239
17240 // Add reject handler to r2.
17241 CompileRun("var r4 = r2.catch(function() {});");
17242 CHECK(GetPromise("r0")->HasHandler());
17243 CHECK(!GetPromise("r1")->HasHandler());
17244 CHECK(GetPromise("r2")->HasHandler());
17245 CHECK(!GetPromise("r3")->HasHandler());
17246 CHECK(!GetPromise("r4")->HasHandler());
17247 CHECK_EQ(1, promise_reject_counter);
17248 CHECK_EQ(1, promise_revoke_counter);
17249 CHECK(
17250 GetPromise("revoked")->Equals(env.local(), GetPromise("r2")).FromJust());
17251 CHECK(RejectValue()->Equals(env.local(), v8_str("rrr")).FromJust());
17252
17253 // Add reject handlers to r4.
17254 CompileRun("var r5 = r4.then(function() {}, function() {});");
17255 CHECK(GetPromise("r0")->HasHandler());
17256 CHECK(!GetPromise("r1")->HasHandler());
17257 CHECK(GetPromise("r2")->HasHandler());
17258 CHECK(!GetPromise("r3")->HasHandler());
17259 CHECK(GetPromise("r4")->HasHandler());
17260 CHECK(!GetPromise("r5")->HasHandler());
17261 CHECK_EQ(1, promise_reject_counter);
17262 CHECK_EQ(1, promise_revoke_counter);
17263
17264 ResetPromiseStates();
17265
17266 // Create promise s0, which has three handlers, none of which handle rejects.
17267 CompileRun(
17268 "var s0 = new Promise( \n"
17269 " function(res, rej) { \n"
17270 " reject = rej; \n"
17271 " } \n"
17272 "); \n"
17273 "var s1 = s0.then(function() {}); \n"
17274 "var s2 = s0.then(function() {}); \n"
17275 "var s3 = s0.then(function() {}); \n");
17276 CHECK(GetPromise("s0")->HasHandler());
17277 CHECK(!GetPromise("s1")->HasHandler());
17278 CHECK(!GetPromise("s2")->HasHandler());
17279 CHECK(!GetPromise("s3")->HasHandler());
17280 CHECK_EQ(0, promise_reject_counter);
17281 CHECK_EQ(0, promise_revoke_counter);
17282
17283 // Reject s0.
17284 CompileRun("reject('sss')");
17285 CHECK(GetPromise("s0")->HasHandler());
17286 CHECK(!GetPromise("s1")->HasHandler());
17287 CHECK(!GetPromise("s2")->HasHandler());
17288 CHECK(!GetPromise("s3")->HasHandler());
17289 CHECK_EQ(3, promise_reject_counter);
17290 CHECK_EQ(0, promise_revoke_counter);
17291 CHECK(RejectValue()->Equals(env.local(), v8_str("sss")).FromJust());
17292
17293 ResetPromiseStates();
17294
17295 // Swallowed exceptions in the Promise constructor.
17296 CompileRun(
17297 "var v0 = new Promise(\n"
17298 " function(res, rej) {\n"
17299 " res(1);\n"
17300 " throw new Error();\n"
17301 " }\n"
17302 ");\n");
17303 CHECK(!GetPromise("v0")->HasHandler());
17304 CHECK_EQ(0, promise_reject_counter);
17305 CHECK_EQ(0, promise_revoke_counter);
17306 CHECK_EQ(1, promise_reject_after_resolved_counter);
17307 CHECK_EQ(0, promise_resolve_after_resolved_counter);
17308
17309 ResetPromiseStates();
17310
17311 // Duplication resolve.
17312 CompileRun(
17313 "var r;\n"
17314 "var y0 = new Promise(\n"
17315 " function(res, rej) {\n"
17316 " r = res;\n"
17317 " throw new Error();\n"
17318 " }\n"
17319 ");\n"
17320 "r(1);\n");
17321 CHECK(!GetPromise("y0")->HasHandler());
17322 CHECK_EQ(1, promise_reject_counter);
17323 CHECK_EQ(0, promise_revoke_counter);
17324 CHECK_EQ(0, promise_reject_after_resolved_counter);
17325 CHECK_EQ(1, promise_resolve_after_resolved_counter);
17326
17327 // Test stack frames.
17328 env->GetIsolate()->SetCaptureStackTraceForUncaughtExceptions(true);
17329
17330 ResetPromiseStates();
17331
17332 // Create promise t0, which is rejected in the constructor with an error.
17333 CompileRunWithOrigin(
17334 "var t0 = new Promise( \n"
17335 " function(res, rej) { \n"
17336 " reference_error; \n"
17337 " } \n"
17338 "); \n",
17339 "pro", 0, 0);
17340 CHECK(!GetPromise("t0")->HasHandler());
17341 CHECK_EQ(1, promise_reject_counter);
17342 CHECK_EQ(0, promise_revoke_counter);
17343 CHECK_EQ(2, promise_reject_frame_count);
17344 CHECK_EQ(3, promise_reject_line_number);
17345 CHECK_EQ(5, promise_reject_column_number);
17346 CHECK_EQ(3, promise_reject_msg_line_number);
17347 CHECK_EQ(5, promise_reject_msg_column_number);
17348
17349 ResetPromiseStates();
17350
17351 // Create promise u0 and chain u1 to it, which is rejected via throw.
17352 CompileRunWithOrigin(
17353 "var u0 = Promise.resolve(); \n"
17354 "var u1 = u0.then( \n"
17355 " function() { \n"
17356 " (function() { \n"
17357 " throw new Error(); \n"
17358 " })(); \n"
17359 " } \n"
17360 " ); \n",
17361 "pro", 0, 0);
17362 CHECK(GetPromise("u0")->HasHandler());
17363 CHECK(!GetPromise("u1")->HasHandler());
17364 CHECK_EQ(1, promise_reject_counter);
17365 CHECK_EQ(0, promise_revoke_counter);
17366 CHECK_EQ(2, promise_reject_frame_count);
17367 CHECK_EQ(5, promise_reject_line_number);
17368 CHECK_EQ(23, promise_reject_column_number);
17369 CHECK_EQ(5, promise_reject_msg_line_number);
17370 CHECK_EQ(23, promise_reject_msg_column_number);
17371
17372 // Throw in u3, which handles u1's rejection.
17373 CompileRunWithOrigin(
17374 "function f() { \n"
17375 " return (function() { \n"
17376 " return new Error(); \n"
17377 " })(); \n"
17378 "} \n"
17379 "var u2 = Promise.reject(f()); \n"
17380 "var u3 = u1.catch( \n"
17381 " function() { \n"
17382 " return u2; \n"
17383 " } \n"
17384 " ); \n",
17385 "pro", 0, 0);
17386 CHECK(GetPromise("u0")->HasHandler());
17387 CHECK(GetPromise("u1")->HasHandler());
17388 CHECK(GetPromise("u2")->HasHandler());
17389 CHECK(!GetPromise("u3")->HasHandler());
17390 CHECK_EQ(3, promise_reject_counter);
17391 CHECK_EQ(2, promise_revoke_counter);
17392 CHECK_EQ(3, promise_reject_frame_count);
17393 CHECK_EQ(3, promise_reject_line_number);
17394 CHECK_EQ(12, promise_reject_column_number);
17395 CHECK_EQ(3, promise_reject_msg_line_number);
17396 CHECK_EQ(12, promise_reject_msg_column_number);
17397
17398 ResetPromiseStates();
17399
17400 // Create promise rejected promise v0, which is incorrectly handled by v1
17401 // via chaining cycle.
17402 CompileRunWithOrigin(
17403 "var v0 = Promise.reject(); \n"
17404 "var v1 = v0.catch( \n"
17405 " function() { \n"
17406 " return v1; \n"
17407 " } \n"
17408 " ); \n",
17409 "pro", 0, 0);
17410 CHECK(GetPromise("v0")->HasHandler());
17411 CHECK(!GetPromise("v1")->HasHandler());
17412 CHECK_EQ(2, promise_reject_counter);
17413 CHECK_EQ(1, promise_revoke_counter);
17414 CHECK_EQ(0, promise_reject_frame_count);
17415 CHECK_EQ(-1, promise_reject_line_number);
17416 CHECK_EQ(-1, promise_reject_column_number);
17417
17418 ResetPromiseStates();
17419
17420 // Create promise t1, which rejects by throwing syntax error from eval.
17421 CompileRunWithOrigin(
17422 "var t1 = new Promise( \n"
17423 " function(res, rej) { \n"
17424 " var content = '\\n\\\n"
17425 " }'; \n"
17426 " eval(content); \n"
17427 " } \n"
17428 "); \n",
17429 "pro", 0, 0);
17430 CHECK(!GetPromise("t1")->HasHandler());
17431 CHECK_EQ(1, promise_reject_counter);
17432 CHECK_EQ(0, promise_revoke_counter);
17433 CHECK_EQ(2, promise_reject_frame_count);
17434 CHECK_EQ(5, promise_reject_line_number);
17435 CHECK_EQ(10, promise_reject_column_number);
17436 CHECK_EQ(2, promise_reject_msg_line_number);
17437 CHECK_EQ(7, promise_reject_msg_column_number);
17438}
17439
17440TEST(PromiseRejectIsSharedCrossOrigin) {
17441 LocalContext env;
17442 v8::Isolate* isolate = env->GetIsolate();
17443 v8::HandleScope scope(isolate);
17444
17445 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17446
17447 ResetPromiseStates();
17448
17449 // Create promise p0.
17450 CompileRun(
17451 "var reject; \n"
17452 "var p0 = new Promise( \n"
17453 " function(res, rej) { \n"
17454 " reject = rej; \n"
17455 " } \n"
17456 "); \n");
17457 CHECK(!GetPromise("p0")->HasHandler());
17458 CHECK_EQ(0, promise_reject_counter);
17459 CHECK_EQ(0, promise_revoke_counter);
17460 // Not set because it's not yet rejected.
17461 CHECK(!promise_reject_is_shared_cross_origin);
17462
17463 // Reject p0.
17464 CompileRun("reject('ppp');");
17465 CHECK_EQ(1, promise_reject_counter);
17466 CHECK_EQ(0, promise_revoke_counter);
17467 // Not set because the ScriptOriginOptions is from the script.
17468 CHECK(!promise_reject_is_shared_cross_origin);
17469
17470 ResetPromiseStates();
17471
17472 // Create promise p1
17473 CompileRun(
17474 "var reject; \n"
17475 "var p1 = new Promise( \n"
17476 " function(res, rej) { \n"
17477 " reject = rej; \n"
17478 " } \n"
17479 "); \n");
17480 CHECK(!GetPromise("p1")->HasHandler());
17481 CHECK_EQ(0, promise_reject_counter);
17482 CHECK_EQ(0, promise_revoke_counter);
17483 // Not set because it's not yet rejected.
17484 CHECK(!promise_reject_is_shared_cross_origin);
17485
17486 // Add resolve handler (and default reject handler) to p1.
17487 CompileRun("var p2 = p1.then(function(){});");
17488 CHECK(GetPromise("p1")->HasHandler());
17489 CHECK(!GetPromise("p2")->HasHandler());
17490 CHECK_EQ(0, promise_reject_counter);
17491 CHECK_EQ(0, promise_revoke_counter);
17492
17493 // Reject p1.
17494 CompileRun("reject('ppp');");
17495 CHECK_EQ(1, promise_reject_counter);
17496 CHECK_EQ(0, promise_revoke_counter);
17497 // Set because the event is from an empty script.
17498 CHECK(promise_reject_is_shared_cross_origin);
17499}
17500
17501TEST(PromiseRejectMarkAsHandled) {
17502 LocalContext env;
17503 v8::Isolate* isolate = env->GetIsolate();
17504 v8::HandleScope scope(isolate);
17505
17506 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
17507
17508 ResetPromiseStates();
17509
17510 // Create promise p0.
17511 CompileRun(
17512 "var reject; \n"
17513 "var p0 = new Promise( \n"
17514 " function(res, rej) { \n"
17515 " reject = rej; \n"
17516 " } \n"
17517 "); \n");
17518 CHECK(!GetPromise("p0")->HasHandler());
17519 CHECK_EQ(0, promise_reject_counter);
17520 CHECK_EQ(0, promise_revoke_counter);
17521 GetPromise("p0")->MarkAsHandled();
17522
17523 // Reject p0. promise_reject_counter shouldn't be incremented because
17524 // it's marked as handled.
17525 CompileRun("reject('ppp');");
17526 CHECK_EQ(0, promise_reject_counter);
17527 CHECK_EQ(0, promise_revoke_counter);
17528}
17529void PromiseRejectCallbackConstructError(
17530 v8::PromiseRejectMessage reject_message) {
17531 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17532 CHECK_EQ(v8::Promise::PromiseState::kRejected,
17533 reject_message.GetPromise()->State());
17534 USE(v8::Script::Compile(context, v8_str("new Error('test')"))
17535 .ToLocalChecked()
17536 ->Run(context));
17537}
17538
17539TEST(PromiseRejectCallbackConstructError) {
17540 i::FLAG_allow_natives_syntax = true;
17541 LocalContext env;
17542 v8::Isolate* isolate = env->GetIsolate();
17543 v8::HandleScope scope(isolate);
17544
17545 isolate->SetPromiseRejectCallback(PromiseRejectCallbackConstructError);
17546
17547 ResetPromiseStates();
17548 CompileRun(
17549 "function f(p) {"
17550 " p.catch(() => {});"
17551 "}"
17552 "f(Promise.reject());"
17553 "f(Promise.reject());"
17554 "%OptimizeFunctionOnNextCall(f);"
17555 "let p = Promise.reject();"
17556 "f(p);");
17557}
17558
17559void AnalyzeStackOfEvalWithSourceURL(
17560 const v8::FunctionCallbackInfo<v8::Value>& args) {
17561 v8::HandleScope scope(args.GetIsolate());
17562 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17563 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17564 CHECK_EQ(5, stackTrace->GetFrameCount());
17565 v8::Local<v8::String> url = v8_str("eval_url");
17566 for (int i = 0; i < 3; i++) {
17567 v8::Local<v8::String> name =
17568 stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17569 CHECK(!name.IsEmpty());
17570 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17571 }
17572}
17573
17574
17575TEST(SourceURLInStackTrace) {
17576 v8::Isolate* isolate = CcTest::isolate();
17577 v8::HandleScope scope(isolate);
17578 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17579 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17580 v8::FunctionTemplate::New(isolate,
17581 AnalyzeStackOfEvalWithSourceURL));
17582 LocalContext context(nullptr, templ);
17583
17584 const char *source =
17585 "function outer() {\n"
17586 "function bar() {\n"
17587 " AnalyzeStackOfEvalWithSourceURL();\n"
17588 "}\n"
17589 "function foo() {\n"
17590 "\n"
17591 " bar();\n"
17592 "}\n"
17593 "foo();\n"
17594 "}\n"
17595 "eval('(' + outer +')()%s');";
17596
17597 i::ScopedVector<char> code(1024);
17598 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17599 CHECK(CompileRun(code.start())->IsUndefined());
17600 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17601 CHECK(CompileRun(code.start())->IsUndefined());
17602}
17603
17604
17605static int scriptIdInStack[2];
17606
17607void AnalyzeScriptIdInStack(
17608 const v8::FunctionCallbackInfo<v8::Value>& args) {
17609 v8::HandleScope scope(args.GetIsolate());
17610 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17611 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17612 CHECK_EQ(2, stackTrace->GetFrameCount());
17613 for (int i = 0; i < 2; i++) {
17614 scriptIdInStack[i] =
17615 stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptId();
17616 }
17617}
17618
17619
17620TEST(ScriptIdInStackTrace) {
17621 v8::Isolate* isolate = CcTest::isolate();
17622 v8::HandleScope scope(isolate);
17623 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17624 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17625 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17626 LocalContext context(nullptr, templ);
17627
17628 v8::Local<v8::String> scriptSource = v8_str(
17629 "function foo() {\n"
17630 " AnalyzeScriptIdInStack();"
17631 "}\n"
17632 "foo();\n");
17633 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test", false);
17634 script->Run(context.local()).ToLocalChecked();
17635 for (int i = 0; i < 2; i++) {
17636 CHECK_NE(scriptIdInStack[i], v8::Message::kNoScriptIdInfo);
17637 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17638 }
17639}
17640
17641
17642void AnalyzeStackOfInlineScriptWithSourceURL(
17643 const v8::FunctionCallbackInfo<v8::Value>& args) {
17644 v8::HandleScope scope(args.GetIsolate());
17645 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17646 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17647 CHECK_EQ(4, stackTrace->GetFrameCount());
17648 v8::Local<v8::String> url = v8_str("source_url");
17649 for (int i = 0; i < 3; i++) {
17650 v8::Local<v8::String> name =
17651 stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
17652 CHECK(!name.IsEmpty());
17653 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
17654 }
17655}
17656
17657
17658TEST(InlineScriptWithSourceURLInStackTrace) {
17659 v8::Isolate* isolate = CcTest::isolate();
17660 v8::HandleScope scope(isolate);
17661 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17662 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17663 v8::FunctionTemplate::New(
17664 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17665 LocalContext context(nullptr, templ);
17666
17667 const char *source =
17668 "function outer() {\n"
17669 "function bar() {\n"
17670 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17671 "}\n"
17672 "function foo() {\n"
17673 "\n"
17674 " bar();\n"
17675 "}\n"
17676 "foo();\n"
17677 "}\n"
17678 "outer()\n%s";
17679
17680 i::ScopedVector<char> code(1024);
17681 i::SNPrintF(code, source, "//# sourceURL=source_url");
17682 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17683 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17684 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17685}
17686
17687void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
17688 CcTest::global()
17689 ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
17690 .FromJust();
17691}
17692
17693class PromiseHookData {
17694 public:
17695 int before_hook_count = 0;
17696 int after_hook_count = 0;
17697 int promise_hook_count = 0;
17698 int parent_promise_count = 0;
17699 bool check_value = true;
17700 std::string promise_hook_value;
17701
17702 void Reset() {
17703 before_hook_count = 0;
17704 after_hook_count = 0;
17705 promise_hook_count = 0;
17706 parent_promise_count = 0;
17707 check_value = true;
17708 promise_hook_value = "";
17709 }
17710};
17711
17712PromiseHookData* promise_hook_data;
17713
17714void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
17715 v8::Local<v8::Value> parentPromise) {
17716 promise_hook_data->promise_hook_count++;
17717 switch (type) {
17718 case v8::PromiseHookType::kInit:
17719 SetPromise("init", promise);
17720
17721 if (!parentPromise->IsUndefined()) {
17722 promise_hook_data->parent_promise_count++;
17723 SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
17724 }
17725
17726 break;
17727 case v8::PromiseHookType::kResolve:
17728 SetPromise("resolve", promise);
17729 break;
17730 case v8::PromiseHookType::kBefore:
17731 promise_hook_data->before_hook_count++;
17732 CHECK(promise_hook_data->before_hook_count >
17733 promise_hook_data->after_hook_count);
17734 CHECK(CcTest::global()
17735 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17736 .ToLocalChecked()
17737 ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
17738 .FromJust());
17739 SetPromise("before", promise);
17740 break;
17741 case v8::PromiseHookType::kAfter:
17742 promise_hook_data->after_hook_count++;
17743 CHECK(promise_hook_data->after_hook_count <=
17744 promise_hook_data->before_hook_count);
17745 if (promise_hook_data->check_value) {
17746 CHECK(
17747 CcTest::global()
17748 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17749 .ToLocalChecked()
17750 ->Equals(CcTest::isolate()->GetCurrentContext(),
17751 v8_str(promise_hook_data->promise_hook_value.c_str()))
17752 .FromJust());
17753 }
17754 SetPromise("after", promise);
17755 break;
17756 }
17757}
17758
17759TEST(PromiseHook) {
17760 LocalContext env;
17761 v8::Isolate* isolate = env->GetIsolate();
17762 v8::HandleScope scope(isolate);
17763
17764 v8::Local<v8::Object> global = CcTest::global();
17765 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
17766
17767 promise_hook_data = new PromiseHookData();
17768 isolate->SetPromiseHook(CustomPromiseHook);
17769
17770 // Test that an initialized promise is passed to init. Other hooks
17771 // can not have un initialized promise.
17772 promise_hook_data->check_value = false;
17773 CompileRun("var p = new Promise(() => {});");
17774
17775 auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17776 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17777 auto init_promise_obj = v8::Local<v8::Promise>::Cast(init_promise);
17778 CHECK_EQ(init_promise_obj->State(), v8::Promise::PromiseState::kPending);
17779 CHECK(!init_promise_obj->HasHandler());
17780
17781 promise_hook_data->Reset();
17782 promise_hook_data->promise_hook_value = "fulfilled";
17783 const char* source =
17784 "var resolve, value = ''; \n"
17785 "var p = new Promise(r => resolve = r); \n";
17786
17787 CompileRun(source);
17788 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17789 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17790 CHECK_EQ(1, promise_hook_data->promise_hook_count);
17791 CHECK_EQ(0, promise_hook_data->parent_promise_count);
17792
17793 CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
17794 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17795 auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17796 CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17797 CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17798 CHECK_EQ(2, promise_hook_data->promise_hook_count);
17799 CHECK_EQ(1, promise_hook_data->parent_promise_count);
17800
17801 CompileRun("resolve(); \n");
17802 auto resolve_promise =
17803 global->Get(context, v8_str("resolve")).ToLocalChecked();
17804 auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17805 auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17806 CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17807 CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17808 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17809 CHECK_EQ(6, promise_hook_data->promise_hook_count);
17810
17811 CompileRun("value = ''; var p2 = p1.then(() => { value = 'fulfilled' }); \n");
17812 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17813 parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17814 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17815 before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17816 after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17817 CHECK(GetPromise("p2")->Equals(env.local(), init_promise).FromJust());
17818 CHECK(GetPromise("p1")->Equals(env.local(), parent_promise).FromJust());
17819 CHECK(GetPromise("p2")->Equals(env.local(), before_promise).FromJust());
17820 CHECK(GetPromise("p2")->Equals(env.local(), after_promise).FromJust());
17821 CHECK(GetPromise("p2")->Equals(env.local(), resolve_promise).FromJust());
17822 CHECK_EQ(10, promise_hook_data->promise_hook_count);
17823
17824 promise_hook_data->Reset();
17825 promise_hook_data->promise_hook_value = "rejected";
17826 source =
17827 "var reject, value = ''; \n"
17828 "var p = new Promise((_, r) => reject = r); \n";
17829
17830 CompileRun(source);
17831 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17832 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17833 CHECK_EQ(1, promise_hook_data->promise_hook_count);
17834 CHECK_EQ(0, promise_hook_data->parent_promise_count);
17835
17836 CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
17837 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17838 parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17839 CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17840 CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17841 CHECK_EQ(2, promise_hook_data->promise_hook_count);
17842 CHECK_EQ(1, promise_hook_data->parent_promise_count);
17843
17844 CompileRun("reject(); \n");
17845 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17846 before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17847 after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17848 CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17849 CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17850 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17851 CHECK_EQ(6, promise_hook_data->promise_hook_count);
17852
17853 promise_hook_data->Reset();
17854 promise_hook_data->promise_hook_value = "Promise.resolve";
17855 source =
17856 "var value = ''; \n"
17857 "var p = Promise.resolve('Promise.resolve'); \n";
17858
17859 CompileRun(source);
17860 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17861 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17862 // init hook and resolve hook
17863 CHECK_EQ(2, promise_hook_data->promise_hook_count);
17864 CHECK_EQ(0, promise_hook_data->parent_promise_count);
17865 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17866 CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17867
17868 CompileRun("var p1 = p.then((v) => { value = v; }); \n");
17869 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17870 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17871 parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
17872 before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
17873 after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
17874 CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
17875 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17876 CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
17877 CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
17878 CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
17879 CHECK_EQ(6, promise_hook_data->promise_hook_count);
17880 CHECK_EQ(1, promise_hook_data->parent_promise_count);
17881
17882 promise_hook_data->Reset();
17883 source =
17884 "var resolve, value = ''; \n"
17885 "var p = new Promise((_, r) => resolve = r); \n";
17886
17887 CompileRun(source);
17888 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17889 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17890 CHECK_EQ(1, promise_hook_data->promise_hook_count);
17891 CHECK_EQ(0, promise_hook_data->parent_promise_count);
17892
17893 CompileRun("resolve(); \n");
17894 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17895 CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17896 CHECK_EQ(2, promise_hook_data->promise_hook_count);
17897
17898 promise_hook_data->Reset();
17899 source =
17900 "var reject, value = ''; \n"
17901 "var p = new Promise((_, r) => reject = r); \n";
17902
17903 CompileRun(source);
17904 init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
17905 CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
17906 CHECK_EQ(1, promise_hook_data->promise_hook_count);
17907 CHECK_EQ(0, promise_hook_data->parent_promise_count);
17908
17909 CompileRun("reject(); \n");
17910 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17911 CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
17912 CHECK_EQ(2, promise_hook_data->promise_hook_count);
17913
17914 promise_hook_data->Reset();
17915 // This test triggers after callbacks right after each other, so
17916 // lets just check the value at the end.
17917 promise_hook_data->check_value = false;
17918 promise_hook_data->promise_hook_value = "Promise.all";
17919 source =
17920 "var resolve, value = ''; \n"
17921 "var tempPromise = new Promise(r => resolve = r); \n"
17922 "var p = Promise.all([tempPromise]);\n "
17923 "var p1 = p.then(v => value = v[0]); \n";
17924
17925 CompileRun(source);
17926 // 1) init hook (tempPromise)
17927 // 2) init hook (p)
17928 // 3) init hook (throwaway Promise in Promise.all, p)
17929 // 4) init hook (p1, p)
17930 CHECK_EQ(4, promise_hook_data->promise_hook_count);
17931 CHECK_EQ(2, promise_hook_data->parent_promise_count);
17932
17933 promise_hook_data->promise_hook_value = "Promise.all";
17934 CompileRun("resolve('Promise.all'); \n");
17935 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17936 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17937 // 5) resolve hook (tempPromise)
17938 // 6) resolve hook (throwaway Promise in Promise.all)
17939 // 6) before hook (throwaway Promise in Promise.all)
17940 // 7) after hook (throwaway Promise in Promise.all)
17941 // 8) before hook (p)
17942 // 9) after hook (p)
17943 // 10) resolve hook (p1)
17944 // 11) before hook (p1)
17945 // 12) after hook (p1)
17946 CHECK_EQ(12, promise_hook_data->promise_hook_count);
17947 CHECK(CcTest::global()
17948 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17949 .ToLocalChecked()
17950 ->Equals(CcTest::isolate()->GetCurrentContext(),
17951 v8_str(promise_hook_data->promise_hook_value.c_str()))
17952 .FromJust());
17953
17954 promise_hook_data->Reset();
17955 // This test triggers after callbacks right after each other, so
17956 // lets just check the value at the end.
17957 promise_hook_data->check_value = false;
17958 promise_hook_data->promise_hook_value = "Promise.race";
17959 source =
17960 "var resolve, value = ''; \n"
17961 "var tempPromise = new Promise(r => resolve = r); \n"
17962 "var p = Promise.race([tempPromise]);\n "
17963 "var p1 = p.then(v => value = v); \n";
17964
17965 CompileRun(source);
17966 // 1) init hook (tempPromise)
17967 // 2) init hook (p)
17968 // 3) init hook (throwaway Promise in Promise.race, p)
17969 // 4) init hook (p1, p)
17970 CHECK_EQ(4, promise_hook_data->promise_hook_count);
17971 CHECK_EQ(2, promise_hook_data->parent_promise_count);
17972
17973 promise_hook_data->promise_hook_value = "Promise.race";
17974 CompileRun("resolve('Promise.race'); \n");
17975 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
17976 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
17977 // 5) resolve hook (tempPromise)
17978 // 6) resolve hook (throwaway Promise in Promise.race)
17979 // 6) before hook (throwaway Promise in Promise.race)
17980 // 7) after hook (throwaway Promise in Promise.race)
17981 // 8) before hook (p)
17982 // 9) after hook (p)
17983 // 10) resolve hook (p1)
17984 // 11) before hook (p1)
17985 // 12) after hook (p1)
17986 CHECK_EQ(12, promise_hook_data->promise_hook_count);
17987 CHECK(CcTest::global()
17988 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
17989 .ToLocalChecked()
17990 ->Equals(CcTest::isolate()->GetCurrentContext(),
17991 v8_str(promise_hook_data->promise_hook_value.c_str()))
17992 .FromJust());
17993
17994 promise_hook_data->Reset();
17995 promise_hook_data->promise_hook_value = "subclass";
17996 source =
17997 "var resolve, value = '';\n"
17998 "class MyPromise extends Promise { \n"
17999 " then(onFulfilled, onRejected) { \n"
18000 " return super.then(onFulfilled, onRejected); \n"
18001 " };\n"
18002 "};\n"
18003 "var p = new MyPromise(r => resolve = r);\n";
18004
18005 CompileRun(source);
18006 // 1) init hook (p)
18007 CHECK_EQ(1, promise_hook_data->promise_hook_count);
18008
18009 CompileRun("var p1 = p.then(() => value = 'subclass');\n");
18010 // 2) init hook (p1)
18011 CHECK_EQ(2, promise_hook_data->promise_hook_count);
18012
18013 CompileRun("resolve();\n");
18014 resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
18015 before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
18016 after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
18017 CHECK(GetPromise("p1")->Equals(env.local(), before_promise).FromJust());
18018 CHECK(GetPromise("p1")->Equals(env.local(), after_promise).FromJust());
18019 CHECK(GetPromise("p1")->Equals(env.local(), resolve_promise).FromJust());
18020 // 3) resolve hook (p)
18021 // 4) before hook (p)
18022 // 5) after hook (p)
18023 // 6) resolve hook (p1)
18024 CHECK_EQ(6, promise_hook_data->promise_hook_count);
18025
18026 promise_hook_data->Reset();
18027 source =
18028 "class X extends Promise {\n"
18029 " static get [Symbol.species]() {\n"
18030 " return Y;\n"
18031 " }\n"
18032 "}\n"
18033 "class Y {\n"
18034 " constructor(executor) {\n"
18035 " return new Proxy(new Promise(executor), {});\n"
18036 " }\n"
18037 "}\n"
18038 "var x = X.resolve().then(() => {});\n";
18039
18040 CompileRun(source);
18041
18042 promise_hook_data->Reset();
18043 source =
18044 "var resolve, value = '';\n"
18045 "var p = new Promise(r => resolve = r);\n";
18046
18047 CompileRun(source);
18048 CHECK_EQ(v8::Promise::kPending, GetPromise("p")->State());
18049 CompileRun("resolve(Promise.resolve(value));\n");
18050 CHECK_EQ(v8::Promise::kFulfilled, GetPromise("p")->State());
18051 CHECK_EQ(9, promise_hook_data->promise_hook_count);
18052
18053 delete promise_hook_data;
18054 isolate->SetPromiseHook(nullptr);
18055}
18056
18057void AnalyzeStackOfDynamicScriptWithSourceURL(
18058 const v8::FunctionCallbackInfo<v8::Value>& args) {
18059 v8::HandleScope scope(args.GetIsolate());
18060 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18061 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18062 CHECK_EQ(4, stackTrace->GetFrameCount());
18063 v8::Local<v8::String> url = v8_str("source_url");
18064 for (int i = 0; i < 3; i++) {
18065 v8::Local<v8::String> name =
18066 stackTrace->GetFrame(args.GetIsolate(), i)->GetScriptNameOrSourceURL();
18067 CHECK(!name.IsEmpty());
18068 CHECK(url->Equals(args.GetIsolate()->GetCurrentContext(), name).FromJust());
18069 }
18070}
18071
18072
18073TEST(DynamicWithSourceURLInStackTrace) {
18074 v8::Isolate* isolate = CcTest::isolate();
18075 v8::HandleScope scope(isolate);
18076 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18077 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18078 v8::FunctionTemplate::New(
18079 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18080 LocalContext context(nullptr, templ);
18081
18082 const char *source =
18083 "function outer() {\n"
18084 "function bar() {\n"
18085 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18086 "}\n"
18087 "function foo() {\n"
18088 "\n"
18089 " bar();\n"
18090 "}\n"
18091 "foo();\n"
18092 "}\n"
18093 "outer()\n%s";
18094
18095 i::ScopedVector<char> code(1024);
18096 i::SNPrintF(code, source, "//# sourceURL=source_url");
18097 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18098 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18099 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18100}
18101
18102
18103TEST(DynamicWithSourceURLInStackTraceString) {
18104 LocalContext context;
18105 v8::HandleScope scope(context->GetIsolate());
18106
18107 const char *source =
18108 "function outer() {\n"
18109 " function foo() {\n"
18110 " FAIL.FAIL;\n"
18111 " }\n"
18112 " foo();\n"
18113 "}\n"
18114 "outer()\n%s";
18115
18116 i::ScopedVector<char> code(1024);
18117 i::SNPrintF(code, source, "//# sourceURL=source_url");
18118 v8::TryCatch try_catch(context->GetIsolate());
18119 CompileRunWithOrigin(code.start(), "", 0, 0);
18120 CHECK(try_catch.HasCaught());
18121 v8::String::Utf8Value stack(
18122 context->GetIsolate(),
18123 try_catch.StackTrace(context.local()).ToLocalChecked());
18124 CHECK_NOT_NULL(strstr(*stack, "at foo (source_url:3:5)"));
18125}
18126
18127
18128TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18129 LocalContext context;
18130 v8::HandleScope scope(context->GetIsolate());
18131
18132 const char *source =
18133 "function outer() {\n"
18134 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18135 " //# sourceURL=source_url\";\n"
18136 " eval(scriptContents);\n"
18137 " foo(); }\n"
18138 "outer();\n"
18139 "//# sourceURL=outer_url";
18140
18141 v8::TryCatch try_catch(context->GetIsolate());
18142 CompileRun(source);
18143 CHECK(try_catch.HasCaught());
18144
18145 Local<v8::Message> message = try_catch.Message();
18146 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18147 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18148 "source_url"));
18149}
18150
18151
18152TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18153 LocalContext context;
18154 v8::HandleScope scope(context->GetIsolate());
18155
18156 const char *source =
18157 "function outer() {\n"
18158 " var scriptContents = \"function boo(){ boo(); }\\\n"
18159 " //# sourceURL=source_url\";\n"
18160 " eval(scriptContents);\n"
18161 " boo(); }\n"
18162 "outer();\n"
18163 "//# sourceURL=outer_url";
18164
18165 v8::TryCatch try_catch(context->GetIsolate());
18166 CompileRun(source);
18167 CHECK(try_catch.HasCaught());
18168
18169 Local<v8::Message> message = try_catch.Message();
18170 Local<Value> sourceURL = message->GetScriptOrigin().ResourceName();
18171 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(context->GetIsolate(), sourceURL),
18172 "source_url"));
18173}
18174
18175
18176static void CreateGarbageInOldSpace() {
18177 i::Factory* factory = CcTest::i_isolate()->factory();
18178 v8::HandleScope scope(CcTest::isolate());
18179 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18180 for (int i = 0; i < 1000; i++) {
18181 factory->NewFixedArray(1000, i::AllocationType::kOld);
18182 }
18183}
18184
18185
18186// Test that idle notification can be handled and eventually collects garbage.
18187TEST(TestIdleNotification) {
18188 if (!i::FLAG_incremental_marking) return;
18189 ManualGCScope manual_gc_scope;
18190 const intptr_t MB = 1024 * 1024;
18191 const double IdlePauseInSeconds = 1.0;
18192 LocalContext env;
18193 v8::HandleScope scope(env->GetIsolate());
18194 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18195 CreateGarbageInOldSpace();
18196 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18197 CHECK_GT(size_with_garbage, initial_size + MB);
18198 bool finished = false;
18199 for (int i = 0; i < 200 && !finished; i++) {
18200 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
18201 CcTest::heap()->StartIdleIncrementalMarking(
18202 i::GarbageCollectionReason::kTesting);
18203 }
18204 finished = env->GetIsolate()->IdleNotificationDeadline(
18205 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
18206 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
18207 IdlePauseInSeconds);
18208 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
18209 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
18210 }
18211 }
18212 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18213 CHECK(finished);
18214 CHECK_LT(final_size, initial_size + 1);
18215}
18216
18217TEST(TestMemorySavingsMode) {
18218 LocalContext context;
18219 v8::Isolate* isolate = context->GetIsolate();
18220 v8::internal::Isolate* i_isolate =
18221 reinterpret_cast<v8::internal::Isolate*>(isolate);
18222 CHECK(!i_isolate->IsMemorySavingsModeActive());
18223 isolate->EnableMemorySavingsMode();
18224 CHECK(i_isolate->IsMemorySavingsModeActive());
18225 isolate->DisableMemorySavingsMode();
18226 CHECK(!i_isolate->IsMemorySavingsModeActive());
18227}
18228
18229TEST(Regress2333) {
18230 LocalContext env;
18231 for (int i = 0; i < 3; i++) {
18232 CcTest::CollectGarbage(i::NEW_SPACE);
18233 }
18234}
18235
18236static uint32_t* stack_limit;
18237
18238static void GetStackLimitCallback(
18239 const v8::FunctionCallbackInfo<v8::Value>& args) {
18240 stack_limit = reinterpret_cast<uint32_t*>(
18241 CcTest::i_isolate()->stack_guard()->real_climit());
18242}
18243
18244
18245// Uses the address of a local variable to determine the stack top now.
18246// Given a size, returns an address that is that far from the current
18247// top of stack.
18248static uint32_t* ComputeStackLimit(uint32_t size) {
18249 uint32_t* answer = &size - (size / sizeof(size));
18250 // If the size is very large and the stack is very near the bottom of
18251 // memory then the calculation above may wrap around and give an address
18252 // that is above the (downwards-growing) stack. In that case we return
18253 // a very low address.
18254 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18255 return answer;
18256}
18257
18258
18259// We need at least 165kB for an x64 debug build with clang and ASAN.
18260static const int stack_breathing_room = 256 * i::KB;
18261
18262
18263TEST(SetStackLimit) {
18264 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18265
18266 // Set stack limit.
18267 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18268
18269 // Execute a script.
18270 LocalContext env;
18271 v8::HandleScope scope(env->GetIsolate());
18272 Local<v8::FunctionTemplate> fun_templ =
18273 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18274 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18275 CHECK(env->Global()
18276 ->Set(env.local(), v8_str("get_stack_limit"), fun)
18277 .FromJust());
18278 CompileRun("get_stack_limit();");
18279
18280 CHECK(stack_limit == set_limit);
18281}
18282
18283
18284TEST(SetStackLimitInThread) {
18285 uint32_t* set_limit;
18286 {
18287 v8::Locker locker(CcTest::isolate());
18288 set_limit = ComputeStackLimit(stack_breathing_room);
18289
18290 // Set stack limit.
18291 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18292
18293 // Execute a script.
18294 v8::HandleScope scope(CcTest::isolate());
18295 LocalContext env;
18296 Local<v8::FunctionTemplate> fun_templ =
18297 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18298 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
18299 CHECK(env->Global()
18300 ->Set(env.local(), v8_str("get_stack_limit"), fun)
18301 .FromJust());
18302 CompileRun("get_stack_limit();");
18303
18304 CHECK(stack_limit == set_limit);
18305 }
18306 {
18307 v8::Locker locker(CcTest::isolate());
18308 CHECK(stack_limit == set_limit);
18309 }
18310}
18311
18312THREADED_TEST(GetHeapStatistics) {
18313 LocalContext c1;
18314 v8::HandleScope scope(c1->GetIsolate());
18315 v8::HeapStatistics heap_statistics;
18316 CHECK_EQ(0u, heap_statistics.total_heap_size());
18317 CHECK_EQ(0u, heap_statistics.used_heap_size());
18318 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18319 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18320 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18321}
18322
18323TEST(GetHeapSpaceStatistics) {
18324 LocalContext c1;
18325 v8::Isolate* isolate = c1->GetIsolate();
18326 v8::HandleScope scope(isolate);
18327 v8::HeapStatistics heap_statistics;
18328
18329 // Force allocation in LO_SPACE so that every space has non-zero size.
18330 v8::internal::Isolate* i_isolate =
18331 reinterpret_cast<v8::internal::Isolate*>(isolate);
18332 auto unused = i_isolate->factory()->TryNewFixedArray(512 * 1024,
18333 i::AllocationType::kOld);
18334 USE(unused);
18335
18336 isolate->GetHeapStatistics(&heap_statistics);
18337
18338 // Ensure that the sum of all the spaces matches the totals from
18339 // GetHeapSpaceStatics.
18340 size_t total_size = 0u;
18341 size_t total_used_size = 0u;
18342 size_t total_available_size = 0u;
18343 size_t total_physical_size = 0u;
18344 for (size_t i = 0; i < isolate->NumberOfHeapSpaces(); ++i) {
18345 v8::HeapSpaceStatistics space_statistics;
18346 isolate->GetHeapSpaceStatistics(&space_statistics, i);
18347 CHECK_NOT_NULL(space_statistics.space_name());
18348 total_size += space_statistics.space_size();
18349 total_used_size += space_statistics.space_used_size();
18350 total_available_size += space_statistics.space_available_size();
18351 total_physical_size += space_statistics.physical_space_size();
18352 }
18353 total_available_size += CcTest::heap()->memory_allocator()->Available();
18354
18355 CHECK_EQ(total_size, heap_statistics.total_heap_size());
18356 CHECK_EQ(total_used_size, heap_statistics.used_heap_size());
18357 CHECK_EQ(total_available_size, heap_statistics.total_available_size());
18358 CHECK_EQ(total_physical_size, heap_statistics.total_physical_size());
18359}
18360
18361TEST(NumberOfNativeContexts) {
18362 static const size_t kNumTestContexts = 10;
18363 i::Isolate* isolate = CcTest::i_isolate();
18364 i::HandleScope scope(isolate);
18365 v8::Global<v8::Context> context[kNumTestContexts];
18366 v8::HeapStatistics heap_statistics;
18367 CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18368 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18369 CHECK_EQ(0u, heap_statistics.number_of_native_contexts());
18370 for (size_t i = 0; i < kNumTestContexts; i++) {
18371 i::HandleScope inner(isolate);
18372 context[i].Reset(CcTest::isolate(), v8::Context::New(CcTest::isolate()));
18373 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18374 CHECK_EQ(i + 1, heap_statistics.number_of_native_contexts());
18375 }
18376 for (size_t i = 0; i < kNumTestContexts; i++) {
18377 context[i].Reset();
18378 CcTest::PreciseCollectAllGarbage();
18379 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18380 CHECK_EQ(kNumTestContexts - i - 1u,
18381 heap_statistics.number_of_native_contexts());
18382 }
18383}
18384
18385TEST(NumberOfDetachedContexts) {
18386 static const size_t kNumTestContexts = 10;
18387 i::Isolate* isolate = CcTest::i_isolate();
18388 i::HandleScope scope(isolate);
18389 v8::Global<v8::Context> context[kNumTestContexts];
18390 v8::HeapStatistics heap_statistics;
18391 CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18392 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18393 CHECK_EQ(0u, heap_statistics.number_of_detached_contexts());
18394 for (size_t i = 0; i < kNumTestContexts; i++) {
18395 i::HandleScope inner(isolate);
18396 v8::Local<v8::Context> local = v8::Context::New(CcTest::isolate());
18397 context[i].Reset(CcTest::isolate(), local);
18398 local->DetachGlobal();
18399 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18400 CHECK_EQ(i + 1, heap_statistics.number_of_detached_contexts());
18401 }
18402 for (size_t i = 0; i < kNumTestContexts; i++) {
18403 context[i].Reset();
18404 CcTest::PreciseCollectAllGarbage();
18405 CcTest::isolate()->GetHeapStatistics(&heap_statistics);
18406 CHECK_EQ(kNumTestContexts - i - 1u,
18407 heap_statistics.number_of_detached_contexts());
18408 }
18409}
18410
18411class VisitorImpl : public v8::ExternalResourceVisitor {
18412 public:
18413 explicit VisitorImpl(TestResource** resource) {
18414 for (int i = 0; i < 4; i++) {
18415 resource_[i] = resource[i];
18416 found_resource_[i] = false;
18417 }
18418 }
18419 ~VisitorImpl() override = default;
18420 void VisitExternalString(v8::Local<v8::String> string) override {
18421 if (!string->IsExternal()) {
18422 CHECK(string->IsExternalOneByte());
18423 return;
18424 }
18425 v8::String::ExternalStringResource* resource =
18426 string->GetExternalStringResource();
18427 CHECK(resource);
18428 for (int i = 0; i < 4; i++) {
18429 if (resource_[i] == resource) {
18430 CHECK(!found_resource_[i]);
18431 found_resource_[i] = true;
18432 }
18433 }
18434 }
18435 void CheckVisitedResources() {
18436 for (int i = 0; i < 4; i++) {
18437 CHECK(found_resource_[i]);
18438 }
18439 }
18440
18441 private:
18442 v8::String::ExternalStringResource* resource_[4];
18443 bool found_resource_[4];
18444};
18445
18446
18447TEST(ExternalizeOldSpaceTwoByteCons) {
18448 v8::Isolate* isolate = CcTest::isolate();
18449 LocalContext env;
18450 v8::HandleScope scope(isolate);
18451 v8::Local<v8::String> cons =
18452 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18453 ->ToString(env.local())
18454 .ToLocalChecked();
18455 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18456 CcTest::CollectAllAvailableGarbage();
18457 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18458
18459 TestResource* resource = new TestResource(
18460 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18461 cons->MakeExternal(resource);
18462
18463 CHECK(cons->IsExternal());
18464 CHECK_EQ(resource, cons->GetExternalStringResource());
18465 String::Encoding encoding;
18466 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18467 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18468}
18469
18470
18471TEST(ExternalizeOldSpaceOneByteCons) {
18472 v8::Isolate* isolate = CcTest::isolate();
18473 LocalContext env;
18474 v8::HandleScope scope(isolate);
18475 v8::Local<v8::String> cons =
18476 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")
18477 ->ToString(env.local())
18478 .ToLocalChecked();
18479 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18480 CcTest::CollectAllAvailableGarbage();
18481 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
18482
18483 TestOneByteResource* resource =
18484 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18485 cons->MakeExternal(resource);
18486
18487 CHECK(cons->IsExternalOneByte());
18488 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18489 String::Encoding encoding;
18490 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18491 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18492}
18493
18494
18495TEST(VisitExternalStrings) {
18496 v8::Isolate* isolate = CcTest::isolate();
18497 LocalContext env;
18498 v8::HandleScope scope(isolate);
18499 const char* string = "Some string";
18500 uint16_t* two_byte_string = AsciiToTwoByteString(string);
18501 TestResource* resource[4];
18502 resource[0] = new TestResource(two_byte_string);
18503 v8::Local<v8::String> string0 =
18504 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[0])
18505 .ToLocalChecked();
18506 resource[1] = new TestResource(two_byte_string, nullptr, false);
18507 v8::Local<v8::String> string1 =
18508 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[1])
18509 .ToLocalChecked();
18510
18511 // Externalized symbol.
18512 resource[2] = new TestResource(two_byte_string, nullptr, false);
18513 v8::Local<v8::String> string2 =
18514 v8::String::NewFromUtf8(env->GetIsolate(), string,
18515 v8::NewStringType::kInternalized)
18516 .ToLocalChecked();
18517 CHECK(string2->MakeExternal(resource[2]));
18518
18519 // Symbolized External.
18520 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18521 v8::Local<v8::String> string3 =
18522 v8::String::NewExternalTwoByte(env->GetIsolate(), resource[3])
18523 .ToLocalChecked();
18524 CcTest::CollectAllAvailableGarbage(); // Tenure string.
18525 // Turn into a symbol.
18526 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18527 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18528 string3_i).is_null());
18529 CHECK(string3_i->IsInternalizedString());
18530
18531 // We need to add usages for string* to avoid warnings in GCC 4.7
18532 CHECK(string0->IsExternal());
18533 CHECK(string1->IsExternal());
18534 CHECK(string2->IsExternal());
18535 CHECK(string3->IsExternal());
18536
18537 VisitorImpl visitor(resource);
18538 isolate->VisitExternalResources(&visitor);
18539 visitor.CheckVisitedResources();
18540}
18541
18542
18543TEST(ExternalStringCollectedAtTearDown) {
18544 int destroyed = 0;
18545 v8::Isolate::CreateParams create_params;
18546 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18547 v8::Isolate* isolate = v8::Isolate::New(create_params);
18548 { v8::Isolate::Scope isolate_scope(isolate);
18549 v8::HandleScope handle_scope(isolate);
18550 const char* s = "One string to test them all, one string to find them.";
18551 TestOneByteResource* inscription =
18552 new TestOneByteResource(i::StrDup(s), &destroyed);
18553 v8::Local<v8::String> ring =
18554 v8::String::NewExternalOneByte(isolate, inscription).ToLocalChecked();
18555 // Ring is still alive. Orcs are roaming freely across our lands.
18556 CHECK_EQ(0, destroyed);
18557 USE(ring);
18558 }
18559
18560 isolate->Dispose();
18561 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18562 CHECK_EQ(1, destroyed);
18563}
18564
18565
18566TEST(ExternalInternalizedStringCollectedAtTearDown) {
18567 int destroyed = 0;
18568 v8::Isolate::CreateParams create_params;
18569 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18570 v8::Isolate* isolate = v8::Isolate::New(create_params);
18571 { v8::Isolate::Scope isolate_scope(isolate);
18572 LocalContext env(isolate);
18573 v8::HandleScope handle_scope(isolate);
18574 CompileRun("var ring = 'One string to test them all';");
18575 const char* s = "One string to test them all";
18576 TestOneByteResource* inscription =
18577 new TestOneByteResource(i::StrDup(s), &destroyed);
18578 v8::Local<v8::String> ring =
18579 CompileRun("ring")->ToString(env.local()).ToLocalChecked();
18580 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18581 ring->MakeExternal(inscription);
18582 // Ring is still alive. Orcs are roaming freely across our lands.
18583 CHECK_EQ(0, destroyed);
18584 USE(ring);
18585 }
18586
18587 isolate->Dispose();
18588 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18589 CHECK_EQ(1, destroyed);
18590}
18591
18592
18593TEST(ExternalInternalizedStringCollectedAtGC) {
18594 int destroyed = 0;
18595 { LocalContext env;
18596 v8::HandleScope handle_scope(env->GetIsolate());
18597 CompileRun("var ring = 'One string to test them all';");
18598 const char* s = "One string to test them all";
18599 TestOneByteResource* inscription =
18600 new TestOneByteResource(i::StrDup(s), &destroyed);
18601 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
18602 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18603 ring->MakeExternal(inscription);
18604 // Ring is still alive. Orcs are roaming freely across our lands.
18605 CHECK_EQ(0, destroyed);
18606 USE(ring);
18607 }
18608
18609 // Garbage collector deals swift blows to evil.
18610 CcTest::i_isolate()->compilation_cache()->Clear();
18611 CcTest::CollectAllAvailableGarbage();
18612
18613 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18614 CHECK_EQ(1, destroyed);
18615}
18616
18617
18618static double DoubleFromBits(uint64_t value) {
18619 double target;
18620 i::MemCopy(&target, &value, sizeof(target));
18621 return target;
18622}
18623
18624
18625static uint64_t DoubleToBits(double value) {
18626 uint64_t target;
18627 i::MemCopy(&target, &value, sizeof(target));
18628 return target;
18629}
18630
18631
18632static double DoubleToDateTime(double input) {
18633 double date_limit = 864e13;
18634 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18635 return std::numeric_limits<double>::quiet_NaN();
18636 }
18637 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18638}
18639
18640
18641// We don't have a consistent way to write 64-bit constants syntactically, so we
18642// split them into two 32-bit constants and combine them programmatically.
18643static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18644 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18645}
18646
18647
18648THREADED_TEST(QuietSignalingNaNs) {
18649 LocalContext context;
18650 v8::Isolate* isolate = context->GetIsolate();
18651 v8::HandleScope scope(isolate);
18652 v8::TryCatch try_catch(isolate);
18653
18654 // Special double values.
18655 double snan = DoubleFromBits(0x7FF00000, 0x00000001);
18656 double qnan = DoubleFromBits(0x7FF80000, 0x00000000);
18657 double infinity = DoubleFromBits(0x7FF00000, 0x00000000);
18658 double max_normal = DoubleFromBits(0x7FEFFFFF, 0xFFFFFFFFu);
18659 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18660 double max_denormal = DoubleFromBits(0x000FFFFF, 0xFFFFFFFFu);
18661 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18662
18663 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18664 // on either side of the epoch.
18665 double date_limit = 864e13;
18666
18667 double test_values[] = {
18668 snan,
18669 qnan,
18670 infinity,
18671 max_normal,
18672 date_limit + 1,
18673 date_limit,
18674 min_normal,
18675 max_denormal,
18676 min_denormal,
18677 0,
18678 -0,
18679 -min_denormal,
18680 -max_denormal,
18681 -min_normal,
18682 -date_limit,
18683 -date_limit - 1,
18684 -max_normal,
18685 -infinity,
18686 -qnan,
18687 -snan
18688 };
18689 int num_test_values = 20;
18690
18691 for (int i = 0; i < num_test_values; i++) {
18692 double test_value = test_values[i];
18693
18694 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18695 v8::Local<v8::Value> number = v8::Number::New(isolate, test_value);
18696 double stored_number = number->NumberValue(context.local()).FromJust();
18697 if (!std::isnan(test_value)) {
18698 CHECK_EQ(test_value, stored_number);
18699 } else {
18700 uint64_t stored_bits = DoubleToBits(stored_number);
18701 // Check if quiet nan (bits 51..62 all set).
18702#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18703 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18704 !defined(USE_SIMULATOR)
18705 // Most significant fraction bit for quiet nan is set to 0
18706 // on MIPS architecture. Allowed by IEEE-754.
18707 CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18708#else
18709 CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18710#endif
18711 }
18712
18713 // Check that Date::New preserves non-NaNs in the date range and
18714 // quiets SNaNs.
18715 v8::Local<v8::Value> date =
18716 v8::Date::New(context.local(), test_value).ToLocalChecked();
18717 double expected_stored_date = DoubleToDateTime(test_value);
18718 double stored_date = date->NumberValue(context.local()).FromJust();
18719 if (!std::isnan(expected_stored_date)) {
18720 CHECK_EQ(expected_stored_date, stored_date);
18721 } else {
18722 uint64_t stored_bits = DoubleToBits(stored_date);
18723 // Check if quiet nan (bits 51..62 all set).
18724#if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18725 !defined(_MIPS_ARCH_MIPS64R6) && !defined(_MIPS_ARCH_MIPS32R6) && \
18726 !defined(USE_SIMULATOR)
18727 // Most significant fraction bit for quiet nan is set to 0
18728 // on MIPS architecture. Allowed by IEEE-754.
18729 CHECK_EQ(0xFFE, static_cast<int>((stored_bits >> 51) & 0xFFF));
18730#else
18731 CHECK_EQ(0xFFF, static_cast<int>((stored_bits >> 51) & 0xFFF));
18732#endif
18733 }
18734 }
18735}
18736
18737
18738static void SpaghettiIncident(
18739 const v8::FunctionCallbackInfo<v8::Value>& args) {
18740 v8::HandleScope scope(args.GetIsolate());
18741 v8::TryCatch tc(args.GetIsolate());
18742 v8::MaybeLocal<v8::String> str(
18743 args[0]->ToString(args.GetIsolate()->GetCurrentContext()));
18744 USE(str);
18745 if (tc.HasCaught())
18746 tc.ReThrow();
18747}
18748
18749
18750// Test that an exception can be propagated down through a spaghetti
18751// stack using ReThrow.
18752THREADED_TEST(SpaghettiStackReThrow) {
18753 v8::Isolate* isolate = CcTest::isolate();
18754 v8::HandleScope scope(isolate);
18755 LocalContext context;
18756 context->Global()
18757 ->Set(context.local(), v8_str("s"),
18758 v8::FunctionTemplate::New(isolate, SpaghettiIncident)
18759 ->GetFunction(context.local())
18760 .ToLocalChecked())
18761 .FromJust();
18762 v8::TryCatch try_catch(isolate);
18763 CompileRun(
18764 "var i = 0;"
18765 "var o = {"
18766 " toString: function () {"
18767 " if (i == 10) {"
18768 " throw 'Hey!';"
18769 " } else {"
18770 " i++;"
18771 " return s(o);"
18772 " }"
18773 " }"
18774 "};"
18775 "s(o);");
18776 CHECK(try_catch.HasCaught());
18777 v8::String::Utf8Value value(isolate, try_catch.Exception());
18778 CHECK_EQ(0, strcmp(*value, "Hey!"));
18779}
18780
18781
18782TEST(Regress528) {
18783 ManualGCScope manual_gc_scope;
18784 v8::V8::Initialize();
18785 v8::Isolate* isolate = CcTest::isolate();
18786 i::FLAG_retain_maps_for_n_gc = 0;
18787 v8::HandleScope scope(isolate);
18788 v8::Local<Context> other_context;
18789 int gc_count;
18790
18791 // Create a context used to keep the code from aging in the compilation
18792 // cache.
18793 other_context = Context::New(isolate);
18794
18795 // Context-dependent context data creates reference from the compilation
18796 // cache to the global object.
18797 const char* source_simple = "1";
18798 {
18799 v8::HandleScope scope(isolate);
18800 v8::Local<Context> context = Context::New(isolate);
18801
18802 context->Enter();
18803 Local<v8::String> obj = v8_str("");
18804 context->SetEmbedderData(0, obj);
18805 CompileRun(source_simple);
18806 context->Exit();
18807 }
18808 isolate->ContextDisposedNotification();
18809 for (gc_count = 1; gc_count < 10; gc_count++) {
18810 other_context->Enter();
18811 CompileRun(source_simple);
18812 other_context->Exit();
18813 CcTest::CollectAllGarbage();
18814 if (GetGlobalObjectsCount() == 1) break;
18815 }
18816 CHECK_GE(2, gc_count);
18817 CHECK_EQ(1, GetGlobalObjectsCount());
18818
18819 // Eval in a function creates reference from the compilation cache to the
18820 // global object.
18821 const char* source_eval = "function f(){eval('1')}; f()";
18822 {
18823 v8::HandleScope scope(isolate);
18824 v8::Local<Context> context = Context::New(isolate);
18825
18826 context->Enter();
18827 CompileRun(source_eval);
18828 context->Exit();
18829 }
18830 isolate->ContextDisposedNotification();
18831 for (gc_count = 1; gc_count < 10; gc_count++) {
18832 other_context->Enter();
18833 CompileRun(source_eval);
18834 other_context->Exit();
18835 CcTest::CollectAllGarbage();
18836 if (GetGlobalObjectsCount() == 1) break;
18837 }
18838 CHECK_GE(2, gc_count);
18839 CHECK_EQ(1, GetGlobalObjectsCount());
18840
18841 // Looking up the line number for an exception creates reference from the
18842 // compilation cache to the global object.
18843 const char* source_exception = "function f(){throw 1;} f()";
18844 {
18845 v8::HandleScope scope(isolate);
18846 v8::Local<Context> context = Context::New(isolate);
18847
18848 context->Enter();
18849 v8::TryCatch try_catch(isolate);
18850 CompileRun(source_exception);
18851 CHECK(try_catch.HasCaught());
18852 v8::Local<v8::Message> message = try_catch.Message();
18853 CHECK(!message.IsEmpty());
18854 CHECK_EQ(1, message->GetLineNumber(context).FromJust());
18855 context->Exit();
18856 }
18857 isolate->ContextDisposedNotification();
18858 for (gc_count = 1; gc_count < 10; gc_count++) {
18859 other_context->Enter();
18860 CompileRun(source_exception);
18861 other_context->Exit();
18862 CcTest::CollectAllGarbage();
18863 if (GetGlobalObjectsCount() == 1) break;
18864 }
18865 CHECK_GE(2, gc_count);
18866 CHECK_EQ(1, GetGlobalObjectsCount());
18867
18868 isolate->ContextDisposedNotification();
18869}
18870
18871
18872THREADED_TEST(ScriptOrigin) {
18873 LocalContext env;
18874 v8::Isolate* isolate = env->GetIsolate();
18875 v8::HandleScope scope(isolate);
18876 Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 1));
18877 Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
18878 array->Set(isolate, 0, symbol);
18879
18880 v8::ScriptOrigin origin = v8::ScriptOrigin(
18881 v8_str("test"), v8::Integer::New(env->GetIsolate(), 1),
18882 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
18883 v8::Local<v8::Integer>(), v8_str("http://sourceMapUrl"),
18884 v8::True(env->GetIsolate()), v8::False(env->GetIsolate()),
18885 v8::False(env->GetIsolate()), array);
18886 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
18887 v8::Script::Compile(env.local(), script, &origin)
18888 .ToLocalChecked()
18889 ->Run(env.local())
18890 .ToLocalChecked();
18891 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18892 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18893 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18894 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
18895
18896 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18897 CHECK_EQ(0, strcmp("test",
18898 *v8::String::Utf8Value(env->GetIsolate(),
18899 script_origin_f.ResourceName())));
18900 CHECK_EQ(
18901 1,
18902 script_origin_f.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18903 CHECK(script_origin_f.Options().IsSharedCrossOrigin());
18904 CHECK(script_origin_f.Options().IsOpaque());
18905 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
18906 CHECK(script_origin_f.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18907
18908 CHECK_EQ(0, strcmp("http://sourceMapUrl",
18909 *v8::String::Utf8Value(env->GetIsolate(),
18910 script_origin_f.SourceMapUrl())));
18911
18912 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18913 CHECK_EQ(0, strcmp("test",
18914 *v8::String::Utf8Value(env->GetIsolate(),
18915 script_origin_g.ResourceName())));
18916 CHECK_EQ(
18917 1,
18918 script_origin_g.ResourceLineOffset()->Int32Value(env.local()).FromJust());
18919 CHECK(script_origin_g.Options().IsSharedCrossOrigin());
18920 CHECK(script_origin_g.Options().IsOpaque());
18921 CHECK_EQ(0, strcmp("http://sourceMapUrl",
18922 *v8::String::Utf8Value(env->GetIsolate(),
18923 script_origin_g.SourceMapUrl())));
18924 CHECK(script_origin_g.HostDefinedOptions()->Get(isolate, 0)->IsSymbol());
18925}
18926
18927
18928THREADED_TEST(FunctionGetInferredName) {
18929 LocalContext env;
18930 v8::HandleScope scope(env->GetIsolate());
18931 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18932 v8::Local<v8::String> script =
18933 v8_str("var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18934 v8::Script::Compile(env.local(), script, &origin)
18935 .ToLocalChecked()
18936 ->Run(env.local())
18937 .ToLocalChecked();
18938 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18939 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
18940 CHECK_EQ(0,
18941 strcmp("foo.bar.baz", *v8::String::Utf8Value(env->GetIsolate(),
18942 f->GetInferredName())));
18943}
18944
18945
18946THREADED_TEST(FunctionGetDebugName) {
18947 LocalContext env;
18948 v8::Isolate* isolate = env->GetIsolate();
18949 v8::HandleScope scope(isolate);
18950 const char* code =
18951 "var error = false;"
18952 "function a() { this.x = 1; };"
18953 "a.displayName = 'display_a';"
18954 "var b = (function() {"
18955 " var f = function() { this.x = 2; };"
18956 " f.displayName = 'display_b';"
18957 " return f;"
18958 "})();"
18959 "var c = function() {};"
18960 "c.__defineGetter__('displayName', function() {"
18961 " error = true;"
18962 " throw new Error();"
18963 "});"
18964 "function d() {};"
18965 "d.__defineGetter__('displayName', function() {"
18966 " error = true;"
18967 " return 'wrong_display_name';"
18968 "});"
18969 "function e() {};"
18970 "e.displayName = 'wrong_display_name';"
18971 "e.__defineSetter__('displayName', function() {"
18972 " error = true;"
18973 " throw new Error();"
18974 "});"
18975 "function f() {};"
18976 "f.displayName = { 'foo': 6, toString: function() {"
18977 " error = true;"
18978 " return 'wrong_display_name';"
18979 "}};"
18980 "var g = function() {"
18981 " arguments.callee.displayName = 'set_in_runtime';"
18982 "}; g();"
18983 "var h = function() {};"
18984 "h.displayName = 'displayName';"
18985 "Object.defineProperty(h, 'name', { value: 'function.name' });"
18986 "var i = function() {};"
18987 "i.displayName = 239;"
18988 "Object.defineProperty(i, 'name', { value: 'function.name' });"
18989 "var j = function() {};"
18990 "Object.defineProperty(j, 'name', { value: 'function.name' });"
18991 "var foo = { bar : { baz : (0, function() {})}}; var k = foo.bar.baz;"
18992 "var foo = { bar : { baz : function() {} }}; var l = foo.bar.baz;";
18993 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
18994 v8::Script::Compile(env.local(), v8_str(code), &origin)
18995 .ToLocalChecked()
18996 ->Run(env.local())
18997 .ToLocalChecked();
18998 v8::Local<v8::Value> error =
18999 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19000 CHECK(!error->BooleanValue(isolate));
19001 const char* functions[] = {"a", "display_a",
19002 "b", "display_b",
19003 "c", "c",
19004 "d", "d",
19005 "e", "e",
19006 "f", "f",
19007 "g", "set_in_runtime",
19008 "h", "displayName",
19009 "i", "function.name",
19010 "j", "function.name",
19011 "k", "foo.bar.baz",
19012 "l", "baz"};
19013 for (size_t i = 0; i < sizeof(functions) / sizeof(functions[0]) / 2; ++i) {
19014 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19015 env->Global()
19016 ->Get(env.local(),
19017 v8::String::NewFromUtf8(isolate, functions[i * 2],
19018 v8::NewStringType::kNormal)
19019 .ToLocalChecked())
19020 .ToLocalChecked());
19021 CHECK_EQ(0, strcmp(functions[i * 2 + 1],
19022 *v8::String::Utf8Value(isolate, f->GetDebugName())));
19023 }
19024}
19025
19026
19027THREADED_TEST(FunctionGetDisplayName) {
19028 LocalContext env;
19029 v8::Isolate* isolate = env->GetIsolate();
19030 v8::HandleScope scope(isolate);
19031 const char* code = "var error = false;"
19032 "function a() { this.x = 1; };"
19033 "a.displayName = 'display_a';"
19034 "var b = (function() {"
19035 " var f = function() { this.x = 2; };"
19036 " f.displayName = 'display_b';"
19037 " return f;"
19038 "})();"
19039 "var c = function() {};"
19040 "c.__defineGetter__('displayName', function() {"
19041 " error = true;"
19042 " throw new Error();"
19043 "});"
19044 "function d() {};"
19045 "d.__defineGetter__('displayName', function() {"
19046 " error = true;"
19047 " return 'wrong_display_name';"
19048 "});"
19049 "function e() {};"
19050 "e.displayName = 'wrong_display_name';"
19051 "e.__defineSetter__('displayName', function() {"
19052 " error = true;"
19053 " throw new Error();"
19054 "});"
19055 "function f() {};"
19056 "f.displayName = { 'foo': 6, toString: function() {"
19057 " error = true;"
19058 " return 'wrong_display_name';"
19059 "}};"
19060 "var g = function() {"
19061 " arguments.callee.displayName = 'set_in_runtime';"
19062 "}; g();";
19063 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19064 v8::Script::Compile(env.local(), v8_str(code), &origin)
19065 .ToLocalChecked()
19066 ->Run(env.local())
19067 .ToLocalChecked();
19068 v8::Local<v8::Value> error =
19069 env->Global()->Get(env.local(), v8_str("error")).ToLocalChecked();
19070 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19071 env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
19072 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19073 env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
19074 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19075 env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked());
19076 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19077 env->Global()->Get(env.local(), v8_str("d")).ToLocalChecked());
19078 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19079 env->Global()->Get(env.local(), v8_str("e")).ToLocalChecked());
19080 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19081 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19082 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19083 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19084 CHECK(!error->BooleanValue(isolate));
19085 CHECK_EQ(0, strcmp("display_a",
19086 *v8::String::Utf8Value(isolate, a->GetDisplayName())));
19087 CHECK_EQ(0, strcmp("display_b",
19088 *v8::String::Utf8Value(isolate, b->GetDisplayName())));
19089 CHECK(c->GetDisplayName()->IsUndefined());
19090 CHECK(d->GetDisplayName()->IsUndefined());
19091 CHECK(e->GetDisplayName()->IsUndefined());
19092 CHECK(f->GetDisplayName()->IsUndefined());
19093 CHECK_EQ(0, strcmp("set_in_runtime",
19094 *v8::String::Utf8Value(isolate, g->GetDisplayName())));
19095}
19096
19097
19098THREADED_TEST(ScriptLineNumber) {
19099 LocalContext env;
19100 v8::HandleScope scope(env->GetIsolate());
19101 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19102 v8::Local<v8::String> script = v8_str("function f() {}\n\nfunction g() {}");
19103 v8::Script::Compile(env.local(), script, &origin)
19104 .ToLocalChecked()
19105 ->Run(env.local())
19106 .ToLocalChecked();
19107 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19108 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19109 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19110 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19111 CHECK_EQ(0, f->GetScriptLineNumber());
19112 CHECK_EQ(2, g->GetScriptLineNumber());
19113}
19114
19115
19116THREADED_TEST(ScriptColumnNumber) {
19117 LocalContext env;
19118 v8::Isolate* isolate = env->GetIsolate();
19119 v8::HandleScope scope(isolate);
19120 v8::ScriptOrigin origin =
19121 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19122 v8::Integer::New(isolate, 2));
19123 v8::Local<v8::String> script =
19124 v8_str("function foo() {}\n\n function bar() {}");
19125 v8::Script::Compile(env.local(), script, &origin)
19126 .ToLocalChecked()
19127 ->Run(env.local())
19128 .ToLocalChecked();
19129 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19130 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19131 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19132 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19133 CHECK_EQ(14, foo->GetScriptColumnNumber());
19134 CHECK_EQ(17, bar->GetScriptColumnNumber());
19135}
19136
19137
19138THREADED_TEST(FunctionGetScriptId) {
19139 LocalContext env;
19140 v8::Isolate* isolate = env->GetIsolate();
19141 v8::HandleScope scope(isolate);
19142 v8::ScriptOrigin origin =
19143 v8::ScriptOrigin(v8_str("test"), v8::Integer::New(isolate, 3),
19144 v8::Integer::New(isolate, 2));
19145 v8::Local<v8::String> scriptSource =
19146 v8_str("function foo() {}\n\n function bar() {}");
19147 v8::Local<v8::Script> script(
19148 v8::Script::Compile(env.local(), scriptSource, &origin).ToLocalChecked());
19149 script->Run(env.local()).ToLocalChecked();
19150 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19151 env->Global()->Get(env.local(), v8_str("foo")).ToLocalChecked());
19152 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19153 env->Global()->Get(env.local(), v8_str("bar")).ToLocalChecked());
19154 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19155 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19156}
19157
19158
19159THREADED_TEST(FunctionGetBoundFunction) {
19160 LocalContext env;
19161 v8::HandleScope scope(env->GetIsolate());
19162 v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str("test"));
19163 v8::Local<v8::String> script = v8_str(
19164 "var a = new Object();\n"
19165 "a.x = 1;\n"
19166 "function f () { return this.x };\n"
19167 "var g = f.bind(a);\n"
19168 "var b = g();");
19169 v8::Script::Compile(env.local(), script, &origin)
19170 .ToLocalChecked()
19171 ->Run(env.local())
19172 .ToLocalChecked();
19173 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19174 env->Global()->Get(env.local(), v8_str("f")).ToLocalChecked());
19175 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19176 env->Global()->Get(env.local(), v8_str("g")).ToLocalChecked());
19177 CHECK(g->GetBoundFunction()->IsFunction());
19178 Local<v8::Function> original_function = Local<v8::Function>::Cast(
19179 g->GetBoundFunction());
19180 CHECK(f->GetName()
19181 ->Equals(env.local(), original_function->GetName())
19182 .FromJust());
19183 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19184 CHECK_EQ(f->GetScriptColumnNumber(),
19185 original_function->GetScriptColumnNumber());
19186}
19187
19188
19189static void GetterWhichReturns42(
19190 Local<String> name,
19191 const v8::PropertyCallbackInfo<v8::Value>& info) {
19192 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19193 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19194 info.GetReturnValue().Set(v8_num(42));
19195}
19196
19197
19198static void SetterWhichSetsYOnThisTo23(
19199 Local<String> name,
19200 Local<Value> value,
19201 const v8::PropertyCallbackInfo<void>& info) {
19202 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19203 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19204 Local<Object>::Cast(info.This())
19205 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19206 .FromJust();
19207}
19208
19209
19210void FooGetInterceptor(Local<Name> name,
19211 const v8::PropertyCallbackInfo<v8::Value>& info) {
19212 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19213 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19214 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19215 .FromJust()) {
19216 return;
19217 }
19218 info.GetReturnValue().Set(v8_num(42));
19219}
19220
19221
19222void FooSetInterceptor(Local<Name> name, Local<Value> value,
19223 const v8::PropertyCallbackInfo<v8::Value>& info) {
19224 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19225 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19226 if (!name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
19227 .FromJust()) {
19228 return;
19229 }
19230 Local<Object>::Cast(info.This())
19231 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19232 .FromJust();
19233 info.GetReturnValue().Set(v8_num(23));
19234}
19235
19236
19237TEST(SetterOnConstructorPrototype) {
19238 v8::Isolate* isolate = CcTest::isolate();
19239 v8::HandleScope scope(isolate);
19240 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19241 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19242 SetterWhichSetsYOnThisTo23);
19243 LocalContext context;
19244 CHECK(context->Global()
19245 ->Set(context.local(), v8_str("P"),
19246 templ->NewInstance(context.local()).ToLocalChecked())
19247 .FromJust());
19248 CompileRun("function C1() {"
19249 " this.x = 23;"
19250 "};"
19251 "C1.prototype = P;"
19252 "function C2() {"
19253 " this.x = 23"
19254 "};"
19255 "C2.prototype = { };"
19256 "C2.prototype.__proto__ = P;");
19257
19258 v8::Local<v8::Script> script;
19259 script = v8_compile("new C1();");
19260 for (int i = 0; i < 10; i++) {
19261 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19262 script->Run(context.local()).ToLocalChecked());
19263 CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19264 .ToLocalChecked()
19265 ->Int32Value(context.local())
19266 .FromJust());
19267 CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19268 .ToLocalChecked()
19269 ->Int32Value(context.local())
19270 .FromJust());
19271 }
19272
19273 script = v8_compile("new C2();");
19274 for (int i = 0; i < 10; i++) {
19275 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19276 script->Run(context.local()).ToLocalChecked());
19277 CHECK_EQ(42, c2->Get(context.local(), v8_str("x"))
19278 .ToLocalChecked()
19279 ->Int32Value(context.local())
19280 .FromJust());
19281 CHECK_EQ(23, c2->Get(context.local(), v8_str("y"))
19282 .ToLocalChecked()
19283 ->Int32Value(context.local())
19284 .FromJust());
19285 }
19286}
19287
19288
19289static void NamedPropertySetterWhichSetsYOnThisTo23(
19290 Local<Name> name, Local<Value> value,
19291 const v8::PropertyCallbackInfo<v8::Value>& info) {
19292 if (name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("x"))
19293 .FromJust()) {
19294 Local<Object>::Cast(info.This())
19295 ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(23))
19296 .FromJust();
19297 }
19298}
19299
19300
19301THREADED_TEST(InterceptorOnConstructorPrototype) {
19302 v8::Isolate* isolate = CcTest::isolate();
19303 v8::HandleScope scope(isolate);
19304 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19305 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19306 NamedPropertyGetterWhichReturns42,
19307 NamedPropertySetterWhichSetsYOnThisTo23));
19308 LocalContext context;
19309 CHECK(context->Global()
19310 ->Set(context.local(), v8_str("P"),
19311 templ->NewInstance(context.local()).ToLocalChecked())
19312 .FromJust());
19313 CompileRun("function C1() {"
19314 " this.x = 23;"
19315 "};"
19316 "C1.prototype = P;"
19317 "function C2() {"
19318 " this.x = 23"
19319 "};"
19320 "C2.prototype = { };"
19321 "C2.prototype.__proto__ = P;");
19322
19323 v8::Local<v8::Script> script;
19324 script = v8_compile("new C1();");
19325 for (int i = 0; i < 10; i++) {
19326 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19327 script->Run(context.local()).ToLocalChecked());
19328 CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19329 .ToLocalChecked()
19330 ->Int32Value(context.local())
19331 .FromJust());
19332 CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19333 .ToLocalChecked()
19334 ->Int32Value(context.local())
19335 .FromJust());
19336 }
19337
19338 script = v8_compile("new C2();");
19339 for (int i = 0; i < 10; i++) {
19340 v8::Local<v8::Object> c2 = v8::Local<v8::Object>::Cast(
19341 script->Run(context.local()).ToLocalChecked());
19342 CHECK_EQ(23, c2->Get(context.local(), v8_str("x"))
19343 .ToLocalChecked()
19344 ->Int32Value(context.local())
19345 .FromJust());
19346 CHECK_EQ(42, c2->Get(context.local(), v8_str("y"))
19347 .ToLocalChecked()
19348 ->Int32Value(context.local())
19349 .FromJust());
19350 }
19351}
19352
19353
19354TEST(Regress618) {
19355 const char* source = "function C1() {"
19356 " this.x = 23;"
19357 "};"
19358 "C1.prototype = P;";
19359
19360 LocalContext context;
19361 v8::Isolate* isolate = context->GetIsolate();
19362 v8::HandleScope scope(isolate);
19363 v8::Local<v8::Script> script;
19364
19365 // Use a simple object as prototype.
19366 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19367 prototype->Set(context.local(), v8_str("y"), v8_num(42)).FromJust();
19368 CHECK(context->Global()
19369 ->Set(context.local(), v8_str("P"), prototype)
19370 .FromJust());
19371
19372 // This compile will add the code to the compilation cache.
19373 CompileRun(source);
19374
19375 script = v8_compile("new C1();");
19376 // Allow enough iterations for the inobject slack tracking logic
19377 // to finalize instance size and install the fast construct stub.
19378 for (int i = 0; i < 256; i++) {
19379 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19380 script->Run(context.local()).ToLocalChecked());
19381 CHECK_EQ(23, c1->Get(context.local(), v8_str("x"))
19382 .ToLocalChecked()
19383 ->Int32Value(context.local())
19384 .FromJust());
19385 CHECK_EQ(42, c1->Get(context.local(), v8_str("y"))
19386 .ToLocalChecked()
19387 ->Int32Value(context.local())
19388 .FromJust());
19389 }
19390
19391 // Use an API object with accessors as prototype.
19392 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19393 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19394 SetterWhichSetsYOnThisTo23);
19395 CHECK(context->Global()
19396 ->Set(context.local(), v8_str("P"),
19397 templ->NewInstance(context.local()).ToLocalChecked())
19398 .FromJust());
19399
19400 // This compile will get the code from the compilation cache.
19401 CompileRun(source);
19402
19403 script = v8_compile("new C1();");
19404 for (int i = 0; i < 10; i++) {
19405 v8::Local<v8::Object> c1 = v8::Local<v8::Object>::Cast(
19406 script->Run(context.local()).ToLocalChecked());
19407 CHECK_EQ(42, c1->Get(context.local(), v8_str("x"))
19408 .ToLocalChecked()
19409 ->Int32Value(context.local())
19410 .FromJust());
19411 CHECK_EQ(23, c1->Get(context.local(), v8_str("y"))
19412 .ToLocalChecked()
19413 ->Int32Value(context.local())
19414 .FromJust());
19415 }
19416}
19417
19418v8::Isolate* gc_callbacks_isolate = nullptr;
19419int prologue_call_count = 0;
19420int epilogue_call_count = 0;
19421int prologue_call_count_second = 0;
19422int epilogue_call_count_second = 0;
19423int prologue_call_count_alloc = 0;
19424int epilogue_call_count_alloc = 0;
19425
19426void PrologueCallback(v8::Isolate* isolate,
19427 v8::GCType,
19428 v8::GCCallbackFlags flags) {
19429 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19430 CHECK_EQ(gc_callbacks_isolate, isolate);
19431 ++prologue_call_count;
19432}
19433
19434void EpilogueCallback(v8::Isolate* isolate,
19435 v8::GCType,
19436 v8::GCCallbackFlags flags) {
19437 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19438 CHECK_EQ(gc_callbacks_isolate, isolate);
19439 ++epilogue_call_count;
19440}
19441
19442
19443void PrologueCallbackSecond(v8::Isolate* isolate,
19444 v8::GCType,
19445 v8::GCCallbackFlags flags) {
19446 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19447 CHECK_EQ(gc_callbacks_isolate, isolate);
19448 ++prologue_call_count_second;
19449}
19450
19451
19452void EpilogueCallbackSecond(v8::Isolate* isolate,
19453 v8::GCType,
19454 v8::GCCallbackFlags flags) {
19455 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19456 CHECK_EQ(gc_callbacks_isolate, isolate);
19457 ++epilogue_call_count_second;
19458}
19459
19460void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
19461 v8::GCCallbackFlags flags, void* data) {
19462 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19463 CHECK_EQ(gc_callbacks_isolate, isolate);
19464 ++*static_cast<int*>(data);
19465}
19466
19467void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
19468 v8::GCCallbackFlags flags, void* data) {
19469 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19470 CHECK_EQ(gc_callbacks_isolate, isolate);
19471 ++*static_cast<int*>(data);
19472}
19473
19474void PrologueCallbackAlloc(v8::Isolate* isolate,
19475 v8::GCType,
19476 v8::GCCallbackFlags flags) {
19477 v8::HandleScope scope(isolate);
19478
19479 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19480 CHECK_EQ(gc_callbacks_isolate, isolate);
19481 ++prologue_call_count_alloc;
19482
19483 // Simulate full heap to see if we will reenter this callback
19484 i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19485
19486 Local<Object> obj = Object::New(isolate);
19487 CHECK(!obj.IsEmpty());
19488
19489 CcTest::PreciseCollectAllGarbage();
19490}
19491
19492
19493void EpilogueCallbackAlloc(v8::Isolate* isolate,
19494 v8::GCType,
19495 v8::GCCallbackFlags flags) {
19496 v8::HandleScope scope(isolate);
19497
19498 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19499 CHECK_EQ(gc_callbacks_isolate, isolate);
19500 ++epilogue_call_count_alloc;
19501
19502 // Simulate full heap to see if we will reenter this callback
19503 i::heap::SimulateFullSpace(CcTest::heap()->new_space());
19504
19505 Local<Object> obj = Object::New(isolate);
19506 CHECK(!obj.IsEmpty());
19507
19508 CcTest::PreciseCollectAllGarbage();
19509}
19510
19511
19512TEST(GCCallbacksOld) {
19513 LocalContext context;
19514
19515 gc_callbacks_isolate = context->GetIsolate();
19516
19517 context->GetIsolate()->AddGCPrologueCallback(PrologueCallback);
19518 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallback);
19519 CHECK_EQ(0, prologue_call_count);
19520 CHECK_EQ(0, epilogue_call_count);
19521 CcTest::CollectAllGarbage();
19522 CHECK_EQ(1, prologue_call_count);
19523 CHECK_EQ(1, epilogue_call_count);
19524 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackSecond);
19525 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackSecond);
19526 CcTest::CollectAllGarbage();
19527 CHECK_EQ(2, prologue_call_count);
19528 CHECK_EQ(2, epilogue_call_count);
19529 CHECK_EQ(1, prologue_call_count_second);
19530 CHECK_EQ(1, epilogue_call_count_second);
19531 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallback);
19532 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallback);
19533 CcTest::CollectAllGarbage();
19534 CHECK_EQ(2, prologue_call_count);
19535 CHECK_EQ(2, epilogue_call_count);
19536 CHECK_EQ(2, prologue_call_count_second);
19537 CHECK_EQ(2, epilogue_call_count_second);
19538 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackSecond);
19539 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19540 CcTest::CollectAllGarbage();
19541 CHECK_EQ(2, prologue_call_count);
19542 CHECK_EQ(2, epilogue_call_count);
19543 CHECK_EQ(2, prologue_call_count_second);
19544 CHECK_EQ(2, epilogue_call_count_second);
19545}
19546
19547TEST(GCCallbacksWithData) {
19548 LocalContext context;
19549
19550 gc_callbacks_isolate = context->GetIsolate();
19551 int prologue1 = 0;
19552 int epilogue1 = 0;
19553 int prologue2 = 0;
19554 int epilogue2 = 0;
19555
19556 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
19557 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
19558 CHECK_EQ(0, prologue1);
19559 CHECK_EQ(0, epilogue1);
19560 CHECK_EQ(0, prologue2);
19561 CHECK_EQ(0, epilogue2);
19562 CcTest::CollectAllGarbage();
19563 CHECK_EQ(1, prologue1);
19564 CHECK_EQ(1, epilogue1);
19565 CHECK_EQ(0, prologue2);
19566 CHECK_EQ(0, epilogue2);
19567 context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
19568 context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
19569 CcTest::CollectAllGarbage();
19570 CHECK_EQ(2, prologue1);
19571 CHECK_EQ(2, epilogue1);
19572 CHECK_EQ(1, prologue2);
19573 CHECK_EQ(1, epilogue2);
19574 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19575 &prologue1);
19576 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19577 &epilogue1);
19578 CcTest::CollectAllGarbage();
19579 CHECK_EQ(2, prologue1);
19580 CHECK_EQ(2, epilogue1);
19581 CHECK_EQ(2, prologue2);
19582 CHECK_EQ(2, epilogue2);
19583 context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
19584 &prologue2);
19585 context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
19586 &epilogue2);
19587 CcTest::CollectAllGarbage();
19588 CHECK_EQ(2, prologue1);
19589 CHECK_EQ(2, epilogue1);
19590 CHECK_EQ(2, prologue2);
19591 CHECK_EQ(2, epilogue2);
19592}
19593
19594TEST(GCCallbacks) {
19595 LocalContext context;
19596 v8::Isolate* isolate = context->GetIsolate();
19597 gc_callbacks_isolate = isolate;
19598 isolate->AddGCPrologueCallback(PrologueCallback);
19599 isolate->AddGCEpilogueCallback(EpilogueCallback);
19600 CHECK_EQ(0, prologue_call_count);
19601 CHECK_EQ(0, epilogue_call_count);
19602 CcTest::CollectAllGarbage();
19603 CHECK_EQ(1, prologue_call_count);
19604 CHECK_EQ(1, epilogue_call_count);
19605 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19606 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19607 CcTest::CollectAllGarbage();
19608 CHECK_EQ(2, prologue_call_count);
19609 CHECK_EQ(2, epilogue_call_count);
19610 CHECK_EQ(1, prologue_call_count_second);
19611 CHECK_EQ(1, epilogue_call_count_second);
19612 isolate->RemoveGCPrologueCallback(PrologueCallback);
19613 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19614 CcTest::CollectAllGarbage();
19615 CHECK_EQ(2, prologue_call_count);
19616 CHECK_EQ(2, epilogue_call_count);
19617 CHECK_EQ(2, prologue_call_count_second);
19618 CHECK_EQ(2, epilogue_call_count_second);
19619 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19620 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19621 CcTest::CollectAllGarbage();
19622 CHECK_EQ(2, prologue_call_count);
19623 CHECK_EQ(2, epilogue_call_count);
19624 CHECK_EQ(2, prologue_call_count_second);
19625 CHECK_EQ(2, epilogue_call_count_second);
19626
19627 CHECK_EQ(0, prologue_call_count_alloc);
19628 CHECK_EQ(0, epilogue_call_count_alloc);
19629 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19630 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19631 CcTest::PreciseCollectAllGarbage();
19632 CHECK_EQ(1, prologue_call_count_alloc);
19633 CHECK_EQ(1, epilogue_call_count_alloc);
19634 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19635 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19636}
19637
19638
19639THREADED_TEST(TwoByteStringInOneByteCons) {
19640 // See Chromium issue 47824.
19641 LocalContext context;
19642 v8::HandleScope scope(context->GetIsolate());
19643
19644 const char* init_code =
19645 "var str1 = 'abelspendabel';"
19646 "var str2 = str1 + str1 + str1;"
19647 "str2;";
19648 Local<Value> result = CompileRun(init_code);
19649
19650 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19651 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19652
19653 CHECK(result->IsString());
19654 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19655 int length = string->length();
19656 CHECK(string->IsOneByteRepresentation());
19657
19658 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
19659 i::Handle<i::String> flat_string = i::String::Flatten(i_isolate, string);
19660
19661 CHECK(string->IsOneByteRepresentation());
19662 CHECK(flat_string->IsOneByteRepresentation());
19663
19664 // Create external resource.
19665 uint16_t* uc16_buffer = new uint16_t[length + 1];
19666
19667 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19668 uc16_buffer[length] = 0;
19669
19670 TestResource resource(uc16_buffer);
19671
19672 flat_string->MakeExternal(&resource);
19673
19674 CHECK(flat_string->IsTwoByteRepresentation());
19675
19676 // If the cons string has been short-circuited, skip the following checks.
19677 if (!string.is_identical_to(flat_string)) {
19678 // At this point, we should have a Cons string which is flat and one-byte,
19679 // with a first half that is a two-byte string (although it only contains
19680 // one-byte characters). This is a valid sequence of steps, and it can
19681 // happen in real pages.
19682 CHECK(string->IsOneByteRepresentation());
19683 i::ConsString cons = i::ConsString::cast(*string);
19684 CHECK_EQ(0, cons->second()->length());
19685 CHECK(cons->first()->IsTwoByteRepresentation());
19686 }
19687
19688 // Check that some string operations work.
19689
19690 // Atom RegExp.
19691 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19692 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19693
19694 // Nonatom RegExp.
19695 reresult = CompileRun("str2.match(/abe./g).length;");
19696 CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
19697
19698 reresult = CompileRun("str2.search(/bel/g);");
19699 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19700
19701 reresult = CompileRun("str2.search(/be./g);");
19702 CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
19703
19704 ExpectTrue("/bel/g.test(str2);");
19705
19706 ExpectTrue("/be./g.test(str2);");
19707
19708 reresult = CompileRun("/bel/g.exec(str2);");
19709 CHECK(!reresult->IsNull());
19710
19711 reresult = CompileRun("/be./g.exec(str2);");
19712 CHECK(!reresult->IsNull());
19713
19714 ExpectString("str2.substring(2, 10);", "elspenda");
19715
19716 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19717
19718 ExpectString("str2.charAt(2);", "e");
19719
19720 ExpectObject("str2.indexOf('els');", indexof);
19721
19722 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19723
19724 reresult = CompileRun("str2.charCodeAt(2);");
19725 CHECK_EQ(static_cast<int32_t>('e'),
19726 reresult->Int32Value(context.local()).FromJust());
19727 // This avoids the GC from trying to free stack allocated resources.
19728 i::Handle<i::ExternalTwoByteString>::cast(flat_string)
19729 ->SetResource(i_isolate, nullptr);
19730}
19731
19732
19733TEST(ContainsOnlyOneByte) {
19734 v8::V8::Initialize();
19735 v8::Isolate* isolate = CcTest::isolate();
19736 v8::HandleScope scope(isolate);
19737 // Make a buffer long enough that it won't automatically be converted.
19738 const int length = 512;
19739 // Ensure word aligned assignment.
19740 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19741 std::unique_ptr<uintptr_t[]> aligned_contents(new uintptr_t[aligned_length]);
19742 uint16_t* string_contents =
19743 reinterpret_cast<uint16_t*>(aligned_contents.get());
19744 // Set to contain only one byte.
19745 for (int i = 0; i < length-1; i++) {
19746 string_contents[i] = 0x41;
19747 }
19748 string_contents[length-1] = 0;
19749 // Simple case.
19750 Local<String> string =
19751 String::NewExternalTwoByte(
19752 isolate, new TestResource(string_contents, nullptr, false))
19753 .ToLocalChecked();
19754 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19755 // Counter example.
19756 string = String::NewFromTwoByte(isolate, string_contents,
19757 v8::NewStringType::kNormal)
19758 .ToLocalChecked();
19759 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19760 // Test left right and balanced cons strings.
19761 Local<String> base = v8_str("a");
19762 Local<String> left = base;
19763 Local<String> right = base;
19764 for (int i = 0; i < 1000; i++) {
19765 left = String::Concat(isolate, base, left);
19766 right = String::Concat(isolate, right, base);
19767 }
19768 Local<String> balanced = String::Concat(isolate, left, base);
19769 balanced = String::Concat(isolate, balanced, right);
19770 Local<String> cons_strings[] = {left, balanced, right};
19771 Local<String> two_byte =
19772 String::NewExternalTwoByte(
19773 isolate, new TestResource(string_contents, nullptr, false))
19774 .ToLocalChecked();
19775 USE(two_byte); USE(cons_strings);
19776 for (size_t i = 0; i < arraysize(cons_strings); i++) {
19777 // Base assumptions.
19778 string = cons_strings[i];
19779 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19780 // Test left and right concatentation.
19781 string = String::Concat(isolate, two_byte, cons_strings[i]);
19782 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19783 string = String::Concat(isolate, cons_strings[i], two_byte);
19784 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19785 }
19786 // Set bits in different positions
19787 // for strings of different lengths and alignments.
19788 for (int alignment = 0; alignment < 7; alignment++) {
19789 for (int size = 2; alignment + size < length; size *= 2) {
19790 int zero_offset = size + alignment;
19791 string_contents[zero_offset] = 0;
19792 for (int i = 0; i < size; i++) {
19793 int shift = 8 + (i % 7);
19794 string_contents[alignment + i] = 1 << shift;
19795 string = String::NewExternalTwoByte(
19796 isolate, new TestResource(string_contents + alignment,
19797 nullptr, false))
19798 .ToLocalChecked();
19799 CHECK_EQ(size, string->Length());
19800 CHECK(!string->ContainsOnlyOneByte());
19801 string_contents[alignment + i] = 0x41;
19802 }
19803 string_contents[zero_offset] = 0x41;
19804 }
19805 }
19806}
19807
19808
19809// Failed access check callback that performs a GC on each invocation.
19810void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19811 v8::AccessType type,
19812 Local<v8::Value> data) {
19813 CcTest::CollectAllGarbage();
19814 CcTest::isolate()->ThrowException(
19815 v8::Exception::Error(v8_str("cross context")));
19816}
19817
19818
19819TEST(GCInFailedAccessCheckCallback) {
19820 // Install a failed access check callback that performs a GC on each
19821 // invocation. Then force the callback to be called from va
19822
19823 v8::V8::Initialize();
19824 v8::Isolate* isolate = CcTest::isolate();
19825
19826 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19827
19828 v8::HandleScope scope(isolate);
19829
19830 // Create an ObjectTemplate for global objects and install access
19831 // check callbacks that will block access.
19832 v8::Local<v8::ObjectTemplate> global_template =
19833 v8::ObjectTemplate::New(isolate);
19834 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
19835
19836 // Create a context and set an x property on it's global object.
19837 LocalContext context0(nullptr, global_template);
19838 CHECK(context0->Global()
19839 ->Set(context0.local(), v8_str("x"), v8_num(42))
19840 .FromJust());
19841 v8::Local<v8::Object> global0 = context0->Global();
19842
19843 // Create a context with a different security token so that the
19844 // failed access check callback will be called on each access.
19845 LocalContext context1(nullptr, global_template);
19846 CHECK(context1->Global()
19847 ->Set(context1.local(), v8_str("other"), global0)
19848 .FromJust());
19849
19850 v8::TryCatch try_catch(isolate);
19851
19852 // Get property with failed access check.
19853 CHECK(CompileRun("other.x").IsEmpty());
19854 CHECK(try_catch.HasCaught());
19855 try_catch.Reset();
19856
19857 // Get element with failed access check.
19858 CHECK(CompileRun("other[0]").IsEmpty());
19859 CHECK(try_catch.HasCaught());
19860 try_catch.Reset();
19861
19862 // Set property with failed access check.
19863 CHECK(CompileRun("other.x = new Object()").IsEmpty());
19864 CHECK(try_catch.HasCaught());
19865 try_catch.Reset();
19866
19867 // Set element with failed access check.
19868 CHECK(CompileRun("other[0] = new Object()").IsEmpty());
19869 CHECK(try_catch.HasCaught());
19870 try_catch.Reset();
19871
19872 // Get property attribute with failed access check.
19873 CHECK(CompileRun("\'x\' in other").IsEmpty());
19874 CHECK(try_catch.HasCaught());
19875 try_catch.Reset();
19876
19877 // Get property attribute for element with failed access check.
19878 CHECK(CompileRun("0 in other").IsEmpty());
19879 CHECK(try_catch.HasCaught());
19880 try_catch.Reset();
19881
19882 // Delete property.
19883 CHECK(CompileRun("delete other.x").IsEmpty());
19884 CHECK(try_catch.HasCaught());
19885 try_catch.Reset();
19886
19887 // Delete element.
19888 CHECK(global0->Delete(context1.local(), 0).IsNothing());
19889 CHECK(try_catch.HasCaught());
19890 try_catch.Reset();
19891
19892 // DefineAccessor.
19893 CHECK(global0
19894 ->SetAccessor(context1.local(), v8_str("x"), GetXValue, nullptr,
19895 v8_str("x"))
19896 .IsNothing());
19897 CHECK(try_catch.HasCaught());
19898 try_catch.Reset();
19899
19900 // Define JavaScript accessor.
19901 CHECK(CompileRun(
19902 "Object.prototype.__defineGetter__.call("
19903 " other, \'x\', function() { return 42; })").IsEmpty());
19904 CHECK(try_catch.HasCaught());
19905 try_catch.Reset();
19906
19907 // LookupAccessor.
19908 CHECK(CompileRun(
19909 "Object.prototype.__lookupGetter__.call("
19910 " other, \'x\')").IsEmpty());
19911 CHECK(try_catch.HasCaught());
19912 try_catch.Reset();
19913
19914 // HasOwnElement.
19915 CHECK(CompileRun(
19916 "Object.prototype.hasOwnProperty.call("
19917 "other, \'0\')").IsEmpty());
19918 CHECK(try_catch.HasCaught());
19919 try_catch.Reset();
19920
19921 CHECK(global0->HasRealIndexedProperty(context1.local(), 0).IsNothing());
19922 CHECK(try_catch.HasCaught());
19923 try_catch.Reset();
19924
19925 CHECK(
19926 global0->HasRealNamedProperty(context1.local(), v8_str("x")).IsNothing());
19927 CHECK(try_catch.HasCaught());
19928 try_catch.Reset();
19929
19930 CHECK(global0->HasRealNamedCallbackProperty(context1.local(), v8_str("x"))
19931 .IsNothing());
19932 CHECK(try_catch.HasCaught());
19933 try_catch.Reset();
19934
19935 // Reset the failed access check callback so it does not influence
19936 // the other tests.
19937 isolate->SetFailedAccessCheckCallbackFunction(nullptr);
19938}
19939
19940
19941TEST(IsolateNewDispose) {
19942 v8::Isolate* current_isolate = CcTest::isolate();
19943 v8::Isolate::CreateParams create_params;
19944 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19945 v8::Isolate* isolate = v8::Isolate::New(create_params);
19946 CHECK_NOT_NULL(isolate);
19947 CHECK(current_isolate != isolate);
19948 CHECK(current_isolate == CcTest::isolate());
19949 CHECK(isolate->GetArrayBufferAllocator() == CcTest::array_buffer_allocator());
19950
19951 isolate->SetFatalErrorHandler(StoringErrorCallback);
19952 last_location = last_message = nullptr;
19953 isolate->Dispose();
19954 CHECK(!last_location);
19955 CHECK(!last_message);
19956}
19957
19958
19959UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19960 v8::Isolate::CreateParams create_params;
19961 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19962 v8::Isolate* isolate = v8::Isolate::New(create_params);
19963 {
19964 v8::Isolate::Scope i_scope(isolate);
19965 v8::HandleScope scope(isolate);
19966 LocalContext context(isolate);
19967 // Run something in this isolate.
19968 ExpectTrue("true");
19969 isolate->SetFatalErrorHandler(StoringErrorCallback);
19970 last_location = last_message = nullptr;
19971 // Still entered, should fail.
19972 isolate->Dispose();
19973 CHECK(last_location);
19974 CHECK(last_message);
19975 }
19976 isolate->Dispose();
19977}
19978
19979
19980static void BreakArrayGuarantees(const char* script) {
19981 v8::Isolate::CreateParams create_params;
19982 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
19983 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
19984 isolate1->Enter();
19985 v8::Persistent<v8::Context> context1;
19986 {
19987 v8::HandleScope scope(isolate1);
19988 context1.Reset(isolate1, Context::New(isolate1));
19989 }
19990
19991 {
19992 v8::HandleScope scope(isolate1);
19993 v8::Local<v8::Context> context =
19994 v8::Local<v8::Context>::New(isolate1, context1);
19995 v8::Context::Scope context_scope(context);
19996 v8::internal::Isolate* i_isolate =
19997 reinterpret_cast<v8::internal::Isolate*>(isolate1);
19998 CHECK(i_isolate->IsNoElementsProtectorIntact());
19999 // Run something in new isolate.
20000 CompileRun(script);
20001 CHECK(!i_isolate->IsNoElementsProtectorIntact());
20002 }
20003 isolate1->Exit();
20004 isolate1->Dispose();
20005}
20006
20007
20008TEST(VerifyArrayPrototypeGuarantees) {
20009 // Break fast array hole handling by element changes.
20010 BreakArrayGuarantees("[].__proto__[1] = 3;");
20011 BreakArrayGuarantees("Object.prototype[3] = 'three';");
20012 BreakArrayGuarantees("Array.prototype.push(1);");
20013 BreakArrayGuarantees("Array.prototype.unshift(1);");
20014 // Break fast array hole handling by changing length.
20015 BreakArrayGuarantees("Array.prototype.length = 30;");
20016 // Break fast array hole handling by prototype structure changes.
20017 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
20018 // By sending elements to dictionary mode.
20019 BreakArrayGuarantees(
20020 "Object.defineProperty(Array.prototype, 0, {"
20021 " get: function() { return 3; }});");
20022 BreakArrayGuarantees(
20023 "Object.defineProperty(Object.prototype, 0, {"
20024 " get: function() { return 3; }});");
20025}
20026
20027
20028TEST(RunTwoIsolatesOnSingleThread) {
20029 // Run isolate 1.
20030 v8::Isolate::CreateParams create_params;
20031 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20032 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
20033 isolate1->Enter();
20034 v8::Persistent<v8::Context> context1;
20035 {
20036 v8::HandleScope scope(isolate1);
20037 context1.Reset(isolate1, Context::New(isolate1));
20038 }
20039
20040 {
20041 v8::HandleScope scope(isolate1);
20042 v8::Local<v8::Context> context =
20043 v8::Local<v8::Context>::New(isolate1, context1);
20044 v8::Context::Scope context_scope(context);
20045 // Run something in new isolate.
20046 CompileRun("var foo = 'isolate 1';");
20047 ExpectString("function f() { return foo; }; f()", "isolate 1");
20048 }
20049
20050 // Run isolate 2.
20051 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
20052 v8::Persistent<v8::Context> context2;
20053
20054 {
20055 v8::Isolate::Scope iscope(isolate2);
20056 v8::HandleScope scope(isolate2);
20057 context2.Reset(isolate2, Context::New(isolate2));
20058 v8::Local<v8::Context> context =
20059 v8::Local<v8::Context>::New(isolate2, context2);
20060 v8::Context::Scope context_scope(context);
20061
20062 // Run something in new isolate.
20063 CompileRun("var foo = 'isolate 2';");
20064 ExpectString("function f() { return foo; }; f()", "isolate 2");
20065 }
20066
20067 {
20068 v8::HandleScope scope(isolate1);
20069 v8::Local<v8::Context> context =
20070 v8::Local<v8::Context>::New(isolate1, context1);
20071 v8::Context::Scope context_scope(context);
20072 // Now again in isolate 1
20073 ExpectString("function f() { return foo; }; f()", "isolate 1");
20074 }
20075
20076 isolate1->Exit();
20077
20078 // Run some stuff in default isolate.
20079 v8::Persistent<v8::Context> context_default;
20080 {
20081 v8::Isolate* isolate = CcTest::isolate();
20082 v8::Isolate::Scope iscope(isolate);
20083 v8::HandleScope scope(isolate);
20084 context_default.Reset(isolate, Context::New(isolate));
20085 }
20086
20087 {
20088 v8::HandleScope scope(CcTest::isolate());
20089 v8::Local<v8::Context> context =
20090 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20091 v8::Context::Scope context_scope(context);
20092 // Variables in other isolates should be not available, verify there
20093 // is an exception.
20094 ExpectTrue("function f() {"
20095 " try {"
20096 " foo;"
20097 " return false;"
20098 " } catch(e) {"
20099 " return true;"
20100 " }"
20101 "};"
20102 "var isDefaultIsolate = true;"
20103 "f()");
20104 }
20105
20106 isolate1->Enter();
20107
20108 {
20109 v8::Isolate::Scope iscope(isolate2);
20110 v8::HandleScope scope(isolate2);
20111 v8::Local<v8::Context> context =
20112 v8::Local<v8::Context>::New(isolate2, context2);
20113 v8::Context::Scope context_scope(context);
20114 ExpectString("function f() { return foo; }; f()", "isolate 2");
20115 }
20116
20117 {
20118 v8::HandleScope scope(v8::Isolate::GetCurrent());
20119 v8::Local<v8::Context> context =
20120 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20121 v8::Context::Scope context_scope(context);
20122 ExpectString("function f() { return foo; }; f()", "isolate 1");
20123 }
20124
20125 {
20126 v8::Isolate::Scope iscope(isolate2);
20127 context2.Reset();
20128 }
20129
20130 context1.Reset();
20131 isolate1->Exit();
20132
20133 isolate2->SetFatalErrorHandler(StoringErrorCallback);
20134 last_location = last_message = nullptr;
20135
20136 isolate1->Dispose();
20137 CHECK(!last_location);
20138 CHECK(!last_message);
20139
20140 isolate2->Dispose();
20141 CHECK(!last_location);
20142 CHECK(!last_message);
20143
20144 // Check that default isolate still runs.
20145 {
20146 v8::HandleScope scope(CcTest::isolate());
20147 v8::Local<v8::Context> context =
20148 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20149 v8::Context::Scope context_scope(context);
20150 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20151 }
20152}
20153
20154
20155static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20156 v8::Isolate::Scope isolate_scope(isolate);
20157 v8::HandleScope scope(isolate);
20158 LocalContext context(isolate);
20159 i::ScopedVector<char> code(1024);
20160 i::SNPrintF(code, "function fib(n) {"
20161 " if (n <= 2) return 1;"
20162 " return fib(n-1) + fib(n-2);"
20163 "}"
20164 "fib(%d)", limit);
20165 Local<Value> value = CompileRun(code.start());
20166 CHECK(value->IsNumber());
20167 return static_cast<int>(value->NumberValue(context.local()).FromJust());
20168}
20169
20170class IsolateThread : public v8::base::Thread {
20171 public:
20172 explicit IsolateThread(int fib_limit)
20173 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20174
20175 void Run() override {
20176 v8::Isolate::CreateParams create_params;
20177 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20178 v8::Isolate* isolate = v8::Isolate::New(create_params);
20179 result_ = CalcFibonacci(isolate, fib_limit_);
20180 isolate->Dispose();
20181 }
20182
20183 int result() { return result_; }
20184
20185 private:
20186 int fib_limit_;
20187 int result_;
20188};
20189
20190
20191TEST(MultipleIsolatesOnIndividualThreads) {
20192 IsolateThread thread1(21);
20193 IsolateThread thread2(12);
20194
20195 // Compute some fibonacci numbers on 3 threads in 3 isolates.
20196 thread1.Start();
20197 thread2.Start();
20198
20199 int result1 = CalcFibonacci(CcTest::isolate(), 21);
20200 int result2 = CalcFibonacci(CcTest::isolate(), 12);
20201
20202 thread1.Join();
20203 thread2.Join();
20204
20205 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20206 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20207 CHECK_EQ(result1, 10946);
20208 CHECK_EQ(result2, 144);
20209 CHECK_EQ(result1, thread1.result());
20210 CHECK_EQ(result2, thread2.result());
20211}
20212
20213
20214TEST(IsolateDifferentContexts) {
20215 v8::Isolate::CreateParams create_params;
20216 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20217 v8::Isolate* isolate = v8::Isolate::New(create_params);
20218 Local<v8::Context> context;
20219 {
20220 v8::Isolate::Scope isolate_scope(isolate);
20221 v8::HandleScope handle_scope(isolate);
20222 context = v8::Context::New(isolate);
20223 v8::Context::Scope context_scope(context);
20224 Local<Value> v = CompileRun("2");
20225 CHECK(v->IsNumber());
20226 CHECK_EQ(2, static_cast<int>(v->NumberValue(context).FromJust()));
20227 }
20228 {
20229 v8::Isolate::Scope isolate_scope(isolate);
20230 v8::HandleScope handle_scope(isolate);
20231 context = v8::Context::New(isolate);
20232 v8::Context::Scope context_scope(context);
20233 Local<Value> v = CompileRun("22");
20234 CHECK(v->IsNumber());
20235 CHECK_EQ(22, static_cast<int>(v->NumberValue(context).FromJust()));
20236 }
20237 isolate->Dispose();
20238}
20239
20240class InitDefaultIsolateThread : public v8::base::Thread {
20241 public:
20242 enum TestCase {
20243 SetFatalHandler,
20244 SetCounterFunction,
20245 SetCreateHistogramFunction,
20246 SetAddHistogramSampleFunction
20247 };
20248
20249 explicit InitDefaultIsolateThread(TestCase testCase)
20250 : Thread(Options("InitDefaultIsolateThread")),
20251 testCase_(testCase),
20252 result_(false) {}
20253
20254 void Run() override {
20255 v8::Isolate::CreateParams create_params;
20256 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
20257 v8::Isolate* isolate = v8::Isolate::New(create_params);
20258 isolate->Enter();
20259 switch (testCase_) {
20260 case SetFatalHandler:
20261 isolate->SetFatalErrorHandler(nullptr);
20262 break;
20263
20264 case SetCounterFunction:
20265 CcTest::isolate()->SetCounterFunction(nullptr);
20266 break;
20267
20268 case SetCreateHistogramFunction:
20269 CcTest::isolate()->SetCreateHistogramFunction(nullptr);
20270 break;
20271
20272 case SetAddHistogramSampleFunction:
20273 CcTest::isolate()->SetAddHistogramSampleFunction(nullptr);
20274 break;
20275 }
20276 isolate->Exit();
20277 isolate->Dispose();
20278 result_ = true;
20279 }
20280
20281 bool result() { return result_; }
20282
20283 private:
20284 TestCase testCase_;
20285 bool result_;
20286};
20287
20288
20289static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20290 InitDefaultIsolateThread thread(testCase);
20291 thread.Start();
20292 thread.Join();
20293 CHECK(thread.result());
20294}
20295
20296TEST(InitializeDefaultIsolateOnSecondaryThread_FatalHandler) {
20297 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20298}
20299
20300TEST(InitializeDefaultIsolateOnSecondaryThread_CounterFunction) {
20301 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20302}
20303
20304TEST(InitializeDefaultIsolateOnSecondaryThread_CreateHistogramFunction) {
20305 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20306}
20307
20308TEST(InitializeDefaultIsolateOnSecondaryThread_AddHistogramSampleFunction) {
20309 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20310}
20311
20312
20313TEST(StringCheckMultipleContexts) {
20314 const char* code =
20315 "(function() { return \"a\".charAt(0); })()";
20316
20317 {
20318 // Run the code twice in the first context to initialize the call IC.
20319 LocalContext context1;
20320 v8::HandleScope scope(context1->GetIsolate());
20321 ExpectString(code, "a");
20322 ExpectString(code, "a");
20323 }
20324
20325 {
20326 // Change the String.prototype in the second context and check
20327 // that the right function gets called.
20328 LocalContext context2;
20329 v8::HandleScope scope(context2->GetIsolate());
20330 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20331 ExpectString(code, "not a");
20332 }
20333}
20334
20335
20336TEST(NumberCheckMultipleContexts) {
20337 const char* code =
20338 "(function() { return (42).toString(); })()";
20339
20340 {
20341 // Run the code twice in the first context to initialize the call IC.
20342 LocalContext context1;
20343 v8::HandleScope scope(context1->GetIsolate());
20344 ExpectString(code, "42");
20345 ExpectString(code, "42");
20346 }
20347
20348 {
20349 // Change the Number.prototype in the second context and check
20350 // that the right function gets called.
20351 LocalContext context2;
20352 v8::HandleScope scope(context2->GetIsolate());
20353 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20354 ExpectString(code, "not 42");
20355 }
20356}
20357
20358
20359TEST(BooleanCheckMultipleContexts) {
20360 const char* code =
20361 "(function() { return true.toString(); })()";
20362
20363 {
20364 // Run the code twice in the first context to initialize the call IC.
20365 LocalContext context1;
20366 v8::HandleScope scope(context1->GetIsolate());
20367 ExpectString(code, "true");
20368 ExpectString(code, "true");
20369 }
20370
20371 {
20372 // Change the Boolean.prototype in the second context and check
20373 // that the right function gets called.
20374 LocalContext context2;
20375 v8::HandleScope scope(context2->GetIsolate());
20376 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20377 ExpectString(code, "");
20378 }
20379}
20380
20381
20382TEST(DontDeleteCellLoadIC) {
20383 const char* function_code =
20384 "function readCell() { while (true) { return cell; } }";
20385
20386 {
20387 // Run the code twice in the first context to initialize the load
20388 // IC for a don't delete cell.
20389 LocalContext context1;
20390 v8::HandleScope scope(context1->GetIsolate());
20391 CompileRun("var cell = \"first\";");
20392 ExpectBoolean("delete cell", false);
20393 CompileRun(function_code);
20394 ExpectString("readCell()", "first");
20395 ExpectString("readCell()", "first");
20396 }
20397
20398 {
20399 // Use a deletable cell in the second context.
20400 LocalContext context2;
20401 v8::HandleScope scope(context2->GetIsolate());
20402 CompileRun("cell = \"second\";");
20403 CompileRun(function_code);
20404 ExpectString("readCell()", "second");
20405 ExpectBoolean("delete cell", true);
20406 ExpectString("(function() {"
20407 " try {"
20408 " return readCell();"
20409 " } catch(e) {"
20410 " return e.toString();"
20411 " }"
20412 "})()",
20413 "ReferenceError: cell is not defined");
20414 CompileRun("cell = \"new_second\";");
20415 CcTest::CollectAllGarbage();
20416 ExpectString("readCell()", "new_second");
20417 ExpectString("readCell()", "new_second");
20418 }
20419}
20420
20421
20422class Visitor42 : public v8::PersistentHandleVisitor {
20423 public:
20424 explicit Visitor42(v8::Persistent<v8::Object>* object)
20425 : counter_(0), object_(object) { }
20426
20427 void VisitPersistentHandle(Persistent<Value>* value,
20428 uint16_t class_id) override {
20429 if (class_id != 42) return;
20430 CHECK_EQ(42, value->WrapperClassId());
20431 v8::Isolate* isolate = CcTest::isolate();
20432 v8::HandleScope handle_scope(isolate);
20433 v8::Local<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20434 v8::Local<v8::Value> object = v8::Local<v8::Object>::New(isolate, *object_);
20435 CHECK(handle->IsObject());
20436 CHECK(Local<Object>::Cast(handle)
20437 ->Equals(isolate->GetCurrentContext(), object)
20438 .FromJust());
20439 ++counter_;
20440 }
20441
20442 int counter_;
20443 v8::Persistent<v8::Object>* object_;
20444};
20445
20446
20447TEST(PersistentHandleVisitor) {
20448 LocalContext context;
20449 v8::Isolate* isolate = context->GetIsolate();
20450 v8::HandleScope scope(isolate);
20451 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20452 CHECK_EQ(0, object.WrapperClassId());
20453 object.SetWrapperClassId(42);
20454 CHECK_EQ(42, object.WrapperClassId());
20455
20456 Visitor42 visitor(&object);
20457 isolate->VisitHandlesWithClassIds(&visitor);
20458 CHECK_EQ(1, visitor.counter_);
20459
20460 object.Reset();
20461}
20462
20463
20464TEST(WrapperClassId) {
20465 LocalContext context;
20466 v8::Isolate* isolate = context->GetIsolate();
20467 v8::HandleScope scope(isolate);
20468 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20469 CHECK_EQ(0, object.WrapperClassId());
20470 object.SetWrapperClassId(65535);
20471 CHECK_EQ(65535, object.WrapperClassId());
20472 object.Reset();
20473}
20474
20475TEST(RegExp) {
20476 LocalContext context;
20477 v8::HandleScope scope(context->GetIsolate());
20478
20479 v8::Local<v8::RegExp> re =
20480 v8::RegExp::New(context.local(), v8_str("foo"), v8::RegExp::kNone)
20481 .ToLocalChecked();
20482 CHECK(re->IsRegExp());
20483 CHECK(re->GetSource()->Equals(context.local(), v8_str("foo")).FromJust());
20484 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20485
20486 re = v8::RegExp::New(context.local(), v8_str("bar"),
20487 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20488 v8::RegExp::kGlobal))
20489 .ToLocalChecked();
20490 CHECK(re->IsRegExp());
20491 CHECK(re->GetSource()->Equals(context.local(), v8_str("bar")).FromJust());
20492 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20493 static_cast<int>(re->GetFlags()));
20494
20495 re = v8::RegExp::New(context.local(), v8_str("baz"),
20496 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20497 v8::RegExp::kMultiline))
20498 .ToLocalChecked();
20499 CHECK(re->IsRegExp());
20500 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20501 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20502 static_cast<int>(re->GetFlags()));
20503
20504 re = v8::RegExp::New(context.local(), v8_str("baz"),
20505 static_cast<v8::RegExp::Flags>(v8::RegExp::kUnicode |
20506 v8::RegExp::kSticky))
20507 .ToLocalChecked();
20508 CHECK(re->IsRegExp());
20509 CHECK(re->GetSource()->Equals(context.local(), v8_str("baz")).FromJust());
20510 CHECK_EQ(v8::RegExp::kUnicode | v8::RegExp::kSticky,
20511 static_cast<int>(re->GetFlags()));
20512
20513 re = CompileRun("/quux/").As<v8::RegExp>();
20514 CHECK(re->IsRegExp());
20515 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20516 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20517
20518 re = CompileRun("/quux/gm").As<v8::RegExp>();
20519 CHECK(re->IsRegExp());
20520 CHECK(re->GetSource()->Equals(context.local(), v8_str("quux")).FromJust());
20521 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20522 static_cast<int>(re->GetFlags()));
20523
20524 // Override the RegExp constructor and check the API constructor
20525 // still works.
20526 CompileRun("RegExp = function() {}");
20527
20528 re = v8::RegExp::New(context.local(), v8_str("foobar"), v8::RegExp::kNone)
20529 .ToLocalChecked();
20530 CHECK(re->IsRegExp());
20531 CHECK(re->GetSource()->Equals(context.local(), v8_str("foobar")).FromJust());
20532 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20533
20534 re = v8::RegExp::New(context.local(), v8_str("foobarbaz"),
20535 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20536 v8::RegExp::kMultiline))
20537 .ToLocalChecked();
20538 CHECK(re->IsRegExp());
20539 CHECK(
20540 re->GetSource()->Equals(context.local(), v8_str("foobarbaz")).FromJust());
20541 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20542 static_cast<int>(re->GetFlags()));
20543
20544 CHECK(context->Global()->Set(context.local(), v8_str("re"), re).FromJust());
20545 ExpectTrue("re.test('FoobarbaZ')");
20546
20547 // RegExps are objects on which you can set properties.
20548 re->Set(context.local(), v8_str("property"),
20549 v8::Integer::New(context->GetIsolate(), 32))
20550 .FromJust();
20551 v8::Local<v8::Value> value(CompileRun("re.property"));
20552 CHECK_EQ(32, value->Int32Value(context.local()).FromJust());
20553
20554 v8::TryCatch try_catch(context->GetIsolate());
20555 CHECK(v8::RegExp::New(context.local(), v8_str("foo["), v8::RegExp::kNone)
20556 .IsEmpty());
20557 CHECK(try_catch.HasCaught());
20558 CHECK(context->Global()
20559 ->Set(context.local(), v8_str("ex"), try_catch.Exception())
20560 .FromJust());
20561 ExpectTrue("ex instanceof SyntaxError");
20562}
20563
20564
20565THREADED_TEST(Equals) {
20566 LocalContext localContext;
20567 v8::HandleScope handleScope(localContext->GetIsolate());
20568
20569 v8::Local<v8::Object> globalProxy = localContext->Global();
20570 v8::Local<Value> global = globalProxy->GetPrototype();
20571
20572 CHECK(global->StrictEquals(global));
20573 CHECK(!global->StrictEquals(globalProxy));
20574 CHECK(!globalProxy->StrictEquals(global));
20575 CHECK(globalProxy->StrictEquals(globalProxy));
20576
20577 CHECK(global->Equals(localContext.local(), global).FromJust());
20578 CHECK(!global->Equals(localContext.local(), globalProxy).FromJust());
20579 CHECK(!globalProxy->Equals(localContext.local(), global).FromJust());
20580 CHECK(globalProxy->Equals(localContext.local(), globalProxy).FromJust());
20581}
20582
20583
20584static void Getter(v8::Local<v8::Name> property,
20585 const v8::PropertyCallbackInfo<v8::Value>& info) {
20586 info.GetReturnValue().Set(v8_str("42!"));
20587}
20588
20589
20590static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20591 v8::Local<v8::Array> result = v8::Array::New(info.GetIsolate());
20592 result->Set(info.GetIsolate()->GetCurrentContext(), 0,
20593 v8_str("universalAnswer"))
20594 .FromJust();
20595 info.GetReturnValue().Set(result);
20596}
20597
20598
20599TEST(NamedEnumeratorAndForIn) {
20600 LocalContext context;
20601 v8::Isolate* isolate = context->GetIsolate();
20602 v8::HandleScope handle_scope(isolate);
20603 v8::Context::Scope context_scope(context.local());
20604
20605 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20606 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
20607 Getter, nullptr, nullptr, nullptr, Enumerator));
20608 CHECK(context->Global()
20609 ->Set(context.local(), v8_str("o"),
20610 tmpl->NewInstance(context.local()).ToLocalChecked())
20611 .FromJust());
20612 v8::Local<v8::Array> result = v8::Local<v8::Array>::Cast(
20613 CompileRun("var result = []; for (var k in o) result.push(k); result"));
20614 CHECK_EQ(1u, result->Length());
20615 CHECK(v8_str("universalAnswer")
20616 ->Equals(context.local(),
20617 result->Get(context.local(), 0).ToLocalChecked())
20618 .FromJust());
20619}
20620
20621
20622TEST(DefinePropertyPostDetach) {
20623 LocalContext context;
20624 v8::HandleScope scope(context->GetIsolate());
20625 v8::Local<v8::Object> proxy = context->Global();
20626 v8::Local<v8::Function> define_property =
20627 CompileRun(
20628 "(function() {"
20629 " Object.defineProperty("
20630 " this,"
20631 " 1,"
20632 " { configurable: true, enumerable: true, value: 3 });"
20633 "})")
20634 .As<Function>();
20635 context->DetachGlobal();
20636 CHECK(define_property->Call(context.local(), proxy, 0, nullptr).IsEmpty());
20637}
20638
20639
20640static void InstallContextId(v8::Local<Context> context, int id) {
20641 Context::Scope scope(context);
20642 CHECK(CompileRun("Object.prototype")
20643 .As<Object>()
20644 ->Set(context, v8_str("context_id"),
20645 v8::Integer::New(context->GetIsolate(), id))
20646 .FromJust());
20647}
20648
20649
20650static void CheckContextId(v8::Local<Object> object, int expected) {
20651 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20652 CHECK_EQ(expected, object->Get(context, v8_str("context_id"))
20653 .ToLocalChecked()
20654 ->Int32Value(context)
20655 .FromJust());
20656}
20657
20658
20659THREADED_TEST(CreationContext) {
20660 v8::Isolate* isolate = CcTest::isolate();
20661 HandleScope handle_scope(isolate);
20662 Local<Context> context1 = Context::New(isolate);
20663 InstallContextId(context1, 1);
20664 Local<Context> context2 = Context::New(isolate);
20665 InstallContextId(context2, 2);
20666 Local<Context> context3 = Context::New(isolate);
20667 InstallContextId(context3, 3);
20668
20669 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20670
20671 Local<Object> object1;
20672 Local<Function> func1;
20673 {
20674 Context::Scope scope(context1);
20675 object1 = Object::New(isolate);
20676 func1 = tmpl->GetFunction(context1).ToLocalChecked();
20677 }
20678
20679 Local<Object> object2;
20680 Local<Function> func2;
20681 {
20682 Context::Scope scope(context2);
20683 object2 = Object::New(isolate);
20684 func2 = tmpl->GetFunction(context2).ToLocalChecked();
20685 }
20686
20687 Local<Object> instance1;
20688 Local<Object> instance2;
20689
20690 {
20691 Context::Scope scope(context3);
20692 instance1 = func1->NewInstance(context3).ToLocalChecked();
20693 instance2 = func2->NewInstance(context3).ToLocalChecked();
20694 }
20695
20696 {
20697 Local<Context> other_context = Context::New(isolate);
20698 Context::Scope scope(other_context);
20699 CHECK(object1->CreationContext() == context1);
20700 CheckContextId(object1, 1);
20701 CHECK(func1->CreationContext() == context1);
20702 CheckContextId(func1, 1);
20703 CHECK(instance1->CreationContext() == context1);
20704 CheckContextId(instance1, 1);
20705 CHECK(object2->CreationContext() == context2);
20706 CheckContextId(object2, 2);
20707 CHECK(func2->CreationContext() == context2);
20708 CheckContextId(func2, 2);
20709 CHECK(instance2->CreationContext() == context2);
20710 CheckContextId(instance2, 2);
20711 }
20712
20713 {
20714 Context::Scope scope(context1);
20715 CHECK(object1->CreationContext() == context1);
20716 CheckContextId(object1, 1);
20717 CHECK(func1->CreationContext() == context1);
20718 CheckContextId(func1, 1);
20719 CHECK(instance1->CreationContext() == context1);
20720 CheckContextId(instance1, 1);
20721 CHECK(object2->CreationContext() == context2);
20722 CheckContextId(object2, 2);
20723 CHECK(func2->CreationContext() == context2);
20724 CheckContextId(func2, 2);
20725 CHECK(instance2->CreationContext() == context2);
20726 CheckContextId(instance2, 2);
20727 }
20728
20729 {
20730 Context::Scope scope(context2);
20731 CHECK(object1->CreationContext() == context1);
20732 CheckContextId(object1, 1);
20733 CHECK(func1->CreationContext() == context1);
20734 CheckContextId(func1, 1);
20735 CHECK(instance1->CreationContext() == context1);
20736 CheckContextId(instance1, 1);
20737 CHECK(object2->CreationContext() == context2);
20738 CheckContextId(object2, 2);
20739 CHECK(func2->CreationContext() == context2);
20740 CheckContextId(func2, 2);
20741 CHECK(instance2->CreationContext() == context2);
20742 CheckContextId(instance2, 2);
20743 }
20744}
20745
20746
20747THREADED_TEST(CreationContextOfJsFunction) {
20748 HandleScope handle_scope(CcTest::isolate());
20749 Local<Context> context = Context::New(CcTest::isolate());
20750 InstallContextId(context, 1);
20751
20752 Local<Object> function;
20753 {
20754 Context::Scope scope(context);
20755 function = CompileRun("function foo() {}; foo").As<Object>();
20756 }
20757
20758 Local<Context> other_context = Context::New(CcTest::isolate());
20759 Context::Scope scope(other_context);
20760 CHECK(function->CreationContext() == context);
20761 CheckContextId(function, 1);
20762}
20763
20764
20765THREADED_TEST(CreationContextOfJsBoundFunction) {
20766 HandleScope handle_scope(CcTest::isolate());
20767 Local<Context> context1 = Context::New(CcTest::isolate());
20768 InstallContextId(context1, 1);
20769 Local<Context> context2 = Context::New(CcTest::isolate());
20770 InstallContextId(context2, 2);
20771
20772 Local<Function> target_function;
20773 {
20774 Context::Scope scope(context1);
20775 target_function = CompileRun("function foo() {}; foo").As<Function>();
20776 }
20777
20778 Local<Function> bound_function1, bound_function2;
20779 {
20780 Context::Scope scope(context2);
20781 CHECK(context2->Global()
20782 ->Set(context2, v8_str("foo"), target_function)
20783 .FromJust());
20784 bound_function1 = CompileRun("foo.bind(1)").As<Function>();
20785 bound_function2 =
20786 CompileRun("Function.prototype.bind.call(foo, 2)").As<Function>();
20787 }
20788
20789 Local<Context> other_context = Context::New(CcTest::isolate());
20790 Context::Scope scope(other_context);
20791 CHECK(bound_function1->CreationContext() == context1);
20792 CheckContextId(bound_function1, 1);
20793 CHECK(bound_function2->CreationContext() == context1);
20794 CheckContextId(bound_function2, 1);
20795}
20796
20797
20798void HasOwnPropertyIndexedPropertyGetter(
20799 uint32_t index,
20800 const v8::PropertyCallbackInfo<v8::Value>& info) {
20801 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20802}
20803
20804
20805void HasOwnPropertyNamedPropertyGetter(
20806 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20807 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20808 .FromJust()) {
20809 info.GetReturnValue().Set(v8_str("yes"));
20810 }
20811}
20812
20813
20814void HasOwnPropertyIndexedPropertyQuery(
20815 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20816 if (index == 42) info.GetReturnValue().Set(1);
20817}
20818
20819
20820void HasOwnPropertyNamedPropertyQuery(
20821 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20822 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
20823 .FromJust()) {
20824 info.GetReturnValue().Set(1);
20825 }
20826}
20827
20828
20829void HasOwnPropertyNamedPropertyQuery2(
20830 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20831 if (property->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("bar"))
20832 .FromJust()) {
20833 info.GetReturnValue().Set(1);
20834 }
20835}
20836
20837void HasOwnPropertyAccessorGetter(
20838 Local<String> property,
20839 const v8::PropertyCallbackInfo<v8::Value>& info) {
20840 info.GetReturnValue().Set(v8_str("yes"));
20841}
20842
20843void HasOwnPropertyAccessorNameGetter(
20844 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
20845 info.GetReturnValue().Set(v8_str("yes"));
20846}
20847
20848TEST(HasOwnProperty) {
20849 LocalContext env;
20850 v8::Isolate* isolate = env->GetIsolate();
20851 v8::HandleScope scope(isolate);
20852 { // Check normal properties and defined getters.
20853 Local<Value> value = CompileRun(
20854 "function Foo() {"
20855 " this.foo = 11;"
20856 " this.__defineGetter__('baz', function() { return 1; });"
20857 "};"
20858 "function Bar() { "
20859 " this.bar = 13;"
20860 " this.__defineGetter__('bla', function() { return 2; });"
20861 "};"
20862 "Bar.prototype = new Foo();"
20863 "new Bar();");
20864 CHECK(value->IsObject());
20865 Local<Object> object = value->ToObject(env.local()).ToLocalChecked();
20866 CHECK(object->Has(env.local(), v8_str("foo")).FromJust());
20867 CHECK(!object->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20868 CHECK(object->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20869 CHECK(object->Has(env.local(), v8_str("baz")).FromJust());
20870 CHECK(!object->HasOwnProperty(env.local(), v8_str("baz")).FromJust());
20871 CHECK(object->HasOwnProperty(env.local(), v8_str("bla")).FromJust());
20872 }
20873 { // Check named getter interceptors.
20874 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20875 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20876 HasOwnPropertyNamedPropertyGetter));
20877 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20878 CHECK(!instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20879 CHECK(!instance->HasOwnProperty(env.local(), 42).FromJust());
20880 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20881 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20882 }
20883 { // Check indexed getter interceptors.
20884 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20885 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20886 HasOwnPropertyIndexedPropertyGetter));
20887 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20888 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20889 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20890 CHECK(!instance->HasOwnProperty(env.local(), v8_str("43")).FromJust());
20891 CHECK(!instance->HasOwnProperty(env.local(), 43).FromJust());
20892 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20893 }
20894 { // Check named query interceptors.
20895 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20896 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20897 nullptr, nullptr, HasOwnPropertyNamedPropertyQuery));
20898 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20899 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20900 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20901 }
20902 { // Check indexed query interceptors.
20903 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20904 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20905 nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
20906 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20907 CHECK(instance->HasOwnProperty(env.local(), v8_str("42")).FromJust());
20908 CHECK(instance->HasOwnProperty(env.local(), 42).FromJust());
20909 CHECK(!instance->HasOwnProperty(env.local(), v8_str("41")).FromJust());
20910 CHECK(!instance->HasOwnProperty(env.local(), 41).FromJust());
20911 }
20912 { // Check callbacks.
20913 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20914 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20915 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20916 CHECK(instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20917 CHECK(!instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20918 }
20919 { // Check that query wins on disagreement.
20920 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20921 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20922 HasOwnPropertyNamedPropertyGetter, nullptr,
20923 HasOwnPropertyNamedPropertyQuery2));
20924 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20925 CHECK(!instance->HasOwnProperty(env.local(), v8_str("foo")).FromJust());
20926 CHECK(instance->HasOwnProperty(env.local(), v8_str("bar")).FromJust());
20927 }
20928 { // Check that non-internalized keys are handled correctly.
20929 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20930 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
20931 HasOwnPropertyAccessorNameGetter));
20932 Local<Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
20933 env->Global()->Set(env.local(), v8_str("obj"), instance).FromJust();
20934 const char* src =
20935 "var dyn_string = 'this string ';"
20936 "dyn_string += 'does not exist elsewhere';"
20937 "({}).hasOwnProperty.call(obj, dyn_string)";
20938 CHECK(CompileRun(src)->BooleanValue(isolate));
20939 }
20940}
20941
20942
20943TEST(IndexedInterceptorWithStringProto) {
20944 v8::Isolate* isolate = CcTest::isolate();
20945 v8::HandleScope scope(isolate);
20946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20947 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
20948 nullptr, nullptr, HasOwnPropertyIndexedPropertyQuery));
20949 LocalContext context;
20950 CHECK(context->Global()
20951 ->Set(context.local(), v8_str("obj"),
20952 templ->NewInstance(context.local()).ToLocalChecked())
20953 .FromJust());
20954 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20955 // These should be intercepted.
20956 CHECK(CompileRun("42 in obj")->BooleanValue(isolate));
20957 CHECK(CompileRun("'42' in obj")->BooleanValue(isolate));
20958 // These should fall through to the String prototype.
20959 CHECK(CompileRun("0 in obj")->BooleanValue(isolate));
20960 CHECK(CompileRun("'0' in obj")->BooleanValue(isolate));
20961 // And these should both fail.
20962 CHECK(!CompileRun("32 in obj")->BooleanValue(isolate));
20963 CHECK(!CompileRun("'32' in obj")->BooleanValue(isolate));
20964}
20965
20966
20967void CheckCodeGenerationAllowed() {
20968 Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
20969 Local<Value> result = CompileRun("eval('42')");
20970 CHECK_EQ(42, result->Int32Value(context).FromJust());
20971 result = CompileRun("(function(e) { return e('42'); })(eval)");
20972 CHECK_EQ(42, result->Int32Value(context).FromJust());
20973 result = CompileRun("var f = new Function('return 42'); f()");
20974 CHECK_EQ(42, result->Int32Value(context).FromJust());
20975}
20976
20977
20978void CheckCodeGenerationDisallowed() {
20979 TryCatch try_catch(CcTest::isolate());
20980
20981 Local<Value> result = CompileRun("eval('42')");
20982 CHECK(result.IsEmpty());
20983 CHECK(try_catch.HasCaught());
20984 try_catch.Reset();
20985
20986 result = CompileRun("(function(e) { return e('42'); })(eval)");
20987 CHECK(result.IsEmpty());
20988 CHECK(try_catch.HasCaught());
20989 try_catch.Reset();
20990
20991 result = CompileRun("var f = new Function('return 42'); f()");
20992 CHECK(result.IsEmpty());
20993 CHECK(try_catch.HasCaught());
20994}
20995
20996char first_fourty_bytes[41];
20997
20998bool CodeGenerationAllowed(Local<Context> context, Local<String> source) {
20999 String::Utf8Value str(CcTest::isolate(), source);
21000 size_t len = std::min(sizeof(first_fourty_bytes) - 1,
21001 static_cast<size_t>(str.length()));
21002 strncpy(first_fourty_bytes, *str, len);
21003 first_fourty_bytes[len] = 0;
21004 ApiTestFuzzer::Fuzz();
21005 return true;
21006}
21007
21008bool CodeGenerationDisallowed(Local<Context> context, Local<String> source) {
21009 ApiTestFuzzer::Fuzz();
21010 return false;
21011}
21012
21013
21014THREADED_TEST(AllowCodeGenFromStrings) {
21015 LocalContext context;
21016 v8::HandleScope scope(context->GetIsolate());
21017
21018 // eval and the Function constructor allowed by default.
21019 CHECK(context->IsCodeGenerationFromStringsAllowed());
21020 CheckCodeGenerationAllowed();
21021
21022 // Disallow eval and the Function constructor.
21023 context->AllowCodeGenerationFromStrings(false);
21024 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21025 CheckCodeGenerationDisallowed();
21026
21027 // Allow again.
21028 context->AllowCodeGenerationFromStrings(true);
21029 CheckCodeGenerationAllowed();
21030
21031 // Disallow but setting a global callback that will allow the calls.
21032 context->AllowCodeGenerationFromStrings(false);
21033 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21034 &CodeGenerationAllowed);
21035 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21036 CheckCodeGenerationAllowed();
21037
21038 // Set a callback that disallows the code generation.
21039 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21040 &CodeGenerationDisallowed);
21041 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21042 CheckCodeGenerationDisallowed();
21043}
21044
21045
21046TEST(SetErrorMessageForCodeGenFromStrings) {
21047 LocalContext context;
21048 v8::HandleScope scope(context->GetIsolate());
21049 TryCatch try_catch(context->GetIsolate());
21050
21051 Local<String> message = v8_str("Message");
21052 Local<String> expected_message = v8_str("Uncaught EvalError: Message");
21053 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21054 &CodeGenerationDisallowed);
21055 context->AllowCodeGenerationFromStrings(false);
21056 context->SetErrorMessageForCodeGenerationFromStrings(message);
21057 Local<Value> result = CompileRun("eval('42')");
21058 CHECK(result.IsEmpty());
21059 CHECK(try_catch.HasCaught());
21060 Local<String> actual_message = try_catch.Message()->Get();
21061 CHECK(expected_message->Equals(context.local(), actual_message).FromJust());
21062}
21063
21064TEST(CaptureSourceForCodeGenFromStrings) {
21065 LocalContext context;
21066 v8::HandleScope scope(context->GetIsolate());
21067 TryCatch try_catch(context->GetIsolate());
21068
21069 context->GetIsolate()->SetAllowCodeGenerationFromStringsCallback(
21070 &CodeGenerationAllowed);
21071 context->AllowCodeGenerationFromStrings(false);
21072 CompileRun("eval('42')");
21073 CHECK(!strcmp(first_fourty_bytes, "42"));
21074}
21075
21076static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21077}
21078
21079
21080THREADED_TEST(CallAPIFunctionOnNonObject) {
21081 LocalContext context;
21082 v8::Isolate* isolate = context->GetIsolate();
21083 v8::HandleScope scope(isolate);
21084 Local<FunctionTemplate> templ =
21085 v8::FunctionTemplate::New(isolate, NonObjectThis);
21086 Local<Function> function =
21087 templ->GetFunction(context.local()).ToLocalChecked();
21088 CHECK(context->Global()
21089 ->Set(context.local(), v8_str("f"), function)
21090 .FromJust());
21091 TryCatch try_catch(isolate);
21092 CompileRun("f.call(2)");
21093}
21094
21095
21096// Regression test for issue 1470.
21097THREADED_TEST(ReadOnlyIndexedProperties) {
21098 v8::Isolate* isolate = CcTest::isolate();
21099 v8::HandleScope scope(isolate);
21100 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21101
21102 LocalContext context;
21103 Local<v8::Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
21104 CHECK(context->Global()->Set(context.local(), v8_str("obj"), obj).FromJust());
21105 obj->DefineOwnProperty(context.local(), v8_str("1"), v8_str("DONT_CHANGE"),
21106 v8::ReadOnly)
21107 .FromJust();
21108 obj->Set(context.local(), v8_str("1"), v8_str("foobar")).FromJust();
21109 CHECK(v8_str("DONT_CHANGE")
21110 ->Equals(context.local(),
21111 obj->Get(context.local(), v8_str("1")).ToLocalChecked())
21112 .FromJust());
21113 obj->DefineOwnProperty(context.local(), v8_str("2"), v8_str("DONT_CHANGE"),
21114 v8::ReadOnly)
21115 .FromJust();
21116 obj->Set(context.local(), v8_num(2), v8_str("foobar")).FromJust();
21117 CHECK(v8_str("DONT_CHANGE")
21118 ->Equals(context.local(),
21119 obj->Get(context.local(), v8_num(2)).ToLocalChecked())
21120 .FromJust());
21121
21122 // Test non-smi case.
21123 obj->DefineOwnProperty(context.local(), v8_str("2000000000"),
21124 v8_str("DONT_CHANGE"), v8::ReadOnly)
21125 .FromJust();
21126 obj->Set(context.local(), v8_str("2000000000"), v8_str("foobar")).FromJust();
21127 CHECK(v8_str("DONT_CHANGE")
21128 ->Equals(context.local(),
21129 obj->Get(context.local(), v8_str("2000000000"))
21130 .ToLocalChecked())
21131 .FromJust());
21132}
21133
21134static int CountLiveMapsInMapCache(i::Context context) {
21135 i::WeakFixedArray map_cache = i::WeakFixedArray::cast(context->map_cache());
21136 int length = map_cache->length();
21137 int count = 0;
21138 for (int i = 0; i < length; i++) {
21139 if (map_cache->Get(i)->IsWeak()) count++;
21140 }
21141 return count;
21142}
21143
21144
21145THREADED_TEST(Regress1516) {
21146 LocalContext context;
21147 v8::HandleScope scope(context->GetIsolate());
21148
21149 // Object with 20 properties is not a common case, so it should be removed
21150 // from the cache after GC.
21151 { v8::HandleScope temp_scope(context->GetIsolate());
21152 CompileRun(
21153 "({"
21154 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21155 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21156 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21157 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21158 "})");
21159 }
21160
21161 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21162 CHECK_LE(1, elements);
21163
21164 // We have to abort incremental marking here to abandon black pages.
21165 CcTest::PreciseCollectAllGarbage();
21166
21167 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21168}
21169
21170
21171static void TestReceiver(Local<Value> expected_result,
21172 Local<Value> expected_receiver,
21173 const char* code) {
21174 Local<Value> result = CompileRun(code);
21175 Local<Context> context = CcTest::isolate()->GetCurrentContext();
21176 CHECK(result->IsObject());
21177 CHECK(expected_receiver
21178 ->Equals(context,
21179 result.As<v8::Object>()->Get(context, 1).ToLocalChecked())
21180 .FromJust());
21181 CHECK(expected_result
21182 ->Equals(context,
21183 result.As<v8::Object>()->Get(context, 0).ToLocalChecked())
21184 .FromJust());
21185}
21186
21187
21188THREADED_TEST(ForeignFunctionReceiver) {
21189 v8::Isolate* isolate = CcTest::isolate();
21190 HandleScope scope(isolate);
21191
21192 // Create two contexts with different "id" properties ('i' and 'o').
21193 // Call a function both from its own context and from a the foreign
21194 // context, and see what "this" is bound to (returning both "this"
21195 // and "this.id" for comparison).
21196
21197 Local<Context> foreign_context = v8::Context::New(isolate);
21198 foreign_context->Enter();
21199 Local<Value> foreign_function =
21200 CompileRun("function func() { return { 0: this.id, "
21201 " 1: this, "
21202 " toString: function() { "
21203 " return this[0];"
21204 " }"
21205 " };"
21206 "}"
21207 "var id = 'i';"
21208 "func;");
21209 CHECK(foreign_function->IsFunction());
21210 foreign_context->Exit();
21211
21212 LocalContext context;
21213
21214 Local<String> password = v8_str("Password");
21215 // Don't get hit by security checks when accessing foreign_context's
21216 // global receiver (aka. global proxy).
21217 context->SetSecurityToken(password);
21218 foreign_context->SetSecurityToken(password);
21219
21220 Local<String> i = v8_str("i");
21221 Local<String> o = v8_str("o");
21222 Local<String> id = v8_str("id");
21223
21224 CompileRun("function ownfunc() { return { 0: this.id, "
21225 " 1: this, "
21226 " toString: function() { "
21227 " return this[0];"
21228 " }"
21229 " };"
21230 "}"
21231 "var id = 'o';"
21232 "ownfunc");
21233 CHECK(context->Global()
21234 ->Set(context.local(), v8_str("func"), foreign_function)
21235 .FromJust());
21236
21237 // Sanity check the contexts.
21238 CHECK(
21239 i->Equals(
21240 context.local(),
21241 foreign_context->Global()->Get(context.local(), id).ToLocalChecked())
21242 .FromJust());
21243 CHECK(o->Equals(context.local(),
21244 context->Global()->Get(context.local(), id).ToLocalChecked())
21245 .FromJust());
21246
21247 // Checking local function's receiver.
21248 // Calling function using its call/apply methods.
21249 TestReceiver(o, context->Global(), "ownfunc.call()");
21250 TestReceiver(o, context->Global(), "ownfunc.apply()");
21251 // Making calls through built-in functions.
21252 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21253 CHECK(
21254 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))
21255 .FromJust());
21256 CHECK(
21257 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))
21258 .FromJust());
21259 CHECK(
21260 o->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))
21261 .FromJust());
21262 // Calling with environment record as base.
21263 TestReceiver(o, context->Global(), "ownfunc()");
21264 // Calling with no base.
21265 TestReceiver(o, context->Global(), "(1,ownfunc)()");
21266
21267 // Checking foreign function return value.
21268 // Calling function using its call/apply methods.
21269 TestReceiver(i, foreign_context->Global(), "func.call()");
21270 TestReceiver(i, foreign_context->Global(), "func.apply()");
21271 // Calling function using another context's call/apply methods.
21272 TestReceiver(i, foreign_context->Global(),
21273 "Function.prototype.call.call(func)");
21274 TestReceiver(i, foreign_context->Global(),
21275 "Function.prototype.call.apply(func)");
21276 TestReceiver(i, foreign_context->Global(),
21277 "Function.prototype.apply.call(func)");
21278 TestReceiver(i, foreign_context->Global(),
21279 "Function.prototype.apply.apply(func)");
21280 // Making calls through built-in functions.
21281 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21282 // ToString(func()) is func()[0], i.e., the returned this.id.
21283 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/,func)[1]"))
21284 .FromJust());
21285 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[1]"))
21286 .FromJust());
21287 CHECK(i->Equals(context.local(), CompileRun("'abcbd'.replace(/b/g,func)[3]"))
21288 .FromJust());
21289
21290 // Calling with environment record as base.
21291 TestReceiver(i, foreign_context->Global(), "func()");
21292 // Calling with no base.
21293 TestReceiver(i, foreign_context->Global(), "(1,func)()");
21294}
21295
21296
21297uint8_t callback_fired = 0;
21298uint8_t before_call_entered_callback_count1 = 0;
21299uint8_t before_call_entered_callback_count2 = 0;
21300
21301
21302void CallCompletedCallback1(v8::Isolate*) {
21303 v8::base::OS::Print("Firing callback 1.\n");
21304 callback_fired ^= 1; // Toggle first bit.
21305}
21306
21307
21308void CallCompletedCallback2(v8::Isolate*) {
21309 v8::base::OS::Print("Firing callback 2.\n");
21310 callback_fired ^= 2; // Toggle second bit.
21311}
21312
21313
21314void BeforeCallEnteredCallback1(v8::Isolate*) {
21315 v8::base::OS::Print("Firing before call entered callback 1.\n");
21316 before_call_entered_callback_count1++;
21317}
21318
21319
21320void BeforeCallEnteredCallback2(v8::Isolate*) {
21321 v8::base::OS::Print("Firing before call entered callback 2.\n");
21322 before_call_entered_callback_count2++;
21323}
21324
21325
21326void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21327 int32_t level =
21328 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
21329 if (level < 3) {
21330 level++;
21331 v8::base::OS::Print("Entering recursion level %d.\n", level);
21332 char script[64];
21333 i::Vector<char> script_vector(script, sizeof(script));
21334 i::SNPrintF(script_vector, "recursion(%d)", level);
21335 CompileRun(script_vector.start());
21336 v8::base::OS::Print("Leaving recursion level %d.\n", level);
21337 CHECK_EQ(0, callback_fired);
21338 } else {
21339 v8::base::OS::Print("Recursion ends.\n");
21340 CHECK_EQ(0, callback_fired);
21341 }
21342}
21343
21344
21345TEST(CallCompletedCallback) {
21346 LocalContext env;
21347 v8::HandleScope scope(env->GetIsolate());
21348 v8::Local<v8::FunctionTemplate> recursive_runtime =
21349 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21350 env->Global()
21351 ->Set(env.local(), v8_str("recursion"),
21352 recursive_runtime->GetFunction(env.local()).ToLocalChecked())
21353 .FromJust();
21354 // Adding the same callback a second time has no effect.
21355 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21356 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21357 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21358 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21359 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
21360 env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
21361 v8::base::OS::Print("--- Script (1) ---\n");
21362 callback_fired = 0;
21363 before_call_entered_callback_count1 = 0;
21364 before_call_entered_callback_count2 = 0;
21365 Local<Script> script =
21366 v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
21367 script->Run(env.local()).ToLocalChecked();
21368 CHECK_EQ(3, callback_fired);
21369 CHECK_EQ(4, before_call_entered_callback_count1);
21370 CHECK_EQ(4, before_call_entered_callback_count2);
21371
21372 v8::base::OS::Print("\n--- Script (2) ---\n");
21373 callback_fired = 0;
21374 before_call_entered_callback_count1 = 0;
21375 before_call_entered_callback_count2 = 0;
21376 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21377 env->GetIsolate()->RemoveBeforeCallEnteredCallback(
21378 BeforeCallEnteredCallback1);
21379 script->Run(env.local()).ToLocalChecked();
21380 CHECK_EQ(2, callback_fired);
21381 CHECK_EQ(0, before_call_entered_callback_count1);
21382 CHECK_EQ(4, before_call_entered_callback_count2);
21383
21384 v8::base::OS::Print("\n--- Function ---\n");
21385 callback_fired = 0;
21386 before_call_entered_callback_count1 = 0;
21387 before_call_entered_callback_count2 = 0;
21388 Local<Function> recursive_function = Local<Function>::Cast(
21389 env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
21390 v8::Local<Value> args[] = {v8_num(0)};
21391 recursive_function->Call(env.local(), env->Global(), 1, args)
21392 .ToLocalChecked();
21393 CHECK_EQ(2, callback_fired);
21394 CHECK_EQ(0, before_call_entered_callback_count1);
21395 CHECK_EQ(4, before_call_entered_callback_count2);
21396}
21397
21398
21399void CallCompletedCallbackNoException(v8::Isolate*) {
21400 v8::HandleScope scope(CcTest::isolate());
21401 CompileRun("1+1;");
21402}
21403
21404
21405void CallCompletedCallbackException(v8::Isolate*) {
21406 v8::HandleScope scope(CcTest::isolate());
21407 CompileRun("throw 'second exception';");
21408}
21409
21410
21411TEST(CallCompletedCallbackOneException) {
21412 LocalContext env;
21413 v8::HandleScope scope(env->GetIsolate());
21414 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21415 CompileRun("throw 'exception';");
21416}
21417
21418
21419TEST(CallCompletedCallbackTwoExceptions) {
21420 LocalContext env;
21421 v8::HandleScope scope(env->GetIsolate());
21422 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21423 CompileRun("throw 'first exception';");
21424}
21425
21426
21427static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21428 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21429 v8::HandleScope scope(info.GetIsolate());
21430 v8::MicrotasksScope microtasks(info.GetIsolate(),
21431 v8::MicrotasksScope::kDoNotRunMicrotasks);
21432 CompileRun("ext1Calls++;");
21433}
21434
21435
21436static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21437 CHECK(v8::MicrotasksScope::IsRunningMicrotasks(info.GetIsolate()));
21438 v8::HandleScope scope(info.GetIsolate());
21439 v8::MicrotasksScope microtasks(info.GetIsolate(),
21440 v8::MicrotasksScope::kDoNotRunMicrotasks);
21441 CompileRun("ext2Calls++;");
21442}
21443
21444void* g_passed_to_three = nullptr;
21445
21446static void MicrotaskThree(void* data) {
21447 g_passed_to_three = data;
21448}
21449
21450
21451TEST(EnqueueMicrotask) {
21452 LocalContext env;
21453 v8::HandleScope scope(env->GetIsolate());
21454 CHECK(!v8::MicrotasksScope::IsRunningMicrotasks(env->GetIsolate()));
21455 CompileRun(
21456 "var ext1Calls = 0;"
21457 "var ext2Calls = 0;");
21458 CompileRun("1+1;");
21459 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21460 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21461
21462 env->GetIsolate()->EnqueueMicrotask(
21463 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21464 CompileRun("1+1;");
21465 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21466 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21467
21468 env->GetIsolate()->EnqueueMicrotask(
21469 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21470 env->GetIsolate()->EnqueueMicrotask(
21471 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21472 CompileRun("1+1;");
21473 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21474 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21475
21476 env->GetIsolate()->EnqueueMicrotask(
21477 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21478 CompileRun("1+1;");
21479 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21480 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21481
21482 CompileRun("1+1;");
21483 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21484 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21485
21486 g_passed_to_three = nullptr;
21487 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21488 CompileRun("1+1;");
21489 CHECK(!g_passed_to_three);
21490 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21491 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21492
21493 int dummy;
21494 env->GetIsolate()->EnqueueMicrotask(
21495 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21496 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21497 env->GetIsolate()->EnqueueMicrotask(
21498 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21499 CompileRun("1+1;");
21500 CHECK_EQ(&dummy, g_passed_to_three);
21501 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21502 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21503 g_passed_to_three = nullptr;
21504}
21505
21506
21507static void MicrotaskExceptionOne(
21508 const v8::FunctionCallbackInfo<Value>& info) {
21509 v8::HandleScope scope(info.GetIsolate());
21510 CompileRun("exception1Calls++;");
21511 info.GetIsolate()->ThrowException(
21512 v8::Exception::Error(v8_str("first")));
21513}
21514
21515
21516static void MicrotaskExceptionTwo(
21517 const v8::FunctionCallbackInfo<Value>& info) {
21518 v8::HandleScope scope(info.GetIsolate());
21519 CompileRun("exception2Calls++;");
21520 info.GetIsolate()->ThrowException(
21521 v8::Exception::Error(v8_str("second")));
21522}
21523
21524
21525TEST(RunMicrotasksIgnoresThrownExceptions) {
21526 LocalContext env;
21527 v8::Isolate* isolate = env->GetIsolate();
21528 v8::HandleScope scope(isolate);
21529 CompileRun(
21530 "var exception1Calls = 0;"
21531 "var exception2Calls = 0;");
21532 isolate->EnqueueMicrotask(
21533 Function::New(env.local(), MicrotaskExceptionOne).ToLocalChecked());
21534 isolate->EnqueueMicrotask(
21535 Function::New(env.local(), MicrotaskExceptionTwo).ToLocalChecked());
21536 TryCatch try_catch(isolate);
21537 CompileRun("1+1;");
21538 CHECK(!try_catch.HasCaught());
21539 CHECK_EQ(1,
21540 CompileRun("exception1Calls")->Int32Value(env.local()).FromJust());
21541 CHECK_EQ(1,
21542 CompileRun("exception2Calls")->Int32Value(env.local()).FromJust());
21543}
21544
21545static void ThrowExceptionMicrotask(void* data) {
21546 CcTest::isolate()->ThrowException(v8_str("exception"));
21547}
21548
21549int microtask_callback_count = 0;
21550
21551static void IncrementCounterMicrotask(void* data) {
21552 microtask_callback_count++;
21553}
21554
21555TEST(RunMicrotasksIgnoresThrownExceptionsFromApi) {
21556 LocalContext env;
21557 v8::Isolate* isolate = CcTest::isolate();
21558 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21559 v8::HandleScope scope(isolate);
21560 v8::TryCatch try_catch(isolate);
21561 {
21562 CHECK(!isolate->IsExecutionTerminating());
21563 isolate->EnqueueMicrotask(ThrowExceptionMicrotask);
21564 isolate->EnqueueMicrotask(IncrementCounterMicrotask);
21565 isolate->RunMicrotasks();
21566 CHECK_EQ(1, microtask_callback_count);
21567 CHECK(!try_catch.HasCaught());
21568 }
21569}
21570
21571uint8_t microtasks_completed_callback_count = 0;
21572
21573static void MicrotasksCompletedCallback(v8::Isolate* isolate, void*) {
21574 ++microtasks_completed_callback_count;
21575}
21576
21577TEST(SetAutorunMicrotasks) {
21578 LocalContext env;
21579 v8::HandleScope scope(env->GetIsolate());
21580 env->GetIsolate()->AddMicrotasksCompletedCallback(
21581 &MicrotasksCompletedCallback);
21582 CompileRun(
21583 "var ext1Calls = 0;"
21584 "var ext2Calls = 0;");
21585 CompileRun("1+1;");
21586 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21587 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21588 CHECK_EQ(0u, microtasks_completed_callback_count);
21589
21590 env->GetIsolate()->EnqueueMicrotask(
21591 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21592 CompileRun("1+1;");
21593 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21594 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21595 CHECK_EQ(1u, microtasks_completed_callback_count);
21596
21597 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21598 env->GetIsolate()->EnqueueMicrotask(
21599 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21600 env->GetIsolate()->EnqueueMicrotask(
21601 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21602 CompileRun("1+1;");
21603 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21604 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21605 CHECK_EQ(1u, microtasks_completed_callback_count);
21606
21607 env->GetIsolate()->RunMicrotasks();
21608 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21609 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21610 CHECK_EQ(2u, microtasks_completed_callback_count);
21611
21612 env->GetIsolate()->EnqueueMicrotask(
21613 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21614 CompileRun("1+1;");
21615 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21616 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21617 CHECK_EQ(2u, microtasks_completed_callback_count);
21618
21619 env->GetIsolate()->RunMicrotasks();
21620 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21621 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21622 CHECK_EQ(3u, microtasks_completed_callback_count);
21623
21624 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21625 env->GetIsolate()->EnqueueMicrotask(
21626 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21627 CompileRun("1+1;");
21628 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21629 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21630 CHECK_EQ(4u, microtasks_completed_callback_count);
21631
21632 env->GetIsolate()->EnqueueMicrotask(
21633 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21634 {
21635 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21636 CompileRun("1+1;");
21637 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21638 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21639 CHECK_EQ(4u, microtasks_completed_callback_count);
21640 }
21641
21642 CompileRun("1+1;");
21643 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21644 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21645 CHECK_EQ(5u, microtasks_completed_callback_count);
21646
21647 env->GetIsolate()->RemoveMicrotasksCompletedCallback(
21648 &MicrotasksCompletedCallback);
21649 env->GetIsolate()->EnqueueMicrotask(
21650 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21651 CompileRun("1+1;");
21652 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21653 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21654 CHECK_EQ(5u, microtasks_completed_callback_count);
21655}
21656
21657
21658TEST(RunMicrotasksWithoutEnteringContext) {
21659 v8::Isolate* isolate = CcTest::isolate();
21660 HandleScope handle_scope(isolate);
21661 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
21662 Local<Context> context = Context::New(isolate);
21663 {
21664 Context::Scope context_scope(context);
21665 CompileRun("var ext1Calls = 0;");
21666 isolate->EnqueueMicrotask(
21667 Function::New(context, MicrotaskOne).ToLocalChecked());
21668 }
21669 isolate->RunMicrotasks();
21670 {
21671 Context::Scope context_scope(context);
21672 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
21673 }
21674 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21675}
21676
21677static void Regress808911_MicrotaskCallback(void* data) {
21678 // So here we expect "current context" to be context1 and
21679 // "entered or microtask context" to be context2.
21680 v8::Isolate* isolate = static_cast<v8::Isolate*>(data);
21681 CHECK(isolate->GetCurrentContext() !=
21682 isolate->GetEnteredOrMicrotaskContext());
21683}
21684
21685static void Regress808911_CurrentContextWrapper(
21686 const v8::FunctionCallbackInfo<Value>& info) {
21687 // So here we expect "current context" to be context1 and
21688 // "entered or microtask context" to be context2.
21689 v8::Isolate* isolate = info.GetIsolate();
21690 CHECK(isolate->GetCurrentContext() !=
21691 isolate->GetEnteredOrMicrotaskContext());
21692 isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
21693 isolate->RunMicrotasks();
21694}
21695
21696THREADED_TEST(Regress808911) {
21697 v8::Isolate* isolate = CcTest::isolate();
21698 HandleScope handle_scope(isolate);
21699 Local<Context> context1 = Context::New(isolate);
21700 Local<Function> function;
21701 {
21702 Context::Scope context_scope(context1);
21703 function = Function::New(context1, Regress808911_CurrentContextWrapper)
21704 .ToLocalChecked();
21705 }
21706 Local<Context> context2 = Context::New(isolate);
21707 Context::Scope context_scope(context2);
21708 function->CallAsFunction(context2, v8::Undefined(isolate), 0, nullptr)
21709 .ToLocalChecked();
21710}
21711
21712TEST(ScopedMicrotasks) {
21713 LocalContext env;
21714 v8::HandleScope handles(env->GetIsolate());
21715 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
21716 {
21717 v8::MicrotasksScope scope1(env->GetIsolate(),
21718 v8::MicrotasksScope::kDoNotRunMicrotasks);
21719 env->GetIsolate()->EnqueueMicrotask(
21720 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21721 CompileRun(
21722 "var ext1Calls = 0;"
21723 "var ext2Calls = 0;");
21724 CompileRun("1+1;");
21725 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21726 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21727 {
21728 v8::MicrotasksScope scope2(env->GetIsolate(),
21729 v8::MicrotasksScope::kRunMicrotasks);
21730 CompileRun("1+1;");
21731 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21732 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21733 {
21734 v8::MicrotasksScope scope3(env->GetIsolate(),
21735 v8::MicrotasksScope::kRunMicrotasks);
21736 CompileRun("1+1;");
21737 CHECK_EQ(0,
21738 CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21739 CHECK_EQ(0,
21740 CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21741 }
21742 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21743 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21744 }
21745 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21746 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21747 env->GetIsolate()->EnqueueMicrotask(
21748 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21749 }
21750
21751 {
21752 v8::MicrotasksScope scope(env->GetIsolate(),
21753 v8::MicrotasksScope::kDoNotRunMicrotasks);
21754 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21755 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21756 }
21757
21758 {
21759 v8::MicrotasksScope scope1(env->GetIsolate(),
21760 v8::MicrotasksScope::kRunMicrotasks);
21761 CompileRun("1+1;");
21762 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21763 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21764 {
21765 v8::MicrotasksScope scope2(env->GetIsolate(),
21766 v8::MicrotasksScope::kDoNotRunMicrotasks);
21767 }
21768 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21769 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21770 }
21771
21772 {
21773 v8::MicrotasksScope scope(env->GetIsolate(),
21774 v8::MicrotasksScope::kDoNotRunMicrotasks);
21775 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21776 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21777 env->GetIsolate()->EnqueueMicrotask(
21778 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21779 }
21780
21781 {
21782 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21783 {
21784 v8::MicrotasksScope scope2(env->GetIsolate(),
21785 v8::MicrotasksScope::kRunMicrotasks);
21786 }
21787 v8::MicrotasksScope scope3(env->GetIsolate(),
21788 v8::MicrotasksScope::kDoNotRunMicrotasks);
21789 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21790 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21791 }
21792
21793 {
21794 v8::MicrotasksScope scope1(env->GetIsolate(),
21795 v8::MicrotasksScope::kRunMicrotasks);
21796 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21797 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21798 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21799 }
21800
21801 {
21802 v8::MicrotasksScope scope(env->GetIsolate(),
21803 v8::MicrotasksScope::kDoNotRunMicrotasks);
21804 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21805 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21806 }
21807
21808 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21809
21810 {
21811 v8::MicrotasksScope scope(env->GetIsolate(),
21812 v8::MicrotasksScope::kDoNotRunMicrotasks);
21813 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21814 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21815 env->GetIsolate()->EnqueueMicrotask(
21816 Function::New(env.local(), MicrotaskTwo).ToLocalChecked());
21817 }
21818
21819 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21820
21821 {
21822 v8::MicrotasksScope scope(env->GetIsolate(),
21823 v8::MicrotasksScope::kDoNotRunMicrotasks);
21824 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21825 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21826 }
21827
21828 env->GetIsolate()->EnqueueMicrotask(
21829 Function::New(env.local(), MicrotaskOne).ToLocalChecked());
21830 {
21831 v8::Isolate::SuppressMicrotaskExecutionScope scope1(env->GetIsolate());
21832 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21833 v8::MicrotasksScope scope2(env->GetIsolate(),
21834 v8::MicrotasksScope::kDoNotRunMicrotasks);
21835 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21836 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21837 }
21838
21839 v8::MicrotasksScope::PerformCheckpoint(env->GetIsolate());
21840
21841 {
21842 v8::MicrotasksScope scope(env->GetIsolate(),
21843 v8::MicrotasksScope::kDoNotRunMicrotasks);
21844 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
21845 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
21846 }
21847
21848 env->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
21849}
21850
21851namespace {
21852
21853void AssertCowElements(bool expected, const char* source) {
21854 Local<Value> object = CompileRun(source);
21855 i::Handle<i::JSObject> array =
21856 i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*object.As<Object>()));
21857 CHECK_EQ(expected, array->elements()->IsCowArray());
21858}
21859
21860} // namespace
21861
21862TEST(CheckCOWArraysCreatedRuntimeCounter) {
21863 LocalContext env;
21864 v8::HandleScope scope(env->GetIsolate());
21865 AssertCowElements(true, "[1, 2, 3]");
21866 AssertCowElements(false, "[[1], 2, 3]");
21867 AssertCowElements(true, "[[1], 2, 3][0]");
21868 AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.foo)");
21869 AssertCowElements(true, "({foo: [4, 5, 6], bar: [3, 0]}.bar)");
21870 AssertCowElements(false, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo)");
21871 AssertCowElements(true, "({foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'}.foo[3])");
21872}
21873
21874
21875TEST(StaticGetters) {
21876 LocalContext context;
21877 i::Factory* factory = CcTest::i_isolate()->factory();
21878 v8::Isolate* isolate = CcTest::isolate();
21879 v8::HandleScope scope(isolate);
21880 i::Handle<i::Object> undefined_value = factory->undefined_value();
21881 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21882 i::Handle<i::Object> null_value = factory->null_value();
21883 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21884 i::Handle<i::Object> true_value = factory->true_value();
21885 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21886 i::Handle<i::Object> false_value = factory->false_value();
21887 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21888}
21889
21890
21891UNINITIALIZED_TEST(IsolateEmbedderData) {
21892 CcTest::DisableAutomaticDispose();
21893 v8::Isolate::CreateParams create_params;
21894 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21895 v8::Isolate* isolate = v8::Isolate::New(create_params);
21896 isolate->Enter();
21897 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21898 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21899 CHECK(!isolate->GetData(slot));
21900 CHECK(!i_isolate->GetData(slot));
21901 }
21902 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21903 void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21904 isolate->SetData(slot, data);
21905 }
21906 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21907 void* data = reinterpret_cast<void*>(0xACCE55ED + slot);
21908 CHECK_EQ(data, isolate->GetData(slot));
21909 CHECK_EQ(data, i_isolate->GetData(slot));
21910 }
21911 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21912 void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
21913 isolate->SetData(slot, data);
21914 }
21915 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21916 void* data = reinterpret_cast<void*>(0xDECEA5ED + slot);
21917 CHECK_EQ(data, isolate->GetData(slot));
21918 CHECK_EQ(data, i_isolate->GetData(slot));
21919 }
21920 isolate->Exit();
21921 isolate->Dispose();
21922}
21923
21924
21925TEST(StringEmpty) {
21926 LocalContext context;
21927 i::Factory* factory = CcTest::i_isolate()->factory();
21928 v8::Isolate* isolate = CcTest::isolate();
21929 v8::HandleScope scope(isolate);
21930 i::Handle<i::Object> empty_string = factory->empty_string();
21931 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21932}
21933
21934
21935static int instance_checked_getter_count = 0;
21936static void InstanceCheckedGetter(
21937 Local<String> name,
21938 const v8::PropertyCallbackInfo<v8::Value>& info) {
21939 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21940 .FromJust());
21941 instance_checked_getter_count++;
21942 info.GetReturnValue().Set(v8_num(11));
21943}
21944
21945
21946static int instance_checked_setter_count = 0;
21947static void InstanceCheckedSetter(Local<String> name,
21948 Local<Value> value,
21949 const v8::PropertyCallbackInfo<void>& info) {
21950 CHECK(name->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("foo"))
21951 .FromJust());
21952 CHECK(value->Equals(info.GetIsolate()->GetCurrentContext(), v8_num(23))
21953 .FromJust());
21954 instance_checked_setter_count++;
21955}
21956
21957
21958static void CheckInstanceCheckedResult(int getters, int setters,
21959 bool expects_callbacks,
21960 TryCatch* try_catch) {
21961 if (expects_callbacks) {
21962 CHECK(!try_catch->HasCaught());
21963 CHECK_EQ(getters, instance_checked_getter_count);
21964 CHECK_EQ(setters, instance_checked_setter_count);
21965 } else {
21966 CHECK(try_catch->HasCaught());
21967 CHECK_EQ(0, instance_checked_getter_count);
21968 CHECK_EQ(0, instance_checked_setter_count);
21969 }
21970 try_catch->Reset();
21971}
21972
21973
21974static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21975 instance_checked_getter_count = 0;
21976 instance_checked_setter_count = 0;
21977 TryCatch try_catch(CcTest::isolate());
21978
21979 // Test path through generic runtime code.
21980 CompileRun("obj.foo");
21981 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21982 CompileRun("obj.foo = 23");
21983 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21984
21985 // Test path through generated LoadIC and StoredIC.
21986 CompileRun("function test_get(o) { o.foo; }"
21987 "test_get(obj);");
21988 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21989 CompileRun("test_get(obj);");
21990 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21991 CompileRun("test_get(obj);");
21992 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21993 CompileRun("function test_set(o) { o.foo = 23; }"
21994 "test_set(obj);");
21995 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21996 CompileRun("test_set(obj);");
21997 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21998 CompileRun("test_set(obj);");
21999 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22000
22001 // Test path through optimized code.
22002 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22003 "test_get(obj);");
22004 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22005 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22006 "test_set(obj);");
22007 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22008
22009 // Cleanup so that closures start out fresh in next check.
22010 CompileRun(
22011 "%DeoptimizeFunction(test_get);"
22012 "%ClearFunctionFeedback(test_get);"
22013 "%DeoptimizeFunction(test_set);"
22014 "%ClearFunctionFeedback(test_set);");
22015}
22016
22017
22018THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22019 v8::internal::FLAG_allow_natives_syntax = true;
22020 LocalContext context;
22021 v8::HandleScope scope(context->GetIsolate());
22022
22023 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22024 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22025 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22026 Local<Value>(), v8::DEFAULT, v8::None,
22027 v8::AccessorSignature::New(context->GetIsolate(), templ));
22028 CHECK(context->Global()
22029 ->Set(context.local(), v8_str("f"),
22030 templ->GetFunction(context.local()).ToLocalChecked())
22031 .FromJust());
22032
22033 printf("Testing positive ...\n");
22034 CompileRun("var obj = new f();");
22035 CHECK(templ->HasInstance(
22036 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22037 CheckInstanceCheckedAccessors(true);
22038
22039 printf("Testing negative ...\n");
22040 CompileRun("var obj = {};"
22041 "obj.__proto__ = new f();");
22042 CHECK(!templ->HasInstance(
22043 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22044 CheckInstanceCheckedAccessors(false);
22045}
22046
22047static void EmptyInterceptorGetter(
22048 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
22049
22050static void EmptyInterceptorSetter(
22051 Local<Name> name, Local<Value> value,
22052 const v8::PropertyCallbackInfo<v8::Value>& info) {}
22053
22054THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22055 v8::internal::FLAG_allow_natives_syntax = true;
22056 LocalContext context;
22057 v8::HandleScope scope(context->GetIsolate());
22058
22059 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22060 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22061 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
22062 EmptyInterceptorGetter, EmptyInterceptorSetter));
22063 inst->SetAccessor(v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
22064 Local<Value>(), v8::DEFAULT, v8::None,
22065 v8::AccessorSignature::New(context->GetIsolate(), templ));
22066 CHECK(context->Global()
22067 ->Set(context.local(), v8_str("f"),
22068 templ->GetFunction(context.local()).ToLocalChecked())
22069 .FromJust());
22070
22071 printf("Testing positive ...\n");
22072 CompileRun("var obj = new f();");
22073 CHECK(templ->HasInstance(
22074 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22075 CheckInstanceCheckedAccessors(true);
22076
22077 printf("Testing negative ...\n");
22078 CompileRun("var obj = {};"
22079 "obj.__proto__ = new f();");
22080 CHECK(!templ->HasInstance(
22081 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22082 CheckInstanceCheckedAccessors(false);
22083}
22084
22085
22086THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22087 v8::internal::FLAG_allow_natives_syntax = true;
22088 LocalContext context;
22089 v8::HandleScope scope(context->GetIsolate());
22090
22091 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22092 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22093 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22094 InstanceCheckedSetter, Local<Value>(), v8::DEFAULT,
22095 v8::None,
22096 v8::AccessorSignature::New(context->GetIsolate(), templ));
22097 CHECK(context->Global()
22098 ->Set(context.local(), v8_str("f"),
22099 templ->GetFunction(context.local()).ToLocalChecked())
22100 .FromJust());
22101
22102 printf("Testing positive ...\n");
22103 CompileRun("var obj = new f();");
22104 CHECK(templ->HasInstance(
22105 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22106 CheckInstanceCheckedAccessors(true);
22107
22108 printf("Testing negative ...\n");
22109 CompileRun("var obj = {};"
22110 "obj.__proto__ = new f();");
22111 CHECK(!templ->HasInstance(
22112 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22113 CheckInstanceCheckedAccessors(false);
22114
22115 printf("Testing positive with modified prototype chain ...\n");
22116 CompileRun("var obj = new f();"
22117 "var pro = {};"
22118 "pro.__proto__ = obj.__proto__;"
22119 "obj.__proto__ = pro;");
22120 CHECK(templ->HasInstance(
22121 context->Global()->Get(context.local(), v8_str("obj")).ToLocalChecked()));
22122 CheckInstanceCheckedAccessors(true);
22123}
22124
22125
22126TEST(TryFinallyMessage) {
22127 LocalContext context;
22128 v8::HandleScope scope(context->GetIsolate());
22129 {
22130 // Test that the original error message is not lost if there is a
22131 // recursive call into Javascript is done in the finally block, e.g. to
22132 // initialize an IC. (crbug.com/129171)
22133 TryCatch try_catch(context->GetIsolate());
22134 const char* trigger_ic =
22135 "try { \n"
22136 " throw new Error('test'); \n"
22137 "} finally { \n"
22138 " var x = 0; \n"
22139 " x++; \n" // Trigger an IC initialization here.
22140 "} \n";
22141 CompileRun(trigger_ic);
22142 CHECK(try_catch.HasCaught());
22143 Local<Message> message = try_catch.Message();
22144 CHECK(!message.IsEmpty());
22145 CHECK_EQ(2, message->GetLineNumber(context.local()).FromJust());
22146 }
22147
22148 {
22149 // Test that the original exception message is indeed overwritten if
22150 // a new error is thrown in the finally block.
22151 TryCatch try_catch(context->GetIsolate());
22152 const char* throw_again =
22153 "try { \n"
22154 " throw new Error('test'); \n"
22155 "} finally { \n"
22156 " var x = 0; \n"
22157 " x++; \n"
22158 " throw new Error('again'); \n" // This is the new uncaught error.
22159 "} \n";
22160 CompileRun(throw_again);
22161 CHECK(try_catch.HasCaught());
22162 Local<Message> message = try_catch.Message();
22163 CHECK(!message.IsEmpty());
22164 CHECK_EQ(6, message->GetLineNumber(context.local()).FromJust());
22165 }
22166}
22167
22168
22169static void Helper137002(bool do_store,
22170 bool polymorphic,
22171 bool remove_accessor,
22172 bool interceptor) {
22173 LocalContext context;
22174 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22175 if (interceptor) {
22176 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22177 FooSetInterceptor));
22178 } else {
22179 templ->SetAccessor(v8_str("foo"),
22180 GetterWhichReturns42,
22181 SetterWhichSetsYOnThisTo23);
22182 }
22183 CHECK(context->Global()
22184 ->Set(context.local(), v8_str("obj"),
22185 templ->NewInstance(context.local()).ToLocalChecked())
22186 .FromJust());
22187
22188 // Turn monomorphic on slow object with native accessor, then turn
22189 // polymorphic, finally optimize to create negative lookup and fail.
22190 CompileRun(do_store ?
22191 "function f(x) { x.foo = void 0; }" :
22192 "function f(x) { return x.foo; }");
22193 CompileRun("obj.y = void 0;");
22194 if (!interceptor) {
22195 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22196 }
22197 CompileRun("obj.__proto__ = null;"
22198 "f(obj); f(obj); f(obj);");
22199 if (polymorphic) {
22200 CompileRun("f({});");
22201 }
22202 CompileRun("obj.y = void 0;"
22203 "%OptimizeFunctionOnNextCall(f);");
22204 if (remove_accessor) {
22205 CompileRun("delete obj.foo;");
22206 }
22207 CompileRun("var result = f(obj);");
22208 if (do_store) {
22209 CompileRun("result = obj.y;");
22210 }
22211 if (remove_accessor && !interceptor) {
22212 CHECK(context->Global()
22213 ->Get(context.local(), v8_str("result"))
22214 .ToLocalChecked()
22215 ->IsUndefined());
22216 } else {
22217 CHECK_EQ(do_store ? 23 : 42, context->Global()
22218 ->Get(context.local(), v8_str("result"))
22219 .ToLocalChecked()
22220 ->Int32Value(context.local())
22221 .FromJust());
22222 }
22223}
22224
22225
22226THREADED_TEST(Regress137002a) {
22227 i::FLAG_allow_natives_syntax = true;
22228 i::FLAG_compilation_cache = false;
22229 v8::HandleScope scope(CcTest::isolate());
22230 for (int i = 0; i < 16; i++) {
22231 Helper137002(i & 8, i & 4, i & 2, i & 1);
22232 }
22233}
22234
22235
22236THREADED_TEST(Regress137002b) {
22237 i::FLAG_allow_natives_syntax = true;
22238 LocalContext context;
22239 v8::Isolate* isolate = context->GetIsolate();
22240 v8::HandleScope scope(isolate);
22241 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22242 templ->SetAccessor(v8_str("foo"),
22243 GetterWhichReturns42,
22244 SetterWhichSetsYOnThisTo23);
22245 CHECK(context->Global()
22246 ->Set(context.local(), v8_str("obj"),
22247 templ->NewInstance(context.local()).ToLocalChecked())
22248 .FromJust());
22249
22250 // Turn monomorphic on slow object with native accessor, then just
22251 // delete the property and fail.
22252 CompileRun("function load(x) { return x.foo; }"
22253 "function store(x) { x.foo = void 0; }"
22254 "function keyed_load(x, key) { return x[key]; }"
22255 // Second version of function has a different source (add void 0)
22256 // so that it does not share code with the first version. This
22257 // ensures that the ICs are monomorphic.
22258 "function load2(x) { void 0; return x.foo; }"
22259 "function store2(x) { void 0; x.foo = void 0; }"
22260 "function keyed_load2(x, key) { void 0; return x[key]; }"
22261
22262 "obj.y = void 0;"
22263 "obj.__proto__ = null;"
22264 "var subobj = {};"
22265 "subobj.y = void 0;"
22266 "subobj.__proto__ = obj;"
22267 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22268
22269 // Make the ICs monomorphic.
22270 "load(obj); load(obj);"
22271 "load2(subobj); load2(subobj);"
22272 "store(obj); store(obj);"
22273 "store2(subobj); store2(subobj);"
22274 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22275 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22276
22277 // Actually test the shiny new ICs and better not crash. This
22278 // serves as a regression test for issue 142088 as well.
22279 "load(obj);"
22280 "load2(subobj);"
22281 "store(obj);"
22282 "store2(subobj);"
22283 "keyed_load(obj, 'foo');"
22284 "keyed_load2(subobj, 'foo');"
22285
22286 // Delete the accessor. It better not be called any more now.
22287 "delete obj.foo;"
22288 "obj.y = void 0;"
22289 "subobj.y = void 0;"
22290
22291 "var load_result = load(obj);"
22292 "var load_result2 = load2(subobj);"
22293 "var keyed_load_result = keyed_load(obj, 'foo');"
22294 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22295 "store(obj);"
22296 "store2(subobj);"
22297 "var y_from_obj = obj.y;"
22298 "var y_from_subobj = subobj.y;");
22299 CHECK(context->Global()
22300 ->Get(context.local(), v8_str("load_result"))
22301 .ToLocalChecked()
22302 ->IsUndefined());
22303 CHECK(context->Global()
22304 ->Get(context.local(), v8_str("load_result2"))
22305 .ToLocalChecked()
22306 ->IsUndefined());
22307 CHECK(context->Global()
22308 ->Get(context.local(), v8_str("keyed_load_result"))
22309 .ToLocalChecked()
22310 ->IsUndefined());
22311 CHECK(context->Global()
22312 ->Get(context.local(), v8_str("keyed_load_result2"))
22313 .ToLocalChecked()
22314 ->IsUndefined());
22315 CHECK(context->Global()
22316 ->Get(context.local(), v8_str("y_from_obj"))
22317 .ToLocalChecked()
22318 ->IsUndefined());
22319 CHECK(context->Global()
22320 ->Get(context.local(), v8_str("y_from_subobj"))
22321 .ToLocalChecked()
22322 ->IsUndefined());
22323}
22324
22325
22326THREADED_TEST(Regress142088) {
22327 i::FLAG_allow_natives_syntax = true;
22328 LocalContext context;
22329 v8::Isolate* isolate = context->GetIsolate();
22330 v8::HandleScope scope(isolate);
22331 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22332 templ->SetAccessor(v8_str("foo"),
22333 GetterWhichReturns42,
22334 SetterWhichSetsYOnThisTo23);
22335 CHECK(context->Global()
22336 ->Set(context.local(), v8_str("obj"),
22337 templ->NewInstance(context.local()).ToLocalChecked())
22338 .FromJust());
22339
22340 CompileRun("function load(x) { return x.foo; }"
22341 "var o = Object.create(obj);"
22342 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22343 "load(o); load(o); load(o); load(o);");
22344}
22345
22346
22347THREADED_TEST(Regress137496) {
22348 i::FLAG_expose_gc = true;
22349 LocalContext context;
22350 v8::HandleScope scope(context->GetIsolate());
22351
22352 // Compile a try-finally clause where the finally block causes a GC
22353 // while there still is a message pending for external reporting.
22354 TryCatch try_catch(context->GetIsolate());
22355 try_catch.SetVerbose(true);
22356 CompileRun("try { throw new Error(); } finally { gc(); }");
22357 CHECK(try_catch.HasCaught());
22358}
22359
22360
22361THREADED_TEST(Regress157124) {
22362 LocalContext context;
22363 v8::Isolate* isolate = context->GetIsolate();
22364 v8::HandleScope scope(isolate);
22365 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22366 Local<Object> obj = templ->NewInstance(context.local()).ToLocalChecked();
22367 obj->GetIdentityHash();
22368 obj->DeletePrivate(context.local(),
22369 v8::Private::ForApi(isolate, v8_str("Bug")))
22370 .FromJust();
22371}
22372
22373
22374THREADED_TEST(Regress2535) {
22375 LocalContext context;
22376 v8::HandleScope scope(context->GetIsolate());
22377 Local<Value> set_value = CompileRun("new Set();");
22378 Local<Object> set_object(Local<Object>::Cast(set_value));
22379 CHECK_EQ(0, set_object->InternalFieldCount());
22380 Local<Value> map_value = CompileRun("new Map();");
22381 Local<Object> map_object(Local<Object>::Cast(map_value));
22382 CHECK_EQ(0, map_object->InternalFieldCount());
22383}
22384
22385
22386THREADED_TEST(Regress2746) {
22387 LocalContext context;
22388 v8::Isolate* isolate = context->GetIsolate();
22389 v8::HandleScope scope(isolate);
22390 Local<Object> obj = Object::New(isolate);
22391 Local<v8::Private> key = v8::Private::New(isolate, v8_str("key"));
22392 CHECK(
22393 obj->SetPrivate(context.local(), key, v8::Undefined(isolate)).FromJust());
22394 Local<Value> value = obj->GetPrivate(context.local(), key).ToLocalChecked();
22395 CHECK(!value.IsEmpty());
22396 CHECK(value->IsUndefined());
22397}
22398
22399
22400THREADED_TEST(Regress260106) {
22401 LocalContext context;
22402 v8::Isolate* isolate = context->GetIsolate();
22403 v8::HandleScope scope(isolate);
22404 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22405 DummyCallHandler);
22406 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22407 Local<Function> function =
22408 templ->GetFunction(context.local()).ToLocalChecked();
22409 CHECK(!function.IsEmpty());
22410 CHECK(function->IsFunction());
22411}
22412
22413THREADED_TEST(JSONParseObject) {
22414 LocalContext context;
22415 HandleScope scope(context->GetIsolate());
22416 Local<Value> obj =
22417 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22418 Local<Object> global = context->Global();
22419 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22420 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22421}
22422
22423THREADED_TEST(JSONParseNumber) {
22424 LocalContext context;
22425 HandleScope scope(context->GetIsolate());
22426 Local<Value> obj =
22427 v8::JSON::Parse(context.local(), v8_str("42")).ToLocalChecked();
22428 Local<Object> global = context->Global();
22429 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22430 ExpectString("JSON.stringify(obj)", "42");
22431}
22432
22433namespace {
22434void TestJSONParseArray(Local<Context> context, const char* input_str,
22435 const char* expected_output_str,
22436 i::ElementsKind expected_elements_kind) {
22437 Local<Value> obj =
22438 v8::JSON::Parse(context, v8_str(input_str)).ToLocalChecked();
22439
22440 i::Handle<i::JSArray> a =
22441 i::Handle<i::JSArray>::cast(v8::Utils::OpenHandle(*obj));
22442 CHECK_EQ(expected_elements_kind, a->GetElementsKind());
22443
22444 Local<Object> global = context->Global();
22445 global->Set(context, v8_str("obj"), obj).FromJust();
22446 ExpectString("JSON.stringify(obj)", expected_output_str);
22447}
22448} // namespace
22449
22450THREADED_TEST(JSONParseArray) {
22451 LocalContext context;
22452 HandleScope scope(context->GetIsolate());
22453
22454 TestJSONParseArray(context.local(), "[0, 1, 2]", "[0,1,2]",
22455 i::PACKED_SMI_ELEMENTS);
22456 TestJSONParseArray(context.local(), "[0, 1.2, 2]", "[0,1.2,2]",
22457 i::PACKED_DOUBLE_ELEMENTS);
22458 TestJSONParseArray(context.local(), "[0.2, 1, 2]", "[0.2,1,2]",
22459 i::PACKED_DOUBLE_ELEMENTS);
22460 TestJSONParseArray(context.local(), "[0, \"a\", 2]", "[0,\"a\",2]",
22461 i::PACKED_ELEMENTS);
22462 TestJSONParseArray(context.local(), "[\"a\", 1, 2]", "[\"a\",1,2]",
22463 i::PACKED_ELEMENTS);
22464 TestJSONParseArray(context.local(), "[\"a\", 1.2, 2]", "[\"a\",1.2,2]",
22465 i::PACKED_ELEMENTS);
22466 TestJSONParseArray(context.local(), "[0, 1.2, \"a\"]", "[0,1.2,\"a\"]",
22467 i::PACKED_ELEMENTS);
22468}
22469
22470THREADED_TEST(JSONStringifyObject) {
22471 LocalContext context;
22472 HandleScope scope(context->GetIsolate());
22473 Local<Value> value =
22474 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22475 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22476 Local<Object> global = context->Global();
22477 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22478 Local<String> json =
22479 v8::JSON::Stringify(context.local(), obj).ToLocalChecked();
22480 v8::String::Utf8Value utf8(context->GetIsolate(), json);
22481 ExpectString("JSON.stringify(obj)", *utf8);
22482}
22483
22484THREADED_TEST(JSONStringifyObjectWithGap) {
22485 LocalContext context;
22486 HandleScope scope(context->GetIsolate());
22487 Local<Value> value =
22488 v8::JSON::Parse(context.local(), v8_str("{\"x\":42}")).ToLocalChecked();
22489 Local<Object> obj = value->ToObject(context.local()).ToLocalChecked();
22490 Local<Object> global = context->Global();
22491 global->Set(context.local(), v8_str("obj"), obj).FromJust();
22492 Local<String> json =
22493 v8::JSON::Stringify(context.local(), obj, v8_str("*")).ToLocalChecked();
22494 v8::String::Utf8Value utf8(context->GetIsolate(), json);
22495 ExpectString("JSON.stringify(obj, null, '*')", *utf8);
22496}
22497
22498#if V8_OS_POSIX
22499class ThreadInterruptTest {
22500 public:
22501 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22502 ~ThreadInterruptTest() = default;
22503
22504 void RunTest() {
22505 InterruptThread i_thread(this);
22506 i_thread.Start();
22507
22508 sem_.Wait();
22509 CHECK_EQ(kExpectedValue, sem_value_);
22510 }
22511
22512 private:
22513 static const int kExpectedValue = 1;
22514
22515 class InterruptThread : public v8::base::Thread {
22516 public:
22517 explicit InterruptThread(ThreadInterruptTest* test)
22518 : Thread(Options("InterruptThread")), test_(test) {}
22519
22520 void Run() override {
22521 struct sigaction action;
22522
22523 // Ensure that we'll enter waiting condition
22524 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22525
22526 // Setup signal handler
22527 memset(&action, 0, sizeof(action));
22528 action.sa_handler = SignalHandler;
22529 sigaction(SIGCHLD, &action, nullptr);
22530
22531 // Send signal
22532 kill(getpid(), SIGCHLD);
22533
22534 // Ensure that if wait has returned because of error
22535 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
22536
22537 // Set value and signal semaphore
22538 test_->sem_value_ = 1;
22539 test_->sem_.Signal();
22540 }
22541
22542 static void SignalHandler(int signal) {
22543 }
22544
22545 private:
22546 ThreadInterruptTest* test_;
22547 };
22548
22549 v8::base::Semaphore sem_;
22550 volatile int sem_value_;
22551};
22552
22553
22554THREADED_TEST(SemaphoreInterruption) {
22555 ThreadInterruptTest().RunTest();
22556}
22557
22558
22559#endif // V8_OS_POSIX
22560
22561
22562void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22563 UNREACHABLE();
22564}
22565
22566
22567TEST(JSONStringifyAccessCheck) {
22568 v8::V8::Initialize();
22569 v8::Isolate* isolate = CcTest::isolate();
22570 v8::HandleScope scope(isolate);
22571
22572 // Create an ObjectTemplate for global objects and install access
22573 // check callbacks that will block access.
22574 v8::Local<v8::ObjectTemplate> global_template =
22575 v8::ObjectTemplate::New(isolate);
22576 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22577
22578 // Create a context and set an x property on it's global object.
22579 LocalContext context0(nullptr, global_template);
22580 v8::Local<v8::Object> global0 = context0->Global();
22581 global0->Set(context0.local(), v8_str("x"), v8_num(42)).FromJust();
22582 ExpectString("JSON.stringify(this)", "{\"x\":42}");
22583
22584 for (int i = 0; i < 2; i++) {
22585 if (i == 1) {
22586 // Install a toJSON function on the second run.
22587 v8::Local<v8::FunctionTemplate> toJSON =
22588 v8::FunctionTemplate::New(isolate, UnreachableCallback);
22589
22590 global0->Set(context0.local(), v8_str("toJSON"),
22591 toJSON->GetFunction(context0.local()).ToLocalChecked())
22592 .FromJust();
22593 }
22594 // Create a context with a different security token so that the
22595 // failed access check callback will be called on each access.
22596 LocalContext context1(nullptr, global_template);
22597 CHECK(context1->Global()
22598 ->Set(context1.local(), v8_str("other"), global0)
22599 .FromJust());
22600
22601 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22602 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22603 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22604 }
22605}
22606
22607
22608bool access_check_fail_thrown = false;
22609bool catch_callback_called = false;
22610
22611
22612// Failed access check callback that performs a GC on each invocation.
22613void FailedAccessCheckThrows(Local<v8::Object> target,
22614 v8::AccessType type,
22615 Local<v8::Value> data) {
22616 access_check_fail_thrown = true;
22617 i::PrintF("Access check failed. Error thrown.\n");
22618 CcTest::isolate()->ThrowException(
22619 v8::Exception::Error(v8_str("cross context")));
22620}
22621
22622
22623void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22624 for (int i = 0; i < args.Length(); i++) {
22625 i::PrintF("%s\n", *String::Utf8Value(args.GetIsolate(), args[i]));
22626 }
22627 catch_callback_called = true;
22628}
22629
22630
22631void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22632 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
22633 CHECK(
22634 args[0]
22635 ->ToObject(context)
22636 .ToLocalChecked()
22637 ->HasOwnProperty(context, args[1]->ToString(context).ToLocalChecked())
22638 .IsNothing());
22639}
22640
22641
22642void CheckCorrectThrow(const char* script) {
22643 // Test that the script, when wrapped into a try-catch, triggers the catch
22644 // clause due to failed access check throwing an exception.
22645 // The subsequent try-catch should run without any exception.
22646 access_check_fail_thrown = false;
22647 catch_callback_called = false;
22648 i::ScopedVector<char> source(1024);
22649 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22650 CompileRun(source.start());
22651 CHECK(access_check_fail_thrown);
22652 CHECK(catch_callback_called);
22653
22654 access_check_fail_thrown = false;
22655 catch_callback_called = false;
22656 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22657 CHECK(!access_check_fail_thrown);
22658 CHECK(!catch_callback_called);
22659}
22660
22661
22662TEST(AccessCheckThrows) {
22663 i::FLAG_allow_natives_syntax = true;
22664 v8::V8::Initialize();
22665 v8::Isolate* isolate = CcTest::isolate();
22666 isolate->SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22667 v8::HandleScope scope(isolate);
22668
22669 // Create an ObjectTemplate for global objects and install access
22670 // check callbacks that will block access.
22671 v8::Local<v8::ObjectTemplate> global_template =
22672 v8::ObjectTemplate::New(isolate);
22673 global_template->SetAccessCheckCallback(AccessAlwaysBlocked);
22674
22675 // Create a context and set an x property on it's global object.
22676 LocalContext context0(nullptr, global_template);
22677 v8::Local<v8::Object> global0 = context0->Global();
22678 CHECK(global0->Set(context0.local(), v8_str("x"), global0).FromJust());
22679
22680 // Create a context with a different security token so that the
22681 // failed access check callback will be called on each access.
22682 LocalContext context1(nullptr, global_template);
22683 CHECK(context1->Global()
22684 ->Set(context1.local(), v8_str("other"), global0)
22685 .FromJust());
22686
22687 v8::Local<v8::FunctionTemplate> catcher_fun =
22688 v8::FunctionTemplate::New(isolate, CatcherCallback);
22689 CHECK(context1->Global()
22690 ->Set(context1.local(), v8_str("catcher"),
22691 catcher_fun->GetFunction(context1.local()).ToLocalChecked())
22692 .FromJust());
22693
22694 v8::Local<v8::FunctionTemplate> has_own_property_fun =
22695 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22696 CHECK(context1->Global()
22697 ->Set(context1.local(), v8_str("has_own_property"),
22698 has_own_property_fun->GetFunction(context1.local())
22699 .ToLocalChecked())
22700 .FromJust());
22701
22702 {
22703 v8::TryCatch try_catch(isolate);
22704 access_check_fail_thrown = false;
22705 CompileRun("other.x;");
22706 CHECK(access_check_fail_thrown);
22707 CHECK(try_catch.HasCaught());
22708 }
22709
22710 CheckCorrectThrow("other.x");
22711 CheckCorrectThrow("other[1]");
22712 CheckCorrectThrow("JSON.stringify(other)");
22713 CheckCorrectThrow("has_own_property(other, 'x')");
22714 CheckCorrectThrow("%GetProperty(other, 'x')");
22715 CheckCorrectThrow("%SetKeyedProperty(other, 'x', 'foo')");
22716 CheckCorrectThrow("%SetNamedProperty(other, 'y', 'foo')");
22717 STATIC_ASSERT(static_cast<int>(i::LanguageMode::kSloppy) == 0);
22718 STATIC_ASSERT(static_cast<int>(i::LanguageMode::kStrict) == 1);
22719 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); // 0 == SLOPPY
22720 CheckCorrectThrow("%DeleteProperty(other, 'x', 1)"); // 1 == STRICT
22721 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22722 CheckCorrectThrow("%DeleteProperty(other, '1', 1)");
22723 CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
22724 CheckCorrectThrow("%HasProperty(other, 'x')");
22725 CheckCorrectThrow("Object.prototype.propertyIsEnumerable(other, 'x')");
22726 // PROPERTY_ATTRIBUTES_NONE = 0
22727 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22728 "other, 'x', null, null, 1)");
22729
22730 // Reset the failed access check callback so it does not influence
22731 // the other tests.
22732 isolate->SetFailedAccessCheckCallbackFunction(nullptr);
22733}
22734
22735namespace {
22736
22737const char kOneByteSubjectString[] = {
22738 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22739 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22740 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};
22741const uint16_t kTwoByteSubjectString[] = {
22742 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22743 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
22744 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', '\0'};
22745
22746const int kSubjectStringLength = arraysize(kOneByteSubjectString) - 1;
22747STATIC_ASSERT(arraysize(kOneByteSubjectString) ==
22748 arraysize(kTwoByteSubjectString));
22749
22750OneByteVectorResource one_byte_string_resource(
22751 i::Vector<const char>(&kOneByteSubjectString[0], kSubjectStringLength));
22752UC16VectorResource two_byte_string_resource(
22753 i::Vector<const i::uc16>(&kTwoByteSubjectString[0], kSubjectStringLength));
22754
22755class RegExpInterruptTest {
22756 public:
22757 RegExpInterruptTest()
22758 : i_thread(this),
22759 env_(),
22760 isolate_(env_->GetIsolate()),
22761 sem_(0),
22762 ran_test_body_(false),
22763 ran_to_completion_(false) {}
22764
22765 void RunTest(v8::InterruptCallback test_body_fn) {
22766 v8::HandleScope handle_scope(isolate_);
22767
22768 i_thread.SetTestBody(test_body_fn);
22769 i_thread.Start();
22770
22771 TestBody();
22772
22773 i_thread.Join();
22774 }
22775
22776 static void CollectAllGarbage(v8::Isolate* isolate, void* data) {
22777 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22778 i_isolate->heap()->PreciseCollectAllGarbage(
22779 i::Heap::kNoGCFlags, i::GarbageCollectionReason::kRuntime);
22780 }
22781
22782 static void MakeSubjectOneByteExternal(v8::Isolate* isolate, void* data) {
22783 auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22784
22785 v8::HandleScope scope(isolate);
22786 v8::Local<v8::String> string =
22787 v8::Local<v8::String>::New(isolate, instance->string_handle_);
22788 CHECK(string->CanMakeExternal());
22789 string->MakeExternal(&one_byte_string_resource);
22790 }
22791
22792 static void MakeSubjectTwoByteExternal(v8::Isolate* isolate, void* data) {
22793 auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22794
22795 v8::HandleScope scope(isolate);
22796 v8::Local<v8::String> string =
22797 v8::Local<v8::String>::New(isolate, instance->string_handle_);
22798 CHECK(string->CanMakeExternal());
22799 string->MakeExternal(&two_byte_string_resource);
22800 }
22801
22802 private:
22803 static void SignalSemaphore(v8::Isolate* isolate, void* data) {
22804 reinterpret_cast<RegExpInterruptTest*>(data)->sem_.Signal();
22805 }
22806
22807 void CreateTestStrings() {
22808 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
22809
22810 // The string must be in old space to support externalization.
22811 i::Handle<i::String> i_string =
22812 i_isolate->factory()->NewStringFromAsciiChecked(
22813 &kOneByteSubjectString[0], i::AllocationType::kOld);
22814 v8::Local<v8::String> string = v8::Utils::ToLocal(i_string);
22815
22816 env_->Global()->Set(env_.local(), v8_str("a"), string).FromJust();
22817
22818 string_handle_.Reset(env_->GetIsolate(), string);
22819 }
22820
22821 void TestBody() {
22822 CHECK(!ran_test_body_.load());
22823 CHECK(!ran_to_completion_.load());
22824
22825 CreateTestStrings();
22826
22827 v8::TryCatch try_catch(env_->GetIsolate());
22828
22829 isolate_->RequestInterrupt(&SignalSemaphore, this);
22830 CompileRun("/((a*)*)*b/.exec(a)");
22831
22832 CHECK(try_catch.HasTerminated());
22833 CHECK(ran_test_body_.load());
22834 CHECK(ran_to_completion_.load());
22835 }
22836
22837 class InterruptThread : public v8::base::Thread {
22838 public:
22839 explicit InterruptThread(RegExpInterruptTest* test)
22840 : Thread(Options("RegExpInterruptTest")), test_(test) {}
22841
22842 void Run() override {
22843 CHECK_NOT_NULL(test_body_fn_);
22844
22845 // Wait for JS execution to start.
22846 test_->sem_.Wait();
22847
22848 // Sleep for a bit to allow irregexp execution to start up, then run the
22849 // test body.
22850 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
22851 test_->isolate_->RequestInterrupt(&RunTestBody, test_);
22852 test_->isolate_->RequestInterrupt(&SignalSemaphore, test_);
22853
22854 // Wait for the scheduled interrupt to signal.
22855 test_->sem_.Wait();
22856
22857 // Sleep again to resume irregexp execution, then terminate.
22858 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
22859 test_->ran_to_completion_.store(true);
22860 test_->isolate_->TerminateExecution();
22861 }
22862
22863 static void RunTestBody(v8::Isolate* isolate, void* data) {
22864 auto instance = reinterpret_cast<RegExpInterruptTest*>(data);
22865 instance->i_thread.test_body_fn_(isolate, data);
22866 instance->ran_test_body_.store(true);
22867 }
22868
22869 void SetTestBody(v8::InterruptCallback callback) {
22870 test_body_fn_ = callback;
22871 }
22872
22873 private:
22874 v8::InterruptCallback test_body_fn_;
22875 RegExpInterruptTest* test_;
22876 };
22877
22878 InterruptThread i_thread;
22879
22880 LocalContext env_;
22881 v8::Isolate* isolate_;
22882 v8::base::Semaphore sem_; // Coordinates between main and interrupt threads.
22883
22884 v8::Persistent<v8::String> string_handle_;
22885
22886 std::atomic<bool> ran_test_body_;
22887 std::atomic<bool> ran_to_completion_;
22888};
22889
22890} // namespace
22891
22892TEST(RegExpInterruptAndCollectAllGarbage) {
22893 i::FLAG_always_compact = true; // Move all movable objects on GC.
22894 RegExpInterruptTest test;
22895 test.RunTest(RegExpInterruptTest::CollectAllGarbage);
22896}
22897
22898TEST(RegExpInterruptAndMakeSubjectOneByteExternal) {
22899 RegExpInterruptTest test;
22900 test.RunTest(RegExpInterruptTest::MakeSubjectOneByteExternal);
22901}
22902
22903TEST(RegExpInterruptAndMakeSubjectTwoByteExternal) {
22904 RegExpInterruptTest test;
22905 test.RunTest(RegExpInterruptTest::MakeSubjectTwoByteExternal);
22906}
22907
22908class RequestInterruptTestBase {
22909 public:
22910 RequestInterruptTestBase()
22911 : env_(),
22912 isolate_(env_->GetIsolate()),
22913 sem_(0),
22914 warmup_(20000),
22915 should_continue_(true) {
22916 }
22917
22918 virtual ~RequestInterruptTestBase() = default;
22919
22920 virtual void StartInterruptThread() = 0;
22921
22922 virtual void TestBody() = 0;
22923
22924 void RunTest() {
22925 StartInterruptThread();
22926
22927 v8::HandleScope handle_scope(isolate_);
22928
22929 TestBody();
22930
22931 // Verify we arrived here because interruptor was called
22932 // not due to a bug causing us to exit the loop too early.
22933 CHECK(!should_continue());
22934 }
22935
22936 void WakeUpInterruptor() {
22937 sem_.Signal();
22938 }
22939
22940 bool should_continue() const { return should_continue_; }
22941
22942 bool ShouldContinue() {
22943 if (warmup_ > 0) {
22944 if (--warmup_ == 0) {
22945 WakeUpInterruptor();
22946 }
22947 }
22948
22949 return should_continue_;
22950 }
22951
22952 static void ShouldContinueCallback(
22953 const v8::FunctionCallbackInfo<Value>& info) {
22954 RequestInterruptTestBase* test =
22955 reinterpret_cast<RequestInterruptTestBase*>(
22956 info.Data().As<v8::External>()->Value());
22957 info.GetReturnValue().Set(test->ShouldContinue());
22958 }
22959
22960 LocalContext env_;
22961 v8::Isolate* isolate_;
22962 v8::base::Semaphore sem_;
22963 int warmup_;
22964 bool should_continue_;
22965};
22966
22967
22968class RequestInterruptTestBaseWithSimpleInterrupt
22969 : public RequestInterruptTestBase {
22970 public:
22971 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22972
22973 void StartInterruptThread() override { i_thread.Start(); }
22974
22975 private:
22976 class InterruptThread : public v8::base::Thread {
22977 public:
22978 explicit InterruptThread(RequestInterruptTestBase* test)
22979 : Thread(Options("RequestInterruptTest")), test_(test) {}
22980
22981 void Run() override {
22982 test_->sem_.Wait();
22983 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22984 }
22985
22986 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22987 reinterpret_cast<RequestInterruptTestBase*>(data)->
22988 should_continue_ = false;
22989 }
22990
22991 private:
22992 RequestInterruptTestBase* test_;
22993 };
22994
22995 InterruptThread i_thread;
22996};
22997
22998
22999class RequestInterruptTestWithFunctionCall
23000 : public RequestInterruptTestBaseWithSimpleInterrupt {
23001 public:
23002 void TestBody() override {
23003 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23004 v8::External::New(isolate_, this))
23005 .ToLocalChecked();
23006 CHECK(env_->Global()
23007 ->Set(env_.local(), v8_str("ShouldContinue"), func)
23008 .FromJust());
23009
23010 CompileRun("while (ShouldContinue()) { }");
23011 }
23012};
23013
23014
23015class RequestInterruptTestWithMethodCall
23016 : public RequestInterruptTestBaseWithSimpleInterrupt {
23017 public:
23018 void TestBody() override {
23019 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23020 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23021 proto->Set(v8_str("shouldContinue"),
23022 FunctionTemplate::New(isolate_, ShouldContinueCallback,
23023 v8::External::New(isolate_, this)));
23024 CHECK(env_->Global()
23025 ->Set(env_.local(), v8_str("Klass"),
23026 t->GetFunction(env_.local()).ToLocalChecked())
23027 .FromJust());
23028
23029 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23030 }
23031};
23032
23033
23034class RequestInterruptTestWithAccessor
23035 : public RequestInterruptTestBaseWithSimpleInterrupt {
23036 public:
23037 void TestBody() override {
23038 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23039 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23040 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23041 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23042 CHECK(env_->Global()
23043 ->Set(env_.local(), v8_str("Klass"),
23044 t->GetFunction(env_.local()).ToLocalChecked())
23045 .FromJust());
23046
23047 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23048 }
23049};
23050
23051
23052class RequestInterruptTestWithNativeAccessor
23053 : public RequestInterruptTestBaseWithSimpleInterrupt {
23054 public:
23055 void TestBody() override {
23056 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23057 t->InstanceTemplate()->SetNativeDataProperty(
23058 v8_str("shouldContinue"), &ShouldContinueNativeGetter, nullptr,
23059 v8::External::New(isolate_, this));
23060 CHECK(env_->Global()
23061 ->Set(env_.local(), v8_str("Klass"),
23062 t->GetFunction(env_.local()).ToLocalChecked())
23063 .FromJust());
23064
23065 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23066 }
23067
23068 private:
23069 static void ShouldContinueNativeGetter(
23070 Local<String> property,
23071 const v8::PropertyCallbackInfo<v8::Value>& info) {
23072 RequestInterruptTestBase* test =
23073 reinterpret_cast<RequestInterruptTestBase*>(
23074 info.Data().As<v8::External>()->Value());
23075 info.GetReturnValue().Set(test->ShouldContinue());
23076 }
23077};
23078
23079
23080class RequestInterruptTestWithMethodCallAndInterceptor
23081 : public RequestInterruptTestBaseWithSimpleInterrupt {
23082 public:
23083 void TestBody() override {
23084 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23085 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23086 proto->Set(v8_str("shouldContinue"),
23087 FunctionTemplate::New(isolate_, ShouldContinueCallback,
23088 v8::External::New(isolate_, this)));
23089 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23090 instance_template->SetHandler(
23091 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23092
23093 CHECK(env_->Global()
23094 ->Set(env_.local(), v8_str("Klass"),
23095 t->GetFunction(env_.local()).ToLocalChecked())
23096 .FromJust());
23097
23098 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23099 }
23100
23101 private:
23102 static void EmptyInterceptor(
23103 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23104};
23105
23106
23107class RequestInterruptTestWithMathAbs
23108 : public RequestInterruptTestBaseWithSimpleInterrupt {
23109 public:
23110 void TestBody() override {
23111 env_->Global()
23112 ->Set(env_.local(), v8_str("WakeUpInterruptor"),
23113 Function::New(env_.local(), WakeUpInterruptorCallback,
23114 v8::External::New(isolate_, this))
23115 .ToLocalChecked())
23116 .FromJust();
23117
23118 env_->Global()
23119 ->Set(env_.local(), v8_str("ShouldContinue"),
23120 Function::New(env_.local(), ShouldContinueCallback,
23121 v8::External::New(isolate_, this))
23122 .ToLocalChecked())
23123 .FromJust();
23124
23125 i::FLAG_allow_natives_syntax = true;
23126 CompileRun("function loopish(o) {"
23127 " var pre = 10;"
23128 " while (o.abs(1) > 0) {"
23129 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23130 " if (pre > 0) {"
23131 " if (--pre === 0) WakeUpInterruptor(o === Math);"
23132 " }"
23133 " }"
23134 "}"
23135 "var i = 50;"
23136 "var obj = {abs: function () { return i-- }, x: null};"
23137 "delete obj.x;"
23138 "loopish(obj);"
23139 "%OptimizeFunctionOnNextCall(loopish);"
23140 "loopish(Math);");
23141
23142 i::FLAG_allow_natives_syntax = false;
23143 }
23144
23145 private:
23146 static void WakeUpInterruptorCallback(
23147 const v8::FunctionCallbackInfo<Value>& info) {
23148 if (!info[0]->BooleanValue(info.GetIsolate())) {
23149 return;
23150 }
23151
23152 RequestInterruptTestBase* test =
23153 reinterpret_cast<RequestInterruptTestBase*>(
23154 info.Data().As<v8::External>()->Value());
23155 test->WakeUpInterruptor();
23156 }
23157
23158 static void ShouldContinueCallback(
23159 const v8::FunctionCallbackInfo<Value>& info) {
23160 RequestInterruptTestBase* test =
23161 reinterpret_cast<RequestInterruptTestBase*>(
23162 info.Data().As<v8::External>()->Value());
23163 info.GetReturnValue().Set(test->should_continue());
23164 }
23165};
23166
23167
23168TEST(RequestInterruptTestWithFunctionCall) {
23169 RequestInterruptTestWithFunctionCall().RunTest();
23170}
23171
23172
23173TEST(RequestInterruptTestWithMethodCall) {
23174 RequestInterruptTestWithMethodCall().RunTest();
23175}
23176
23177
23178TEST(RequestInterruptTestWithAccessor) {
23179 RequestInterruptTestWithAccessor().RunTest();
23180}
23181
23182
23183TEST(RequestInterruptTestWithNativeAccessor) {
23184 RequestInterruptTestWithNativeAccessor().RunTest();
23185}
23186
23187
23188TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23189 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23190}
23191
23192
23193TEST(RequestInterruptTestWithMathAbs) {
23194 RequestInterruptTestWithMathAbs().RunTest();
23195}
23196
23197
23198class RequestMultipleInterrupts : public RequestInterruptTestBase {
23199 public:
23200 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23201
23202 void StartInterruptThread() override { i_thread.Start(); }
23203
23204 void TestBody() override {
23205 Local<Function> func = Function::New(env_.local(), ShouldContinueCallback,
23206 v8::External::New(isolate_, this))
23207 .ToLocalChecked();
23208 CHECK(env_->Global()
23209 ->Set(env_.local(), v8_str("ShouldContinue"), func)
23210 .FromJust());
23211
23212 CompileRun("while (ShouldContinue()) { }");
23213 }
23214
23215 private:
23216 class InterruptThread : public v8::base::Thread {
23217 public:
23218 enum { NUM_INTERRUPTS = 10 };
23219 explicit InterruptThread(RequestMultipleInterrupts* test)
23220 : Thread(Options("RequestInterruptTest")), test_(test) {}
23221
23222 void Run() override {
23223 test_->sem_.Wait();
23224 for (int i = 0; i < NUM_INTERRUPTS; i++) {
23225 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23226 }
23227 }
23228
23229 static void OnInterrupt(v8::Isolate* isolate, void* data) {
23230 RequestMultipleInterrupts* test =
23231 reinterpret_cast<RequestMultipleInterrupts*>(data);
23232 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23233 }
23234
23235 private:
23236 RequestMultipleInterrupts* test_;
23237 };
23238
23239 InterruptThread i_thread;
23240 int counter_;
23241};
23242
23243
23244TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23245
23246
23247static bool interrupt_was_called = false;
23248
23249
23250void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
23251 interrupt_was_called = true;
23252}
23253
23254
23255TEST(RequestInterruptSmallScripts) {
23256 LocalContext env;
23257 v8::Isolate* isolate = CcTest::isolate();
23258 v8::HandleScope scope(isolate);
23259
23260 interrupt_was_called = false;
23261 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, nullptr);
23262 CompileRun("(function(x){return x;})(1);");
23263 CHECK(interrupt_was_called);
23264}
23265
23266
23267static Local<Value> function_new_expected_env;
23268static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23269 CHECK(
23270 function_new_expected_env->Equals(info.GetIsolate()->GetCurrentContext(),
23271 info.Data())
23272 .FromJust());
23273 info.GetReturnValue().Set(17);
23274}
23275
23276
23277THREADED_TEST(FunctionNew) {
23278 LocalContext env;
23279 v8::Isolate* isolate = env->GetIsolate();
23280 v8::HandleScope scope(isolate);
23281 Local<Object> data = v8::Object::New(isolate);
23282 function_new_expected_env = data;
23283 Local<Function> func =
23284 Function::New(env.local(), FunctionNewCallback, data).ToLocalChecked();
23285 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
23286 Local<Value> result = CompileRun("func();");
23287 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result).FromJust());
23288 // Serial number should be invalid => should not be cached.
23289 auto serial_number =
23290 i::Smi::cast(i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*func))
23291 ->shared()
23292 ->get_api_func_data()
23293 ->serial_number())
23294 ->value();
23295 CHECK_EQ(i::FunctionTemplateInfo::kInvalidSerialNumber, serial_number);
23296
23297 // Verify that each Function::New creates a new function instance
23298 Local<Object> data2 = v8::Object::New(isolate);
23299 function_new_expected_env = data2;
23300 Local<Function> func2 =
23301 Function::New(env.local(), FunctionNewCallback, data2).ToLocalChecked();
23302 CHECK(!func2->IsNull());
23303 CHECK(!func->Equals(env.local(), func2).FromJust());
23304 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
23305 Local<Value> result2 = CompileRun("func2();");
23306 CHECK(v8::Integer::New(isolate, 17)->Equals(env.local(), result2).FromJust());
23307}
23308
23309namespace {
23310
23311void Verify(v8::Isolate* isolate, Local<v8::Object> obj) {
23312#if VERIFY_HEAP
23313 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23314 i::Handle<i::JSReceiver> i_obj = v8::Utils::OpenHandle(*obj);
23315 i_obj->ObjectVerify(i_isolate);
23316#endif
23317}
23318
23319} // namespace
23320
23321THREADED_TEST(ObjectNew) {
23322 LocalContext env;
23323 v8::Isolate* isolate = env->GetIsolate();
23324 v8::HandleScope scope(isolate);
23325 {
23326 // Verify that Object::New(null) produces an object with a null
23327 // [[Prototype]].
23328 Local<v8::Object> obj =
23329 v8::Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0);
23330 CHECK(obj->GetPrototype()->IsNull());
23331 Verify(isolate, obj);
23332 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23333 CHECK_EQ(0, keys->Length());
23334 }
23335 {
23336 // Verify that Object::New(proto) produces an object with
23337 // proto as it's [[Prototype]].
23338 Local<v8::Object> proto = v8::Object::New(isolate);
23339 Local<v8::Object> obj =
23340 v8::Object::New(isolate, proto, nullptr, nullptr, 0);
23341 Verify(isolate, obj);
23342 CHECK(obj->GetPrototype()->SameValue(proto));
23343 }
23344 {
23345 // Verify that the properties are installed correctly.
23346 Local<v8::Name> names[3] = {v8_str("a"), v8_str("b"), v8_str("c")};
23347 Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23348 Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23349 values, arraysize(values));
23350 Verify(isolate, obj);
23351 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23352 CHECK_EQ(arraysize(names), keys->Length());
23353 for (uint32_t i = 0; i < arraysize(names); ++i) {
23354 CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23355 CHECK(values[i]->SameValue(
23356 obj->Get(env.local(), names[i]).ToLocalChecked()));
23357 }
23358 }
23359 {
23360 // Same as above, but with non-null prototype.
23361 Local<v8::Object> proto = v8::Object::New(isolate);
23362 Local<v8::Name> names[3] = {v8_str("x"), v8_str("y"), v8_str("z")};
23363 Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23364 Local<v8::Object> obj =
23365 v8::Object::New(isolate, proto, names, values, arraysize(values));
23366 CHECK(obj->GetPrototype()->SameValue(proto));
23367 Verify(isolate, obj);
23368 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23369 CHECK_EQ(arraysize(names), keys->Length());
23370 for (uint32_t i = 0; i < arraysize(names); ++i) {
23371 CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23372 CHECK(values[i]->SameValue(
23373 obj->Get(env.local(), names[i]).ToLocalChecked()));
23374 }
23375 }
23376 {
23377 // This has to work with duplicate names too.
23378 Local<v8::Name> names[3] = {v8_str("a"), v8_str("a"), v8_str("a")};
23379 Local<v8::Value> values[3] = {v8_num(1), v8_num(2), v8_num(3)};
23380 Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23381 values, arraysize(values));
23382 Verify(isolate, obj);
23383 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23384 CHECK_EQ(1, keys->Length());
23385 CHECK(v8_str("a")->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23386 CHECK(v8_num(3)->SameValue(
23387 obj->Get(env.local(), v8_str("a")).ToLocalChecked()));
23388 }
23389 {
23390 // This has to work with array indices too.
23391 Local<v8::Name> names[2] = {v8_str("0"), v8_str("1")};
23392 Local<v8::Value> values[2] = {v8_num(0), v8_num(1)};
23393 Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23394 values, arraysize(values));
23395 Verify(isolate, obj);
23396 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23397 CHECK_EQ(arraysize(names), keys->Length());
23398 for (uint32_t i = 0; i < arraysize(names); ++i) {
23399 CHECK(v8::Number::New(isolate, i)
23400 ->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23401 CHECK(values[i]->SameValue(obj->Get(env.local(), i).ToLocalChecked()));
23402 }
23403 }
23404 {
23405 // This has to work with mixed array indices / property names too.
23406 Local<v8::Name> names[2] = {v8_str("0"), v8_str("x")};
23407 Local<v8::Value> values[2] = {v8_num(42), v8_num(24)};
23408 Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23409 values, arraysize(values));
23410 Verify(isolate, obj);
23411 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23412 CHECK_EQ(arraysize(names), keys->Length());
23413 // 0 -> 42
23414 CHECK(v8_num(0)->SameValue(keys->Get(env.local(), 0).ToLocalChecked()));
23415 CHECK(
23416 values[0]->SameValue(obj->Get(env.local(), names[0]).ToLocalChecked()));
23417 // "x" -> 24
23418 CHECK(v8_str("x")->SameValue(keys->Get(env.local(), 1).ToLocalChecked()));
23419 CHECK(
23420 values[1]->SameValue(obj->Get(env.local(), names[1]).ToLocalChecked()));
23421 }
23422 {
23423 // Verify that this also works for a couple thousand properties.
23424 size_t const kLength = 10 * 1024;
23425 Local<v8::Name> names[kLength];
23426 Local<v8::Value> values[kLength];
23427 for (size_t i = 0; i < arraysize(names); ++i) {
23428 std::ostringstream ost;
23429 ost << "a" << i;
23430 names[i] = v8_str(ost.str().c_str());
23431 values[i] = v8_num(static_cast<double>(i));
23432 }
23433 Local<v8::Object> obj = v8::Object::New(isolate, v8::Null(isolate), names,
23434 values, arraysize(names));
23435 Verify(isolate, obj);
23436 Local<Array> keys = obj->GetOwnPropertyNames(env.local()).ToLocalChecked();
23437 CHECK_EQ(arraysize(names), keys->Length());
23438 for (uint32_t i = 0; i < arraysize(names); ++i) {
23439 CHECK(names[i]->SameValue(keys->Get(env.local(), i).ToLocalChecked()));
23440 CHECK(values[i]->SameValue(
23441 obj->Get(env.local(), names[i]).ToLocalChecked()));
23442 }
23443 }
23444}
23445
23446TEST(EscapableHandleScope) {
23447 HandleScope outer_scope(CcTest::isolate());
23448 LocalContext context;
23449 const int runs = 10;
23450 Local<String> values[runs];
23451 for (int i = 0; i < runs; i++) {
23452 v8::EscapableHandleScope inner_scope(CcTest::isolate());
23453 Local<String> value;
23454 if (i != 0) value = v8_str("escape value");
23455 if (i < runs / 2) {
23456 values[i] = inner_scope.Escape(value);
23457 } else {
23458 values[i] = inner_scope.EscapeMaybe(v8::MaybeLocal<String>(value))
23459 .ToLocalChecked();
23460 }
23461 }
23462 for (int i = 0; i < runs; i++) {
23463 Local<String> expected;
23464 if (i != 0) {
23465 CHECK(v8_str("escape value")
23466 ->Equals(context.local(), values[i])
23467 .FromJust());
23468 } else {
23469 CHECK(values[i].IsEmpty());
23470 }
23471 }
23472}
23473
23474
23475static void SetterWhichExpectsThisAndHolderToDiffer(
23476 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23477 CHECK(info.Holder() != info.This());
23478}
23479
23480
23481TEST(Regress239669) {
23482 LocalContext context;
23483 v8::Isolate* isolate = context->GetIsolate();
23484 v8::HandleScope scope(isolate);
23485 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23486 templ->SetAccessor(v8_str("x"), nullptr,
23487 SetterWhichExpectsThisAndHolderToDiffer);
23488 CHECK(context->Global()
23489 ->Set(context.local(), v8_str("P"),
23490 templ->NewInstance(context.local()).ToLocalChecked())
23491 .FromJust());
23492 CompileRun(
23493 "function C1() {"
23494 " this.x = 23;"
23495 "};"
23496 "C1.prototype = P;"
23497 "for (var i = 0; i < 4; i++ ) {"
23498 " new C1();"
23499 "}");
23500}
23501
23502
23503class ApiCallOptimizationChecker {
23504 private:
23505 static Local<Object> data;
23506 static Local<Object> receiver;
23507 static Local<Object> holder;
23508 static Local<Object> callee;
23509 static int count;
23510
23511 static void OptimizationCallback(
23512 const v8::FunctionCallbackInfo<v8::Value>& info) {
23513 CHECK(data == info.Data());
23514 CHECK(receiver == info.This());
23515 if (info.Length() == 1) {
23516 CHECK(v8_num(1)
23517 ->Equals(info.GetIsolate()->GetCurrentContext(), info[0])
23518 .FromJust());
23519 }
23520 CHECK(holder == info.Holder());
23521 count++;
23522 info.GetReturnValue().Set(v8_str("returned"));
23523 }
23524
23525 public:
23526 enum SignatureType {
23527 kNoSignature,
23528 kSignatureOnReceiver,
23529 kSignatureOnPrototype
23530 };
23531
23532 void RunAll() {
23533 SignatureType signature_types[] =
23534 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23535 for (unsigned i = 0; i < arraysize(signature_types); i++) {
23536 SignatureType signature_type = signature_types[i];
23537 for (int j = 0; j < 2; j++) {
23538 bool global = j == 0;
23539 int key = signature_type +
23540 arraysize(signature_types) * (global ? 1 : 0);
23541 Run(signature_type, global, key);
23542 }
23543 }
23544 }
23545
23546 void Run(SignatureType signature_type, bool global, int key) {
23547 v8::Isolate* isolate = CcTest::isolate();
23548 v8::HandleScope scope(isolate);
23549 // Build a template for signature checks.
23550 Local<v8::ObjectTemplate> signature_template;
23551 Local<v8::Signature> signature;
23552 {
23553 Local<v8::FunctionTemplate> parent_template =
23554 FunctionTemplate::New(isolate);
23555 Local<v8::FunctionTemplate> function_template
23556 = FunctionTemplate::New(isolate);
23557 function_template->Inherit(parent_template);
23558 switch (signature_type) {
23559 case kNoSignature:
23560 break;
23561 case kSignatureOnReceiver:
23562 signature = v8::Signature::New(isolate, function_template);
23563 break;
23564 case kSignatureOnPrototype:
23565 signature = v8::Signature::New(isolate, parent_template);
23566 break;
23567 }
23568 signature_template = function_template->InstanceTemplate();
23569 }
23570 // Global object must pass checks.
23571 Local<v8::Context> context =
23572 v8::Context::New(isolate, nullptr, signature_template);
23573 v8::Context::Scope context_scope(context);
23574 // Install regular object that can pass signature checks.
23575 Local<Object> function_receiver =
23576 signature_template->NewInstance(context).ToLocalChecked();
23577 CHECK(context->Global()
23578 ->Set(context, v8_str("function_receiver"), function_receiver)
23579 .FromJust());
23580 // Get the holder objects.
23581 Local<Object> inner_global =
23582 Local<Object>::Cast(context->Global()->GetPrototype());
23583 data = Object::New(isolate);
23584 Local<FunctionTemplate> function_template = FunctionTemplate::New(
23585 isolate, OptimizationCallback, data, signature);
23586 Local<Function> function =
23587 function_template->GetFunction(context).ToLocalChecked();
23588 Local<Object> global_holder = inner_global;
23589 Local<Object> function_holder = function_receiver;
23590 if (signature_type == kSignatureOnPrototype) {
23591 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23592 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23593 }
23594 global_holder->Set(context, v8_str("g_f"), function).FromJust();
23595 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23596 function_holder->Set(context, v8_str("f"), function).FromJust();
23597 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23598 // Initialize expected values.
23599 callee = function;
23600 count = 0;
23601 if (global) {
23602 receiver = context->Global();
23603 holder = inner_global;
23604 } else {
23605 holder = function_receiver;
23606 // If not using a signature, add something else to the prototype chain
23607 // to test the case that holder != receiver
23608 if (signature_type == kNoSignature) {
23609 receiver = Local<Object>::Cast(CompileRun(
23610 "var receiver_subclass = {};\n"
23611 "receiver_subclass.__proto__ = function_receiver;\n"
23612 "receiver_subclass"));
23613 } else {
23614 receiver = Local<Object>::Cast(CompileRun(
23615 "var receiver_subclass = function_receiver;\n"
23616 "receiver_subclass"));
23617 }
23618 }
23619 // With no signature, the holder is not set.
23620 if (signature_type == kNoSignature) holder = receiver;
23621 // build wrap_function
23622 i::ScopedVector<char> wrap_function(200);
23623 if (global) {
23624 i::SNPrintF(
23625 wrap_function,
23626 "function wrap_f_%d() { var f = g_f; return f(); }\n"
23627 "function wrap_get_%d() { return this.g_acc; }\n"
23628 "function wrap_set_%d() { return this.g_acc = 1; }\n",
23629 key, key, key);
23630 } else {
23631 i::SNPrintF(
23632 wrap_function,
23633 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23634 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23635 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23636 key, key, key);
23637 }
23638 // build source string
23639 i::ScopedVector<char> source(1000);
23640 i::SNPrintF(
23641 source,
23642 "%s\n" // wrap functions
23643 "function wrap_f() { return wrap_f_%d(); }\n"
23644 "function wrap_get() { return wrap_get_%d(); }\n"
23645 "function wrap_set() { return wrap_set_%d(); }\n"
23646 "check = function(returned) {\n"
23647 " if (returned !== 'returned') { throw returned; }\n"
23648 "}\n"
23649 "\n"
23650 "check(wrap_f());\n"
23651 "check(wrap_f());\n"
23652 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23653 "check(wrap_f());\n"
23654 "\n"
23655 "check(wrap_get());\n"
23656 "check(wrap_get());\n"
23657 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23658 "check(wrap_get());\n"
23659 "\n"
23660 "check = function(returned) {\n"
23661 " if (returned !== 1) { throw returned; }\n"
23662 "}\n"
23663 "check(wrap_set());\n"
23664 "check(wrap_set());\n"
23665 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23666 "check(wrap_set());\n",
23667 wrap_function.start(), key, key, key, key, key, key);
23668 v8::TryCatch try_catch(isolate);
23669 CompileRun(source.start());
23670 CHECK(!try_catch.HasCaught());
23671 CHECK_EQ(9, count);
23672 }
23673};
23674
23675
23676Local<Object> ApiCallOptimizationChecker::data;
23677Local<Object> ApiCallOptimizationChecker::receiver;
23678Local<Object> ApiCallOptimizationChecker::holder;
23679Local<Object> ApiCallOptimizationChecker::callee;
23680int ApiCallOptimizationChecker::count = 0;
23681
23682
23683TEST(FunctionCallOptimization) {
23684 i::FLAG_allow_natives_syntax = true;
23685 ApiCallOptimizationChecker checker;
23686 checker.RunAll();
23687}
23688
23689
23690TEST(FunctionCallOptimizationMultipleArgs) {
23691 i::FLAG_allow_natives_syntax = true;
23692 LocalContext context;
23693 v8::Isolate* isolate = context->GetIsolate();
23694 v8::HandleScope scope(isolate);
23695 Local<Object> global = context->Global();
23696 Local<v8::Function> function =
23697 Function::New(context.local(), Returns42).ToLocalChecked();
23698 global->Set(context.local(), v8_str("x"), function).FromJust();
23699 CompileRun(
23700 "function x_wrap() {\n"
23701 " for (var i = 0; i < 5; i++) {\n"
23702 " x(1,2,3);\n"
23703 " }\n"
23704 "}\n"
23705 "x_wrap();\n"
23706 "%OptimizeFunctionOnNextCall(x_wrap);"
23707 "x_wrap();\n");
23708}
23709
23710
23711static void ReturnsSymbolCallback(
23712 const v8::FunctionCallbackInfo<v8::Value>& info) {
23713 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
23714}
23715
23716
23717TEST(ApiCallbackCanReturnSymbols) {
23718 i::FLAG_allow_natives_syntax = true;
23719 LocalContext context;
23720 v8::Isolate* isolate = context->GetIsolate();
23721 v8::HandleScope scope(isolate);
23722 Local<Object> global = context->Global();
23723 Local<v8::Function> function =
23724 Function::New(context.local(), ReturnsSymbolCallback).ToLocalChecked();
23725 global->Set(context.local(), v8_str("x"), function).FromJust();
23726 CompileRun(
23727 "function x_wrap() {\n"
23728 " for (var i = 0; i < 5; i++) {\n"
23729 " x();\n"
23730 " }\n"
23731 "}\n"
23732 "x_wrap();\n"
23733 "%OptimizeFunctionOnNextCall(x_wrap);"
23734 "x_wrap();\n");
23735}
23736
23737
23738TEST(EmptyApiCallback) {
23739 LocalContext context;
23740 auto isolate = context->GetIsolate();
23741 v8::HandleScope scope(isolate);
23742 auto global = context->Global();
23743 auto function = FunctionTemplate::New(isolate)
23744 ->GetFunction(context.local())
23745 .ToLocalChecked();
23746 global->Set(context.local(), v8_str("x"), function).FromJust();
23747
23748 auto result = CompileRun("x()");
23749 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23750
23751 result = CompileRun("x(1,2,3)");
23752 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23753
23754 result = CompileRun("x.call(undefined)");
23755 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23756
23757 result = CompileRun("x.call(null)");
23758 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
23759
23760 result = CompileRun("7 + x.call(3) + 11");
23761 CHECK(result->IsInt32());
23762 CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23763
23764 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
23765 CHECK(result->IsInt32());
23766 CHECK_EQ(21, result->Int32Value(context.local()).FromJust());
23767
23768 result = CompileRun("var y = []; x.call(y)");
23769 CHECK(result->IsArray());
23770
23771 result = CompileRun("x.call(y, 1, 2, 3, 4)");
23772 CHECK(result->IsArray());
23773}
23774
23775
23776TEST(SimpleSignatureCheck) {
23777 LocalContext context;
23778 auto isolate = context->GetIsolate();
23779 v8::HandleScope scope(isolate);
23780 auto global = context->Global();
23781 auto sig_obj = FunctionTemplate::New(isolate);
23782 auto sig = v8::Signature::New(isolate, sig_obj);
23783 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23784 global->Set(context.local(), v8_str("sig_obj"),
23785 sig_obj->GetFunction(context.local()).ToLocalChecked())
23786 .FromJust();
23787 global->Set(context.local(), v8_str("x"),
23788 x->GetFunction(context.local()).ToLocalChecked())
23789 .FromJust();
23790 CompileRun("var s = new sig_obj();");
23791 {
23792 TryCatch try_catch(isolate);
23793 CompileRun("x()");
23794 CHECK(try_catch.HasCaught());
23795 }
23796 {
23797 TryCatch try_catch(isolate);
23798 CompileRun("x.call(1)");
23799 CHECK(try_catch.HasCaught());
23800 }
23801 {
23802 TryCatch try_catch(isolate);
23803 auto result = CompileRun("s.x = x; s.x()");
23804 CHECK(!try_catch.HasCaught());
23805 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23806 }
23807 {
23808 TryCatch try_catch(isolate);
23809 auto result = CompileRun("x.call(s)");
23810 CHECK(!try_catch.HasCaught());
23811 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23812 }
23813}
23814
23815
23816TEST(ChainSignatureCheck) {
23817 LocalContext context;
23818 auto isolate = context->GetIsolate();
23819 v8::HandleScope scope(isolate);
23820 auto global = context->Global();
23821 auto sig_obj = FunctionTemplate::New(isolate);
23822 auto sig = v8::Signature::New(isolate, sig_obj);
23823 for (int i = 0; i < 4; ++i) {
23824 auto temp = FunctionTemplate::New(isolate);
23825 temp->Inherit(sig_obj);
23826 sig_obj = temp;
23827 }
23828 auto x = FunctionTemplate::New(isolate, Returns42, Local<Value>(), sig);
23829 global->Set(context.local(), v8_str("sig_obj"),
23830 sig_obj->GetFunction(context.local()).ToLocalChecked())
23831 .FromJust();
23832 global->Set(context.local(), v8_str("x"),
23833 x->GetFunction(context.local()).ToLocalChecked())
23834 .FromJust();
23835 CompileRun("var s = new sig_obj();");
23836 {
23837 TryCatch try_catch(isolate);
23838 CompileRun("x()");
23839 CHECK(try_catch.HasCaught());
23840 }
23841 {
23842 TryCatch try_catch(isolate);
23843 CompileRun("x.call(1)");
23844 CHECK(try_catch.HasCaught());
23845 }
23846 {
23847 TryCatch try_catch(isolate);
23848 auto result = CompileRun("s.x = x; s.x()");
23849 CHECK(!try_catch.HasCaught());
23850 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23851 }
23852 {
23853 TryCatch try_catch(isolate);
23854 auto result = CompileRun("x.call(s)");
23855 CHECK(!try_catch.HasCaught());
23856 CHECK_EQ(42, result->Int32Value(context.local()).FromJust());
23857 }
23858}
23859
23860
23861static const char* last_event_message;
23862static int last_event_status;
23863void StoringEventLoggerCallback(const char* message, int status) {
23864 last_event_message = message;
23865 last_event_status = status;
23866}
23867
23868
23869TEST(EventLogging) {
23870 v8::Isolate* isolate = CcTest::isolate();
23871 isolate->SetEventLogger(StoringEventLoggerCallback);
23872 v8::internal::HistogramTimer histogramTimer(
23873 "V8.Test", 0, 10000, v8::internal::HistogramTimerResolution::MILLISECOND,
23874 50, reinterpret_cast<v8::internal::Isolate*>(isolate)->counters());
23875 histogramTimer.Start();
23876 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23877 CHECK_EQ(0, last_event_status);
23878 histogramTimer.Stop();
23879 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
23880 CHECK_EQ(1, last_event_status);
23881}
23882
23883TEST(PropertyDescriptor) {
23884 LocalContext context;
23885 v8::Isolate* isolate = context->GetIsolate();
23886 v8::HandleScope scope(isolate);
23887
23888 { // empty descriptor
23889 v8::PropertyDescriptor desc;
23890 CHECK(!desc.has_value());
23891 CHECK(!desc.has_set());
23892 CHECK(!desc.has_get());
23893 CHECK(!desc.has_enumerable());
23894 CHECK(!desc.has_configurable());
23895 CHECK(!desc.has_writable());
23896 }
23897 {
23898 // data descriptor
23899 v8::PropertyDescriptor desc(v8_num(42));
23900 desc.set_enumerable(false);
23901 CHECK(desc.value() == v8_num(42));
23902 CHECK(desc.has_value());
23903 CHECK(!desc.has_set());
23904 CHECK(!desc.has_get());
23905 CHECK(desc.has_enumerable());
23906 CHECK(!desc.enumerable());
23907 CHECK(!desc.has_configurable());
23908 CHECK(!desc.has_writable());
23909 }
23910 {
23911 // data descriptor
23912 v8::PropertyDescriptor desc(v8_num(42));
23913 desc.set_configurable(true);
23914 CHECK(desc.value() == v8_num(42));
23915 CHECK(desc.has_value());
23916 CHECK(!desc.has_set());
23917 CHECK(!desc.has_get());
23918 CHECK(desc.has_configurable());
23919 CHECK(desc.configurable());
23920 CHECK(!desc.has_enumerable());
23921 CHECK(!desc.has_writable());
23922 }
23923 {
23924 // data descriptor
23925 v8::PropertyDescriptor desc(v8_num(42));
23926 desc.set_configurable(false);
23927 CHECK(desc.value() == v8_num(42));
23928 CHECK(desc.has_value());
23929 CHECK(!desc.has_set());
23930 CHECK(!desc.has_get());
23931 CHECK(desc.has_configurable());
23932 CHECK(!desc.configurable());
23933 CHECK(!desc.has_enumerable());
23934 CHECK(!desc.has_writable());
23935 }
23936 {
23937 // data descriptor
23938 v8::PropertyDescriptor desc(v8_num(42), false);
23939 CHECK(desc.value() == v8_num(42));
23940 CHECK(desc.has_value());
23941 CHECK(!desc.has_set());
23942 CHECK(!desc.has_get());
23943 CHECK(!desc.has_enumerable());
23944 CHECK(!desc.has_configurable());
23945 CHECK(desc.has_writable());
23946 CHECK(!desc.writable());
23947 }
23948 {
23949 // data descriptor
23950 v8::PropertyDescriptor desc(v8::Local<v8::Value>(), true);
23951 CHECK(!desc.has_value());
23952 CHECK(!desc.has_set());
23953 CHECK(!desc.has_get());
23954 CHECK(!desc.has_enumerable());
23955 CHECK(!desc.has_configurable());
23956 CHECK(desc.has_writable());
23957 CHECK(desc.writable());
23958 }
23959 {
23960 // accessor descriptor
23961 CompileRun("var set = function() {return 43;};");
23962
23963 v8::Local<v8::Function> set =
23964 v8::Local<v8::Function>::Cast(context->Global()
23965 ->Get(context.local(), v8_str("set"))
23966 .ToLocalChecked());
23967 v8::PropertyDescriptor desc(v8::Undefined(isolate), set);
23968 desc.set_configurable(false);
23969 CHECK(!desc.has_value());
23970 CHECK(desc.has_get());
23971 CHECK(desc.get() == v8::Undefined(isolate));
23972 CHECK(desc.has_set());
23973 CHECK(desc.set() == set);
23974 CHECK(!desc.has_enumerable());
23975 CHECK(desc.has_configurable());
23976 CHECK(!desc.configurable());
23977 CHECK(!desc.has_writable());
23978 }
23979 {
23980 // accessor descriptor with Proxy
23981 CompileRun(
23982 "var set = new Proxy(function() {}, {});"
23983 "var get = undefined;");
23984
23985 v8::Local<v8::Value> get =
23986 v8::Local<v8::Value>::Cast(context->Global()
23987 ->Get(context.local(), v8_str("get"))
23988 .ToLocalChecked());
23989 v8::Local<v8::Function> set =
23990 v8::Local<v8::Function>::Cast(context->Global()
23991 ->Get(context.local(), v8_str("set"))
23992 .ToLocalChecked());
23993 v8::PropertyDescriptor desc(get, set);
23994 desc.set_configurable(false);
23995 CHECK(!desc.has_value());
23996 CHECK(desc.get() == v8::Undefined(isolate));
23997 CHECK(desc.has_get());
23998 CHECK(desc.set() == set);
23999 CHECK(desc.has_set());
24000 CHECK(!desc.has_enumerable());
24001 CHECK(desc.has_configurable());
24002 CHECK(!desc.configurable());
24003 CHECK(!desc.has_writable());
24004 }
24005 {
24006 // accessor descriptor with empty function handle
24007 v8::Local<v8::Function> get = v8::Local<v8::Function>();
24008 v8::PropertyDescriptor desc(get, get);
24009 CHECK(!desc.has_value());
24010 CHECK(!desc.has_get());
24011 CHECK(!desc.has_set());
24012 CHECK(!desc.has_enumerable());
24013 CHECK(!desc.has_configurable());
24014 CHECK(!desc.has_writable());
24015 }
24016}
24017
24018TEST(Promises) {
24019 LocalContext context;
24020 v8::Isolate* isolate = context->GetIsolate();
24021 v8::HandleScope scope(isolate);
24022
24023 // Creation.
24024 Local<v8::Promise::Resolver> pr =
24025 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24026 Local<v8::Promise::Resolver> rr =
24027 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24028 Local<v8::Promise> p = pr->GetPromise();
24029 Local<v8::Promise> r = rr->GetPromise();
24030
24031 // IsPromise predicate.
24032 CHECK(p->IsPromise());
24033 CHECK(r->IsPromise());
24034 Local<Value> o = v8::Object::New(isolate);
24035 CHECK(!o->IsPromise());
24036
24037 // Resolution and rejection.
24038 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24039 CHECK(p->IsPromise());
24040 rr->Reject(context.local(), v8::Integer::New(isolate, 2)).FromJust();
24041 CHECK(r->IsPromise());
24042}
24043
24044// Promise.Then(on_fulfilled)
24045TEST(PromiseThen) {
24046 LocalContext context;
24047 v8::Isolate* isolate = context->GetIsolate();
24048 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24049 v8::HandleScope scope(isolate);
24050 Local<Object> global = context->Global();
24051
24052 // Creation.
24053 Local<v8::Promise::Resolver> pr =
24054 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24055 Local<v8::Promise::Resolver> qr =
24056 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24057 Local<v8::Promise> p = pr->GetPromise();
24058 Local<v8::Promise> q = qr->GetPromise();
24059
24060 CHECK(p->IsPromise());
24061 CHECK(q->IsPromise());
24062
24063 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24064 qr->Resolve(context.local(), p).FromJust();
24065
24066 // Chaining non-pending promises.
24067 CompileRun(
24068 "var x1 = 0;\n"
24069 "var x2 = 0;\n"
24070 "function f1(x) { x1 = x; return x+1 };\n"
24071 "function f2(x) { x2 = x; return x+1 };\n");
24072 Local<Function> f1 = Local<Function>::Cast(
24073 global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24074 Local<Function> f2 = Local<Function>::Cast(
24075 global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24076
24077 // Then
24078 CompileRun("x1 = x2 = 0;");
24079 q->Then(context.local(), f1).ToLocalChecked();
24080 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24081 .ToLocalChecked()
24082 ->Int32Value(context.local())
24083 .FromJust());
24084 isolate->RunMicrotasks();
24085 CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24086 .ToLocalChecked()
24087 ->Int32Value(context.local())
24088 .FromJust());
24089
24090 // Then
24091 CompileRun("x1 = x2 = 0;");
24092 pr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24093 qr = v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24094
24095 qr->Resolve(context.local(), pr).FromJust();
24096 qr->GetPromise()
24097 ->Then(context.local(), f1)
24098 .ToLocalChecked()
24099 ->Then(context.local(), f2)
24100 .ToLocalChecked();
24101
24102 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24103 .ToLocalChecked()
24104 ->Int32Value(context.local())
24105 .FromJust());
24106 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24107 .ToLocalChecked()
24108 ->Int32Value(context.local())
24109 .FromJust());
24110 isolate->RunMicrotasks();
24111 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24112 .ToLocalChecked()
24113 ->Int32Value(context.local())
24114 .FromJust());
24115 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24116 .ToLocalChecked()
24117 ->Int32Value(context.local())
24118 .FromJust());
24119
24120 pr->Resolve(context.local(), v8::Integer::New(isolate, 3)).FromJust();
24121
24122 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24123 .ToLocalChecked()
24124 ->Int32Value(context.local())
24125 .FromJust());
24126 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24127 .ToLocalChecked()
24128 ->Int32Value(context.local())
24129 .FromJust());
24130 isolate->RunMicrotasks();
24131 CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
24132 .ToLocalChecked()
24133 ->Int32Value(context.local())
24134 .FromJust());
24135 CHECK_EQ(4, global->Get(context.local(), v8_str("x2"))
24136 .ToLocalChecked()
24137 ->Int32Value(context.local())
24138 .FromJust());
24139}
24140
24141// Promise.Then(on_fulfilled, on_rejected)
24142TEST(PromiseThen2) {
24143 LocalContext context;
24144 v8::Isolate* isolate = context->GetIsolate();
24145 isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
24146 v8::HandleScope scope(isolate);
24147 Local<Object> global = context->Global();
24148
24149 // Creation.
24150 Local<v8::Promise::Resolver> pr =
24151 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24152 Local<v8::Promise> p = pr->GetPromise();
24153
24154 CHECK(p->IsPromise());
24155
24156 pr->Resolve(context.local(), v8::Integer::New(isolate, 1)).FromJust();
24157
24158 // Chaining non-pending promises.
24159 CompileRun(
24160 "var x1 = 0;\n"
24161 "var x2 = 0;\n"
24162 "function f1(x) { x1 = x; return x+1 };\n"
24163 "function f2(x) { x2 = x; return x+1 };\n"
24164 "function f3(x) { throw x + 100 };\n");
24165 Local<Function> f1 = Local<Function>::Cast(
24166 global->Get(context.local(), v8_str("f1")).ToLocalChecked());
24167 Local<Function> f2 = Local<Function>::Cast(
24168 global->Get(context.local(), v8_str("f2")).ToLocalChecked());
24169 Local<Function> f3 = Local<Function>::Cast(
24170 global->Get(context.local(), v8_str("f3")).ToLocalChecked());
24171
24172 // Then
24173 CompileRun("x1 = x2 = 0;");
24174 Local<v8::Promise> a = p->Then(context.local(), f1, f2).ToLocalChecked();
24175 CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
24176 .ToLocalChecked()
24177 ->Int32Value(context.local())
24178 .FromJust());
24179 isolate->RunMicrotasks();
24180 CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24181 .ToLocalChecked()
24182 ->Int32Value(context.local())
24183 .FromJust());
24184 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24185 .ToLocalChecked()
24186 ->Int32Value(context.local())
24187 .FromJust());
24188
24189 Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
24190 isolate->RunMicrotasks();
24191 CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24192 .ToLocalChecked()
24193 ->Int32Value(context.local())
24194 .FromJust());
24195 CHECK_EQ(0, global->Get(context.local(), v8_str("x2"))
24196 .ToLocalChecked()
24197 ->Int32Value(context.local())
24198 .FromJust());
24199
24200 Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
24201 isolate->RunMicrotasks();
24202 CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
24203 .ToLocalChecked()
24204 ->Int32Value(context.local())
24205 .FromJust());
24206 CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24207 .ToLocalChecked()
24208 ->Int32Value(context.local())
24209 .FromJust());
24210
24211 v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
24212 isolate->RunMicrotasks();
24213 CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24214 .ToLocalChecked()
24215 ->Int32Value(context.local())
24216 .FromJust());
24217 CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24218 .ToLocalChecked()
24219 ->Int32Value(context.local())
24220 .FromJust());
24221
24222 v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
24223 isolate->RunMicrotasks();
24224 CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24225 .ToLocalChecked()
24226 ->Int32Value(context.local())
24227 .FromJust());
24228 CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24229 .ToLocalChecked()
24230 ->Int32Value(context.local())
24231 .FromJust());
24232
24233 v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
24234 isolate->RunMicrotasks();
24235 CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24236 .ToLocalChecked()
24237 ->Int32Value(context.local())
24238 .FromJust());
24239 CHECK_EQ(102, global->Get(context.local(), v8_str("x2"))
24240 .ToLocalChecked()
24241 ->Int32Value(context.local())
24242 .FromJust());
24243
24244 f->Then(context.local(), f1, f2).ToLocalChecked();
24245 isolate->RunMicrotasks();
24246 CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
24247 .ToLocalChecked()
24248 ->Int32Value(context.local())
24249 .FromJust());
24250 CHECK_EQ(304, global->Get(context.local(), v8_str("x2"))
24251 .ToLocalChecked()
24252 ->Int32Value(context.local())
24253 .FromJust());
24254}
24255
24256TEST(PromiseStateAndValue) {
24257 LocalContext context;
24258 v8::Isolate* isolate = context->GetIsolate();
24259 v8::HandleScope scope(isolate);
24260 v8::Local<v8::Value> result = CompileRun(
24261 "var resolver;"
24262 "new Promise((res, rej) => { resolver = res; })");
24263 v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(result);
24264 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24265
24266 CompileRun("resolver('fulfilled')");
24267 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24268 CHECK(v8_str("fulfilled")->SameValue(promise->Result()));
24269
24270 result = CompileRun("Promise.reject('rejected')");
24271 promise = v8::Local<v8::Promise>::Cast(result);
24272 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24273 CHECK(v8_str("rejected")->SameValue(promise->Result()));
24274}
24275
24276TEST(ResolvedPromiseReFulfill) {
24277 LocalContext context;
24278 v8::Isolate* isolate = context->GetIsolate();
24279 v8::HandleScope scope(isolate);
24280 v8::Local<v8::String> value1 =
24281 v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24282 .ToLocalChecked();
24283 v8::Local<v8::String> value2 =
24284 v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24285 .ToLocalChecked();
24286
24287 v8::Local<v8::Promise::Resolver> resolver =
24288 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24289 v8::Local<v8::Promise> promise = resolver->GetPromise();
24290 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24291
24292 resolver->Resolve(context.local(), value1).ToChecked();
24293 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24294 CHECK_EQ(promise->Result(), value1);
24295
24296 // This should be a no-op.
24297 resolver->Resolve(context.local(), value2).ToChecked();
24298 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24299 CHECK_EQ(promise->Result(), value1);
24300
24301 // This should be a no-op.
24302 resolver->Reject(context.local(), value2).ToChecked();
24303 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kFulfilled);
24304 CHECK_EQ(promise->Result(), value1);
24305}
24306
24307TEST(RejectedPromiseReFulfill) {
24308 LocalContext context;
24309 v8::Isolate* isolate = context->GetIsolate();
24310 v8::HandleScope scope(isolate);
24311 v8::Local<v8::String> value1 =
24312 v8::String::NewFromUtf8(isolate, "foo", v8::NewStringType::kNormal)
24313 .ToLocalChecked();
24314 v8::Local<v8::String> value2 =
24315 v8::String::NewFromUtf8(isolate, "bar", v8::NewStringType::kNormal)
24316 .ToLocalChecked();
24317
24318 v8::Local<v8::Promise::Resolver> resolver =
24319 v8::Promise::Resolver::New(context.local()).ToLocalChecked();
24320 v8::Local<v8::Promise> promise = resolver->GetPromise();
24321 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kPending);
24322
24323 resolver->Reject(context.local(), value1).ToChecked();
24324 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24325 CHECK_EQ(promise->Result(), value1);
24326
24327 // This should be a no-op.
24328 resolver->Reject(context.local(), value2).ToChecked();
24329 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24330 CHECK_EQ(promise->Result(), value1);
24331
24332 // This should be a no-op.
24333 resolver->Resolve(context.local(), value2).ToChecked();
24334 CHECK_EQ(promise->State(), v8::Promise::PromiseState::kRejected);
24335 CHECK_EQ(promise->Result(), value1);
24336}
24337
24338TEST(DisallowJavascriptExecutionScope) {
24339 LocalContext context;
24340 v8::Isolate* isolate = context->GetIsolate();
24341 v8::HandleScope scope(isolate);
24342 v8::Isolate::DisallowJavascriptExecutionScope no_js(
24343 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24344 CompileRun("2+2");
24345}
24346
24347TEST(AllowJavascriptExecutionScope) {
24348 LocalContext context;
24349 v8::Isolate* isolate = context->GetIsolate();
24350 v8::HandleScope scope(isolate);
24351 v8::Isolate::DisallowJavascriptExecutionScope no_js(
24352 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
24353 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24354 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24355 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
24356 CompileRun("1+1");
24357 }
24358}
24359
24360TEST(ThrowOnJavascriptExecution) {
24361 LocalContext context;
24362 v8::Isolate* isolate = context->GetIsolate();
24363 v8::HandleScope scope(isolate);
24364 v8::TryCatch try_catch(isolate);
24365 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24366 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
24367 CompileRun("1+1");
24368 CHECK(try_catch.HasCaught());
24369}
24370
24371namespace {
24372
24373class MockPlatform : public TestPlatform {
24374 public:
24375 MockPlatform() : old_platform_(i::V8::GetCurrentPlatform()) {
24376 // Now that it's completely constructed, make this the current platform.
24377 i::V8::SetPlatformForTesting(this);
24378 }
24379 ~MockPlatform() override { i::V8::SetPlatformForTesting(old_platform_); }
24380
24381 bool dump_without_crashing_called() const {
24382 return dump_without_crashing_called_;
24383 }
24384
24385 void DumpWithoutCrashing() override { dump_without_crashing_called_ = true; }
24386
24387 private:
24388 v8::Platform* old_platform_;
24389 bool dump_without_crashing_called_ = false;
24390};
24391
24392} // namespace
24393
24394TEST(DumpOnJavascriptExecution) {
24395 MockPlatform platform;
24396
24397 LocalContext context;
24398 v8::Isolate* isolate = context->GetIsolate();
24399 v8::HandleScope scope(isolate);
24400 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
24401 isolate, v8::Isolate::DisallowJavascriptExecutionScope::DUMP_ON_FAILURE);
24402 CHECK(!platform.dump_without_crashing_called());
24403 CompileRun("1+1");
24404 CHECK(platform.dump_without_crashing_called());
24405}
24406
24407TEST(Regress354123) {
24408 LocalContext current;
24409 v8::Isolate* isolate = current->GetIsolate();
24410 v8::HandleScope scope(isolate);
24411
24412 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
24413 templ->SetAccessCheckCallback(AccessCounter);
24414 CHECK(current->Global()
24415 ->Set(current.local(), v8_str("friend"),
24416 templ->NewInstance(current.local()).ToLocalChecked())
24417 .FromJust());
24418
24419 // Test access using __proto__ from the prototype chain.
24420 access_count = 0;
24421 CompileRun("friend.__proto__ = {};");
24422 CHECK_EQ(2, access_count);
24423 CompileRun("friend.__proto__;");
24424 CHECK_EQ(4, access_count);
24425
24426 // Test access using __proto__ as a hijacked function (A).
24427 access_count = 0;
24428 CompileRun("var p = Object.prototype;"
24429 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
24430 "f.call(friend, {});");
24431 CHECK_EQ(1, access_count);
24432 CompileRun("var p = Object.prototype;"
24433 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
24434 "f.call(friend);");
24435 CHECK_EQ(2, access_count);
24436
24437 // Test access using __proto__ as a hijacked function (B).
24438 access_count = 0;
24439 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
24440 "f.call(friend, {});");
24441 CHECK_EQ(1, access_count);
24442 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
24443 "f.call(friend);");
24444 CHECK_EQ(2, access_count);
24445
24446 // Test access using Object.setPrototypeOf reflective method.
24447 access_count = 0;
24448 CompileRun("Object.setPrototypeOf(friend, {});");
24449 CHECK_EQ(1, access_count);
24450 CompileRun("Object.getPrototypeOf(friend);");
24451 CHECK_EQ(2, access_count);
24452}
24453
24454
24455TEST(CaptureStackTraceForStackOverflow) {
24456 v8::internal::FLAG_stack_size = 150;
24457 LocalContext current;
24458 v8::Isolate* isolate = current->GetIsolate();
24459 v8::HandleScope scope(isolate);
24460 isolate->SetCaptureStackTraceForUncaughtExceptions(true, 10,
24461 v8::StackTrace::kDetailed);
24462 v8::TryCatch try_catch(isolate);
24463 CompileRun("(function f(x) { f(x+1); })(0)");
24464 CHECK(try_catch.HasCaught());
24465}
24466
24467namespace {
24468bool ValueEqualsString(v8::Isolate* isolate, Local<Value> lhs,
24469 const char* rhs) {
24470 CHECK(!lhs.IsEmpty());
24471 CHECK(lhs->IsString());
24472 String::Utf8Value utf8_lhs(isolate, lhs);
24473 return strcmp(rhs, *utf8_lhs) == 0;
24474}
24475} // namespace
24476
24477TEST(ScriptNameAndLineNumber) {
24478 LocalContext env;
24479 v8::Isolate* isolate = env->GetIsolate();
24480 v8::HandleScope scope(isolate);
24481 const char* url = "http://www.foo.com/foo.js";
24482 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24483 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
24484
24485 Local<Script> script =
24486 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24487 CHECK(ValueEqualsString(isolate, script->GetUnboundScript()->GetScriptName(),
24488 url));
24489
24490 int line_number = script->GetUnboundScript()->GetLineNumber(0);
24491 CHECK_EQ(13, line_number);
24492}
24493
24494TEST(ScriptPositionInfo) {
24495 LocalContext env;
24496 v8::Isolate* isolate = env->GetIsolate();
24497 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
24498 v8::HandleScope scope(isolate);
24499 const char* url = "http://www.foo.com/foo.js";
24500 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
24501 v8::ScriptCompiler::Source script_source(v8_str("var foo;\n"
24502 "var bar;\n"
24503 "var fisk = foo + bar;\n"),
24504 origin);
24505 Local<Script> script =
24506 v8::ScriptCompiler::Compile(env.local(), &script_source).ToLocalChecked();
24507
24508 i::Handle<i::SharedFunctionInfo> obj = i::Handle<i::SharedFunctionInfo>::cast(
24509 v8::Utils::OpenHandle(*script->GetUnboundScript()));
24510 CHECK(obj->script()->IsScript());
24511
24512 i::Handle<i::Script> script1(i::Script::cast(obj->script()), i_isolate);
24513
24514 v8::internal::Script::PositionInfo info;
24515
24516 for (int i = 0; i < 2; ++i) {
24517 // With offset.
24518
24519 // Behave as if 0 was passed if position is negative.
24520 CHECK(script1->GetPositionInfo(-1, &info, script1->WITH_OFFSET));
24521 CHECK_EQ(13, info.line);
24522 CHECK_EQ(0, info.column);
24523 CHECK_EQ(0, info.line_start);
24524 CHECK_EQ(8, info.line_end);
24525
24526 CHECK(script1->GetPositionInfo(0, &info, script1->WITH_OFFSET));
24527 CHECK_EQ(13, info.line);
24528 CHECK_EQ(0, info.column);
24529 CHECK_EQ(0, info.line_start);
24530 CHECK_EQ(8, info.line_end);
24531
24532 CHECK(script1->GetPositionInfo(8, &info, script1->WITH_OFFSET));
24533 CHECK_EQ(13, info.line);
24534 CHECK_EQ(8, info.column);
24535 CHECK_EQ(0, info.line_start);
24536 CHECK_EQ(8, info.line_end);
24537
24538 CHECK(script1->GetPositionInfo(9, &info, script1->WITH_OFFSET));
24539 CHECK_EQ(14, info.line);
24540 CHECK_EQ(0, info.column);
24541 CHECK_EQ(9, info.line_start);
24542 CHECK_EQ(17, info.line_end);
24543
24544 // Fail when position is larger than script size.
24545 CHECK(!script1->GetPositionInfo(220384, &info, script1->WITH_OFFSET));
24546
24547 // Without offset.
24548
24549 // Behave as if 0 was passed if position is negative.
24550 CHECK(script1->GetPositionInfo(-1, &info, script1->NO_OFFSET));
24551 CHECK_EQ(0, info.line);
24552 CHECK_EQ(0, info.column);
24553 CHECK_EQ(0, info.line_start);
24554 CHECK_EQ(8, info.line_end);
24555
24556 CHECK(script1->GetPositionInfo(0, &info, script1->NO_OFFSET));
24557 CHECK_EQ(0, info.line);
24558 CHECK_EQ(0, info.column);
24559 CHECK_EQ(0, info.line_start);
24560 CHECK_EQ(8, info.line_end);
24561
24562 CHECK(script1->GetPositionInfo(8, &info, script1->NO_OFFSET));
24563 CHECK_EQ(0, info.line);
24564 CHECK_EQ(8, info.column);
24565 CHECK_EQ(0, info.line_start);
24566 CHECK_EQ(8, info.line_end);
24567
24568 CHECK(script1->GetPositionInfo(9, &info, script1->NO_OFFSET));
24569 CHECK_EQ(1, info.line);
24570 CHECK_EQ(0, info.column);
24571 CHECK_EQ(9, info.line_start);
24572 CHECK_EQ(17, info.line_end);
24573
24574 // Fail when position is larger than script size.
24575 CHECK(!script1->GetPositionInfo(220384, &info, script1->NO_OFFSET));
24576
24577 i::Script::InitLineEnds(script1);
24578 }
24579}
24580
24581void CheckMagicComments(v8::Isolate* isolate, Local<Script> script,
24582 const char* expected_source_url,
24583 const char* expected_source_mapping_url) {
24584 if (expected_source_url != nullptr) {
24585 v8::String::Utf8Value url(isolate,
24586 script->GetUnboundScript()->GetSourceURL());
24587 CHECK_EQ(0, strcmp(expected_source_url, *url));
24588 } else {
24589 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24590 }
24591 if (expected_source_mapping_url != nullptr) {
24592 v8::String::Utf8Value url(
24593 isolate, script->GetUnboundScript()->GetSourceMappingURL());
24594 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
24595 } else {
24596 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24597 }
24598}
24599
24600void SourceURLHelper(v8::Isolate* isolate, const char* source,
24601 const char* expected_source_url,
24602 const char* expected_source_mapping_url) {
24603 Local<Script> script = v8_compile(source);
24604 CheckMagicComments(isolate, script, expected_source_url,
24605 expected_source_mapping_url);
24606}
24607
24608
24609TEST(ScriptSourceURLAndSourceMappingURL) {
24610 LocalContext env;
24611 v8::Isolate* isolate = env->GetIsolate();
24612 v8::HandleScope scope(isolate);
24613 SourceURLHelper(isolate,
24614 "function foo() {}\n"
24615 "//# sourceURL=bar1.js\n",
24616 "bar1.js", nullptr);
24617 SourceURLHelper(isolate,
24618 "function foo() {}\n"
24619 "//# sourceMappingURL=bar2.js\n",
24620 nullptr, "bar2.js");
24621
24622 // Both sourceURL and sourceMappingURL.
24623 SourceURLHelper(isolate,
24624 "function foo() {}\n"
24625 "//# sourceURL=bar3.js\n"
24626 "//# sourceMappingURL=bar4.js\n",
24627 "bar3.js", "bar4.js");
24628
24629 // Two source URLs; the first one is ignored.
24630 SourceURLHelper(isolate,
24631 "function foo() {}\n"
24632 "//# sourceURL=ignoreme.js\n"
24633 "//# sourceURL=bar5.js\n",
24634 "bar5.js", nullptr);
24635 SourceURLHelper(isolate,
24636 "function foo() {}\n"
24637 "//# sourceMappingURL=ignoreme.js\n"
24638 "//# sourceMappingURL=bar6.js\n",
24639 nullptr, "bar6.js");
24640
24641 // SourceURL or sourceMappingURL in the middle of the script.
24642 SourceURLHelper(isolate,
24643 "function foo() {}\n"
24644 "//# sourceURL=bar7.js\n"
24645 "function baz() {}\n",
24646 "bar7.js", nullptr);
24647 SourceURLHelper(isolate,
24648 "function foo() {}\n"
24649 "//# sourceMappingURL=bar8.js\n"
24650 "function baz() {}\n",
24651 nullptr, "bar8.js");
24652
24653 // Too much whitespace.
24654 SourceURLHelper(isolate,
24655 "function foo() {}\n"
24656 "//# sourceURL=bar9.js\n"
24657 "//# sourceMappingURL=bar10.js\n",
24658 nullptr, nullptr);
24659 SourceURLHelper(isolate,
24660 "function foo() {}\n"
24661 "//# sourceURL =bar11.js\n"
24662 "//# sourceMappingURL =bar12.js\n",
24663 nullptr, nullptr);
24664
24665 // Disallowed characters in value.
24666 SourceURLHelper(isolate,
24667 "function foo() {}\n"
24668 "//# sourceURL=bar13 .js \n"
24669 "//# sourceMappingURL=bar14 .js \n",
24670 nullptr, nullptr);
24671 SourceURLHelper(isolate,
24672 "function foo() {}\n"
24673 "//# sourceURL=bar15\t.js \n"
24674 "//# sourceMappingURL=bar16\t.js \n",
24675 nullptr, nullptr);
24676 SourceURLHelper(isolate,
24677 "function foo() {}\n"
24678 "//# sourceURL=bar17'.js \n"
24679 "//# sourceMappingURL=bar18'.js \n",
24680 nullptr, nullptr);
24681 SourceURLHelper(isolate,
24682 "function foo() {}\n"
24683 "//# sourceURL=bar19\".js \n"
24684 "//# sourceMappingURL=bar20\".js \n",
24685 nullptr, nullptr);
24686
24687 // Not too much whitespace.
24688 SourceURLHelper(isolate,
24689 "function foo() {}\n"
24690 "//# sourceURL= bar21.js \n"
24691 "//# sourceMappingURL= bar22.js \n",
24692 "bar21.js", "bar22.js");
24693}
24694
24695
24696TEST(GetOwnPropertyDescriptor) {
24697 LocalContext env;
24698 v8::Isolate* isolate = env->GetIsolate();
24699 v8::HandleScope scope(isolate);
24700 CompileRun(
24701 "var x = { value : 13};"
24702 "Object.defineProperty(x, 'p0', {value : 12});"
24703 "Object.defineProperty(x, Symbol.toStringTag, {value: 'foo'});"
24704 "Object.defineProperty(x, 'p1', {"
24705 " set : function(value) { this.value = value; },"
24706 " get : function() { return this.value; },"
24707 "});");
24708 Local<Object> x = Local<Object>::Cast(
24709 env->Global()->Get(env.local(), v8_str("x")).ToLocalChecked());
24710 Local<Value> desc =
24711 x->GetOwnPropertyDescriptor(env.local(), v8_str("no_prop"))
24712 .ToLocalChecked();
24713 CHECK(desc->IsUndefined());
24714 desc =
24715 x->GetOwnPropertyDescriptor(env.local(), v8_str("p0")).ToLocalChecked();
24716 CHECK(v8_num(12)
24717 ->Equals(env.local(), Local<Object>::Cast(desc)
24718 ->Get(env.local(), v8_str("value"))
24719 .ToLocalChecked())
24720 .FromJust());
24721 desc =
24722 x->GetOwnPropertyDescriptor(env.local(), v8_str("p1")).ToLocalChecked();
24723 Local<Function> set =
24724 Local<Function>::Cast(Local<Object>::Cast(desc)
24725 ->Get(env.local(), v8_str("set"))
24726 .ToLocalChecked());
24727 Local<Function> get =
24728 Local<Function>::Cast(Local<Object>::Cast(desc)
24729 ->Get(env.local(), v8_str("get"))
24730 .ToLocalChecked());
24731 CHECK(v8_num(13)
24732 ->Equals(env.local(),
24733 get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24734 .FromJust());
24735 Local<Value> args[] = {v8_num(14)};
24736 set->Call(env.local(), x, 1, args).ToLocalChecked();
24737 CHECK(v8_num(14)
24738 ->Equals(env.local(),
24739 get->Call(env.local(), x, 0, nullptr).ToLocalChecked())
24740 .FromJust());
24741 desc =
24742 x->GetOwnPropertyDescriptor(env.local(), Symbol::GetToStringTag(isolate))
24743 .ToLocalChecked();
24744 CHECK(v8_str("foo")
24745 ->Equals(env.local(), Local<Object>::Cast(desc)
24746 ->Get(env.local(), v8_str("value"))
24747 .ToLocalChecked())
24748 .FromJust());
24749}
24750
24751
24752TEST(Regress411877) {
24753 v8::Isolate* isolate = CcTest::isolate();
24754 v8::HandleScope handle_scope(isolate);
24755 v8::Local<v8::ObjectTemplate> object_template =
24756 v8::ObjectTemplate::New(isolate);
24757 object_template->SetAccessCheckCallback(AccessCounter);
24758
24759 v8::Local<Context> context = Context::New(isolate);
24760 v8::Context::Scope context_scope(context);
24761
24762 CHECK(context->Global()
24763 ->Set(context, v8_str("o"),
24764 object_template->NewInstance(context).ToLocalChecked())
24765 .FromJust());
24766 CompileRun("Object.getOwnPropertyNames(o)");
24767}
24768
24769
24770TEST(GetHiddenPropertyTableAfterAccessCheck) {
24771 v8::Isolate* isolate = CcTest::isolate();
24772 v8::HandleScope handle_scope(isolate);
24773 v8::Local<v8::ObjectTemplate> object_template =
24774 v8::ObjectTemplate::New(isolate);
24775 object_template->SetAccessCheckCallback(AccessCounter);
24776
24777 v8::Local<Context> context = Context::New(isolate);
24778 v8::Context::Scope context_scope(context);
24779
24780 v8::Local<v8::Object> obj =
24781 object_template->NewInstance(context).ToLocalChecked();
24782 obj->Set(context, v8_str("key"), v8_str("value")).FromJust();
24783 obj->Delete(context, v8_str("key")).FromJust();
24784
24785 obj->SetPrivate(context, v8::Private::New(isolate, v8_str("hidden key 2")),
24786 v8_str("hidden value 2"))
24787 .FromJust();
24788}
24789
24790
24791TEST(Regress411793) {
24792 v8::Isolate* isolate = CcTest::isolate();
24793 v8::HandleScope handle_scope(isolate);
24794 v8::Local<v8::ObjectTemplate> object_template =
24795 v8::ObjectTemplate::New(isolate);
24796 object_template->SetAccessCheckCallback(AccessCounter);
24797
24798 v8::Local<Context> context = Context::New(isolate);
24799 v8::Context::Scope context_scope(context);
24800
24801 CHECK(context->Global()
24802 ->Set(context, v8_str("o"),
24803 object_template->NewInstance(context).ToLocalChecked())
24804 .FromJust());
24805 CompileRun(
24806 "Object.defineProperty(o, 'key', "
24807 " { get: function() {}, set: function() {} });");
24808}
24809
24810class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24811 public:
24812 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24813
24814 size_t GetMoreData(const uint8_t** src) override {
24815 // Unlike in real use cases, this function will never block.
24816 if (chunks_[index_] == nullptr) {
24817 return 0;
24818 }
24819 // Copy the data, since the caller takes ownership of it.
24820 size_t len = strlen(chunks_[index_]);
24821 // We don't need to zero-terminate since we return the length.
24822 uint8_t* copy = new uint8_t[len];
24823 memcpy(copy, chunks_[index_], len);
24824 *src = copy;
24825 ++index_;
24826 return len;
24827 }
24828
24829 // Helper for constructing a string from chunks (the compilation needs it
24830 // too).
24831 static char* FullSourceString(const char** chunks) {
24832 size_t total_len = 0;
24833 for (size_t i = 0; chunks[i] != nullptr; ++i) {
24834 total_len += strlen(chunks[i]);
24835 }
24836 char* full_string = new char[total_len + 1];
24837 size_t offset = 0;
24838 for (size_t i = 0; chunks[i] != nullptr; ++i) {
24839 size_t len = strlen(chunks[i]);
24840 memcpy(full_string + offset, chunks[i], len);
24841 offset += len;
24842 }
24843 full_string[total_len] = 0;
24844 return full_string;
24845 }
24846
24847 private:
24848 const char** chunks_;
24849 unsigned index_;
24850};
24851
24852
24853// Helper function for running streaming tests.
24854void RunStreamingTest(const char** chunks,
24855 v8::ScriptCompiler::StreamedSource::Encoding encoding =
24856 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24857 bool expected_success = true,
24858 const char* expected_source_url = nullptr,
24859 const char* expected_source_mapping_url = nullptr) {
24860 LocalContext env;
24861 v8::Isolate* isolate = env->GetIsolate();
24862 v8::HandleScope scope(isolate);
24863 v8::TryCatch try_catch(isolate);
24864
24865 v8::ScriptCompiler::StreamedSource source(
24866 v8::base::make_unique<TestSourceStream>(chunks), encoding);
24867 v8::ScriptCompiler::ScriptStreamingTask* task =
24868 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24869
24870 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24871 // task here in the main thread.
24872 task->Run();
24873 delete task;
24874
24875 // Possible errors are only produced while compiling.
24876 CHECK(!try_catch.HasCaught());
24877
24878 v8::ScriptOrigin origin(v8_str("http://foo.com"));
24879 char* full_source = TestSourceStream::FullSourceString(chunks);
24880 v8::MaybeLocal<Script> script = v8::ScriptCompiler::Compile(
24881 env.local(), &source, v8_str(full_source), origin);
24882 if (expected_success) {
24883 CHECK(!script.IsEmpty());
24884 v8::Local<Value> result(
24885 script.ToLocalChecked()->Run(env.local()).ToLocalChecked());
24886 // All scripts are supposed to return the fixed value 13 when ran.
24887 CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
24888 CheckMagicComments(isolate, script.ToLocalChecked(), expected_source_url,
24889 expected_source_mapping_url);
24890 } else {
24891 CHECK(script.IsEmpty());
24892 CHECK(try_catch.HasCaught());
24893 }
24894 delete[] full_source;
24895}
24896
24897TEST(StreamingSimpleScript) {
24898 // This script is unrealistically small, since no one chunk is enough to fill
24899 // the backing buffer of Scanner, let alone overflow it.
24900 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24901 nullptr};
24902 RunStreamingTest(chunks);
24903}
24904
24905TEST(StreamingScriptConstantArray) {
24906 // When run with Ignition, tests that the streaming parser canonicalizes
24907 // handles so that they are only added to the constant pool array once.
24908 const char* chunks[] = {
24909 "var a = {};", "var b = {};", "var c = 'testing';",
24910 "var d = 'testing';", "13;", nullptr};
24911 RunStreamingTest(chunks);
24912}
24913
24914TEST(StreamingScriptEvalShadowing) {
24915 // When run with Ignition, tests that the streaming parser canonicalizes
24916 // handles so the Variable::is_possibly_eval() is correct.
24917 const char* chunk1 =
24918 "(function() {\n"
24919 " var y = 2;\n"
24920 " return (function() {\n"
24921 " eval('var y = 13;');\n"
24922 " function g() {\n"
24923 " return y\n"
24924 " }\n"
24925 " return g();\n"
24926 " })()\n"
24927 "})()\n";
24928 const char* chunks[] = {chunk1, nullptr};
24929 RunStreamingTest(chunks);
24930}
24931
24932TEST(StreamingBiggerScript) {
24933 const char* chunk1 =
24934 "function foo() {\n"
24935 " // Make this chunk sufficiently long so that it will overflow the\n"
24936 " // backing buffer of the Scanner.\n"
24937 " var i = 0;\n"
24938 " var result = 0;\n"
24939 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24940 " result = 0;\n"
24941 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24942 " result = 0;\n"
24943 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24944 " result = 0;\n"
24945 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24946 " return result;\n"
24947 "}\n";
24948 const char* chunks[] = {chunk1, "foo(); ", nullptr};
24949 RunStreamingTest(chunks);
24950}
24951
24952
24953TEST(StreamingScriptWithParseError) {
24954 // Test that parse errors from streamed scripts are propagated correctly.
24955 {
24956 char chunk1[] =
24957 " // This will result in a parse error.\n"
24958 " var if else then foo";
24959 char chunk2[] = " 13\n";
24960 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24961
24962 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24963 false);
24964 }
24965 // Test that the next script succeeds normally.
24966 {
24967 char chunk1[] =
24968 " // This will be parsed successfully.\n"
24969 " function foo() { return ";
24970 char chunk2[] = " 13; }\n";
24971 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
24972
24973 RunStreamingTest(chunks);
24974 }
24975}
24976
24977
24978TEST(StreamingUtf8Script) {
24979 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
24980 // don't like it.
24981 const char* chunk1 =
24982 "function foo() {\n"
24983 " // This function will contain an UTF-8 character which is not in\n"
24984 " // ASCII.\n"
24985 " var foob\xec\x92\x81r = 13;\n"
24986 " return foob\xec\x92\x81r;\n"
24987 "}\n";
24988 const char* chunks[] = {chunk1, "foo(); ", nullptr};
24989 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24990}
24991
24992
24993TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24994 // A sanity check to prove that the approach of splitting UTF-8
24995 // characters is correct. Here is an UTF-8 character which will take three
24996 // bytes.
24997 const char* reference = "\xec\x92\x81";
24998 CHECK_EQ(3, strlen(reference));
24999
25000 char chunk1[] =
25001 "function foo() {\n"
25002 " // This function will contain an UTF-8 character which is not in\n"
25003 " // ASCII.\n"
25004 " var foob";
25005 char chunk2[] =
25006 "XXXr = 13;\n"
25007 " return foob\xec\x92\x81r;\n"
25008 "}\n";
25009 for (int i = 0; i < 3; ++i) {
25010 chunk2[i] = reference[i];
25011 }
25012 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25013 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25014}
25015
25016
25017TEST(StreamingUtf8ScriptWithSplitCharacters) {
25018 // Stream data where a multi-byte UTF-8 character is split between two data
25019 // chunks.
25020 const char* reference = "\xec\x92\x81";
25021 char chunk1[] =
25022 "function foo() {\n"
25023 " // This function will contain an UTF-8 character which is not in\n"
25024 " // ASCII.\n"
25025 " var foobX";
25026 char chunk2[] =
25027 "XXr = 13;\n"
25028 " return foob\xec\x92\x81r;\n"
25029 "}\n";
25030 chunk1[strlen(chunk1) - 1] = reference[0];
25031 chunk2[0] = reference[1];
25032 chunk2[1] = reference[2];
25033 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25034 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25035}
25036
25037
25038TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
25039 // Tests edge cases which should still be decoded correctly.
25040
25041 // Case 1: a chunk contains only bytes for a split character (and no other
25042 // data). This kind of a chunk would be exceptionally small, but we should
25043 // still decode it correctly.
25044 const char* reference = "\xec\x92\x81";
25045 // The small chunk is at the beginning of the split character
25046 {
25047 char chunk1[] =
25048 "function foo() {\n"
25049 " // This function will contain an UTF-8 character which is not in\n"
25050 " // ASCII.\n"
25051 " var foob";
25052 char chunk2[] = "XX";
25053 char chunk3[] =
25054 "Xr = 13;\n"
25055 " return foob\xec\x92\x81r;\n"
25056 "}\n";
25057 chunk2[0] = reference[0];
25058 chunk2[1] = reference[1];
25059 chunk3[0] = reference[2];
25060 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25061 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25062 }
25063 // The small chunk is at the end of a character
25064 {
25065 char chunk1[] =
25066 "function foo() {\n"
25067 " // This function will contain an UTF-8 character which is not in\n"
25068 " // ASCII.\n"
25069 " var foobX";
25070 char chunk2[] = "XX";
25071 char chunk3[] =
25072 "r = 13;\n"
25073 " return foob\xec\x92\x81r;\n"
25074 "}\n";
25075 chunk1[strlen(chunk1) - 1] = reference[0];
25076 chunk2[0] = reference[1];
25077 chunk2[1] = reference[2];
25078 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25079 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25080 }
25081 // Case 2: the script ends with a multi-byte character. Make sure that it's
25082 // decoded correctly and not just ignored.
25083 {
25084 char chunk1[] =
25085 "var foob\xec\x92\x81 = 13;\n"
25086 "foob\xec\x92\x81";
25087 const char* chunks[] = {chunk1, nullptr};
25088 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25089 }
25090}
25091
25092
25093TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
25094 // Test cases where a UTF-8 character is split over several chunks. Those
25095 // cases are not supported (the embedder should give the data in big enough
25096 // chunks), but we shouldn't crash and parse this just fine.
25097 const char* reference = "\xec\x92\x81";
25098 char chunk1[] =
25099 "function foo() {\n"
25100 " // This function will contain an UTF-8 character which is not in\n"
25101 " // ASCII.\n"
25102 " var foobX";
25103 char chunk2[] = "X";
25104 char chunk3[] =
25105 "Xr = 13;\n"
25106 " return foob\xec\x92\x81r;\n"
25107 "}\n";
25108 chunk1[strlen(chunk1) - 1] = reference[0];
25109 chunk2[0] = reference[1];
25110 chunk3[0] = reference[2];
25111 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
25112
25113 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25114}
25115
25116
25117
25118TEST(StreamingWithDebuggingEnabledLate) {
25119 // The streaming parser can only parse lazily, i.e. inner functions are not
25120 // fully parsed. However, we may compile inner functions eagerly when
25121 // debugging. Make sure that we can deal with this when turning on debugging
25122 // after streaming parser has already finished parsing.
25123 const char* chunks[] = {"with({x:1}) {",
25124 " var foo = function foo(y) {",
25125 " return x + y;",
25126 " };",
25127 " foo(2);",
25128 "}",
25129 nullptr};
25130
25131 LocalContext env;
25132 v8::Isolate* isolate = env->GetIsolate();
25133 v8::HandleScope scope(isolate);
25134 v8::TryCatch try_catch(isolate);
25135
25136 v8::ScriptCompiler::StreamedSource source(
25137 v8::base::make_unique<TestSourceStream>(chunks),
25138 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25139 v8::ScriptCompiler::ScriptStreamingTask* task =
25140 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25141
25142 task->Run();
25143 delete task;
25144
25145 CHECK(!try_catch.HasCaught());
25146
25147 v8::ScriptOrigin origin(v8_str("http://foo.com"));
25148 char* full_source = TestSourceStream::FullSourceString(chunks);
25149
25150 EnableDebugger(isolate);
25151
25152 v8::Local<Script> script =
25153 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25154 origin)
25155 .ToLocalChecked();
25156
25157 Maybe<uint32_t> result =
25158 script->Run(env.local()).ToLocalChecked()->Uint32Value(env.local());
25159 CHECK_EQ(3U, result.FromMaybe(0));
25160
25161 delete[] full_source;
25162
25163 DisableDebugger(isolate);
25164}
25165
25166
25167TEST(StreamingScriptWithInvalidUtf8) {
25168 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
25169 // chunk don't produce a crash.
25170 const char* reference = "\xec\x92\x81\x80\x80";
25171 char chunk1[] =
25172 "function foo() {\n"
25173 " // This function will contain an UTF-8 character which is not in\n"
25174 " // ASCII.\n"
25175 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
25176 char chunk2[] =
25177 "r = 13;\n"
25178 " return foob\xec\x92\x81\x80\x80r;\n"
25179 "}\n";
25180 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
25181
25182 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25183 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
25184}
25185
25186
25187TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
25188 // Regression test: Stream data where there are several multi-byte UTF-8
25189 // characters in a sequence and one of them is split between two data chunks.
25190 const char* reference = "\xec\x92\x81";
25191 char chunk1[] =
25192 "function foo() {\n"
25193 " // This function will contain an UTF-8 character which is not in\n"
25194 " // ASCII.\n"
25195 " var foob\xec\x92\x81X";
25196 char chunk2[] =
25197 "XXr = 13;\n"
25198 " return foob\xec\x92\x81\xec\x92\x81r;\n"
25199 "}\n";
25200 chunk1[strlen(chunk1) - 1] = reference[0];
25201 chunk2[0] = reference[1];
25202 chunk2[1] = reference[2];
25203 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25204 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25205}
25206
25207
25208TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
25209 // Another regression test, similar to the previous one. The difference is
25210 // that the split character is not the last one in the sequence.
25211 const char* reference = "\xec\x92\x81";
25212 char chunk1[] =
25213 "function foo() {\n"
25214 " // This function will contain an UTF-8 character which is not in\n"
25215 " // ASCII.\n"
25216 " var foobX";
25217 char chunk2[] =
25218 "XX\xec\x92\x81r = 13;\n"
25219 " return foob\xec\x92\x81\xec\x92\x81r;\n"
25220 "}\n";
25221 chunk1[strlen(chunk1) - 1] = reference[0];
25222 chunk2[0] = reference[1];
25223 chunk2[1] = reference[2];
25224 const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
25225 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
25226}
25227
25228
25229TEST(StreamingWithHarmonyScopes) {
25230 // Don't use RunStreamingTest here so that both scripts get to use the same
25231 // LocalContext and HandleScope.
25232 LocalContext env;
25233 v8::Isolate* isolate = env->GetIsolate();
25234 v8::HandleScope scope(isolate);
25235
25236 // First, run a script with a let variable.
25237 CompileRun("\"use strict\"; let x = 1;");
25238
25239 // Then stream a script which (erroneously) tries to introduce the same
25240 // variable again.
25241 const char* chunks[] = {"\"use strict\"; let x = 2;", nullptr};
25242
25243 v8::TryCatch try_catch(isolate);
25244 v8::ScriptCompiler::StreamedSource source(
25245 v8::base::make_unique<TestSourceStream>(chunks),
25246 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
25247 v8::ScriptCompiler::ScriptStreamingTask* task =
25248 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
25249 task->Run();
25250 delete task;
25251
25252 // Parsing should succeed (the script will be parsed and compiled in a context
25253 // independent way, so the error is not detected).
25254 CHECK(!try_catch.HasCaught());
25255
25256 v8::ScriptOrigin origin(v8_str("http://foo.com"));
25257 char* full_source = TestSourceStream::FullSourceString(chunks);
25258 v8::Local<Script> script =
25259 v8::ScriptCompiler::Compile(env.local(), &source, v8_str(full_source),
25260 origin)
25261 .ToLocalChecked();
25262 CHECK(!script.IsEmpty());
25263 CHECK(!try_catch.HasCaught());
25264
25265 // Running the script exposes the error.
25266 CHECK(script->Run(env.local()).IsEmpty());
25267 CHECK(try_catch.HasCaught());
25268 delete[] full_source;
25269}
25270
25271
25272TEST(CodeCache) {
25273 v8::Isolate::CreateParams create_params;
25274 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25275
25276 const char* source = "Math.sqrt(4)";
25277 const char* origin = "code cache test";
25278 v8::ScriptCompiler::CachedData* cache;
25279
25280 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
25281 {
25282 v8::Isolate::Scope iscope(isolate1);
25283 v8::HandleScope scope(isolate1);
25284 v8::Local<v8::Context> context = v8::Context::New(isolate1);
25285 v8::Context::Scope cscope(context);
25286 v8::Local<v8::String> source_string = v8_str(source);
25287 v8::ScriptOrigin script_origin(v8_str(origin));
25288 v8::ScriptCompiler::Source source(source_string, script_origin);
25289 v8::ScriptCompiler::CompileOptions option =
25290 v8::ScriptCompiler::kNoCompileOptions;
25291 v8::Local<v8::Script> script =
25292 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25293 cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25294 }
25295 isolate1->Dispose();
25296
25297 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
25298 {
25299 v8::Isolate::Scope iscope(isolate2);
25300 v8::HandleScope scope(isolate2);
25301 v8::Local<v8::Context> context = v8::Context::New(isolate2);
25302 v8::Context::Scope cscope(context);
25303 v8::Local<v8::String> source_string = v8_str(source);
25304 v8::ScriptOrigin script_origin(v8_str(origin));
25305 v8::ScriptCompiler::Source source(source_string, script_origin, cache);
25306 v8::ScriptCompiler::CompileOptions option =
25307 v8::ScriptCompiler::kConsumeCodeCache;
25308 v8::Local<v8::Script> script;
25309 {
25310 i::DisallowCompilation no_compile(
25311 reinterpret_cast<i::Isolate*>(isolate2));
25312 script = v8::ScriptCompiler::Compile(context, &source, option)
25313 .ToLocalChecked();
25314 }
25315 CHECK_EQ(2, script->Run(context)
25316 .ToLocalChecked()
25317 ->ToInt32(context)
25318 .ToLocalChecked()
25319 ->Int32Value(context)
25320 .FromJust());
25321 }
25322 isolate2->Dispose();
25323}
25324
25325v8::MaybeLocal<Module> UnexpectedModuleResolveCallback(Local<Context> context,
25326 Local<String> specifier,
25327 Local<Module> referrer) {
25328 CHECK_WITH_MSG(false, "Unexpected call to resolve callback");
25329}
25330
25331namespace {
25332
25333Local<Module> CompileAndInstantiateModule(v8::Isolate* isolate,
25334 Local<Context> context,
25335 const char* resource_name,
25336 const char* source) {
25337 Local<String> source_string = v8_str(source);
25338 v8::ScriptOrigin script_origin(
25339 v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25340 Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25341 Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25342 v8::ScriptCompiler::Source script_compiler_source(source_string,
25343 script_origin);
25344 Local<Module> module =
25345 v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source)
25346 .ToLocalChecked();
25347 module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25348 .ToChecked();
25349
25350 return module;
25351}
25352
25353Local<Module> CompileAndInstantiateModuleFromCache(
25354 v8::Isolate* isolate, Local<Context> context, const char* resource_name,
25355 const char* source, v8::ScriptCompiler::CachedData* cache) {
25356 Local<String> source_string = v8_str(source);
25357 v8::ScriptOrigin script_origin(
25358 v8_str(resource_name), Local<v8::Integer>(), Local<v8::Integer>(),
25359 Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25360 Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25361 v8::ScriptCompiler::Source script_compiler_source(source_string,
25362 script_origin, cache);
25363
25364 Local<Module> module =
25365 v8::ScriptCompiler::CompileModule(isolate, &script_compiler_source,
25366 v8::ScriptCompiler::kConsumeCodeCache)
25367 .ToLocalChecked();
25368 module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25369 .ToChecked();
25370
25371 return module;
25372}
25373
25374} // namespace
25375
25376TEST(ModuleCodeCache) {
25377 v8::Isolate::CreateParams create_params;
25378 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25379
25380 const char* origin = "code cache test";
25381 const char* source =
25382 "export default 5; export const a = 10; function f() { return 42; } "
25383 "(function() { return f(); })();";
25384
25385 v8::ScriptCompiler::CachedData* cache;
25386 {
25387 v8::Isolate* isolate = v8::Isolate::New(create_params);
25388 {
25389 v8::Isolate::Scope iscope(isolate);
25390 v8::HandleScope scope(isolate);
25391 v8::Local<v8::Context> context = v8::Context::New(isolate);
25392 v8::Context::Scope cscope(context);
25393
25394 Local<Module> module =
25395 CompileAndInstantiateModule(isolate, context, origin, source);
25396
25397 // Fetch the shared function info before evaluation.
25398 Local<v8::UnboundModuleScript> unbound_module_script =
25399 module->GetUnboundModuleScript();
25400
25401 // Evaluate for possible lazy compilation.
25402 Local<Value> completion_value =
25403 module->Evaluate(context).ToLocalChecked();
25404 CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25405
25406 // Now create the cache. Note that it is freed, obscurely, when
25407 // ScriptCompiler::Source goes out of scope below.
25408 cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25409 }
25410 isolate->Dispose();
25411 }
25412
25413 // Test that the cache is consumed and execution still works.
25414 {
25415 // Disable --always_opt, otherwise we try to optimize during module
25416 // instantiation, violating the DisallowCompilation scope.
25417 i::FLAG_always_opt = false;
25418 v8::Isolate* isolate = v8::Isolate::New(create_params);
25419 {
25420 v8::Isolate::Scope iscope(isolate);
25421 v8::HandleScope scope(isolate);
25422 v8::Local<v8::Context> context = v8::Context::New(isolate);
25423 v8::Context::Scope cscope(context);
25424
25425 Local<Module> module;
25426 {
25427 i::DisallowCompilation no_compile(
25428 reinterpret_cast<i::Isolate*>(isolate));
25429 module = CompileAndInstantiateModuleFromCache(isolate, context, origin,
25430 source, cache);
25431 }
25432
25433 Local<Value> completion_value =
25434 module->Evaluate(context).ToLocalChecked();
25435 CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25436 }
25437 isolate->Dispose();
25438 }
25439}
25440
25441// Tests that the code cache does not confuse the same source code compiled as a
25442// script and as a module.
25443TEST(CodeCacheModuleScriptMismatch) {
25444 v8::Isolate::CreateParams create_params;
25445 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25446
25447 const char* origin = "code cache test";
25448 const char* source = "42";
25449
25450 v8::ScriptCompiler::CachedData* cache;
25451 {
25452 v8::Isolate* isolate = v8::Isolate::New(create_params);
25453 {
25454 v8::Isolate::Scope iscope(isolate);
25455 v8::HandleScope scope(isolate);
25456 v8::Local<v8::Context> context = v8::Context::New(isolate);
25457 v8::Context::Scope cscope(context);
25458
25459 Local<Module> module =
25460 CompileAndInstantiateModule(isolate, context, origin, source);
25461
25462 // Fetch the shared function info before evaluation.
25463 Local<v8::UnboundModuleScript> unbound_module_script =
25464 module->GetUnboundModuleScript();
25465
25466 // Evaluate for possible lazy compilation.
25467 Local<Value> completion_value =
25468 module->Evaluate(context).ToLocalChecked();
25469 CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25470
25471 // Now create the cache. Note that it is freed, obscurely, when
25472 // ScriptCompiler::Source goes out of scope below.
25473 cache = v8::ScriptCompiler::CreateCodeCache(unbound_module_script);
25474 }
25475 isolate->Dispose();
25476 }
25477
25478 // Test that the cache is not consumed when source is compiled as a script.
25479 {
25480 v8::Isolate* isolate = v8::Isolate::New(create_params);
25481 {
25482 v8::Isolate::Scope iscope(isolate);
25483 v8::HandleScope scope(isolate);
25484 v8::Local<v8::Context> context = v8::Context::New(isolate);
25485 v8::Context::Scope cscope(context);
25486
25487 v8::ScriptOrigin script_origin(v8_str(origin));
25488 v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25489 script_origin, cache);
25490
25491 v8::Local<v8::Script> script =
25492 v8::ScriptCompiler::Compile(context, &script_compiler_source,
25493 v8::ScriptCompiler::kConsumeCodeCache)
25494 .ToLocalChecked();
25495
25496 CHECK(cache->rejected);
25497
25498 CHECK_EQ(42, script->Run(context)
25499 .ToLocalChecked()
25500 ->ToInt32(context)
25501 .ToLocalChecked()
25502 ->Int32Value(context)
25503 .FromJust());
25504 }
25505 isolate->Dispose();
25506 }
25507}
25508
25509// Same as above but other way around.
25510TEST(CodeCacheScriptModuleMismatch) {
25511 v8::Isolate::CreateParams create_params;
25512 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
25513
25514 const char* origin = "code cache test";
25515 const char* source = "42";
25516
25517 v8::ScriptCompiler::CachedData* cache;
25518 {
25519 v8::Isolate* isolate = v8::Isolate::New(create_params);
25520 {
25521 v8::Isolate::Scope iscope(isolate);
25522 v8::HandleScope scope(isolate);
25523 v8::Local<v8::Context> context = v8::Context::New(isolate);
25524 v8::Context::Scope cscope(context);
25525 v8::Local<v8::String> source_string = v8_str(source);
25526 v8::ScriptOrigin script_origin(v8_str(origin));
25527 v8::ScriptCompiler::Source source(source_string, script_origin);
25528 v8::ScriptCompiler::CompileOptions option =
25529 v8::ScriptCompiler::kNoCompileOptions;
25530 v8::Local<v8::Script> script =
25531 v8::ScriptCompiler::Compile(context, &source, option)
25532 .ToLocalChecked();
25533 cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
25534 }
25535 isolate->Dispose();
25536 }
25537
25538 // Test that the cache is not consumed when source is compiled as a module.
25539 {
25540 v8::Isolate* isolate = v8::Isolate::New(create_params);
25541 {
25542 v8::Isolate::Scope iscope(isolate);
25543 v8::HandleScope scope(isolate);
25544 v8::Local<v8::Context> context = v8::Context::New(isolate);
25545 v8::Context::Scope cscope(context);
25546
25547 v8::ScriptOrigin script_origin(
25548 v8_str(origin), Local<v8::Integer>(), Local<v8::Integer>(),
25549 Local<v8::Boolean>(), Local<v8::Integer>(), Local<v8::Value>(),
25550 Local<v8::Boolean>(), Local<v8::Boolean>(), True(isolate));
25551 v8::ScriptCompiler::Source script_compiler_source(v8_str(source),
25552 script_origin, cache);
25553
25554 Local<Module> module = v8::ScriptCompiler::CompileModule(
25555 isolate, &script_compiler_source,
25556 v8::ScriptCompiler::kConsumeCodeCache)
25557 .ToLocalChecked();
25558 module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25559 .ToChecked();
25560
25561 CHECK(cache->rejected);
25562
25563 Local<Value> completion_value =
25564 module->Evaluate(context).ToLocalChecked();
25565 CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
25566 }
25567 isolate->Dispose();
25568 }
25569}
25570
25571// Tests that compilation can handle a garbled cache.
25572TEST(InvalidCodeCacheDataInCompileModule) {
25573 v8::V8::Initialize();
25574 v8::Isolate* isolate = CcTest::isolate();
25575 v8::HandleScope scope(isolate);
25576 LocalContext local_context;
25577
25578 const char* garbage = "garbage garbage garbage garbage garbage garbage";
25579 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25580 Local<String> origin = v8_str("origin");
25581 int length = 16;
25582 v8::ScriptCompiler::CachedData* cached_data =
25583 new v8::ScriptCompiler::CachedData(data, length);
25584 CHECK(!cached_data->rejected);
25585
25586 v8::ScriptOrigin script_origin(
25587 origin, Local<v8::Integer>(), Local<v8::Integer>(), Local<v8::Boolean>(),
25588 Local<v8::Integer>(), Local<v8::Value>(), Local<v8::Boolean>(),
25589 Local<v8::Boolean>(), True(isolate));
25590 v8::ScriptCompiler::Source source(v8_str("42"), script_origin, cached_data);
25591 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25592
25593 Local<Module> module =
25594 v8::ScriptCompiler::CompileModule(isolate, &source,
25595 v8::ScriptCompiler::kConsumeCodeCache)
25596 .ToLocalChecked();
25597 module->InstantiateModule(context, UnexpectedModuleResolveCallback)
25598 .ToChecked();
25599
25600 CHECK(cached_data->rejected);
25601 CHECK_EQ(42, module->Evaluate(context)
25602 .ToLocalChecked()
25603 ->Int32Value(context)
25604 .FromJust());
25605}
25606
25607void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
25608 const char* garbage = "garbage garbage garbage garbage garbage garbage";
25609 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
25610 int length = 16;
25611 v8::ScriptCompiler::CachedData* cached_data =
25612 new v8::ScriptCompiler::CachedData(data, length);
25613 CHECK(!cached_data->rejected);
25614 v8::ScriptOrigin origin(v8_str("origin"));
25615 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
25616 v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
25617 v8::Local<v8::Script> script =
25618 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
25619 CHECK(cached_data->rejected);
25620 CHECK_EQ(
25621 42,
25622 script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
25623}
25624
25625
25626TEST(InvalidCodeCacheData) {
25627 v8::V8::Initialize();
25628 v8::HandleScope scope(CcTest::isolate());
25629 LocalContext context;
25630 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
25631}
25632
25633
25634TEST(StringConcatOverflow) {
25635 v8::V8::Initialize();
25636 v8::Isolate* isolate = CcTest::isolate();
25637 v8::HandleScope scope(isolate);
25638 RandomLengthOneByteResource* r =
25639 new RandomLengthOneByteResource(i::String::kMaxLength);
25640 v8::Local<v8::String> str =
25641 v8::String::NewExternalOneByte(isolate, r).ToLocalChecked();
25642 CHECK(!str.IsEmpty());
25643 v8::TryCatch try_catch(isolate);
25644 v8::Local<v8::String> result = v8::String::Concat(isolate, str, str);
25645 v8::String::Concat(CcTest::isolate(), str, str);
25646 CHECK(result.IsEmpty());
25647 CHECK(!try_catch.HasCaught());
25648}
25649
25650TEST(TurboAsmDisablesDetach) {
25651#ifndef V8_LITE_MODE
25652 i::FLAG_opt = true;
25653 i::FLAG_allow_natives_syntax = true;
25654 v8::V8::Initialize();
25655 v8::HandleScope scope(CcTest::isolate());
25656 LocalContext context;
25657 const char* load =
25658 "function Module(stdlib, foreign, heap) {"
25659 " 'use asm';"
25660 " var MEM32 = new stdlib.Int32Array(heap);"
25661 " function load() { return MEM32[0] | 0; }"
25662 " return { load: load };"
25663 "}"
25664 "var buffer = new ArrayBuffer(4096);"
25665 "var module = Module(this, {}, buffer);"
25666 "%OptimizeFunctionOnNextCall(module.load);"
25667 "module.load();"
25668 "buffer";
25669
25670 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
25671 CHECK(!result->IsDetachable());
25672
25673 const char* store =
25674 "function Module(stdlib, foreign, heap) {"
25675 " 'use asm';"
25676 " var MEM32 = new stdlib.Int32Array(heap);"
25677 " function store() { MEM32[0] = 0; }"
25678 " return { store: store };"
25679 "}"
25680 "var buffer = new ArrayBuffer(4096);"
25681 "var module = Module(this, {}, buffer);"
25682 "%OptimizeFunctionOnNextCall(module.store);"
25683 "module.store();"
25684 "buffer";
25685
25686 result = CompileRun(store).As<v8::ArrayBuffer>();
25687 CHECK(!result->IsDetachable());
25688#endif // V8_LITE_MODE
25689}
25690
25691TEST(ClassPrototypeCreationContext) {
25692 v8::Isolate* isolate = CcTest::isolate();
25693 v8::HandleScope handle_scope(isolate);
25694 LocalContext env;
25695
25696 Local<Object> result = Local<Object>::Cast(
25697 CompileRun("'use strict'; class Example { }; Example.prototype"));
25698 CHECK(env.local() == result->CreationContext());
25699}
25700
25701
25702TEST(SimpleStreamingScriptWithSourceURL) {
25703 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
25704 "//# sourceURL=bar2.js\n", nullptr};
25705 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25706 "bar2.js");
25707}
25708
25709
25710TEST(StreamingScriptWithSplitSourceURL) {
25711 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
25712 "oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
25713 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25714 "bar2.js");
25715}
25716
25717
25718TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
25719 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
25720 " sourceMappingURL=bar2.js\n", "foo();", nullptr};
25721 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
25722 nullptr, "bar2.js");
25723}
25724
25725
25726TEST(NewStringRangeError) {
25727 // This test uses a lot of memory and fails with flaky OOM when run
25728 // with --stress-incremental-marking on TSAN.
25729 i::FLAG_stress_incremental_marking = false;
25730 v8::Isolate* isolate = CcTest::isolate();
25731 v8::HandleScope handle_scope(isolate);
25732 const int length = i::String::kMaxLength + 1;
25733 const int buffer_size = length * sizeof(uint16_t);
25734 void* buffer = malloc(buffer_size);
25735 if (buffer == nullptr) return;
25736 memset(buffer, 'A', buffer_size);
25737 {
25738 v8::TryCatch try_catch(isolate);
25739 char* data = reinterpret_cast<char*>(buffer);
25740 CHECK(v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal,
25741 length)
25742 .IsEmpty());
25743 CHECK(!try_catch.HasCaught());
25744 }
25745 {
25746 v8::TryCatch try_catch(isolate);
25747 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
25748 CHECK(v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal,
25749 length)
25750 .IsEmpty());
25751 CHECK(!try_catch.HasCaught());
25752 }
25753 {
25754 v8::TryCatch try_catch(isolate);
25755 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
25756 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::NewStringType::kNormal,
25757 length)
25758 .IsEmpty());
25759 CHECK(!try_catch.HasCaught());
25760 }
25761 free(buffer);
25762}
25763
25764
25765TEST(SealHandleScope) {
25766 v8::Isolate* isolate = CcTest::isolate();
25767 v8::HandleScope handle_scope(isolate);
25768 LocalContext env;
25769
25770 v8::SealHandleScope seal(isolate);
25771
25772 // Should fail
25773 v8::Local<v8::Object> obj = v8::Object::New(isolate);
25774
25775 USE(obj);
25776}
25777
25778
25779TEST(SealHandleScopeNested) {
25780 v8::Isolate* isolate = CcTest::isolate();
25781 v8::HandleScope handle_scope(isolate);
25782 LocalContext env;
25783
25784 v8::SealHandleScope seal(isolate);
25785
25786 {
25787 v8::HandleScope handle_scope(isolate);
25788
25789 // Should work
25790 v8::Local<v8::Object> obj = v8::Object::New(isolate);
25791
25792 USE(obj);
25793 }
25794}
25795
25796
25797static void ExtrasBindingTestRuntimeFunction(
25798 const v8::FunctionCallbackInfo<v8::Value>& args) {
25799 CHECK_EQ(
25800 3,
25801 args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust());
25802 args.GetReturnValue().Set(v8_num(7));
25803}
25804
25805TEST(ExtrasFunctionSource) {
25806 v8::Isolate* isolate = CcTest::isolate();
25807 v8::HandleScope handle_scope(isolate);
25808 LocalContext env;
25809
25810 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25811
25812 // Functions defined in extras do not expose source code.
25813 auto func = binding->Get(env.local(), v8_str("testFunctionToString"))
25814 .ToLocalChecked()
25815 .As<v8::Function>();
25816 auto undefined = v8::Undefined(isolate);
25817 auto result = func->Call(env.local(), undefined, 0, {})
25818 .ToLocalChecked()
25819 .As<v8::String>();
25820 CHECK(result->StrictEquals(v8_str("function foo() { [native code] }")));
25821
25822 // Functions defined in extras do not show up in the stack trace.
25823 auto wrapper = binding->Get(env.local(), v8_str("testStackTrace"))
25824 .ToLocalChecked()
25825 .As<v8::Function>();
25826 CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust());
25827 ExpectString(
25828 "function f(x) { return wrapper(x) }"
25829 "function g() { return new Error().stack; }"
25830 "f(g)",
25831 "Error\n"
25832 " at g (<anonymous>:1:58)\n"
25833 " at f (<anonymous>:1:24)\n"
25834 " at <anonymous>:1:78");
25835}
25836
25837TEST(ExtrasBindingObject) {
25838 v8::Isolate* isolate = CcTest::isolate();
25839 v8::HandleScope handle_scope(isolate);
25840 LocalContext env;
25841
25842 // standalone.gypi ensures we include the test-extra.js file, which should
25843 // export the tested functions.
25844 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25845
25846 auto func = binding->Get(env.local(), v8_str("testExtraShouldReturnFive"))
25847 .ToLocalChecked()
25848 .As<v8::Function>();
25849 auto undefined = v8::Undefined(isolate);
25850 auto result = func->Call(env.local(), undefined, 0, {})
25851 .ToLocalChecked()
25852 .As<v8::Number>();
25853 CHECK_EQ(5, result->Int32Value(env.local()).FromJust());
25854
25855 v8::Local<v8::FunctionTemplate> runtimeFunction =
25856 v8::FunctionTemplate::New(isolate, ExtrasBindingTestRuntimeFunction);
25857 binding->Set(env.local(), v8_str("runtime"),
25858 runtimeFunction->GetFunction(env.local()).ToLocalChecked())
25859 .FromJust();
25860 func = binding->Get(env.local(), v8_str("testExtraShouldCallToRuntime"))
25861 .ToLocalChecked()
25862 .As<v8::Function>();
25863 result = func->Call(env.local(), undefined, 0, {})
25864 .ToLocalChecked()
25865 .As<v8::Number>();
25866 CHECK_EQ(7, result->Int32Value(env.local()).FromJust());
25867}
25868
25869
25870TEST(ExtrasCreatePromise) {
25871 i::FLAG_allow_natives_syntax = true;
25872 LocalContext context;
25873 v8::Isolate* isolate = context->GetIsolate();
25874 v8::HandleScope handle_scope(isolate);
25875
25876 LocalContext env;
25877 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25878
25879 auto func = binding->Get(env.local(), v8_str("testCreatePromise"))
25880 .ToLocalChecked()
25881 .As<v8::Function>();
25882 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25883
25884 auto promise = CompileRun(
25885 "func();\n"
25886 "func();\n"
25887 "%OptimizeFunctionOnNextCall(func);\n"
25888 "func()\n")
25889 .As<v8::Promise>();
25890 CHECK_EQ(v8::Promise::kPending, promise->State());
25891}
25892
25893TEST(ExtrasCreatePromiseWithParent) {
25894 i::FLAG_allow_natives_syntax = true;
25895 LocalContext context;
25896 v8::Isolate* isolate = context->GetIsolate();
25897 v8::HandleScope handle_scope(isolate);
25898
25899 LocalContext env;
25900 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25901
25902 auto func = binding->Get(env.local(), v8_str("testCreatePromiseWithParent"))
25903 .ToLocalChecked()
25904 .As<v8::Function>();
25905 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25906
25907 auto promise = CompileRun(
25908 "var parent = new Promise((a, b) => {});\n"
25909 "func(parent);\n"
25910 "func(parent);\n"
25911 "%OptimizeFunctionOnNextCall(func);\n"
25912 "func(parent)\n")
25913 .As<v8::Promise>();
25914 CHECK_EQ(v8::Promise::kPending, promise->State());
25915}
25916
25917TEST(ExtrasRejectPromise) {
25918 i::FLAG_allow_natives_syntax = true;
25919 LocalContext context;
25920 v8::Isolate* isolate = context->GetIsolate();
25921 v8::HandleScope handle_scope(isolate);
25922
25923 LocalContext env;
25924 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25925
25926 auto func = binding->Get(env.local(), v8_str("testRejectPromise"))
25927 .ToLocalChecked()
25928 .As<v8::Function>();
25929 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25930
25931 auto rejected_promise = CompileRun(
25932 "function newPromise() {\n"
25933 " return new Promise((a, b) => {});\n"
25934 "}\n"
25935 "func(newPromise(), 1);\n"
25936 "func(newPromise(), 1);\n"
25937 "%OptimizeFunctionOnNextCall(func);\n"
25938 "var promise = newPromise();\n"
25939 "func(promise, 1);\n"
25940 "promise;\n")
25941 .As<v8::Promise>();
25942 CHECK_EQ(v8::Promise::kRejected, rejected_promise->State());
25943 CHECK_EQ(1, rejected_promise->Result()->Int32Value(env.local()).FromJust());
25944}
25945
25946TEST(ExtrasResolvePromise) {
25947 i::FLAG_allow_natives_syntax = true;
25948 LocalContext context;
25949 v8::Isolate* isolate = context->GetIsolate();
25950 v8::HandleScope handle_scope(isolate);
25951
25952 LocalContext env;
25953 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25954
25955 auto func = binding->Get(env.local(), v8_str("testResolvePromise"))
25956 .ToLocalChecked()
25957 .As<v8::Function>();
25958 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
25959
25960 auto pending_promise = CompileRun(
25961 "function newPromise() {\n"
25962 " return new Promise((a, b) => {});\n"
25963 "}\n"
25964 "func(newPromise(), newPromise());\n"
25965 "func(newPromise(), newPromise());\n"
25966 "%OptimizeFunctionOnNextCall(func);\n"
25967 "var promise = newPromise();\n"
25968 "func(promise, newPromise());\n"
25969 "promise;\n")
25970 .As<v8::Promise>();
25971 CHECK_EQ(v8::Promise::kPending, pending_promise->State());
25972
25973 auto fulfilled_promise = CompileRun(
25974 "function newPromise() {\n"
25975 " return new Promise((a, b) => {});\n"
25976 "}\n"
25977 "func(newPromise(), 1);\n"
25978 "func(newPromise(), 1);\n"
25979 "%OptimizeFunctionOnNextCall(func);\n"
25980 "var promise = newPromise();\n"
25981 "func(promise, 1);\n"
25982 "promise;\n")
25983 .As<v8::Promise>();
25984 CHECK_EQ(v8::Promise::kFulfilled, fulfilled_promise->State());
25985 CHECK_EQ(1, fulfilled_promise->Result()->Int32Value(env.local()).FromJust());
25986}
25987
25988TEST(ExtrasUtilsObject) {
25989 LocalContext context;
25990 v8::Isolate* isolate = context->GetIsolate();
25991 v8::HandleScope handle_scope(isolate);
25992
25993 LocalContext env;
25994 v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
25995
25996 auto func = binding->Get(env.local(), v8_str("testExtraCanUseUtils"))
25997 .ToLocalChecked()
25998 .As<v8::Function>();
25999 auto undefined = v8::Undefined(isolate);
26000 auto result = func->Call(env.local(), undefined, 0, {})
26001 .ToLocalChecked()
26002 .As<v8::Object>();
26003
26004 auto private_symbol = result->Get(env.local(), v8_str("privateSymbol"))
26005 .ToLocalChecked()
26006 .As<v8::Symbol>();
26007 i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
26008 CHECK(ips->IsPrivate());
26009
26010 CompileRun("var result = 0; function store(x) { result = x; }");
26011 auto store = CompileRun("store").As<v8::Function>();
26012
26013 auto fulfilled_promise = result->Get(env.local(), v8_str("fulfilledPromise"))
26014 .ToLocalChecked()
26015 .As<v8::Promise>();
26016 fulfilled_promise->Then(env.local(), store).ToLocalChecked();
26017 isolate->RunMicrotasks();
26018 CHECK_EQ(1, CompileRun("result")->Int32Value(env.local()).FromJust());
26019
26020 auto fulfilled_promise_2 =
26021 result->Get(env.local(), v8_str("fulfilledPromise2"))
26022 .ToLocalChecked()
26023 .As<v8::Promise>();
26024 fulfilled_promise_2->Then(env.local(), store).ToLocalChecked();
26025 isolate->RunMicrotasks();
26026 CHECK_EQ(2, CompileRun("result")->Int32Value(env.local()).FromJust());
26027
26028 auto rejected_promise = result->Get(env.local(), v8_str("rejectedPromise"))
26029 .ToLocalChecked()
26030 .As<v8::Promise>();
26031 rejected_promise->Catch(env.local(), store).ToLocalChecked();
26032 isolate->RunMicrotasks();
26033 CHECK_EQ(3, CompileRun("result")->Int32Value(env.local()).FromJust());
26034
26035 auto rejected_but_handled_promise =
26036 result->Get(env.local(), v8_str("rejectedButHandledPromise"))
26037 .ToLocalChecked()
26038 .As<v8::Promise>();
26039 CHECK(rejected_but_handled_promise->HasHandler());
26040
26041 auto promise_states = result->Get(env.local(), v8_str("promiseStates"))
26042 .ToLocalChecked()
26043 .As<v8::String>();
26044 String::Utf8Value promise_states_string(isolate, promise_states);
26045 CHECK_EQ(0, strcmp(*promise_states_string, "pending fulfilled rejected"));
26046
26047 auto promise_is_promise = result->Get(env.local(), v8_str("promiseIsPromise"))
26048 .ToLocalChecked()
26049 .As<v8::Boolean>();
26050 CHECK_EQ(true, promise_is_promise->Value());
26051
26052 auto thenable_is_promise =
26053 result->Get(env.local(), v8_str("thenableIsPromise"))
26054 .ToLocalChecked()
26055 .As<v8::Boolean>();
26056 CHECK_EQ(false, thenable_is_promise->Value());
26057
26058 auto uncurry_this = result->Get(env.local(), v8_str("uncurryThis"))
26059 .ToLocalChecked()
26060 .As<v8::Boolean>();
26061 CHECK_EQ(true, uncurry_this->Value());
26062}
26063
26064
26065TEST(Map) {
26066 v8::Isolate* isolate = CcTest::isolate();
26067 v8::HandleScope handle_scope(isolate);
26068 LocalContext env;
26069
26070 v8::Local<v8::Map> map = v8::Map::New(isolate);
26071 CHECK(map->IsObject());
26072 CHECK(map->IsMap());
26073 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
26074 CHECK_EQ(0U, map->Size());
26075
26076 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
26077 CHECK(val->IsMap());
26078 map = v8::Local<v8::Map>::Cast(val);
26079 CHECK_EQ(2U, map->Size());
26080
26081 v8::Local<v8::Array> contents = map->AsArray();
26082 CHECK_EQ(4U, contents->Length());
26083 CHECK_EQ(
26084 1,
26085 contents->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26086 CHECK_EQ(
26087 2,
26088 contents->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26089 CHECK_EQ(
26090 3,
26091 contents->Get(env.local(), 2).ToLocalChecked().As<v8::Int32>()->Value());
26092 CHECK_EQ(
26093 4,
26094 contents->Get(env.local(), 3).ToLocalChecked().As<v8::Int32>()->Value());
26095
26096 CHECK_EQ(2U, map->Size());
26097
26098 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26099 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26100
26101 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26102 CHECK(!map->Has(env.local(), map).FromJust());
26103
26104 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
26105 .ToLocalChecked()
26106 ->Int32Value(env.local())
26107 .FromJust());
26108 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
26109 .ToLocalChecked()
26110 ->Int32Value(env.local())
26111 .FromJust());
26112
26113 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
26114 .ToLocalChecked()
26115 ->IsUndefined());
26116
26117 CHECK(!map->Set(env.local(), map, map).IsEmpty());
26118 CHECK_EQ(3U, map->Size());
26119 CHECK(map->Has(env.local(), map).FromJust());
26120
26121 CHECK(map->Delete(env.local(), map).FromJust());
26122 CHECK_EQ(2U, map->Size());
26123 CHECK(!map->Has(env.local(), map).FromJust());
26124 CHECK(!map->Delete(env.local(), map).FromJust());
26125
26126 map->Clear();
26127 CHECK_EQ(0U, map->Size());
26128}
26129
26130
26131TEST(Set) {
26132 v8::Isolate* isolate = CcTest::isolate();
26133 v8::HandleScope handle_scope(isolate);
26134 LocalContext env;
26135
26136 v8::Local<v8::Set> set = v8::Set::New(isolate);
26137 CHECK(set->IsObject());
26138 CHECK(set->IsSet());
26139 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
26140 CHECK_EQ(0U, set->Size());
26141
26142 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
26143 CHECK(val->IsSet());
26144 set = v8::Local<v8::Set>::Cast(val);
26145 CHECK_EQ(2U, set->Size());
26146
26147 v8::Local<v8::Array> keys = set->AsArray();
26148 CHECK_EQ(2U, keys->Length());
26149 CHECK_EQ(1,
26150 keys->Get(env.local(), 0).ToLocalChecked().As<v8::Int32>()->Value());
26151 CHECK_EQ(2,
26152 keys->Get(env.local(), 1).ToLocalChecked().As<v8::Int32>()->Value());
26153
26154 CHECK_EQ(2U, set->Size());
26155
26156 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
26157 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
26158
26159 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
26160 CHECK(!set->Has(env.local(), set).FromJust());
26161
26162 CHECK(!set->Add(env.local(), set).IsEmpty());
26163 CHECK_EQ(3U, set->Size());
26164 CHECK(set->Has(env.local(), set).FromJust());
26165
26166 CHECK(set->Delete(env.local(), set).FromJust());
26167 CHECK_EQ(2U, set->Size());
26168 CHECK(!set->Has(env.local(), set).FromJust());
26169 CHECK(!set->Delete(env.local(), set).FromJust());
26170
26171 set->Clear();
26172 CHECK_EQ(0U, set->Size());
26173}
26174
26175TEST(SetDeleteThenAsArray) {
26176 // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26177 v8::Isolate* isolate = CcTest::isolate();
26178 v8::HandleScope handle_scope(isolate);
26179 LocalContext env;
26180
26181 // make a Set
26182 v8::Local<v8::Value> val = CompileRun("new Set([1, 2, 3])");
26183 v8::Local<v8::Set> set = v8::Local<v8::Set>::Cast(val);
26184 CHECK_EQ(3U, set->Size());
26185
26186 // delete the "middle" element (using AsArray to
26187 // determine which element is the "middle" element)
26188 v8::Local<v8::Array> array1 = set->AsArray();
26189 CHECK_EQ(3U, array1->Length());
26190 CHECK(set->Delete(env.local(), array1->Get(env.local(), 1).ToLocalChecked())
26191 .FromJust());
26192
26193 // make sure there are no undefined values when we convert to an array again.
26194 v8::Local<v8::Array> array2 = set->AsArray();
26195 uint32_t length = array2->Length();
26196 CHECK_EQ(2U, length);
26197 for (uint32_t i = 0; i < length; i++) {
26198 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26199 }
26200}
26201
26202TEST(MapDeleteThenAsArray) {
26203 // https://bugs.chromium.org/p/v8/issues/detail?id=4946
26204 v8::Isolate* isolate = CcTest::isolate();
26205 v8::HandleScope handle_scope(isolate);
26206 LocalContext env;
26207
26208 // make a Map
26209 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4], [5, 6]])");
26210 v8::Local<v8::Map> map = v8::Local<v8::Map>::Cast(val);
26211 CHECK_EQ(3U, map->Size());
26212
26213 // delete the "middle" element (using AsArray to
26214 // determine which element is the "middle" element)
26215 v8::Local<v8::Array> array1 = map->AsArray();
26216 CHECK_EQ(6U, array1->Length());
26217 // Map::AsArray returns a flat array, so the second key is at index 2.
26218 v8::Local<v8::Value> key = array1->Get(env.local(), 2).ToLocalChecked();
26219 CHECK(map->Delete(env.local(), key).FromJust());
26220
26221 // make sure there are no undefined values when we convert to an array again.
26222 v8::Local<v8::Array> array2 = map->AsArray();
26223 uint32_t length = array2->Length();
26224 CHECK_EQ(4U, length);
26225 for (uint32_t i = 0; i < length; i++) {
26226 CHECK(!array2->Get(env.local(), i).ToLocalChecked()->IsUndefined());
26227 }
26228}
26229
26230TEST(CompatibleReceiverCheckOnCachedICHandler) {
26231 v8::Isolate* isolate = CcTest::isolate();
26232 v8::HandleScope scope(isolate);
26233 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
26234 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
26235 auto returns_42 =
26236 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
26237 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
26238 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
26239 child->Inherit(parent);
26240 LocalContext env;
26241 CHECK(env->Global()
26242 ->Set(env.local(), v8_str("Child"),
26243 child->GetFunction(env.local()).ToLocalChecked())
26244 .FromJust());
26245
26246 // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
26247 CompileRun(
26248 "var real = new Child();\n"
26249 "for (var i = 0; i < 3; ++i) {\n"
26250 " real.age;\n"
26251 "}\n");
26252
26253 // Check that the cached stub is never used.
26254 ExpectInt32(
26255 "var fake = Object.create(Child.prototype);\n"
26256 "var result = 0;\n"
26257 "function test(d) {\n"
26258 " if (d == 3) return;\n"
26259 " try {\n"
26260 " fake.age;\n"
26261 " result = 1;\n"
26262 " } catch (e) {\n"
26263 " }\n"
26264 " test(d+1);\n"
26265 "}\n"
26266 "test(0);\n"
26267 "result;\n",
26268 0);
26269}
26270
26271THREADED_TEST(ReceiverConversionForAccessors) {
26272 LocalContext env;
26273 v8::Isolate* isolate = CcTest::isolate();
26274 v8::HandleScope scope(isolate);
26275 Local<v8::FunctionTemplate> acc =
26276 v8::FunctionTemplate::New(isolate, Returns42);
26277 CHECK(env->Global()
26278 ->Set(env.local(), v8_str("acc"),
26279 acc->GetFunction(env.local()).ToLocalChecked())
26280 .FromJust());
26281
26282 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
26283 templ->SetAccessorProperty(v8_str("acc"), acc, acc);
26284 Local<v8::Object> instance = templ->NewInstance(env.local()).ToLocalChecked();
26285
26286 CHECK(env->Global()->Set(env.local(), v8_str("p"), instance).FromJust());
26287 CHECK(CompileRun("(p.acc == 42)")->BooleanValue(isolate));
26288 CHECK(CompileRun("(p.acc = 7) == 7")->BooleanValue(isolate));
26289
26290 CHECK(!CompileRun("Number.prototype.__proto__ = p;"
26291 "var a = 1;")
26292 .IsEmpty());
26293 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26294 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26295
26296 CHECK(!CompileRun("Boolean.prototype.__proto__ = p;"
26297 "var a = true;")
26298 .IsEmpty());
26299 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26300 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26301
26302 CHECK(!CompileRun("String.prototype.__proto__ = p;"
26303 "var a = 'foo';")
26304 .IsEmpty());
26305 CHECK(CompileRun("(a.acc == 42)")->BooleanValue(isolate));
26306 CHECK(CompileRun("(a.acc = 7) == 7")->BooleanValue(isolate));
26307
26308 CHECK(CompileRun("acc.call(1) == 42")->BooleanValue(isolate));
26309 CHECK(CompileRun("acc.call(true)==42")->BooleanValue(isolate));
26310 CHECK(CompileRun("acc.call('aa')==42")->BooleanValue(isolate));
26311 CHECK(CompileRun("acc.call(null) == 42")->BooleanValue(isolate));
26312 CHECK(CompileRun("acc.call(undefined) == 42")->BooleanValue(isolate));
26313}
26314
26315class FutexInterruptionThread : public v8::base::Thread {
26316 public:
26317 explicit FutexInterruptionThread(v8::Isolate* isolate)
26318 : Thread(Options("FutexInterruptionThread")), isolate_(isolate) {}
26319
26320 void Run() override {
26321 // Wait a bit before terminating.
26322 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
26323 isolate_->TerminateExecution();
26324 }
26325
26326 private:
26327 v8::Isolate* isolate_;
26328};
26329
26330
26331TEST(FutexInterruption) {
26332 i::FLAG_harmony_sharedarraybuffer = true;
26333 v8::Isolate* isolate = CcTest::isolate();
26334 v8::HandleScope scope(isolate);
26335 LocalContext env;
26336
26337 FutexInterruptionThread timeout_thread(isolate);
26338
26339 v8::TryCatch try_catch(CcTest::isolate());
26340 timeout_thread.Start();
26341
26342 CompileRun(
26343 "var ab = new SharedArrayBuffer(4);"
26344 "var i32a = new Int32Array(ab);"
26345 "Atomics.wait(i32a, 0, 0);");
26346 CHECK(try_catch.HasTerminated());
26347 timeout_thread.Join();
26348}
26349
26350THREADED_TEST(SharedArrayBuffer_AllocationInformation) {
26351 i::FLAG_harmony_sharedarraybuffer = true;
26352 LocalContext env;
26353 v8::Isolate* isolate = env->GetIsolate();
26354 v8::HandleScope handle_scope(isolate);
26355
26356 const size_t ab_size = 1024;
26357 Local<v8::SharedArrayBuffer> ab =
26358 v8::SharedArrayBuffer::New(isolate, ab_size);
26359 ScopedSharedArrayBufferContents contents(ab->Externalize());
26360
26361 // Array buffers should have normal allocation mode.
26362 CHECK_EQ(contents.AllocationMode(),
26363 v8::ArrayBuffer::Allocator::AllocationMode::kNormal);
26364 // The allocation must contain the buffer (normally they will be equal, but
26365 // this is not required by the contract).
26366 CHECK_NOT_NULL(contents.AllocationBase());
26367 const uintptr_t alloc =
26368 reinterpret_cast<uintptr_t>(contents.AllocationBase());
26369 const uintptr_t data = reinterpret_cast<uintptr_t>(contents.Data());
26370 CHECK_LE(alloc, data);
26371 CHECK_LE(data + contents.ByteLength(), alloc + contents.AllocationLength());
26372}
26373
26374static int nb_uncaught_exception_callback_calls = 0;
26375
26376
26377bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
26378 ++nb_uncaught_exception_callback_calls;
26379 return false;
26380}
26381
26382
26383TEST(AbortOnUncaughtExceptionNoAbort) {
26384 v8::Isolate* isolate = CcTest::isolate();
26385 v8::HandleScope handle_scope(isolate);
26386 v8::Local<v8::ObjectTemplate> global_template =
26387 v8::ObjectTemplate::New(isolate);
26388 LocalContext env(nullptr, global_template);
26389
26390 i::FLAG_abort_on_uncaught_exception = true;
26391 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
26392
26393 CompileRun("function boom() { throw new Error(\"boom\") }");
26394
26395 v8::Local<v8::Object> global_object = env->Global();
26396 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
26397 global_object->Get(env.local(), v8_str("boom")).ToLocalChecked());
26398
26399 CHECK(foo->Call(env.local(), global_object, 0, nullptr).IsEmpty());
26400
26401 CHECK_EQ(1, nb_uncaught_exception_callback_calls);
26402}
26403
26404
26405TEST(AccessCheckedIsConcatSpreadable) {
26406 v8::Isolate* isolate = CcTest::isolate();
26407 HandleScope scope(isolate);
26408 LocalContext env;
26409
26410 // Object with access check
26411 Local<ObjectTemplate> spreadable_template = v8::ObjectTemplate::New(isolate);
26412 spreadable_template->SetAccessCheckCallback(AccessBlocker);
26413 spreadable_template->Set(v8::Symbol::GetIsConcatSpreadable(isolate),
26414 v8::Boolean::New(isolate, true));
26415 Local<Object> object =
26416 spreadable_template->NewInstance(env.local()).ToLocalChecked();
26417
26418 allowed_access = true;
26419 CHECK(env->Global()->Set(env.local(), v8_str("object"), object).FromJust());
26420 object->Set(env.local(), v8_str("length"), v8_num(2)).FromJust();
26421 object->Set(env.local(), 0U, v8_str("a")).FromJust();
26422 object->Set(env.local(), 1U, v8_str("b")).FromJust();
26423
26424 // Access check is allowed, and the object is spread
26425 CompileRun("var result = [].concat(object)");
26426 ExpectTrue("Array.isArray(result)");
26427 ExpectString("result[0]", "a");
26428 ExpectString("result[1]", "b");
26429 ExpectTrue("result.length === 2");
26430 ExpectTrue("object[Symbol.isConcatSpreadable]");
26431
26432 // If access check fails, the value of @@isConcatSpreadable is ignored
26433 allowed_access = false;
26434 CompileRun("var result = [].concat(object)");
26435 ExpectTrue("Array.isArray(result)");
26436 ExpectTrue("result[0] === object");
26437 ExpectTrue("result.length === 1");
26438 ExpectTrue("object[Symbol.isConcatSpreadable] === undefined");
26439}
26440
26441
26442TEST(AccessCheckedToStringTag) {
26443 v8::Isolate* isolate = CcTest::isolate();
26444 HandleScope scope(isolate);
26445 LocalContext env;
26446
26447 // Object with access check
26448 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26449 object_template->SetAccessCheckCallback(AccessBlocker);
26450 Local<Object> object =
26451 object_template->NewInstance(env.local()).ToLocalChecked();
26452
26453 allowed_access = true;
26454 env->Global()->Set(env.local(), v8_str("object"), object).FromJust();
26455 object->Set(env.local(), v8::Symbol::GetToStringTag(isolate), v8_str("hello"))
26456 .FromJust();
26457
26458 // Access check is allowed, and the toStringTag is read
26459 CompileRun("var result = Object.prototype.toString.call(object)");
26460 ExpectString("result", "[object hello]");
26461 ExpectString("object[Symbol.toStringTag]", "hello");
26462
26463 // ToString through the API should succeed too.
26464 String::Utf8Value result_allowed(
26465 isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26466 CHECK_EQ(0, strcmp(*result_allowed, "[object hello]"));
26467
26468 // If access check fails, the value of @@toStringTag is ignored
26469 allowed_access = false;
26470 CompileRun("var result = Object.prototype.toString.call(object)");
26471 ExpectString("result", "[object Object]");
26472 ExpectTrue("object[Symbol.toStringTag] === undefined");
26473
26474 // ToString through the API should also fail.
26475 String::Utf8Value result_denied(
26476 isolate, object->ObjectProtoToString(env.local()).ToLocalChecked());
26477 CHECK_EQ(0, strcmp(*result_denied, "[object Object]"));
26478}
26479
26480TEST(TemplateIteratorPrototypeIntrinsics) {
26481 v8::Isolate* isolate = CcTest::isolate();
26482 v8::HandleScope scope(isolate);
26483 LocalContext env;
26484
26485 // Object templates.
26486 {
26487 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26488 object_template->SetIntrinsicDataProperty(v8_str("iter_proto"),
26489 v8::kIteratorPrototype);
26490 Local<Object> object =
26491 object_template->NewInstance(env.local()).ToLocalChecked();
26492 CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26493 ExpectTrue("obj.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26494 }
26495 // Setting %IteratorProto% on the function object's prototype template.
26496 {
26497 Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26498 func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26499 v8_str("iter_proto"), v8::kIteratorPrototype);
26500 Local<Function> func1 =
26501 func_template->GetFunction(env.local()).ToLocalChecked();
26502 CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26503 Local<Function> func2 =
26504 func_template->GetFunction(env.local()).ToLocalChecked();
26505 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26506 ExpectTrue(
26507 "func1.prototype.iter_proto === "
26508 "[][Symbol.iterator]().__proto__.__proto__");
26509 ExpectTrue(
26510 "func2.prototype.iter_proto === "
26511 "[][Symbol.iterator]().__proto__.__proto__");
26512 ExpectTrue("func1.prototype.iter_proto === func2.prototype.iter_proto");
26513
26514 Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26515 CHECK(env->Global()
26516 ->Set(env.local(), v8_str("instance1"), instance1)
26517 .FromJust());
26518 ExpectFalse("instance1.hasOwnProperty('iter_proto')");
26519 ExpectTrue("'iter_proto' in instance1.__proto__");
26520 ExpectTrue(
26521 "instance1.iter_proto === [][Symbol.iterator]().__proto__.__proto__");
26522 }
26523 // Put %IteratorProto% in a function object's inheritance chain.
26524 {
26525 Local<FunctionTemplate> parent_template =
26526 v8::FunctionTemplate::New(isolate);
26527 parent_template->RemovePrototype(); // Remove so there is no name clash.
26528 parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26529 v8::kIteratorPrototype);
26530 Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26531 func_template->Inherit(parent_template);
26532
26533 Local<Function> func =
26534 func_template->GetFunction(env.local()).ToLocalChecked();
26535 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26536 ExpectTrue(
26537 "func.prototype.__proto__ === "
26538 "[][Symbol.iterator]().__proto__.__proto__");
26539
26540 Local<Object> func_instance =
26541 func->NewInstance(env.local()).ToLocalChecked();
26542 CHECK(env->Global()
26543 ->Set(env.local(), v8_str("instance"), func_instance)
26544 .FromJust());
26545 ExpectTrue(
26546 "instance.__proto__.__proto__ === "
26547 "[][Symbol.iterator]().__proto__.__proto__");
26548 ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26549 }
26550}
26551
26552TEST(TemplateErrorPrototypeIntrinsics) {
26553 v8::Isolate* isolate = CcTest::isolate();
26554 v8::HandleScope scope(isolate);
26555 LocalContext env;
26556
26557 // Object templates.
26558 {
26559 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26560 object_template->SetIntrinsicDataProperty(v8_str("error_proto"),
26561 v8::kErrorPrototype);
26562 Local<Object> object =
26563 object_template->NewInstance(env.local()).ToLocalChecked();
26564 CHECK(env->Global()->Set(env.local(), v8_str("obj"), object).FromJust());
26565 ExpectTrue("obj.error_proto === Error.prototype");
26566 Local<Value> error = v8::Exception::Error(v8_str("error message"));
26567 CHECK(env->Global()->Set(env.local(), v8_str("err"), error).FromJust());
26568 ExpectTrue("obj.error_proto === Object.getPrototypeOf(err)");
26569 }
26570 // Setting %ErrorPrototype% on the function object's prototype template.
26571 {
26572 Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26573 func_template->PrototypeTemplate()->SetIntrinsicDataProperty(
26574 v8_str("error_proto"), v8::kErrorPrototype);
26575 Local<Function> func1 =
26576 func_template->GetFunction(env.local()).ToLocalChecked();
26577 CHECK(env->Global()->Set(env.local(), v8_str("func1"), func1).FromJust());
26578 Local<Function> func2 =
26579 func_template->GetFunction(env.local()).ToLocalChecked();
26580 CHECK(env->Global()->Set(env.local(), v8_str("func2"), func2).FromJust());
26581 ExpectTrue("func1.prototype.error_proto === Error.prototype");
26582 ExpectTrue("func2.prototype.error_proto === Error.prototype");
26583 ExpectTrue("func1.prototype.error_proto === func2.prototype.error_proto");
26584
26585 Local<Object> instance1 = func1->NewInstance(env.local()).ToLocalChecked();
26586 CHECK(env->Global()
26587 ->Set(env.local(), v8_str("instance1"), instance1)
26588 .FromJust());
26589 ExpectFalse("instance1.hasOwnProperty('error_proto')");
26590 ExpectTrue("'error_proto' in instance1.__proto__");
26591 ExpectTrue("instance1.error_proto === Error.prototype");
26592 }
26593 // Put %ErrorPrototype% in a function object's inheritance chain.
26594 {
26595 Local<FunctionTemplate> parent_template =
26596 v8::FunctionTemplate::New(isolate);
26597 parent_template->RemovePrototype(); // Remove so there is no name clash.
26598 parent_template->SetIntrinsicDataProperty(v8_str("prototype"),
26599 v8::kErrorPrototype);
26600 Local<FunctionTemplate> func_template = v8::FunctionTemplate::New(isolate);
26601 func_template->Inherit(parent_template);
26602
26603 Local<Function> func =
26604 func_template->GetFunction(env.local()).ToLocalChecked();
26605 CHECK(env->Global()->Set(env.local(), v8_str("func"), func).FromJust());
26606 ExpectTrue("func.prototype.__proto__ === Error.prototype");
26607
26608 Local<Object> func_instance =
26609 func->NewInstance(env.local()).ToLocalChecked();
26610 CHECK(env->Global()
26611 ->Set(env.local(), v8_str("instance"), func_instance)
26612 .FromJust());
26613 ExpectTrue("instance.__proto__.__proto__.__proto__ === Object.prototype");
26614 // Now let's check if %ErrorPrototype% properties are in the instance.
26615 ExpectTrue("'constructor' in instance");
26616 ExpectTrue("'message' in instance");
26617 ExpectTrue("'name' in instance");
26618 ExpectTrue("'toString' in instance");
26619 }
26620}
26621
26622TEST(ObjectTemplateArrayProtoIntrinsics) {
26623 v8::Isolate* isolate = CcTest::isolate();
26624 v8::HandleScope scope(isolate);
26625 LocalContext env;
26626
26627 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26628 object_template->SetIntrinsicDataProperty(v8_str("prop_entries"),
26629 v8::kArrayProto_entries);
26630 object_template->SetIntrinsicDataProperty(v8_str("prop_forEach"),
26631 v8::kArrayProto_forEach);
26632 object_template->SetIntrinsicDataProperty(v8_str("prop_keys"),
26633 v8::kArrayProto_keys);
26634 object_template->SetIntrinsicDataProperty(v8_str("prop_values"),
26635 v8::kArrayProto_values);
26636 Local<Object> object =
26637 object_template->NewInstance(env.local()).ToLocalChecked();
26638 CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26639
26640 const struct {
26641 const char* const object_property_name;
26642 const char* const array_property_name;
26643 } intrinsics_comparisons[] = {
26644 {"prop_entries", "Array.prototype.entries"},
26645 {"prop_forEach", "Array.prototype.forEach"},
26646 {"prop_keys", "Array.prototype.keys"},
26647 {"prop_values", "Array.prototype[Symbol.iterator]"},
26648 };
26649
26650 for (unsigned i = 0; i < arraysize(intrinsics_comparisons); i++) {
26651 i::ScopedVector<char> test_string(64);
26652
26653 i::SNPrintF(test_string, "typeof obj1.%s",
26654 intrinsics_comparisons[i].object_property_name);
26655 ExpectString(test_string.start(), "function");
26656
26657 i::SNPrintF(test_string, "obj1.%s === %s",
26658 intrinsics_comparisons[i].object_property_name,
26659 intrinsics_comparisons[i].array_property_name);
26660 ExpectTrue(test_string.start());
26661
26662 i::SNPrintF(test_string, "obj1.%s = 42",
26663 intrinsics_comparisons[i].object_property_name);
26664 CompileRun(test_string.start());
26665
26666 i::SNPrintF(test_string, "obj1.%s === %s",
26667 intrinsics_comparisons[i].object_property_name,
26668 intrinsics_comparisons[i].array_property_name);
26669 ExpectFalse(test_string.start());
26670
26671 i::SNPrintF(test_string, "typeof obj1.%s",
26672 intrinsics_comparisons[i].object_property_name);
26673 ExpectString(test_string.start(), "number");
26674 }
26675}
26676
26677TEST(ObjectTemplatePerContextIntrinsics) {
26678 v8::Isolate* isolate = CcTest::isolate();
26679 v8::HandleScope scope(isolate);
26680 LocalContext env;
26681
26682 Local<ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate);
26683 object_template->SetIntrinsicDataProperty(v8_str("values"),
26684 v8::kArrayProto_values);
26685 Local<Object> object =
26686 object_template->NewInstance(env.local()).ToLocalChecked();
26687
26688 CHECK(env->Global()->Set(env.local(), v8_str("obj1"), object).FromJust());
26689 ExpectString("typeof obj1.values", "function");
26690
26691 auto values = Local<Function>::Cast(
26692 object->Get(env.local(), v8_str("values")).ToLocalChecked());
26693 auto fn = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values));
26694 auto ctx = v8::Utils::OpenHandle(*env.local());
26695 CHECK_EQ(*fn->GetCreationContext(), *ctx);
26696
26697 {
26698 LocalContext env2;
26699 Local<Object> object2 =
26700 object_template->NewInstance(env2.local()).ToLocalChecked();
26701 CHECK(
26702 env2->Global()->Set(env2.local(), v8_str("obj2"), object2).FromJust());
26703 ExpectString("typeof obj2.values", "function");
26704 CHECK_NE(*object->Get(env2.local(), v8_str("values")).ToLocalChecked(),
26705 *object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26706
26707 auto values2 = Local<Function>::Cast(
26708 object2->Get(env2.local(), v8_str("values")).ToLocalChecked());
26709 auto fn2 = i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*values2));
26710 auto ctx2 = v8::Utils::OpenHandle(*env2.local());
26711 CHECK_EQ(*fn2->GetCreationContext(), *ctx2);
26712 }
26713}
26714
26715
26716TEST(Proxy) {
26717 LocalContext context;
26718 v8::Isolate* isolate = CcTest::isolate();
26719 v8::HandleScope scope(isolate);
26720 v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
26721 v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
26722
26723 v8::Local<v8::Proxy> proxy =
26724 v8::Proxy::New(context.local(), target, handler).ToLocalChecked();
26725 CHECK(proxy->IsProxy());
26726 CHECK(!target->IsProxy());
26727 CHECK(!proxy->IsRevoked());
26728 CHECK(proxy->GetTarget()->SameValue(target));
26729 CHECK(proxy->GetHandler()->SameValue(handler));
26730
26731 proxy->Revoke();
26732 CHECK(proxy->IsProxy());
26733 CHECK(!target->IsProxy());
26734 CHECK(proxy->IsRevoked());
26735 CHECK(proxy->GetTarget()->IsNull());
26736 CHECK(proxy->GetHandler()->IsNull());
26737}
26738
26739WeakCallCounterAndPersistent<Value>* CreateGarbageWithWeakCallCounter(
26740 v8::Isolate* isolate, WeakCallCounter* counter) {
26741 v8::Locker locker(isolate);
26742 LocalContext env;
26743 HandleScope scope(isolate);
26744 WeakCallCounterAndPersistent<Value>* val =
26745 new WeakCallCounterAndPersistent<Value>(counter);
26746 val->handle.Reset(isolate, Object::New(isolate));
26747 val->handle.SetWeak(val, &WeakPointerCallback,
26748 v8::WeakCallbackType::kParameter);
26749 return val;
26750}
26751
26752class MemoryPressureThread : public v8::base::Thread {
26753 public:
26754 explicit MemoryPressureThread(v8::Isolate* isolate,
26755 v8::MemoryPressureLevel level)
26756 : Thread(Options("MemoryPressureThread")),
26757 isolate_(isolate),
26758 level_(level) {}
26759
26760 void Run() override { isolate_->MemoryPressureNotification(level_); }
26761
26762 private:
26763 v8::Isolate* isolate_;
26764 v8::MemoryPressureLevel level_;
26765};
26766
26767TEST(MemoryPressure) {
26768 if (v8::internal::FLAG_optimize_for_size) return;
26769 v8::Isolate* isolate = CcTest::isolate();
26770 WeakCallCounter counter(1234);
26771
26772 // Check that critical memory pressure notification sets GC interrupt.
26773 auto garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26774 CHECK(!v8::Locker::IsLocked(isolate));
26775 {
26776 v8::Locker locker(isolate);
26777 v8::HandleScope scope(isolate);
26778 LocalContext env;
26779 MemoryPressureThread memory_pressure_thread(
26780 isolate, v8::MemoryPressureLevel::kCritical);
26781 memory_pressure_thread.Start();
26782 memory_pressure_thread.Join();
26783 // This should trigger GC.
26784 CHECK_EQ(0, counter.NumberOfWeakCalls());
26785 CompileRun("(function noop() { return 0; })()");
26786 CHECK_EQ(1, counter.NumberOfWeakCalls());
26787 }
26788 delete garbage;
26789 // Check that critical memory pressure notification triggers GC.
26790 garbage = CreateGarbageWithWeakCallCounter(isolate, &counter);
26791 {
26792 v8::Locker locker(isolate);
26793 // If isolate is locked, memory pressure notification should trigger GC.
26794 CHECK_EQ(1, counter.NumberOfWeakCalls());
26795 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical);
26796 CHECK_EQ(2, counter.NumberOfWeakCalls());
26797 }
26798 delete garbage;
26799 // Check that moderate memory pressure notification sets GC into memory
26800 // optimizing mode.
26801 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
26802 CHECK(CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26803 // Check that disabling memory pressure returns GC into normal mode.
26804 isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kNone);
26805 CHECK(!CcTest::i_isolate()->heap()->ShouldOptimizeForMemoryUsage());
26806}
26807
26808TEST(SetIntegrityLevel) {
26809 LocalContext context;
26810 v8::Isolate* isolate = CcTest::isolate();
26811 v8::HandleScope scope(isolate);
26812
26813 v8::Local<v8::Object> obj = v8::Object::New(isolate);
26814 CHECK(context->Global()->Set(context.local(), v8_str("o"), obj).FromJust());
26815
26816 v8::Local<v8::Value> is_frozen = CompileRun("Object.isFrozen(o)");
26817 CHECK(!is_frozen->BooleanValue(isolate));
26818
26819 CHECK(obj->SetIntegrityLevel(context.local(), v8::IntegrityLevel::kFrozen)
26820 .FromJust());
26821
26822 is_frozen = CompileRun("Object.isFrozen(o)");
26823 CHECK(is_frozen->BooleanValue(isolate));
26824}
26825
26826TEST(PrivateForApiIsNumber) {
26827 LocalContext context;
26828 v8::Isolate* isolate = CcTest::isolate();
26829 v8::HandleScope scope(isolate);
26830
26831 // Shouldn't crash.
26832 v8::Private::ForApi(isolate, v8_str("42"));
26833}
26834
26835THREADED_TEST(ImmutableProto) {
26836 LocalContext context;
26837 v8::Isolate* isolate = context->GetIsolate();
26838 v8::HandleScope handle_scope(isolate);
26839
26840 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26841 templ->InstanceTemplate()->SetImmutableProto();
26842
26843 Local<v8::Object> object = templ->GetFunction(context.local())
26844 .ToLocalChecked()
26845 ->NewInstance(context.local())
26846 .ToLocalChecked();
26847
26848 // Look up the prototype
26849 Local<v8::Value> original_proto =
26850 object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26851
26852 // Setting the prototype (e.g., to null) throws
26853 CHECK(object->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26854
26855 // The original prototype is still there
26856 Local<Value> new_proto =
26857 object->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26858 CHECK(new_proto->IsObject());
26859 CHECK(new_proto.As<v8::Object>()
26860 ->Equals(context.local(), original_proto)
26861 .FromJust());
26862}
26863
26864Local<v8::Context> call_eval_context;
26865Local<v8::Function> call_eval_bound_function;
26866
26867static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
26868 v8::Context::Scope scope(call_eval_context);
26869 args.GetReturnValue().Set(
26870 call_eval_bound_function
26871 ->Call(call_eval_context, call_eval_context->Global(), 0, nullptr)
26872 .ToLocalChecked());
26873}
26874
26875TEST(CrossActivationEval) {
26876 LocalContext env;
26877 v8::Isolate* isolate = env->GetIsolate();
26878 v8::HandleScope scope(isolate);
26879 {
26880 call_eval_context = v8::Context::New(isolate);
26881 v8::Context::Scope scope(call_eval_context);
26882 call_eval_bound_function =
26883 Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
26884 }
26885 env->Global()
26886 ->Set(env.local(), v8_str("CallEval"),
26887 v8::FunctionTemplate::New(isolate, CallEval)
26888 ->GetFunction(env.local())
26889 .ToLocalChecked())
26890 .FromJust();
26891 Local<Value> result = CompileRun("CallEval();");
26892 CHECK(result->IsInt32());
26893 CHECK_EQ(1, result->Int32Value(env.local()).FromJust());
26894}
26895
26896TEST(EvalInAccessCheckedContext) {
26897 v8::Isolate* isolate = CcTest::isolate();
26898 v8::HandleScope scope(isolate);
26899
26900 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26901
26902 obj_template->SetAccessCheckCallback(AccessAlwaysAllowed);
26903
26904 v8::Local<Context> context0 = Context::New(isolate, nullptr, obj_template);
26905 v8::Local<Context> context1 = Context::New(isolate, nullptr, obj_template);
26906
26907 Local<Value> foo = v8_str("foo");
26908 Local<Value> bar = v8_str("bar");
26909
26910 // Set to different domains.
26911 context0->SetSecurityToken(foo);
26912 context1->SetSecurityToken(bar);
26913
26914 // Set up function in context0 that uses eval from context0.
26915 context0->Enter();
26916 v8::Local<v8::Value> fun = CompileRun(
26917 "var x = 42;"
26918 "(function() {"
26919 " var e = eval;"
26920 " return function(s) { return e(s); }"
26921 "})()");
26922 context0->Exit();
26923
26924 // Put the function into context1 and call it. Since the access check
26925 // callback always returns true, the call succeeds even though the tokens
26926 // are different.
26927 context1->Enter();
26928 context1->Global()->Set(context1, v8_str("fun"), fun).FromJust();
26929 v8::Local<v8::Value> x_value = CompileRun("fun('x')");
26930 CHECK_EQ(42, x_value->Int32Value(context1).FromJust());
26931 context1->Exit();
26932}
26933
26934THREADED_TEST(ImmutableProtoWithParent) {
26935 LocalContext context;
26936 v8::Isolate* isolate = context->GetIsolate();
26937 v8::HandleScope handle_scope(isolate);
26938
26939 Local<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(isolate);
26940
26941 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
26942 templ->Inherit(parent);
26943 templ->PrototypeTemplate()->SetImmutableProto();
26944
26945 Local<v8::Function> function =
26946 templ->GetFunction(context.local()).ToLocalChecked();
26947 Local<v8::Object> instance =
26948 function->NewInstance(context.local()).ToLocalChecked();
26949 Local<v8::Object> prototype =
26950 instance->Get(context.local(), v8_str("__proto__"))
26951 .ToLocalChecked()
26952 ->ToObject(context.local())
26953 .ToLocalChecked();
26954
26955 // Look up the prototype
26956 Local<v8::Value> original_proto =
26957 prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26958
26959 // Setting the prototype (e.g., to null) throws
26960 CHECK(
26961 prototype->SetPrototype(context.local(), v8::Null(isolate)).IsNothing());
26962
26963 // The original prototype is still there
26964 Local<Value> new_proto =
26965 prototype->Get(context.local(), v8_str("__proto__")).ToLocalChecked();
26966 CHECK(new_proto->IsObject());
26967 CHECK(new_proto.As<v8::Object>()
26968 ->Equals(context.local(), original_proto)
26969 .FromJust());
26970}
26971
26972TEST(InternalFieldsOnGlobalProxy) {
26973 v8::Isolate* isolate = CcTest::isolate();
26974 v8::HandleScope scope(isolate);
26975
26976 v8::Local<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate);
26977 obj_template->SetInternalFieldCount(1);
26978
26979 v8::Local<v8::Context> context = Context::New(isolate, nullptr, obj_template);
26980 v8::Local<v8::Object> global = context->Global();
26981 CHECK_EQ(1, global->InternalFieldCount());
26982}
26983
26984THREADED_TEST(ImmutableProtoGlobal) {
26985 v8::Isolate* isolate = CcTest::isolate();
26986 v8::HandleScope handle_scope(isolate);
26987 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
26988 global_template->SetImmutableProto();
26989 v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
26990 Context::Scope context_scope(context);
26991 v8::Local<Value> result = CompileRun(
26992 "global = this;"
26993 "(function() {"
26994 " try {"
26995 " global.__proto__ = {};"
26996 " return 0;"
26997 " } catch (e) {"
26998 " return 1;"
26999 " }"
27000 "})()");
27001 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 1))
27002 .FromJust());
27003}
27004
27005THREADED_TEST(MutableProtoGlobal) {
27006 v8::Isolate* isolate = CcTest::isolate();
27007 v8::HandleScope handle_scope(isolate);
27008 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
27009 v8::Local<Context> context = Context::New(isolate, nullptr, global_template);
27010 Context::Scope context_scope(context);
27011 v8::Local<Value> result = CompileRun(
27012 "global = this;"
27013 "(function() {"
27014 " try {"
27015 " global.__proto__ = {};"
27016 " return 0;"
27017 " } catch (e) {"
27018 " return 1;"
27019 " }"
27020 "})()");
27021 CHECK(result->Equals(context, v8::Integer::New(CcTest::isolate(), 0))
27022 .FromJust());
27023}
27024
27025TEST(InternalFieldsOnTypedArray) {
27026 LocalContext env;
27027 v8::Isolate* isolate = env->GetIsolate();
27028 v8::HandleScope scope(isolate);
27029 v8::Local<v8::Context> context = env.local();
27030 Context::Scope context_scope(context);
27031 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27032 v8::Local<v8::Uint8Array> array = v8::Uint8Array::New(buffer, 0, 1);
27033 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27034 CHECK_EQ(static_cast<void*>(nullptr),
27035 array->GetAlignedPointerFromInternalField(i));
27036 }
27037}
27038
27039TEST(InternalFieldsOnDataView) {
27040 LocalContext env;
27041 v8::Isolate* isolate = env->GetIsolate();
27042 v8::HandleScope scope(isolate);
27043 v8::Local<v8::Context> context = env.local();
27044 Context::Scope context_scope(context);
27045 v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1);
27046 v8::Local<v8::DataView> array = v8::DataView::New(buffer, 0, 1);
27047 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
27048 CHECK_EQ(static_cast<void*>(nullptr),
27049 array->GetAlignedPointerFromInternalField(i));
27050 }
27051}
27052
27053TEST(SetPrototypeTemplate) {
27054 LocalContext env;
27055 v8::Isolate* isolate = env->GetIsolate();
27056 v8::HandleScope scope(isolate);
27057
27058 Local<FunctionTemplate> HTMLElementTemplate = FunctionTemplate::New(isolate);
27059 Local<FunctionTemplate> HTMLImageElementTemplate =
27060 FunctionTemplate::New(isolate);
27061 HTMLImageElementTemplate->Inherit(HTMLElementTemplate);
27062
27063 Local<FunctionTemplate> ImageTemplate = FunctionTemplate::New(isolate);
27064 ImageTemplate->SetPrototypeProviderTemplate(HTMLImageElementTemplate);
27065
27066 Local<Function> HTMLImageElement =
27067 HTMLImageElementTemplate->GetFunction(env.local()).ToLocalChecked();
27068 Local<Function> Image =
27069 ImageTemplate->GetFunction(env.local()).ToLocalChecked();
27070
27071 CHECK(env->Global()
27072 ->Set(env.local(), v8_str("HTMLImageElement"), HTMLImageElement)
27073 .FromJust());
27074 CHECK(env->Global()->Set(env.local(), v8_str("Image"), Image).FromJust());
27075
27076 ExpectTrue("Image.prototype === HTMLImageElement.prototype");
27077}
27078
27079void ensure_receiver_is_global_proxy(
27080 v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
27081 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSGlobalProxy());
27082}
27083
27084THREADED_TEST(GlobalAccessorInfo) {
27085 v8::Isolate* isolate = CcTest::isolate();
27086 v8::HandleScope scope(isolate);
27087 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
27088 global_template->SetAccessor(
27089 v8::String::NewFromUtf8(isolate, "prop", v8::NewStringType::kInternalized)
27090 .ToLocalChecked(),
27091 &ensure_receiver_is_global_proxy);
27092 LocalContext env(nullptr, global_template);
27093 CompileRun("for (var i = 0; i < 10; i++) this.prop");
27094 CompileRun("for (var i = 0; i < 10; i++) prop");
27095}
27096
27097TEST(DeterministicRandomNumberGeneration) {
27098 v8::HandleScope scope(CcTest::isolate());
27099
27100 int previous_seed = v8::internal::FLAG_random_seed;
27101 v8::internal::FLAG_random_seed = 1234;
27102
27103 double first_value;
27104 double second_value;
27105 {
27106 v8::Local<Context> context = Context::New(CcTest::isolate());
27107 Context::Scope context_scope(context);
27108 v8::Local<Value> result = CompileRun("Math.random();");
27109 first_value = result->ToNumber(context).ToLocalChecked()->Value();
27110 }
27111 {
27112 v8::Local<Context> context = Context::New(CcTest::isolate());
27113 Context::Scope context_scope(context);
27114 v8::Local<Value> result = CompileRun("Math.random();");
27115 second_value = result->ToNumber(context).ToLocalChecked()->Value();
27116 }
27117 CHECK_EQ(first_value, second_value);
27118
27119 v8::internal::FLAG_random_seed = previous_seed;
27120}
27121
27122UNINITIALIZED_TEST(AllowAtomicsWait) {
27123 v8::Isolate::CreateParams create_params;
27124 create_params.allow_atomics_wait = false;
27125 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
27126 v8::Isolate* isolate = v8::Isolate::New(create_params);
27127 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27128 {
27129 CHECK_EQ(false, i_isolate->allow_atomics_wait());
27130 isolate->SetAllowAtomicsWait(true);
27131 CHECK_EQ(true, i_isolate->allow_atomics_wait());
27132 }
27133 isolate->Dispose();
27134}
27135
27136enum ContextId { EnteredContext, CurrentContext };
27137
27138void CheckContexts(v8::Isolate* isolate) {
27139 CHECK_EQ(CurrentContext, isolate->GetCurrentContext()
27140 ->GetEmbedderData(1)
27141 .As<v8::Integer>()
27142 ->Value());
27143 CHECK_EQ(EnteredContext, isolate->GetEnteredOrMicrotaskContext()
27144 ->GetEmbedderData(1)
27145 .As<v8::Integer>()
27146 ->Value());
27147}
27148
27149void ContextCheckGetter(Local<String> name,
27150 const v8::PropertyCallbackInfo<v8::Value>& info) {
27151 CheckContexts(info.GetIsolate());
27152 info.GetReturnValue().Set(true);
27153}
27154
27155void ContextCheckSetter(Local<String> name, Local<Value>,
27156 const v8::PropertyCallbackInfo<void>& info) {
27157 CheckContexts(info.GetIsolate());
27158}
27159
27160void ContextCheckToString(const v8::FunctionCallbackInfo<v8::Value>& info) {
27161 CheckContexts(info.GetIsolate());
27162 info.GetReturnValue().Set(v8_str("foo"));
27163}
27164
27165TEST(CorrectEnteredContext) {
27166 v8::HandleScope scope(CcTest::isolate());
27167
27168 LocalContext currentContext;
27169 currentContext->SetEmbedderData(
27170 1, v8::Integer::New(currentContext->GetIsolate(), CurrentContext));
27171 LocalContext enteredContext;
27172 enteredContext->SetEmbedderData(
27173 1, v8::Integer::New(enteredContext->GetIsolate(), EnteredContext));
27174
27175 v8::Context::Scope contextScope(enteredContext.local());
27176
27177 v8::Local<v8::ObjectTemplate> object_template =
27178 ObjectTemplate::New(currentContext->GetIsolate());
27179 object_template->SetAccessor(v8_str("p"), &ContextCheckGetter,
27180 &ContextCheckSetter);
27181
27182 v8::Local<v8::Object> object =
27183 object_template->NewInstance(currentContext.local()).ToLocalChecked();
27184
27185 object->Get(currentContext.local(), v8_str("p")).ToLocalChecked();
27186 object->Set(currentContext.local(), v8_str("p"), v8_int(0)).FromJust();
27187
27188 v8::Local<v8::Function> to_string =
27189 v8::Function::New(currentContext.local(), ContextCheckToString)
27190 .ToLocalChecked();
27191
27192 to_string->Call(currentContext.local(), object, 0, nullptr).ToLocalChecked();
27193
27194 object
27195 ->CreateDataProperty(currentContext.local(), v8_str("toString"),
27196 to_string)
27197 .FromJust();
27198
27199 object->ToString(currentContext.local()).ToLocalChecked();
27200}
27201
27202v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallbackResolve(
27203 Local<Context> context, Local<v8::ScriptOrModule> referrer,
27204 Local<String> specifier) {
27205 CHECK(!referrer.IsEmpty());
27206 String::Utf8Value referrer_utf8(
27207 context->GetIsolate(), Local<String>::Cast(referrer->GetResourceName()));
27208 CHECK_EQ(0, strcmp("www.google.com", *referrer_utf8));
27209 CHECK(referrer->GetHostDefinedOptions()
27210 ->Get(context->GetIsolate(), 0)
27211 ->IsSymbol());
27212
27213 CHECK(!specifier.IsEmpty());
27214 String::Utf8Value specifier_utf8(context->GetIsolate(), specifier);
27215 CHECK_EQ(0, strcmp("index.js", *specifier_utf8));
27216
27217 Local<v8::Promise::Resolver> resolver =
27218 v8::Promise::Resolver::New(context).ToLocalChecked();
27219 auto result = v8_str("hello world");
27220 resolver->Resolve(context, result).ToChecked();
27221 return resolver->GetPromise();
27222}
27223
27224TEST(DynamicImport) {
27225 i::FLAG_harmony_dynamic_import = true;
27226 LocalContext context;
27227 v8::Isolate* isolate = context->GetIsolate();
27228 v8::HandleScope scope(isolate);
27229
27230 isolate->SetHostImportModuleDynamicallyCallback(
27231 HostImportModuleDynamicallyCallbackResolve);
27232
27233 i::Handle<i::String> url(v8::Utils::OpenHandle(*v8_str("www.google.com")));
27234 i::Handle<i::Object> specifier(v8::Utils::OpenHandle(*v8_str("index.js")));
27235 i::Handle<i::String> result(v8::Utils::OpenHandle(*v8_str("hello world")));
27236 i::Handle<i::String> source(v8::Utils::OpenHandle(*v8_str("foo")));
27237 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27238 i::Handle<i::FixedArray> options = i_isolate->factory()->NewFixedArray(1);
27239 i::Handle<i::Symbol> symbol = i_isolate->factory()->NewSymbol();
27240 options->set(0, *symbol);
27241 i::Handle<i::Script> referrer = i_isolate->factory()->NewScript(source);
27242 referrer->set_name(*url);
27243 referrer->set_host_defined_options(*options);
27244 i::MaybeHandle<i::JSPromise> maybe_promise =
27245 i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
27246 i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
27247 isolate->RunMicrotasks();
27248 CHECK(result->Equals(i::String::cast(promise->result())));
27249}
27250
27251void HostInitializeImportMetaObjectCallbackStatic(Local<Context> context,
27252 Local<Module> module,
27253 Local<Object> meta) {
27254 CHECK(!module.IsEmpty());
27255
27256 meta->CreateDataProperty(context, v8_str("foo"), v8_str("bar")).ToChecked();
27257}
27258
27259TEST(ImportMeta) {
27260 i::FLAG_harmony_dynamic_import = true;
27261 i::FLAG_harmony_import_meta = true;
27262 LocalContext context;
27263 v8::Isolate* isolate = context->GetIsolate();
27264 v8::HandleScope scope(isolate);
27265
27266 isolate->SetHostInitializeImportMetaObjectCallback(
27267 HostInitializeImportMetaObjectCallbackStatic);
27268
27269 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27270 Local<String> url = v8_str("www.google.com");
27271 Local<String> source_text = v8_str("import.meta;");
27272 v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27273 Local<v8::Boolean>(), Local<v8::Integer>(),
27274 Local<v8::Value>(), Local<v8::Boolean>(),
27275 Local<v8::Boolean>(), True(isolate));
27276 v8::ScriptCompiler::Source source(source_text, origin);
27277 Local<Module> module =
27278 v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27279 i::Handle<i::Object> meta =
27280 i_isolate->RunHostInitializeImportMetaObjectCallback(
27281 v8::Utils::OpenHandle(*module));
27282 CHECK(meta->IsJSObject());
27283 Local<Object> meta_obj = Local<Object>::Cast(v8::Utils::ToLocal(meta));
27284 CHECK(meta_obj->Get(context.local(), v8_str("foo"))
27285 .ToLocalChecked()
27286 ->IsString());
27287 CHECK(meta_obj->Get(context.local(), v8_str("zapp"))
27288 .ToLocalChecked()
27289 ->IsUndefined());
27290
27291 module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27292 .ToChecked();
27293 Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
27294 CHECK(result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
27295}
27296
27297TEST(GetModuleNamespace) {
27298 LocalContext context;
27299 v8::Isolate* isolate = context->GetIsolate();
27300 v8::HandleScope scope(isolate);
27301
27302 Local<String> url = v8_str("www.google.com");
27303 Local<String> source_text = v8_str("export default 5; export const a = 10;");
27304 v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27305 Local<v8::Boolean>(), Local<v8::Integer>(),
27306 Local<v8::Value>(), Local<v8::Boolean>(),
27307 Local<v8::Boolean>(), True(isolate));
27308 v8::ScriptCompiler::Source source(source_text, origin);
27309 Local<Module> module =
27310 v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27311 module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27312 .ToChecked();
27313 module->Evaluate(context.local()).ToLocalChecked();
27314
27315 Local<Value> ns_val = module->GetModuleNamespace();
27316 CHECK(ns_val->IsModuleNamespaceObject());
27317 Local<Object> ns = ns_val.As<Object>();
27318 CHECK(ns->Get(context.local(), v8_str("default"))
27319 .ToLocalChecked()
27320 ->StrictEquals(v8::Number::New(isolate, 5)));
27321 CHECK(ns->Get(context.local(), v8_str("a"))
27322 .ToLocalChecked()
27323 ->StrictEquals(v8::Number::New(isolate, 10)));
27324}
27325
27326TEST(ModuleGetUnboundModuleScript) {
27327 LocalContext context;
27328 v8::Isolate* isolate = context->GetIsolate();
27329 v8::HandleScope scope(isolate);
27330
27331 Local<String> url = v8_str("www.google.com");
27332 Local<String> source_text = v8_str("export default 5; export const a = 10;");
27333 v8::ScriptOrigin origin(url, Local<v8::Integer>(), Local<v8::Integer>(),
27334 Local<v8::Boolean>(), Local<v8::Integer>(),
27335 Local<v8::Value>(), Local<v8::Boolean>(),
27336 Local<v8::Boolean>(), True(isolate));
27337 v8::ScriptCompiler::Source source(source_text, origin);
27338 Local<Module> module =
27339 v8::ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
27340 Local<v8::UnboundModuleScript> sfi_before_instantiation =
27341 module->GetUnboundModuleScript();
27342 module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
27343 .ToChecked();
27344 Local<v8::UnboundModuleScript> sfi_after_instantiation =
27345 module->GetUnboundModuleScript();
27346
27347 // Check object identity.
27348 {
27349 i::Handle<i::Object> s1 = v8::Utils::OpenHandle(*sfi_before_instantiation);
27350 i::Handle<i::Object> s2 = v8::Utils::OpenHandle(*sfi_after_instantiation);
27351 CHECK_EQ(*s1, *s2);
27352 }
27353}
27354
27355TEST(GlobalTemplateWithDoubleProperty) {
27356 v8::Isolate* isolate = CcTest::isolate();
27357 v8::HandleScope handle_scope(isolate);
27358
27359 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
27360 global->Set(v8_str("double"), v8_num(3.14));
27361
27362 v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);
27363
27364 v8::Context::Scope context_scope(context);
27365
27366 Local<Value> result = CompileRun("double");
27367 CHECK(result->IsNumber());
27368 CheckDoubleEquals(3.14, result->NumberValue(context).ToChecked());
27369}
27370
27371TEST(PrimitiveArray) {
27372 v8::Isolate* isolate = CcTest::isolate();
27373 v8::HandleScope scope(isolate);
27374 LocalContext env;
27375
27376 int length = 5;
27377 Local<v8::PrimitiveArray> array(v8::PrimitiveArray::New(isolate, 5));
27378 CHECK_EQ(length, array->Length());
27379
27380 for (int i = 0; i < length; i++) {
27381 Local<v8::Primitive> item = array->Get(isolate, i);
27382 CHECK(item->IsUndefined());
27383 }
27384
27385 Local<v8::Symbol> symbol(v8::Symbol::New(isolate));
27386 array->Set(isolate, 0, symbol);
27387 CHECK(array->Get(isolate, 0)->IsSymbol());
27388
27389 Local<v8::String> string =
27390 v8::String::NewFromUtf8(isolate, "test", v8::NewStringType::kInternalized)
27391 .ToLocalChecked();
27392 array->Set(isolate, 1, string);
27393 CHECK(array->Get(isolate, 0)->IsSymbol());
27394 CHECK(array->Get(isolate, 1)->IsString());
27395
27396 Local<v8::Number> num = v8::Number::New(env->GetIsolate(), 3.1415926);
27397 array->Set(isolate, 2, num);
27398 CHECK(array->Get(isolate, 0)->IsSymbol());
27399 CHECK(array->Get(isolate, 1)->IsString());
27400 CHECK(array->Get(isolate, 2)->IsNumber());
27401
27402 v8::Local<v8::Boolean> f = v8::False(isolate);
27403 array->Set(isolate, 3, f);
27404 CHECK(array->Get(isolate, 0)->IsSymbol());
27405 CHECK(array->Get(isolate, 1)->IsString());
27406 CHECK(array->Get(isolate, 2)->IsNumber());
27407 CHECK(array->Get(isolate, 3)->IsBoolean());
27408
27409 v8::Local<v8::Primitive> n = v8::Null(isolate);
27410 array->Set(isolate, 4, n);
27411 CHECK(array->Get(isolate, 0)->IsSymbol());
27412 CHECK(array->Get(isolate, 1)->IsString());
27413 CHECK(array->Get(isolate, 2)->IsNumber());
27414 CHECK(array->Get(isolate, 3)->IsBoolean());
27415 CHECK(array->Get(isolate, 4)->IsNull());
27416}
27417
27418TEST(PersistentValueMap) {
27419 v8::Isolate* isolate = CcTest::isolate();
27420 v8::HandleScope scope(isolate);
27421 LocalContext env;
27422
27423 v8::PersistentValueMap<
27424 std::string, v8::Value,
27425 v8::DefaultPersistentValueMapTraits<std::string, v8::Value>>
27426 map(isolate);
27427 v8::Local<v8::Value> value =
27428 v8::String::NewFromUtf8(isolate, "value",
27429 v8::NewStringType::kInternalized)
27430 .ToLocalChecked();
27431 map.Set("key", value);
27432}
27433
27434namespace {
27435
27436bool wasm_streaming_callback_got_called = false;
27437bool wasm_streaming_data_got_collected = false;
27438
27439void WasmStreamingTestFinalizer(const v8::WeakCallbackInfo<void>& data) {
27440 CHECK(!wasm_streaming_data_got_collected);
27441 wasm_streaming_data_got_collected = true;
27442 i::GlobalHandles::Destroy(reinterpret_cast<i::Address*>(data.GetParameter()));
27443}
27444
27445void WasmStreamingCallbackTestCallbackIsCalled(
27446 const v8::FunctionCallbackInfo<v8::Value>& args) {
27447 CHECK(!wasm_streaming_callback_got_called);
27448 wasm_streaming_callback_got_called = true;
27449
27450 i::Handle<i::Object> global_handle =
27451 reinterpret_cast<i::Isolate*>(args.GetIsolate())
27452 ->global_handles()
27453 ->Create(*v8::Utils::OpenHandle(*args.Data()));
27454 i::GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
27455 WasmStreamingTestFinalizer,
27456 v8::WeakCallbackType::kParameter);
27457}
27458
27459void WasmStreamingCallbackTestOnBytesReceived(
27460 const v8::FunctionCallbackInfo<v8::Value>& args) {
27461 std::shared_ptr<v8::WasmStreaming> streaming =
27462 v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27463
27464 // The first bytes of the WebAssembly magic word.
27465 const uint8_t bytes[]{0x00, 0x61, 0x73};
27466 streaming->OnBytesReceived(bytes, arraysize(bytes));
27467}
27468
27469void WasmStreamingCallbackTestFinishWithSuccess(
27470 const v8::FunctionCallbackInfo<v8::Value>& args) {
27471 std::shared_ptr<v8::WasmStreaming> streaming =
27472 v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27473 // The bytes of a minimal WebAssembly module.
27474 const uint8_t bytes[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00};
27475 streaming->OnBytesReceived(bytes, arraysize(bytes));
27476 streaming->Finish();
27477}
27478
27479void WasmStreamingCallbackTestFinishWithFailure(
27480 const v8::FunctionCallbackInfo<v8::Value>& args) {
27481 std::shared_ptr<v8::WasmStreaming> streaming =
27482 v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27483 streaming->Finish();
27484}
27485
27486void WasmStreamingCallbackTestAbortWithReject(
27487 const v8::FunctionCallbackInfo<v8::Value>& args) {
27488 std::shared_ptr<v8::WasmStreaming> streaming =
27489 v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27490 streaming->Abort(v8::Object::New(args.GetIsolate()));
27491}
27492
27493void WasmStreamingCallbackTestAbortNoReject(
27494 const v8::FunctionCallbackInfo<v8::Value>& args) {
27495 std::shared_ptr<v8::WasmStreaming> streaming =
27496 v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data());
27497 streaming->Abort({});
27498}
27499
27500void TestWasmStreaming(v8::WasmStreamingCallback callback,
27501 v8::Promise::PromiseState expected_state) {
27502 CcTest::isolate()->SetWasmStreamingCallback(callback);
27503 LocalContext env;
27504 v8::Isolate* isolate = env->GetIsolate();
27505 v8::HandleScope scope(isolate);
27506
27507 // Call {WebAssembly.compileStreaming} with {null} as parameter. The parameter
27508 // is only really processed by the embedder, so for this test the value is
27509 // irrelevant.
27510 v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast(
27511 CompileRun("WebAssembly.compileStreaming(null)"));
27512
27513 EmptyMessageQueues(isolate);
27514 CHECK_EQ(expected_state, promise->State());
27515}
27516
27517} // namespace
27518
27519TEST(WasmStreamingCallback) {
27520 TestWasmStreaming(WasmStreamingCallbackTestCallbackIsCalled,
27521 v8::Promise::kPending);
27522 CHECK(wasm_streaming_callback_got_called);
27523 CcTest::CollectAllAvailableGarbage();
27524 CHECK(wasm_streaming_data_got_collected);
27525}
27526
27527TEST(WasmStreamingOnBytesReceived) {
27528 TestWasmStreaming(WasmStreamingCallbackTestOnBytesReceived,
27529 v8::Promise::kPending);
27530}
27531
27532TEST(WasmStreamingFinishWithSuccess) {
27533 TestWasmStreaming(WasmStreamingCallbackTestFinishWithSuccess,
27534 v8::Promise::kFulfilled);
27535}
27536
27537TEST(WasmStreamingFinishWithFailure) {
27538 TestWasmStreaming(WasmStreamingCallbackTestFinishWithFailure,
27539 v8::Promise::kRejected);
27540}
27541
27542TEST(WasmStreamingAbortWithReject) {
27543 TestWasmStreaming(WasmStreamingCallbackTestAbortWithReject,
27544 v8::Promise::kRejected);
27545}
27546
27547TEST(WasmStreamingAbortWithoutReject) {
27548 TestWasmStreaming(WasmStreamingCallbackTestAbortNoReject,
27549 v8::Promise::kPending);
27550}
27551
27552enum class AtomicsWaitCallbackAction {
27553 Interrupt,
27554 StopAndThrowInFirstCall,
27555 StopAndThrowInSecondCall,
27556 StopFromThreadAndThrow,
27557 KeepWaiting
27558};
27559
27560class StopAtomicsWaitThread;
27561
27562struct AtomicsWaitCallbackInfo {
27563 v8::Isolate* isolate;
27564 v8::Isolate::AtomicsWaitWakeHandle* wake_handle;
27565 std::unique_ptr<StopAtomicsWaitThread> stop_thread;
27566 AtomicsWaitCallbackAction action;
27567
27568 Local<v8::SharedArrayBuffer> expected_sab;
27569 v8::Isolate::AtomicsWaitEvent expected_event;
27570 double expected_timeout;
27571 int64_t expected_value;
27572 size_t expected_offset;
27573
27574 size_t ncalls = 0;
27575};
27576
27577class StopAtomicsWaitThread : public v8::base::Thread {
27578 public:
27579 explicit StopAtomicsWaitThread(AtomicsWaitCallbackInfo* info)
27580 : Thread(Options("StopAtomicsWaitThread")), info_(info) {}
27581
27582 void Run() override {
27583 CHECK_NOT_NULL(info_->wake_handle);
27584 info_->wake_handle->Wake();
27585 }
27586
27587 private:
27588 AtomicsWaitCallbackInfo* info_;
27589};
27590
27591void AtomicsWaitCallbackForTesting(
27592 v8::Isolate::AtomicsWaitEvent event, Local<v8::SharedArrayBuffer> sab,
27593 size_t offset_in_bytes, int64_t value, double timeout_in_ms,
27594 v8::Isolate::AtomicsWaitWakeHandle* wake_handle, void* data) {
27595 AtomicsWaitCallbackInfo* info = static_cast<AtomicsWaitCallbackInfo*>(data);
27596 info->ncalls++;
27597 info->wake_handle = wake_handle;
27598 CHECK(sab->StrictEquals(info->expected_sab));
27599 CHECK_EQ(timeout_in_ms, info->expected_timeout);
27600 CHECK_EQ(value, info->expected_value);
27601 CHECK_EQ(offset_in_bytes, info->expected_offset);
27602
27603 auto ThrowSomething = [&]() {
27604 info->isolate->ThrowException(v8::Integer::New(info->isolate, 42));
27605 };
27606
27607 if (event == v8::Isolate::AtomicsWaitEvent::kStartWait) {
27608 CHECK_NOT_NULL(wake_handle);
27609 switch (info->action) {
27610 case AtomicsWaitCallbackAction::Interrupt:
27611 info->isolate->TerminateExecution();
27612 break;
27613 case AtomicsWaitCallbackAction::StopAndThrowInFirstCall:
27614 ThrowSomething();
27615 V8_FALLTHROUGH;
27616 case AtomicsWaitCallbackAction::StopAndThrowInSecondCall:
27617 wake_handle->Wake();
27618 break;
27619 case AtomicsWaitCallbackAction::StopFromThreadAndThrow:
27620 info->stop_thread = v8::base::make_unique<StopAtomicsWaitThread>(info);
27621 info->stop_thread->Start();
27622 break;
27623 case AtomicsWaitCallbackAction::KeepWaiting:
27624 break;
27625 }
27626 } else {
27627 CHECK_EQ(event, info->expected_event);
27628 CHECK_NULL(wake_handle);
27629
27630 if (info->stop_thread) {
27631 info->stop_thread->Join();
27632 info->stop_thread.reset();
27633 }
27634
27635 if (info->action == AtomicsWaitCallbackAction::StopAndThrowInSecondCall ||
27636 info->action == AtomicsWaitCallbackAction::StopFromThreadAndThrow) {
27637 ThrowSomething();
27638 }
27639 }
27640}
27641
27642// Must be called from within HandleScope
27643void AtomicsWaitCallbackCommon(v8::Isolate* isolate, Local<Value> sab,
27644 size_t initial_offset,
27645 size_t offset_multiplier) {
27646 CHECK(sab->IsSharedArrayBuffer());
27647
27648 AtomicsWaitCallbackInfo info;
27649 info.isolate = isolate;
27650 info.expected_sab = sab.As<v8::SharedArrayBuffer>();
27651 isolate->SetAtomicsWaitCallback(AtomicsWaitCallbackForTesting, &info);
27652
27653 {
27654 v8::TryCatch try_catch(isolate);
27655 info.expected_offset = initial_offset;
27656 info.expected_timeout = std::numeric_limits<double>::infinity();
27657 info.expected_value = 0;
27658 info.expected_event = v8::Isolate::AtomicsWaitEvent::kTerminatedExecution;
27659 info.action = AtomicsWaitCallbackAction::Interrupt;
27660 info.ncalls = 0;
27661 CompileRun("wait(0, 0);");
27662 CHECK_EQ(info.ncalls, 2);
27663 CHECK(try_catch.HasTerminated());
27664 }
27665
27666 {
27667 v8::TryCatch try_catch(isolate);
27668 info.expected_offset = initial_offset + offset_multiplier;
27669 info.expected_timeout = std::numeric_limits<double>::infinity();
27670 info.expected_value = 1;
27671 info.expected_event = v8::Isolate::AtomicsWaitEvent::kNotEqual;
27672 info.action = AtomicsWaitCallbackAction::KeepWaiting;
27673 info.ncalls = 0;
27674 CompileRun("wait(1, 1);"); // real value is 0 != 1
27675 CHECK_EQ(info.ncalls, 2);
27676 CHECK(!try_catch.HasCaught());
27677 }
27678
27679 {
27680 v8::TryCatch try_catch(isolate);
27681 info.expected_offset = initial_offset + offset_multiplier;
27682 info.expected_timeout = 0.125;
27683 info.expected_value = 0;
27684 info.expected_event = v8::Isolate::AtomicsWaitEvent::kTimedOut;
27685 info.action = AtomicsWaitCallbackAction::KeepWaiting;
27686 info.ncalls = 0;
27687 CompileRun("wait(1, 0, 0.125);"); // timeout
27688 CHECK_EQ(info.ncalls, 2);
27689 CHECK(!try_catch.HasCaught());
27690 }
27691
27692 {
27693 v8::TryCatch try_catch(isolate);
27694 info.expected_offset = initial_offset + offset_multiplier;
27695 info.expected_timeout = std::numeric_limits<double>::infinity();
27696 info.expected_value = 0;
27697 info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27698 info.action = AtomicsWaitCallbackAction::StopAndThrowInFirstCall;
27699 info.ncalls = 0;
27700 CompileRun("wait(1, 0);");
27701 CHECK_EQ(info.ncalls, 1); // Only one extra call
27702 CHECK(try_catch.HasCaught());
27703 CHECK(try_catch.Exception()->IsInt32());
27704 CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27705 }
27706
27707 {
27708 v8::TryCatch try_catch(isolate);
27709 info.expected_offset = initial_offset + offset_multiplier;
27710 info.expected_timeout = std::numeric_limits<double>::infinity();
27711 info.expected_value = 0;
27712 info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27713 info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27714 info.ncalls = 0;
27715 CompileRun("wait(1, 0);");
27716 CHECK_EQ(info.ncalls, 2);
27717 CHECK(try_catch.HasCaught());
27718 CHECK(try_catch.Exception()->IsInt32());
27719 CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27720 }
27721
27722 {
27723 // Same test as before, but with a different `expected_value`.
27724 v8::TryCatch try_catch(isolate);
27725 info.expected_offset = initial_offset + offset_multiplier;
27726 info.expected_timeout = std::numeric_limits<double>::infinity();
27727 info.expected_value = 200;
27728 info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27729 info.action = AtomicsWaitCallbackAction::StopAndThrowInSecondCall;
27730 info.ncalls = 0;
27731 CompileRun(
27732 "setArrayElemAs(1, 200);"
27733 "wait(1, 200);");
27734 CHECK_EQ(info.ncalls, 2);
27735 CHECK(try_catch.HasCaught());
27736 CHECK(try_catch.Exception()->IsInt32());
27737 CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27738 }
27739
27740 {
27741 // Wake the `Atomics.wait()` call from a thread.
27742 v8::TryCatch try_catch(isolate);
27743 info.expected_offset = initial_offset;
27744 info.expected_timeout = std::numeric_limits<double>::infinity();
27745 info.expected_value = 0;
27746 info.expected_event = v8::Isolate::AtomicsWaitEvent::kAPIStopped;
27747 info.action = AtomicsWaitCallbackAction::StopFromThreadAndThrow;
27748 info.ncalls = 0;
27749 CompileRun(
27750 "setArrayElemAs(1, 0);"
27751 "wait(0, 0);");
27752 CHECK_EQ(info.ncalls, 2);
27753 CHECK(try_catch.HasCaught());
27754 CHECK(try_catch.Exception()->IsInt32());
27755 CHECK_EQ(try_catch.Exception().As<v8::Int32>()->Value(), 42);
27756 }
27757}
27758
27759TEST(AtomicsWaitCallback) {
27760 LocalContext env;
27761 v8::Isolate* isolate = env->GetIsolate();
27762 v8::HandleScope scope(isolate);
27763 const char* init = R"(
27764 let sab = new SharedArrayBuffer(16);
27765 let int32arr = new Int32Array(sab, 4);
27766 let setArrayElemAs = function(id, val) {
27767 int32arr[id] = val;
27768 };
27769 let wait = function(id, val, timeout) {
27770 if(arguments.length == 2) return Atomics.wait(int32arr, id, val);
27771 return Atomics.wait(int32arr, id, val, timeout);
27772 };
27773 sab;)";
27774 AtomicsWaitCallbackCommon(isolate, CompileRun(init), 4, 4);
27775}
27776
27777namespace v8 {
27778namespace internal {
27779namespace wasm {
27780TEST(WasmI32AtomicWaitCallback) {
27781 FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
27782 WasmRunner<int32_t, int32_t, int32_t, double> r(ExecutionTier::kTurbofan);
27783 r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
27784 r.builder().SetHasSharedMemory();
27785 BUILD(r, WASM_ATOMICS_WAIT(kExprI32AtomicWait, WASM_GET_LOCAL(0),
27786 WASM_GET_LOCAL(1),
27787 WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 4));
27788 LocalContext env;
27789 v8::Isolate* isolate = env->GetIsolate();
27790 v8::HandleScope scope(isolate);
27791 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27792 Handle<JSFunction> func = r.builder().WrapCode(0);
27793 CHECK(env->Global()
27794 ->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
27795 .FromJust());
27796 Handle<JSArrayBuffer> memory(
27797 r.builder().instance_object()->memory_object()->array_buffer(),
27798 i_isolate);
27799 CHECK(env->Global()
27800 ->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
27801 .FromJust());
27802
27803 const char* init = R"(
27804 let int32arr = new Int32Array(sab, 4);
27805 let setArrayElemAs = function(id, val) {
27806 int32arr[id] = val;
27807 };
27808 let wait = function(id, val, timeout) {
27809 if(arguments.length === 2)
27810 return func(id << 2, val, -1);
27811 return func(id << 2, val, timeout*1000000);
27812 };
27813 sab;)";
27814 AtomicsWaitCallbackCommon(isolate, CompileRun(init), 4, 4);
27815}
27816
27817TEST(WasmI64AtomicWaitCallback) {
27818 FlagScope<bool> wasm_threads_flag(&i::FLAG_experimental_wasm_threads, true);
27819 WasmRunner<int32_t, int32_t, double, double> r(ExecutionTier::kTurbofan);
27820 r.builder().AddMemory(kWasmPageSize, SharedFlag::kShared);
27821 r.builder().SetHasSharedMemory();
27822 BUILD(r, WASM_ATOMICS_WAIT(kExprI64AtomicWait, WASM_GET_LOCAL(0),
27823 WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(1)),
27824 WASM_I64_SCONVERT_F64(WASM_GET_LOCAL(2)), 8));
27825 LocalContext env;
27826 v8::Isolate* isolate = env->GetIsolate();
27827 v8::HandleScope scope(isolate);
27828 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
27829 Handle<JSFunction> func = r.builder().WrapCode(0);
27830 CHECK(env->Global()
27831 ->Set(env.local(), v8_str("func"), v8::Utils::ToLocal(func))
27832 .FromJust());
27833 Handle<JSArrayBuffer> memory(
27834 r.builder().instance_object()->memory_object()->array_buffer(),
27835 i_isolate);
27836 CHECK(env->Global()
27837 ->Set(env.local(), v8_str("sab"), v8::Utils::ToLocal(memory))
27838 .FromJust());
27839
27840 const char* init = R"(
27841 let int64arr = new BigInt64Array(sab, 8);
27842 let setArrayElemAs = function(id, val) {
27843 int64arr[id] = BigInt(val);
27844 };
27845 let wait = function(id, val, timeout) {
27846 if(arguments.length === 2)
27847 return func(id << 3, val, -1);
27848 return func(id << 3, val, timeout*1000000);
27849 };
27850 sab;)";
27851 AtomicsWaitCallbackCommon(isolate, CompileRun(init), 8, 8);
27852}
27853
27854} // namespace wasm
27855} // namespace internal
27856} // namespace v8
27857
27858// TODO(mstarzinger): Move this into a test-api-wasm.cc file when this large
27859// test file is being split up into chunks.
27860TEST(WasmModuleObjectCompileFailure) {
27861 LocalContext env;
27862 v8::Isolate* isolate = env->GetIsolate();
27863 v8::HandleScope scope(isolate);
27864
27865 {
27866 v8::TryCatch try_catch(isolate);
27867 uint8_t buffer[] = {0xDE, 0xAD, 0xBE, 0xEF};
27868 v8::MemorySpan<const uint8_t> serialized_module;
27869 v8::MemorySpan<const uint8_t> wire_bytes = {buffer, arraysize(buffer)};
27870 v8::MaybeLocal<v8::WasmModuleObject> maybe_module =
27871 v8::WasmModuleObject::DeserializeOrCompile(isolate, serialized_module,
27872 wire_bytes);
27873 CHECK(maybe_module.IsEmpty());
27874 CHECK(try_catch.HasCaught());
27875 }
27876}
27877
27878TEST(BigIntAPI) {
27879 LocalContext env;
27880 v8::Isolate* isolate = env->GetIsolate();
27881 v8::HandleScope scope(isolate);
27882 bool lossless;
27883 uint64_t words1[10];
27884 uint64_t words2[10];
27885
27886 {
27887 Local<Value> bi = CompileRun("12n");
27888 CHECK(bi->IsBigInt());
27889
27890 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 12);
27891 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless), 12);
27892 CHECK_EQ(lossless, true);
27893 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 12);
27894 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 12);
27895 CHECK_EQ(lossless, true);
27896 }
27897
27898 {
27899 Local<Value> bi = CompileRun("-12n");
27900 CHECK(bi->IsBigInt());
27901
27902 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), static_cast<uint64_t>(-12));
27903 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27904 static_cast<uint64_t>(-12));
27905 CHECK_EQ(lossless, false);
27906 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -12);
27907 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), -12);
27908 CHECK_EQ(lossless, true);
27909 }
27910
27911 {
27912 Local<Value> bi = CompileRun("123456789012345678901234567890n");
27913 CHECK(bi->IsBigInt());
27914
27915 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 14083847773837265618ULL);
27916 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27917 14083847773837265618ULL);
27918 CHECK_EQ(lossless, false);
27919 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), -4362896299872285998LL);
27920 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless),
27921 -4362896299872285998LL);
27922 CHECK_EQ(lossless, false);
27923 }
27924
27925 {
27926 Local<Value> bi = CompileRun("-123456789012345678901234567890n");
27927 CHECK(bi->IsBigInt());
27928
27929 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(), 4362896299872285998LL);
27930 CHECK_EQ(bi.As<v8::BigInt>()->Uint64Value(&lossless),
27931 4362896299872285998LL);
27932 CHECK_EQ(lossless, false);
27933 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(), 4362896299872285998LL);
27934 CHECK_EQ(bi.As<v8::BigInt>()->Int64Value(&lossless), 4362896299872285998LL);
27935 CHECK_EQ(lossless, false);
27936 }
27937
27938 {
27939 Local<v8::BigInt> bi =
27940 v8::BigInt::NewFromWords(env.local(), 0, 0, words1).ToLocalChecked();
27941 CHECK_EQ(bi->Uint64Value(), 0);
27942 CHECK_EQ(bi->WordCount(), 0);
27943 }
27944
27945 {
27946 TryCatch try_catch(isolate);
27947 v8::MaybeLocal<v8::BigInt> bi = v8::BigInt::NewFromWords(
27948 env.local(), 0, std::numeric_limits<int>::max(), words1);
27949 CHECK(bi.IsEmpty());
27950 CHECK(try_catch.HasCaught());
27951 }
27952
27953 {
27954 TryCatch try_catch(isolate);
27955 v8::MaybeLocal<v8::BigInt> bi =
27956 v8::BigInt::NewFromWords(env.local(), 0, -1, words1);
27957 CHECK(bi.IsEmpty());
27958 CHECK(try_catch.HasCaught());
27959 }
27960
27961 {
27962 TryCatch try_catch(isolate);
27963 v8::MaybeLocal<v8::BigInt> bi =
27964 v8::BigInt::NewFromWords(env.local(), 0, 1 << 30, words1);
27965 CHECK(bi.IsEmpty());
27966 CHECK(try_catch.HasCaught());
27967 }
27968
27969 for (int sign_bit = 0; sign_bit <= 1; sign_bit++) {
27970 words1[0] = 0xffffffff00000000ULL;
27971 words1[1] = 0x00000000ffffffffULL;
27972 v8::Local<v8::BigInt> bi =
27973 v8::BigInt::NewFromWords(env.local(), sign_bit, 2, words1)
27974 .ToLocalChecked();
27975 CHECK_EQ(bi->Uint64Value(&lossless),
27976 sign_bit ? static_cast<uint64_t>(-static_cast<int64_t>(words1[0]))
27977 : words1[0]);
27978 CHECK_EQ(lossless, false);
27979 CHECK_EQ(bi->Int64Value(&lossless), sign_bit
27980 ? -static_cast<int64_t>(words1[0])
27981 : static_cast<int64_t>(words1[0]));
27982 CHECK_EQ(lossless, false);
27983 CHECK_EQ(bi->WordCount(), 2);
27984 int real_sign_bit;
27985 int word_count = arraysize(words2);
27986 bi->ToWordsArray(&real_sign_bit, &word_count, words2);
27987 CHECK_EQ(real_sign_bit, sign_bit);
27988 CHECK_EQ(word_count, 2);
27989 }
27990}
27991
27992namespace {
27993
27994bool wasm_threads_enabled_value = false;
27995
27996bool MockWasmThreadsEnabledCallback(Local<Context>) {
27997 return wasm_threads_enabled_value;
27998}
27999
28000} // namespace
28001
28002TEST(TestSetWasmThreadsEnabledCallback) {
28003 LocalContext env;
28004 v8::Isolate* isolate = env->GetIsolate();
28005 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28006 v8::HandleScope scope(isolate);
28007 v8::Local<Context> context = Context::New(CcTest::isolate());
28008 i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context);
28009
28010 // {Isolate::AreWasmThreadsEnabled} calls the callback set by the embedder if
28011 // such a callback exists. Otherwise it returns
28012 // {FLAG_experimental_wasm_threads}. First we test that the flag is returned
28013 // correctly if no callback is set. Then we test that the flag is ignored if
28014 // the callback is set.
28015
28016 i::FLAG_experimental_wasm_threads = false;
28017 CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28018
28019 i::FLAG_experimental_wasm_threads = true;
28020 CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28021
28022 isolate->SetWasmThreadsEnabledCallback(MockWasmThreadsEnabledCallback);
28023 wasm_threads_enabled_value = false;
28024 CHECK(!i_isolate->AreWasmThreadsEnabled(i_context));
28025
28026 wasm_threads_enabled_value = true;
28027 i::FLAG_experimental_wasm_threads = false;
28028 CHECK(i_isolate->AreWasmThreadsEnabled(i_context));
28029}
28030
28031TEST(TestGetUnwindState) {
28032 LocalContext env;
28033 v8::Isolate* isolate = env->GetIsolate();
28034 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
28035
28036 v8::UnwindState unwind_state = isolate->GetUnwindState();
28037 v8::MemoryRange builtins_range = unwind_state.embedded_code_range;
28038
28039 // Check that each off-heap builtin is within the builtins code range.
28040 if (i::FLAG_embedded_builtins) {
28041 for (int id = 0; id < i::Builtins::builtin_count; id++) {
28042 if (!i::Builtins::IsIsolateIndependent(id)) continue;
28043 i::Code builtin = i_isolate->builtins()->builtin(id);
28044 i::Address start = builtin->InstructionStart();
28045 i::Address end = start + builtin->InstructionSize();
28046
28047 i::Address builtins_start =
28048 reinterpret_cast<i::Address>(builtins_range.start);
28049 CHECK(start >= builtins_start &&
28050 end < builtins_start + builtins_range.length_in_bytes);
28051 }
28052 } else {
28053 CHECK_EQ(nullptr, builtins_range.start);
28054 CHECK_EQ(0, builtins_range.length_in_bytes);
28055 }
28056
28057 v8::JSEntryStub js_entry_stub = unwind_state.js_entry_stub;
28058
28059 CHECK_EQ(
28060 i_isolate->heap()->builtin(i::Builtins::kJSEntry)->InstructionStart(),
28061 reinterpret_cast<i::Address>(js_entry_stub.code.start));
28062}
28063
28064TEST(MicrotaskContextShouldBeNativeContext) {
28065 LocalContext env;
28066 v8::Isolate* isolate = env->GetIsolate();
28067 v8::HandleScope scope(isolate);
28068
28069 auto callback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
28070 v8::Isolate* isolate = info.GetIsolate();
28071 v8::HandleScope scope(isolate);
28072 i::Handle<i::Context> context =
28073 v8::Utils::OpenHandle(*isolate->GetEnteredOrMicrotaskContext());
28074
28075 CHECK(context->IsNativeContext());
28076 info.GetReturnValue().SetUndefined();
28077 };
28078
28079 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
28080 desc->InstanceTemplate()->SetCallAsFunctionHandler(callback);
28081 Local<v8::Object> obj = desc->GetFunction(env.local())
28082 .ToLocalChecked()
28083 ->NewInstance(env.local())
28084 .ToLocalChecked();
28085
28086 CHECK(env->Global()->Set(env.local(), v8_str("callback"), obj).FromJust());
28087 CompileRun(
28088 "with({}){(async ()=>{"
28089 " await 42;"
28090 "})().then(callback);}");
28091
28092 isolate->RunMicrotasks();
28093}
28094
28095TEST(PreviewSetKeysIteratorEntriesWithDeleted) {
28096 LocalContext env;
28097 v8::HandleScope handle_scope(env->GetIsolate());
28098 v8::Local<v8::Context> context = env.local();
28099
28100 {
28101 // Create set, delete entry, create iterator, preview.
28102 v8::Local<v8::Object> iterator =
28103 CompileRun("var set = new Set([1,2,3]); set.delete(1); set.keys()")
28104 ->ToObject(context)
28105 .ToLocalChecked();
28106 bool is_key;
28107 v8::Local<v8::Array> entries =
28108 iterator->PreviewEntries(&is_key).ToLocalChecked();
28109 CHECK(!is_key);
28110 CHECK_EQ(2, entries->Length());
28111 CHECK_EQ(2, entries->Get(context, 0)
28112 .ToLocalChecked()
28113 ->Int32Value(context)
28114 .FromJust());
28115 CHECK_EQ(3, entries->Get(context, 1)
28116 .ToLocalChecked()
28117 ->Int32Value(context)
28118 .FromJust());
28119 }
28120 {
28121 // Create set, create iterator, delete entry, preview.
28122 v8::Local<v8::Object> iterator =
28123 CompileRun("var set = new Set([1,2,3]); set.keys()")
28124 ->ToObject(context)
28125 .ToLocalChecked();
28126 CompileRun("set.delete(1);");
28127 bool is_key;
28128 v8::Local<v8::Array> entries =
28129 iterator->PreviewEntries(&is_key).ToLocalChecked();
28130 CHECK(!is_key);
28131 CHECK_EQ(2, entries->Length());
28132 CHECK_EQ(2, entries->Get(context, 0)
28133 .ToLocalChecked()
28134 ->Int32Value(context)
28135 .FromJust());
28136 CHECK_EQ(3, entries->Get(context, 1)
28137 .ToLocalChecked()
28138 ->Int32Value(context)
28139 .FromJust());
28140 }
28141 {
28142 // Create set, create iterator, delete entry, iterate, preview.
28143 v8::Local<v8::Object> iterator =
28144 CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28145 ->ToObject(context)
28146 .ToLocalChecked();
28147 CompileRun("set.delete(1); it.next();");
28148 bool is_key;
28149 v8::Local<v8::Array> entries =
28150 iterator->PreviewEntries(&is_key).ToLocalChecked();
28151 CHECK(!is_key);
28152 CHECK_EQ(1, entries->Length());
28153 CHECK_EQ(3, entries->Get(context, 0)
28154 .ToLocalChecked()
28155 ->Int32Value(context)
28156 .FromJust());
28157 }
28158 {
28159 // Create set, create iterator, delete entry, iterate until empty, preview.
28160 v8::Local<v8::Object> iterator =
28161 CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28162 ->ToObject(context)
28163 .ToLocalChecked();
28164 CompileRun("set.delete(1); it.next(); it.next();");
28165 bool is_key;
28166 v8::Local<v8::Array> entries =
28167 iterator->PreviewEntries(&is_key).ToLocalChecked();
28168 CHECK(!is_key);
28169 CHECK_EQ(0, entries->Length());
28170 }
28171 {
28172 // Create set, create iterator, delete entry, iterate, trigger rehash,
28173 // preview.
28174 v8::Local<v8::Object> iterator =
28175 CompileRun("var set = new Set([1,2,3]); var it = set.keys(); it")
28176 ->ToObject(context)
28177 .ToLocalChecked();
28178 CompileRun("set.delete(1); it.next();");
28179 CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28180 bool is_key;
28181 v8::Local<v8::Array> entries =
28182 iterator->PreviewEntries(&is_key).ToLocalChecked();
28183 CHECK(!is_key);
28184 CHECK_EQ(17, entries->Length());
28185 for (uint32_t i = 0; i < 17; i++) {
28186 CHECK_EQ(i + 3, entries->Get(context, i)
28187 .ToLocalChecked()
28188 ->Int32Value(context)
28189 .FromJust());
28190 }
28191 }
28192}
28193
28194TEST(PreviewSetValuesIteratorEntriesWithDeleted) {
28195 LocalContext env;
28196 v8::HandleScope handle_scope(env->GetIsolate());
28197 v8::Local<v8::Context> context = env.local();
28198
28199 {
28200 // Create set, delete entry, create iterator, preview.
28201 v8::Local<v8::Object> iterator =
28202 CompileRun("var set = new Set([1,2,3]); set.delete(1); set.values()")
28203 ->ToObject(context)
28204 .ToLocalChecked();
28205 bool is_key;
28206 v8::Local<v8::Array> entries =
28207 iterator->PreviewEntries(&is_key).ToLocalChecked();
28208 CHECK(!is_key);
28209 CHECK_EQ(2, entries->Length());
28210 CHECK_EQ(2, entries->Get(context, 0)
28211 .ToLocalChecked()
28212 ->Int32Value(context)
28213 .FromJust());
28214 CHECK_EQ(3, entries->Get(context, 1)
28215 .ToLocalChecked()
28216 ->Int32Value(context)
28217 .FromJust());
28218 }
28219 {
28220 // Create set, create iterator, delete entry, preview.
28221 v8::Local<v8::Object> iterator =
28222 CompileRun("var set = new Set([1,2,3]); set.values()")
28223 ->ToObject(context)
28224 .ToLocalChecked();
28225 CompileRun("set.delete(1);");
28226 bool is_key;
28227 v8::Local<v8::Array> entries =
28228 iterator->PreviewEntries(&is_key).ToLocalChecked();
28229 CHECK(!is_key);
28230 CHECK_EQ(2, entries->Length());
28231 CHECK_EQ(2, entries->Get(context, 0)
28232 .ToLocalChecked()
28233 ->Int32Value(context)
28234 .FromJust());
28235 CHECK_EQ(3, entries->Get(context, 1)
28236 .ToLocalChecked()
28237 ->Int32Value(context)
28238 .FromJust());
28239 }
28240 {
28241 // Create set, create iterator, delete entry, iterate, preview.
28242 v8::Local<v8::Object> iterator =
28243 CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28244 ->ToObject(context)
28245 .ToLocalChecked();
28246 CompileRun("set.delete(1); it.next();");
28247 bool is_key;
28248 v8::Local<v8::Array> entries =
28249 iterator->PreviewEntries(&is_key).ToLocalChecked();
28250 CHECK(!is_key);
28251 CHECK_EQ(1, entries->Length());
28252 CHECK_EQ(3, entries->Get(context, 0)
28253 .ToLocalChecked()
28254 ->Int32Value(context)
28255 .FromJust());
28256 }
28257 {
28258 // Create set, create iterator, delete entry, iterate until empty, preview.
28259 v8::Local<v8::Object> iterator =
28260 CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28261 ->ToObject(context)
28262 .ToLocalChecked();
28263 CompileRun("set.delete(1); it.next(); it.next();");
28264 bool is_key;
28265 v8::Local<v8::Array> entries =
28266 iterator->PreviewEntries(&is_key).ToLocalChecked();
28267 CHECK(!is_key);
28268 CHECK_EQ(0, entries->Length());
28269 }
28270 {
28271 // Create set, create iterator, delete entry, iterate, trigger rehash,
28272 // preview.
28273 v8::Local<v8::Object> iterator =
28274 CompileRun("var set = new Set([1,2,3]); var it = set.values(); it")
28275 ->ToObject(context)
28276 .ToLocalChecked();
28277 CompileRun("set.delete(1); it.next();");
28278 CompileRun("for (var i = 4; i < 20; i++) set.add(i);");
28279 bool is_key;
28280 v8::Local<v8::Array> entries =
28281 iterator->PreviewEntries(&is_key).ToLocalChecked();
28282 CHECK(!is_key);
28283 CHECK_EQ(17, entries->Length());
28284 for (uint32_t i = 0; i < 17; i++) {
28285 CHECK_EQ(i + 3, entries->Get(context, i)
28286 .ToLocalChecked()
28287 ->Int32Value(context)
28288 .FromJust());
28289 }
28290 }
28291}
28292
28293TEST(PreviewMapEntriesIteratorEntries) {
28294 LocalContext env;
28295 v8::HandleScope handle_scope(env->GetIsolate());
28296 v8::Local<v8::Context> context = env.local();
28297 {
28298 // Create set, delete entry, create entries iterator, preview.
28299 v8::Local<v8::Object> iterator =
28300 CompileRun("var set = new Set([1,2,3]); set.delete(2); set.entries()")
28301 ->ToObject(context)
28302 .ToLocalChecked();
28303 bool is_key;
28304 v8::Local<v8::Array> entries =
28305 iterator->PreviewEntries(&is_key).ToLocalChecked();
28306 CHECK(is_key);
28307 CHECK_EQ(4, entries->Length());
28308 uint32_t first = entries->Get(context, 0)
28309 .ToLocalChecked()
28310 ->Int32Value(context)
28311 .FromJust();
28312 uint32_t second = entries->Get(context, 2)
28313 .ToLocalChecked()
28314 ->Int32Value(context)
28315 .FromJust();
28316 CHECK_EQ(1, first);
28317 CHECK_EQ(3, second);
28318 CHECK_EQ(first, entries->Get(context, 1)
28319 .ToLocalChecked()
28320 ->Int32Value(context)
28321 .FromJust());
28322 CHECK_EQ(second, entries->Get(context, 3)
28323 .ToLocalChecked()
28324 ->Int32Value(context)
28325 .FromJust());
28326 }
28327}
28328
28329TEST(PreviewMapValuesIteratorEntriesWithDeleted) {
28330 LocalContext env;
28331 v8::HandleScope handle_scope(env->GetIsolate());
28332 v8::Local<v8::Context> context = env.local();
28333
28334 {
28335 // Create map, delete entry, create iterator, preview.
28336 v8::Local<v8::Object> iterator = CompileRun(
28337 "var map = new Map();"
28338 "var key = {}; map.set(key, 1);"
28339 "map.set({}, 2); map.set({}, 3);"
28340 "map.delete(key);"
28341 "map.values()")
28342 ->ToObject(context)
28343 .ToLocalChecked();
28344 bool is_key;
28345 v8::Local<v8::Array> entries =
28346 iterator->PreviewEntries(&is_key).ToLocalChecked();
28347 CHECK(!is_key);
28348 CHECK_EQ(2, entries->Length());
28349 CHECK_EQ(2, entries->Get(context, 0)
28350 .ToLocalChecked()
28351 ->Int32Value(context)
28352 .FromJust());
28353 CHECK_EQ(3, entries->Get(context, 1)
28354 .ToLocalChecked()
28355 ->Int32Value(context)
28356 .FromJust());
28357 }
28358 {
28359 // Create map, create iterator, delete entry, preview.
28360 v8::Local<v8::Object> iterator = CompileRun(
28361 "var map = new Map();"
28362 "var key = {}; map.set(key, 1);"
28363 "map.set({}, 2); map.set({}, 3);"
28364 "map.values()")
28365 ->ToObject(context)
28366 .ToLocalChecked();
28367 CompileRun("map.delete(key);");
28368 bool is_key;
28369 v8::Local<v8::Array> entries =
28370 iterator->PreviewEntries(&is_key).ToLocalChecked();
28371 CHECK(!is_key);
28372 CHECK_EQ(2, entries->Length());
28373 CHECK_EQ(2, entries->Get(context, 0)
28374 .ToLocalChecked()
28375 ->Int32Value(context)
28376 .FromJust());
28377 CHECK_EQ(3, entries->Get(context, 1)
28378 .ToLocalChecked()
28379 ->Int32Value(context)
28380 .FromJust());
28381 }
28382 {
28383 // Create map, create iterator, delete entry, iterate, preview.
28384 v8::Local<v8::Object> iterator = CompileRun(
28385 "var map = new Map();"
28386 "var key = {}; map.set(key, 1);"
28387 "map.set({}, 2); map.set({}, 3);"
28388 "var it = map.values(); it")
28389 ->ToObject(context)
28390 .ToLocalChecked();
28391 CompileRun("map.delete(key); it.next();");
28392 bool is_key;
28393 v8::Local<v8::Array> entries =
28394 iterator->PreviewEntries(&is_key).ToLocalChecked();
28395 CHECK(!is_key);
28396 CHECK_EQ(1, entries->Length());
28397 CHECK_EQ(3, entries->Get(context, 0)
28398 .ToLocalChecked()
28399 ->Int32Value(context)
28400 .FromJust());
28401 }
28402 {
28403 // Create map, create iterator, delete entry, iterate until empty, preview.
28404 v8::Local<v8::Object> iterator = CompileRun(
28405 "var map = new Map();"
28406 "var key = {}; map.set(key, 1);"
28407 "map.set({}, 2); map.set({}, 3);"
28408 "var it = map.values(); it")
28409 ->ToObject(context)
28410 .ToLocalChecked();
28411 CompileRun("map.delete(key); it.next(); it.next();");
28412 bool is_key;
28413 v8::Local<v8::Array> entries =
28414 iterator->PreviewEntries(&is_key).ToLocalChecked();
28415 CHECK(!is_key);
28416 CHECK_EQ(0, entries->Length());
28417 }
28418 {
28419 // Create map, create iterator, delete entry, iterate, trigger rehash,
28420 // preview.
28421 v8::Local<v8::Object> iterator = CompileRun(
28422 "var map = new Map();"
28423 "var key = {}; map.set(key, 1);"
28424 "map.set({}, 2); map.set({}, 3);"
28425 "var it = map.values(); it")
28426 ->ToObject(context)
28427 .ToLocalChecked();
28428 CompileRun("map.delete(key); it.next();");
28429 CompileRun("for (var i = 4; i < 20; i++) map.set({}, i);");
28430 bool is_key;
28431 v8::Local<v8::Array> entries =
28432 iterator->PreviewEntries(&is_key).ToLocalChecked();
28433 CHECK(!is_key);
28434 CHECK_EQ(17, entries->Length());
28435 for (uint32_t i = 0; i < 17; i++) {
28436 CHECK_EQ(i + 3, entries->Get(context, i)
28437 .ToLocalChecked()
28438 ->Int32Value(context)
28439 .FromJust());
28440 }
28441 }
28442}
28443
28444TEST(PreviewMapKeysIteratorEntriesWithDeleted) {
28445 LocalContext env;
28446 v8::HandleScope handle_scope(env->GetIsolate());
28447 v8::Local<v8::Context> context = env.local();
28448
28449 {
28450 // Create map, delete entry, create iterator, preview.
28451 v8::Local<v8::Object> iterator = CompileRun(
28452 "var map = new Map();"
28453 "var key = 1; map.set(key, {});"
28454 "map.set(2, {}); map.set(3, {});"
28455 "map.delete(key);"
28456 "map.keys()")
28457 ->ToObject(context)
28458 .ToLocalChecked();
28459 bool is_key;
28460 v8::Local<v8::Array> entries =
28461 iterator->PreviewEntries(&is_key).ToLocalChecked();
28462 CHECK(!is_key);
28463 CHECK_EQ(2, entries->Length());
28464 CHECK_EQ(2, entries->Get(context, 0)
28465 .ToLocalChecked()
28466 ->Int32Value(context)
28467 .FromJust());
28468 CHECK_EQ(3, entries->Get(context, 1)
28469 .ToLocalChecked()
28470 ->Int32Value(context)
28471 .FromJust());
28472 }
28473 {
28474 // Create map, create iterator, delete entry, preview.
28475 v8::Local<v8::Object> iterator = CompileRun(
28476 "var map = new Map();"
28477 "var key = 1; map.set(key, {});"
28478 "map.set(2, {}); map.set(3, {});"
28479 "map.keys()")
28480 ->ToObject(context)
28481 .ToLocalChecked();
28482 CompileRun("map.delete(key);");
28483 bool is_key;
28484 v8::Local<v8::Array> entries =
28485 iterator->PreviewEntries(&is_key).ToLocalChecked();
28486 CHECK(!is_key);
28487 CHECK_EQ(2, entries->Length());
28488 CHECK_EQ(2, entries->Get(context, 0)
28489 .ToLocalChecked()
28490 ->Int32Value(context)
28491 .FromJust());
28492 CHECK_EQ(3, entries->Get(context, 1)
28493 .ToLocalChecked()
28494 ->Int32Value(context)
28495 .FromJust());
28496 }
28497 {
28498 // Create map, create iterator, delete entry, iterate, preview.
28499 v8::Local<v8::Object> iterator = CompileRun(
28500 "var map = new Map();"
28501 "var key = 1; map.set(key, {});"
28502 "map.set(2, {}); map.set(3, {});"
28503 "var it = map.keys(); it")
28504 ->ToObject(context)
28505 .ToLocalChecked();
28506 CompileRun("map.delete(key); it.next();");
28507 bool is_key;
28508 v8::Local<v8::Array> entries =
28509 iterator->PreviewEntries(&is_key).ToLocalChecked();
28510 CHECK(!is_key);
28511 CHECK_EQ(1, entries->Length());
28512 CHECK_EQ(3, entries->Get(context, 0)
28513 .ToLocalChecked()
28514 ->Int32Value(context)
28515 .FromJust());
28516 }
28517 {
28518 // Create map, create iterator, delete entry, iterate until empty, preview.
28519 v8::Local<v8::Object> iterator = CompileRun(
28520 "var map = new Map();"
28521 "var key = 1; map.set(key, {});"
28522 "map.set(2, {}); map.set(3, {});"
28523 "var it = map.keys(); it")
28524 ->ToObject(context)
28525 .ToLocalChecked();
28526 CompileRun("map.delete(key); it.next(); it.next();");
28527 bool is_key;
28528 v8::Local<v8::Array> entries =
28529 iterator->PreviewEntries(&is_key).ToLocalChecked();
28530 CHECK(!is_key);
28531 CHECK_EQ(0, entries->Length());
28532 }
28533}
28534
28535namespace {
28536static v8::Isolate* isolate_1;
28537static v8::Isolate* isolate_2;
28538v8::Persistent<v8::Context> context_1;
28539v8::Persistent<v8::Context> context_2;
28540
28541static void CallIsolate1(const v8::FunctionCallbackInfo<v8::Value>& args) {
28542 v8::Isolate::Scope isolate_scope(isolate_1);
28543 v8::HandleScope handle_scope(isolate_1);
28544 v8::Local<v8::Context> context =
28545 v8::Local<v8::Context>::New(isolate_1, context_1);
28546 v8::Context::Scope context_scope(context);
28547 CompileRun("f1() //# sourceURL=isolate1b");
28548}
28549
28550static void CallIsolate2(const v8::FunctionCallbackInfo<v8::Value>& args) {
28551 v8::Isolate::Scope isolate_scope(isolate_2);
28552 v8::HandleScope handle_scope(isolate_2);
28553 v8::Local<v8::Context> context =
28554 v8::Local<v8::Context>::New(isolate_2, context_2);
28555 v8::Context::Scope context_scope(context);
28556 reinterpret_cast<i::Isolate*>(isolate_2)->heap()->CollectAllGarbage(
28557 i::Heap::kNoGCFlags, i::GarbageCollectionReason::kTesting,
28558 v8::kGCCallbackFlagForced);
28559 CompileRun("f2() //# sourceURL=isolate2b");
28560}
28561
28562} // anonymous namespace
28563
28564UNINITIALIZED_TEST(NestedIsolates) {
28565#ifdef VERIFY_HEAP
28566 i::FLAG_verify_heap = true;
28567#endif // VERIFY_HEAP
28568 // Create two isolates and set up C++ functions via function templates that
28569 // call into the other isolate. Recurse a few times, trigger GC along the way,
28570 // and finally capture a stack trace. Check that the stack trace only includes
28571 // frames from its own isolate.
28572 v8::Isolate::CreateParams create_params;
28573 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
28574 isolate_1 = v8::Isolate::New(create_params);
28575 isolate_2 = v8::Isolate::New(create_params);
28576
28577 {
28578 v8::Isolate::Scope isolate_scope(isolate_1);
28579 v8::HandleScope handle_scope(isolate_1);
28580
28581 v8::Local<v8::Context> context = v8::Context::New(isolate_1);
28582 v8::Context::Scope context_scope(context);
28583
28584 v8::Local<v8::FunctionTemplate> fun_templ =
28585 v8::FunctionTemplate::New(isolate_1, CallIsolate2);
28586 fun_templ->SetClassName(v8_str(isolate_1, "call_isolate_2"));
28587 Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28588 CHECK(context->Global()
28589 ->Set(context, v8_str(isolate_1, "call_isolate_2"), fun)
28590 .FromJust());
28591 CompileRun(
28592 "let c = 0;"
28593 "function f1() {"
28594 " c++;"
28595 " return call_isolate_2();"
28596 "} //# sourceURL=isolate1a");
28597 context_1.Reset(isolate_1, context);
28598 }
28599
28600 {
28601 v8::Isolate::Scope isolate_scope(isolate_2);
28602 v8::HandleScope handle_scope(isolate_2);
28603
28604 v8::Local<v8::Context> context = v8::Context::New(isolate_2);
28605 v8::Context::Scope context_scope(context);
28606
28607 v8::Local<v8::FunctionTemplate> fun_templ =
28608 v8::FunctionTemplate::New(isolate_2, CallIsolate1);
28609 fun_templ->SetClassName(v8_str(isolate_2, "call_isolate_1"));
28610 Local<Function> fun = fun_templ->GetFunction(context).ToLocalChecked();
28611
28612 CHECK(context->Global()
28613 ->Set(context, v8_str(isolate_2, "call_isolate_1"), fun)
28614 .FromJust());
28615 CompileRun(
28616 "let c = 4;"
28617 "let result = undefined;"
28618 "function f2() {"
28619 " if (c-- > 0) return call_isolate_1();"
28620 " else result = new Error().stack;"
28621 "} //# sourceURL=isolate2a");
28622 context_2.Reset(isolate_2, context);
28623
28624 v8::Local<v8::String> result =
28625 CompileRun("f2(); result //# sourceURL=isolate2c")
28626 ->ToString(context)
28627 .ToLocalChecked();
28628 v8::Local<v8::String> expectation = v8_str(isolate_2,
28629 "Error\n"
28630 " at f2 (isolate2a:1:104)\n"
28631 " at isolate2b:1:1\n"
28632 " at f2 (isolate2a:1:71)\n"
28633 " at isolate2b:1:1\n"
28634 " at f2 (isolate2a:1:71)\n"
28635 " at isolate2b:1:1\n"
28636 " at f2 (isolate2a:1:71)\n"
28637 " at isolate2b:1:1\n"
28638 " at f2 (isolate2a:1:71)\n"
28639 " at isolate2c:1:1");
28640 CHECK(result->StrictEquals(expectation));
28641 }
28642
28643 {
28644 v8::Isolate::Scope isolate_scope(isolate_1);
28645 v8::HandleScope handle_scope(isolate_1);
28646 v8::Local<v8::Context> context =
28647 v8::Local<v8::Context>::New(isolate_1, context_1);
28648 v8::Context::Scope context_scope(context);
28649 ExpectInt32("c", 4);
28650 }
28651
28652 isolate_1->Dispose();
28653 isolate_2->Dispose();
28654}
28655